diff options
author | Nicholas Corgan <nick.corgan@ettus.com> | 2015-06-30 13:36:15 -0700 |
---|---|---|
committer | Martin Braun <martin.braun@ettus.com> | 2015-07-09 09:13:41 -0700 |
commit | d9656de88f7af77b39bfe9985f0ac7c623932d71 (patch) | |
tree | ed83e5b72fa8c2afd25410ce6e1bece5621896cd /firmware/octoclock/octoclock_r4 | |
parent | 1449687bb41e9cd39cc3d94413c993a1ec553251 (diff) | |
download | uhd-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.txt | 2 | ||||
-rw-r--r-- | firmware/octoclock/octoclock_r4/octoclock_r4_main.c | 152 |
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(); } } |