aboutsummaryrefslogtreecommitdiffstats
path: root/firmware/octoclock/octoclock_r4
diff options
context:
space:
mode:
authorNicholas Corgan <nick.corgan@ettus.com>2015-06-30 13:36:15 -0700
committerMartin Braun <martin.braun@ettus.com>2015-07-09 09:13:41 -0700
commitd9656de88f7af77b39bfe9985f0ac7c623932d71 (patch)
treeed83e5b72fa8c2afd25410ce6e1bece5621896cd /firmware/octoclock/octoclock_r4
parent1449687bb41e9cd39cc3d94413c993a1ec553251 (diff)
downloaduhd-d9656de88f7af77b39bfe9985f0ac7c623932d71.tar.gz
uhd-d9656de88f7af77b39bfe9985f0ac7c623932d71.tar.bz2
uhd-d9656de88f7af77b39bfe9985f0ac7c623932d71.zip
OctoClock bugfixes
* Bumped compatibility version to 3 * firmware: Ethernet, clkdist bugfixes * lib: fixed invalid rev detection
Diffstat (limited to 'firmware/octoclock/octoclock_r4')
-rw-r--r--firmware/octoclock/octoclock_r4/CMakeLists.txt2
-rw-r--r--firmware/octoclock/octoclock_r4/octoclock_r4_main.c152
2 files changed, 131 insertions, 23 deletions
diff --git a/firmware/octoclock/octoclock_r4/CMakeLists.txt b/firmware/octoclock/octoclock_r4/CMakeLists.txt
index c3559d8d4..9223721c8 100644
--- a/firmware/octoclock/octoclock_r4/CMakeLists.txt
+++ b/firmware/octoclock/octoclock_r4/CMakeLists.txt
@@ -43,7 +43,7 @@ add_custom_target(
)
add_custom_target(
upload_r4
- ${AVRDUDE} -p atmega128 -c ${PROGRAMMER} -P usb -U efuse:w:0xFF:m -U hfuse:w:0x81:m -U lfuse:w:0xFF:m -U flash:w:octoclock_r4_fw.hex:i
+ ${AVRDUDE} -p atmega128 -c ${PROGRAMMER} -P usb -U efuse:w:0xFF:m -U hfuse:w:0x81:m -U lfuse:w:0xEF:m -U flash:w:octoclock_r4_fw.hex:i
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
DEPENDS octoclock_r4_fw_hex
COMMENT "Uploading OctoClock firmware to device with ${PROGRAMMER}"
diff --git a/firmware/octoclock/octoclock_r4/octoclock_r4_main.c b/firmware/octoclock/octoclock_r4/octoclock_r4_main.c
index 5e8e6d09b..b1df34195 100644
--- a/firmware/octoclock/octoclock_r4/octoclock_r4_main.c
+++ b/firmware/octoclock/octoclock_r4/octoclock_r4_main.c
@@ -36,7 +36,7 @@
* JTAGEN = [X]
* SPIEN = [X]
* EESAVE = [X]
- * BOOTSZ = 4096W_F000
+ * BOOTSZ = 4095W_F000
* BOOTRST = [ ]
* CKOPT = [X]
* BODLEVEL = 2V7
@@ -49,57 +49,165 @@
*
*/
+#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include <avr/eeprom.h>
+#include <avr/interrupt.h>
#include <avr/io.h>
+#include <avrlibdefs.h>
#include <octoclock.h>
-#include <clkdist.h>
#include <debug.h>
+#include <clkdist.h>
#include <state.h>
#include <network.h>
#include <usart.h>
-#include <gpsdo.h>
-#include <net/enc28j60.h>
#include <net/udp_handlers.h>
+/*
+ * Timer 3 (16-bit)
+ * * Set input capture trigger to rising edge
+ * * Set prescaler to 1
+ * * Enable overflow interrupt
+ * * Set timer to 0
+ */
+#define TIMER3_INIT() TCCR3B = (1 << ICES3) | (1 << CS30); \
+ ETIMSK |= (1 << TOIE3); \
+ TCNT3 = 0; \
+ ICR3 = 0;
+
+/*
+ * We use TIMER3 as a watchdog timer for external reference
+ * detection. Once a signal is detected, we allow for five
+ * timer overflows (~26 ms) without another signal before
+ * deciding that there is no external reference connected.
+ */
+#define EXT_REF_TIMEOUT 5
+
+static volatile uint16_t num_overflows = 0;
+static uint16_t current_num_overflows = 0;
+static uint16_t prev_num_overflows = 0;
+static uint16_t current_ICR3 = 0;
+static uint16_t prev_ICR3 = 0;
+static ref_t prev_ref = NO_REF;
+static switch_pos_t prev_switch_pos = PREFER_EXTERNAL;
+bool top = false;
+
+ISR(TIMER3_OVF_vect){
+ num_overflows++;
+}
+
/*******************************************************************************
* Main Routine
*******************************************************************************/
int main(void){
- asm("cli");
+ /*
+ * Initializations
+ */
+ cli();
+ // Make sure interrupts belong to us
+ MCUCR = (1<<IVCE);
+ MCUCR = 0;
+
+ // Initialize global variables
+ g_ext_ref_present = false;
+ g_gps_present = false;
+ g_switch_pos = PREFER_INTERNAL;
+ g_ref = NO_REF;
+
+ // Atmega128
setup_atmel_io_ports();
- network_init();
- #ifndef DEBUG
- asm("sei");
- #endif
+ // Reset ClkDist chip
+ reset_TI_CDCE18005();
- init_udp_listeners();
- register_udp_listener(OCTOCLOCK_UDP_CTRL_PORT, handle_udp_ctrl_packet);
+ // GPSDO communication
+ usart_init();
+
+ // Ethernet stack
+ network_init();
+ register_udp_listener(OCTOCLOCK_UDP_CTRL_PORT, handle_udp_ctrl_packet);
register_udp_listener(OCTOCLOCK_UDP_GPSDO_PORT, handle_udp_gpsdo_packet);
- DEBUG_INIT(); // Does nothing when not in debug mode
- DEBUG_LOG(" "); //Force a newline between runs
- usart_init();
+ // Timers
+ TIMER1_INIT(); // Network
+ TIMER3_INIT(); // External reference check
+
+ // Debug (does nothing when not in debug mode)
+ DEBUG_INIT();
+ DEBUG_LOG(" "); // Force a newline between runs
+
+ leds_off();
+
+ sei();
+
+ // Check if GPS present (should only need to happen once)
+ g_gps_present = (PIND & (1<<DDD4));
+
+ // State of previous iteration
+ prev_ref = NO_REF;
+ prev_switch_pos = PREFER_EXTERNAL;
+ cli();
+ prev_ICR3 = ICR3;
+ sei();
+ prev_num_overflows = 0;
+
+ /*
+ * Main loop
+ */
+ while(true){
+ // Check switch position
+ g_switch_pos = (PINC & (1<<DDC1)) ? PREFER_EXTERNAL : PREFER_INTERNAL;
+
+ /*
+ * Check input capture pin for external reference detection.
+ *
+ * 16-bit reads could be corrupted during an interrupt, so
+ * disable interrupts for safety.
+ */
+ cli();
+ current_ICR3 = ICR3;
+ current_num_overflows = num_overflows;
+ sei();
+
+ // Signal detected, reset timer
+ if(current_ICR3 != prev_ICR3){
+ cli();
+ TCNT3 = 0;
+ num_overflows = 0;
+ sei();
+ g_ext_ref_present = true;
+ }
+
+ // Timeout, no external reference detected
+ if(current_num_overflows >= EXT_REF_TIMEOUT){
+ g_ext_ref_present = false;
+ }
- //Set initial ClkDist and front panel settings
- led(Middle,true);
- setup_TI_CDCE18005(Primary_GPS); // 10 MHz from Internal Source
+ // Determine and set reference based on state
+ if(!g_gps_present && !g_ext_ref_present) g_ref = NO_REF;
+ else if(g_gps_present && !g_ext_ref_present) g_ref = INTERNAL;
+ else if(!g_gps_present && g_ext_ref_present) g_ref = EXTERNAL;
+ else g_ref = (g_switch_pos == PREFER_INTERNAL) ? INTERNAL : EXTERNAL;
- led(Top,true);
- PORTA |= (1<<PA6); // PPS from Internal source
+ if((g_ref != prev_ref) || (g_switch_pos != prev_switch_pos)){
+ if(g_switch_pos == PREFER_INTERNAL) prefer_internal();
+ else prefer_external();
+ }
- TIMER0_INIT();
- TIMER1_INIT();
+ // Record this iteration's state
+ prev_ref = g_ref;
+ prev_switch_pos = g_switch_pos;
+ prev_ICR3 = current_ICR3;
+ prev_num_overflows = current_num_overflows;
- while(true) {
+ // Handle incoming Ethernet packets
network_check();
}
}