aboutsummaryrefslogtreecommitdiffstats
path: root/firmware/octoclock/OctoClock.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/octoclock/OctoClock.c')
-rw-r--r--firmware/octoclock/OctoClock.c1103
1 files changed, 424 insertions, 679 deletions
diff --git a/firmware/octoclock/OctoClock.c b/firmware/octoclock/OctoClock.c
index d81a93fc3..f73c30885 100644
--- a/firmware/octoclock/OctoClock.c
+++ b/firmware/octoclock/OctoClock.c
@@ -1,844 +1,589 @@
/*
- * OctoClock.c
- *
- * V1.00 -- May 2013
- *
- *
- * V1.03 -- Correct the switch to be UP for Internal and DOWN for External
- * This means that the bat handle "points at" (sort of) the lower-left LED, which
- * is the "STATUS" LED, which gets lit up when the external 10 MHz is present
- * The "10 MHz Signal Detect" code accepts a very wide range of "10 MHz" signals
- * 23 April 2013
- *
+ * Copyright 2013 Ettus Research LLC
*
- * V1.02 -- Make LEDs consistent with Chassis - Top LED is INTERNAL; middle is EXTERNAL; bottom is STATUS
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
*
- * STATUS is ON if the 10 MHz external input is present. 19 April 2013
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
*
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Welcome to the firmware code for the USRP Octoclock accessory product!
*
- * V1.01: Modify TI chip initialization to be in differentail mode
- * which allows 10 MHz input down to 0.1 Volts according to the datasheet.
+ * Notes regarding this firmware:
+ * NOT in M103 compatibility mode
+ * no WDT
+ * CKOPT full rail-to-rail
+ * xtal osc
+ * 16K CK (16K clock cycles)
+ * additional delay 65ms for Crystal Oscillator
+ * slowly rising power
*
+ * These settings are very conservative. If a lower power oscillator is
+ * required, change CKOPT to '1' (UNPROGRAMMED).
*
- * New Version that supports CLOCK board Version 1.0
+ * M103C = [ ]
+ * WDTON = [ ]
+ * OCDEN = [ ]
+ * JTAGEN = [X]
+ * SPIEN = [X]
+ * EESAVE = [ ]
+ * BOOTSZ = 4096W_F000
+ * BOOTRST = [ ]
+ * CKOPT = [X]
+ * BODLEVEL = 2V7
+ * BODEN = [ ]
+ * SUT_CKSEL = EXTHIFXTALRES_16KCK_64MS
*
- * Author: Michael@Cheponis.Com with code borrowed liberally from
- * previous AVR projects
+ * EXTENDED = 0xFF (valid)
+ * HIGH = 0x89 (valid)
+ * LOW = 0xFF (valid)
*
*/
-/*
- * Copyright 2013 Ettus Research LLC
- */
-
-
-
-
-
-
-/* CLKSEL0 = 1 SUT1..0 is 11 CKOPT = 0 CKSEL3..1 is 111 => big output swing, long time to start up */
-/*
-
-NOT in M103 compatibility mode, no WDT, CKOPT full rail-to-rail xtal osc, 16K CK (16K clock cycles),
-additional delay 65ms for Crystal Oscillator, slowly rising power
-
-Very conservative settings; if lower power osc required, change CKOPT to '1' (UNPROGRAMMED) or, if you will,
-CKOPT = [ ]
-
-
-
-M103C = [ ]
-WDTON = [ ]
-OCDEN = [ ]
-JTAGEN = [X]
-SPIEN = [X]
-EESAVE = [ ]
-BOOTSZ = 4096W_F000
-BOOTRST = [ ]
-CKOPT = [X]
-BODLEVEL = 2V7
-BODEN = [ ]
-SUT_CKSEL = EXTHIFXTALRES_16KCK_64MS
-
-EXTENDED = 0xFF (valid)
-HIGH = 0x89 (valid)
-LOW = 0xFF (valid)
-
-
-*/
-
-// No interrupts are required
-
-#include "OctoClock-io.h"
-
+#include <stdint.h>
+#include <stdbool.h>
#include <avr/io.h>
#include <avr/interrupt.h>
-
#ifdef On
#undef On
#endif
#ifdef Off
-#undef OFf
+#undef Off
#endif
-#define Off (0)
-#define On (!Off)
-
+#define Off (0)
+#define On (!Off)
-// Important for the Serial Port, not used at the moment
-#define FOSC (7372800)
-#define BAUD (115200)
+#ifdef FALSE
+#undef FALSE
+#endif
-#define MYUBRR FOSC/16/BAUD-1
+#ifdef TRUE
+#undef TRUE
+#endif
+#define FALSE (0)
+#define TRUE (!FALSE)
-#define wait() for(u16 u=14000; u; u--) asm("nop");
+// Important for the Serial Port, not used at the moment
+#define FOSC (7372800)
+#define BAUD (115200)
+#define MYUBRR FOSC/16/BAUD-1
-enum LEDs {Top,Middle,Bottom}; // Top is 0, Mid is 1, and Bottom is 2
+#define wait() for(uint16_t u=14000; u; u--) asm("nop");
-void
-led(enum LEDs which, int turn_it_on){
-
- u8 LED = 0x20 << which; // selects the proper bit
-
- if(turn_it_on)
- PORTC |= LED;
- else
- PORTC &= ~LED;
-
-}
+#define CLK (PA0) // Shift by 0 bits
+#define CE_ (PA1) // Is really the "Chip Disable" signal, as Hi disables SPI
+#define MOSI (PA2)
+#define MISO (PA3)
+#define PD_ (PA4)
+#define SYNC_ (PA5)
+// Top is 0, Mid is 1, and Bottom is 2
+enum LEDs {Top, Middle, Bottom};
enum TI_Input_10_MHz {Primary_GPS, Secondary_Ext};
-void setup_TI_CDCE18005(enum TI_Input_10_MHz);
-
-
+enum Levels {Lo, Hi};
+void led(enum LEDs which, int turn_it_on) {
-/*****************************************************************************************
+ // selects the proper bit
+ uint8_t LED = 0x20 << which;
- SPI routines
+ if(turn_it_on)
+ PORTC |= LED;
+ else
+ PORTC &= ~LED;
+}
-******************************************************************************************/
+/*******************************************************************************
+* SPI routines
+*******************************************************************************/
+/* All macros evaluate to compile-time constants */
-/* All macros evaluate to compile-time constants */
-
-/* *** helper macros * * */
-
/* turn a numeric literal into a hex constant
- (avoids problems with leading zeros)
- 8-bit constants max value 0x11111111, always fits in unsigned long
+ * (avoids problems with leading zeros)
+ * 8-bit constants max value 0x11111111, always fits in unsigned long
*/
- #define HEX__(n) 0x##n##LU
-
+#define HEX__(n) 0x##n##LU
+
/* 8-bit conversion function */
- #define B8__(x) ((x&0x0000000FLU)?1:0) \
- +((x&0x000000F0LU)?2:0) \
- +((x&0x00000F00LU)?4:0) \
- +((x&0x0000F000LU)?8:0) \
- +((x&0x000F0000LU)?16:0) \
- +((x&0x00F00000LU)?32:0) \
- +((x&0x0F000000LU)?64:0) \
- +((x&0xF0000000LU)?128:0)
-
-// Damn, that is SERIOUS magic ... ;-) Yes, I know how it works
-// but it's pretty cool....
-
-
-/* *** user macros *** */
-
-/* for upto 8-bit binary constants */
- #define Bits_8(d) ((unsigned char)B8__(HEX__(d)))
-
-/* for upto 16-bit binary constants, MSB first */
- #define Bits_16(dmsb,dlsb) (((unsigned short)Bits_8(dmsb)<<8) \
- + Bits_8(dlsb))
-
-/* for upto 32-bit binary constants, MSB first */
- #define Bits_32(dmsb,db2,db3,dlsb) (((unsigned long)Bits_8(dmsb)<<24) \
- + ((unsigned long)Bits_8(db2)<<16) \
- + ((unsigned long)Bits_8(db3)<<8) \
- + Bits_8(dlsb))
-
+#define B8__(x) ((x&0x0000000FLU)?1:0) \
+ +((x&0x000000F0LU)?2:0) \
+ +((x&0x00000F00LU)?4:0) \
+ +((x&0x0000F000LU)?8:0) \
+ +((x&0x000F0000LU)?16:0) \
+ +((x&0x00F00000LU)?32:0) \
+ +((x&0x0F000000LU)?64:0) \
+ +((x&0xF0000000LU)?128:0)
+
+/* for up to 8-bit binary constants */
+#define Bits_8(d) ((unsigned char)B8__(HEX__(d)))
+
+/* for up to 16-bit binary constants, MSB first */
+#define Bits_16(dmsb,dlsb) (((unsigned short)Bits_8(dmsb)<<8) \
+ + Bits_8(dlsb))
+
+/* for up to 32-bit binary constants, MSB first */
+#define Bits_32(dmsb,db2,db3,dlsb) (((unsigned long)Bits_8(dmsb)<<24) \
+ + ((unsigned long)Bits_8(db2)<<16) \
+ + ((unsigned long)Bits_8(db3)<<8) \
+ + Bits_8(dlsb))
+
/* Sample usage:
- Bits_8(01010101) = 85
- Bits_16(10101010,01010101) = 43605
- Bits_32(10000000,11111111,10101010,01010101) = 2164238933
+ * Bits_8(01010101) = 85
+ * Bits_16(10101010,01010101) = 43605
+ * Bits_32(10000000,11111111,10101010,01010101) = 2164238933
*/
-
-
-enum CDCE18005 {Reg0, Reg1, Reg2, Reg3, Reg4, Reg5, Reg6, Reg7, Reg8_Status_Control,
- Read_Command=0xE, RAM_EEPROM_Unlock=0x1F, RAM_EEPROM_Lock=0x3f}
- TI_CDCE18005;
-
-// Table of 32-bit constants to be written to the TI chip's registers.
-
-// Damn, inconsistent data sheet! Special settigns see p35 of TI datasheet
+enum CDCE18005 {
+ Reg0, Reg1, Reg2, Reg3, Reg4, Reg5, Reg6, Reg7,
+ Reg8_Status_Control,
+ Read_Command=0xE,
+ RAM_EEPROM_Unlock=0x1F,
+ RAM_EEPROM_Lock=0x3f
+} TI_CDCE18005;
+// Table of 32-bit constants to be written to the TI chip's registers. These are
+// from the "Special Settings" on Page 35 of the datasheet.
// For the GPS's 10 MHz output
-u32 table_Pri_Ref[] = {
-
- Bits_32(1,01010100,0,0), // Reg 0
- Bits_32(1,01010100,0,0), // Outputs LVCMOS Positive&Negative Active - Non-inverted
- Bits_32(1,01010100,0,0),
- Bits_32(1,01010100,0,0),
- Bits_32(1,01010100,0,0), // All have output divide ratio to be 1; Aux Output is OFF
-
- Bits_32(0,0,1001,11010100), // Reg 5 LVCMOS in; p31 of TI datasheet
-
- Bits_32(1,0,0010000,0), // Reg 6 // SCAS863A – NOVEMBER 2008 – REVISED JUNE 2011
-
- Bits_32(1,01000000,0,0), // Reg 7
- // 76543210
- Bits_32(0,0,1,10000000) // Reg8 Status/Control
+uint32_t table_Pri_Ref[] = {
+ Bits_32(1,01010100,0,0), // Reg 0
+ Bits_32(1,01010100,0,0), // Outputs LVCMOS Positive&Negative Active - Non-inverted
+ Bits_32(1,01010100,0,0),
+ Bits_32(1,01010100,0,0),
+ Bits_32(1,01010100,0,0), // All have output divide ratio to be 1; Aux Output is OFF
+ Bits_32(0,0,1001,11010100), // Reg 5 LVCMOS in; p31 of TI datasheet
+ Bits_32(1,0,0010000,0), // Reg 6 // SCAS863A – NOVEMBER 2008 – REVISED JUNE 2011
+ Bits_32(1,01000000,0,0), // Reg 7
+ Bits_32(0,0,1,10000000) // Reg8 Status/Control
};
-
-// Looks like it's doing the correct thing re: SPI interface
-// This is *definitely* AC coupled. I removed those resistors to +3.3 and ground
-// signal looked no different with differential measurement. Added 240+470 to
-// center tap of secondary side to bias up to approx 1.2V for proper LVDS
-//
-// For the External 10 MHz input LVDS with external termination -- Effectively DC coupled
-
-u32 table_Sec_Ref[] = {
- Bits_32(0001,01010100,0,100000),// Reg 0 -- use Secondary Reference for all channels
- Bits_32(0001,01010100,0,100000),// Outputs LVCMOS Positive&Negative Active - Non-inverted
- Bits_32(0001,01010100,0,100000),
- Bits_32(0001,01010100,0,100000),
- Bits_32(0001,01010100,0,100000),
-
-// Bits_32(0,0,00001000,10010111), // Reg 5 LVDS with External Termination p32 of TI datasheet
-// Bits_32(0,0,00001000,11010111), // Reg 5 LVDS with INTERNAL Termination p32 of TI datasheet
-
-// May 2013 -- Turn OFF the LVDS Safe Mode, as it supposedly causes input thresholds to be increased.
-
-// Bits_32(0,0,1001,10011011), // Reg 5, try again. Pretty soon, try new board...
-
- Bits_32(0,0,1,10011011), // Reg 5, Failsafe OFF b5.11 = 0
-
-
-// Bits_32(0,0,1001,11011011), // Reg 5, try again. Pretty soon, try new board...
- // Try with DC input termination; bit 6 is a "1" 2013 March
- // Seems to not work correctly.
-
-
-// Bits_32(1,0,0000000,0), // Reg 6; note that 6.12 must be 1 for LVDS w/External Termination, 0 int
-// Bits_32(1,0,0000000,0), // Reg 6; try Internal and DC coupling
- Bits_32(1,0,10000,0), // Reg 6; try again
-
- Bits_32(1,01000000,0,0),
- Bits_32(0,0,1,10000000) // Reg8 Status/Control
+// For the External 10 MHz input LVDS with external termination,
+// Effectively DC coupled
+uint32_t table_Sec_Ref[] = {
+ Bits_32(0001,01010100,0,100000), // Reg 0 -- use Secondary Reference for all channels
+ Bits_32(0001,01010100,0,100000), // Outputs LVCMOS Positive&Negative Active - Non-inverted
+ Bits_32(0001,01010100,0,100000),
+ Bits_32(0001,01010100,0,100000),
+ Bits_32(0001,01010100,0,100000),
+ Bits_32(0,0,1,10011011), // Reg 5, Failsafe OFF b5.11 = 0
+ Bits_32(1,0,10000,0), // Reg 6; try again
+ Bits_32(1,01000000,0,0),
+ Bits_32(0,0,1,10000000) // Reg8 Status/Control
};
-//; Table 19 conflicts with Tables 5 thru 9 - in how LVCMOS outputs are defined
+// Table 19 conflicts with Tables 5 thru 9 - in how LVCMOS outputs are defined
// extra error in Table 9, for bits 24 and 25
-//
-// Could combine these into just table[][] with 1st subscript being 0 or 1 for Primary or Secondary
-// Maybe want to to that.
+int table_size = sizeof (table_Pri_Ref) / sizeof(uint32_t);
-int table_size = sizeof (table_Pri_Ref) / sizeof(u32);
-//int table_size = 1; // Testing read and write of Register 0 -- don't want excess SPI transactions
-//NOTE!!! Still need to shift left by 4 and OR in register, as defined in TI_CDCE18005 enum, above.
+void set_bit(uint8_t bit_number, enum Levels bit_value) {
-
-enum Levels {Lo, Hi};
-
-#define CLK (PA0) // Shift by 0 bits (PA.0)
-#define CE_ (PA1) // Is really the "Chip Disable" signal, as Hi disables SPI
-#define MOSI (PA2)
-#define MISO (PA3)
-#define PD_ (PA4)
-#define SYNC_ (PA5)
-
-void
-set_bit(u8 bit_number, enum Levels bit_value){
-
- if(bit_value == Hi)
- PORTA |= 1<<bit_number;
- else
- PORTA &= ~ (1<<bit_number);
+ if(bit_value == Hi)
+ PORTA |= 1<<bit_number;
+ else
+ PORTA &= ~ (1<<bit_number);
}
+bool get_bit(uint8_t bit_number) {
+ asm("nop");
-bool
-get_bit(u8 bit_number){
- asm("nop");
-
- u8 portA = PINA; // Maybe something is strange they way PORTA is read?
-// USART_Transmit( hex_table [0xf & (portA >> 4)], Control );
-// USART_Transmit( hex_table [0xf & portA], Control );
-// USART_Transmit(CR, Control); USART_Transmit(LF,Control);
-
- return (portA & 1<< bit_number) > 0 ? TRUE : FALSE;
- //return (portA & 8) != 0; // It's always MISO, so nail it for the moment
+ uint8_t portA = PINA;
+ return (portA & 1<< bit_number) > 0 ? TRUE : FALSE;
}
-
-void
-send_SPI(u32 bits){
// Send 32 bits to TI chip, LSB first.
-// Don't worry about reading any bits back at this
-// time, although for production, may want to do that
-// as an error-check / integrity check.
+// Don't worry about reading any bits back at this time
+void send_SPI(uint32_t bits) {
+
+ // Basically, when the clock is low, one can set MOSI to anything, as it's
+ // ignored.
+ set_bit(CE_, Lo); // Start SPI transaction with TI chip
+
+ // Send each bit, LSB first, add a bit of delay before the clock, and then
+ // toggle the clock line.
+ for (uint8_t i=0; i<32; i++) {
+ set_bit(MOSI, ((bits & (1UL<<i)) ? Hi : Lo) );
+ asm("nop");
+ set_bit(CLK, Hi);
+ set_bit(CLK, Lo);
+ }
-/*
-#define CLK (PA0) // Shift by 0 bits (PA.0)
-#define CE_ (PA1) // Is really the "Chip Disable" signal, as Hi disables SPI
-#define MOSI (PA2)
-#define MISO (PA3)
-#define PD_ (PA4)
-#define SYNC_ (PA5)
-*/
-
-//Basically, when the clock is low, one can set MOSI to anything, as it's ignored.
-
- set_bit(CE_, Lo); // Start SPI transaction with TI chip
-
- for (u8 i=0; i<32; i++){ // Foreach bit we need to send
- set_bit(MOSI, ((bits & (1UL<<i)) ? Hi : Lo) ); // LSB first
- asm("nop"); // Need a little more delay before L->H on clock; (REALLY?)
- set_bit(CLK, Hi);
- set_bit(CLK, Lo); // Pulse the clock to clock in the bit
- }
-// USART_Transmit(CR, Control); USART_Transmit(LF,Control);
- //set_bit(MOSI, Lo); // Not needed, but keeps all bits zeros except /CE when idle
- set_bit(CE_, Hi); // OK, transaction is over
-// USART_Transmit(CR, Control); USART_Transmit(LF,Control);
+ // OK, transaction is over
+ set_bit(CE_, Hi);
}
-// Takes about 7.6 ms to init all regs (as seen on scope)
-// There is a very interesting phenomenon that is occurring --- The bit-to-bit time
-// at the beginning of transmission is 15 usec. However, as the number of bits
-// shifted to the left increases (as i increases in the for() loop )
-// the time between bits elongates. It's about 37 usec between bits
-// 30 and 31 (the last 2 bits). It's kinda cool, because it's easy to
-// know when the new word begins because the clock pulses will be
-// closer together.
-
-// See if it checks: (15+37)/2 = 26 usec between average bits
-// 32 bits * 9 words * 26 usec = 7.49 ms --- but have to add
-// in the little bit of time that CE_ goes high; so 7.6 ms
-// is a very reasonable number. (Assumes linear increase in
-// time as the number of shifts goes up, which seems to
-// work OK here.)
-//
-// Of course, using a table instead of doing those shifts all the
-// time would fix this; but it (should not) doesn't matter for this
-// SPI interface.
-//
-// So far, the first word looks good, and the beginning of writing
-// Register 1 also looks good.
-//
+void reset_TI_CDCE18005() {
+ // First, reset the chip. Or, if you will, pull /SYNC low then high
+ set_bit(CE_, Hi);
+ set_bit(PD_, Lo);
+ wait();
+ // Out of Power Down state
+ set_bit(PD_, Hi);
+ wait();
+ set_bit(SYNC_, Lo);
+ wait();
+ set_bit(SYNC_, Hi);
-
-
-
-// enum TI_Input_10_MHz {Primary_GPS, Secondary_Ext};
-
-void
-reset_TI_CDCE18005(){
-// First, reset the chip. Or, if you will, pull /SYNC low then high
-set_bit(CE_, Hi);
-set_bit(PD_, Lo);
-wait(); // This should put the EEPROM bits into the RAM -- we don't care, but should init the chip
-
-set_bit(PD_, Hi); // Out of Power Down state
-wait();
-
-set_bit(SYNC_, Lo);
-wait();
-set_bit(SYNC_, Hi);
-
-wait();
-// Now, by gosh, that darn chip ought to be fully enabled!
-}
-
-void
-setup_TI_CDCE18005(enum TI_Input_10_MHz which_input){
- // Send the table of data to init the clock distribution chip. Uses SPI.
- u32 temp;
-
- //reset_TI_CDCE18005(); // This REALLY should not be necessary
-
- if(which_input == Primary_GPS){
-
- for(u8 i=0; i<table_size; i++){
- temp = table_Pri_Ref[i]<<4;
- temp |= i;
- // print_u32(temp); // Debug *mac* -- correct
- send_SPI(temp); // Make sure the register's address is in the LSBs
- }
- }
- else { // is Secondary_Ext -- External 10 MHz input from SMA connector
-
- for(u8 i=0; i<table_size; i++){
- temp = table_Sec_Ref[i]<<4;
- temp |= i;
- send_SPI(temp); // Make sure the register's address is in the LSBs
- }
- }
-}
-u32
-receive_SPI(){
- u32 bits;
-
- bits = 0;
-
- set_bit(CE_, Hi); // Make sure we're inactive
- set_bit(CLK, Lo); // and clk line is inactive, too
- set_bit(MOSI,Lo); // Make our bit output zero, for good measure
-
-
- set_bit(CE_, Lo); // Start SPI transaction with TI chip; MOSI is don't care
-
- for (u8 i=0; i<32; i++){ // Foreach bit we need to get
- bits >>= 1; // get ready for next bit - NOTE: Only do this if we REALLY are putting in another bit
- set_bit(CLK, Hi); // CPU is so slow, it easily meets setup & hold times
- // 76543210
- if( get_bit(MISO) ) bits |= 0x80000000; // because we receive the LSB first
- set_bit(CLK, Lo); // Pulse the clock to clock in the bit
- }
- set_bit(CE_, Hi); // OK, transaction is over
-
- return (u32)(bits >> 4); // Ditch the lower 4 bits, which only contain the address
+ wait();
}
-u32
-get_TI_CDCE18005(enum CDCE18005 which_register){
- u32 get_reg_value;
-
- get_reg_value = 0;
- get_reg_value = (0xf0 & which_register << 4) | Read_Command;
- send_SPI(get_reg_value); // This tells the TI chip to send us the reg. value requested
- return receive_SPI();
-};
+void setup_TI_CDCE18005(enum TI_Input_10_MHz which_input) {
+ // Send the table of data to init the clock distribution chip. Uses SPI.
+ uint32_t temp;
+
+ if(which_input == Primary_GPS) {
+ for(uint8_t i=0; i<table_size; i++){
+ temp = table_Pri_Ref[i]<<4;
+ temp |= i;
+ send_SPI(temp); // Make sure the register's address is in the LSBs
+ }
+ } else {
+ // is Secondary_Ext -- External 10 MHz input from SMA connector
+ for(uint8_t i=0; i<table_size; i++){
+ temp = table_Sec_Ref[i]<<4;
+ temp |= i;
+ // Make sure the register's address is in the LSBs
+ send_SPI(temp);
+ }
+ }
+}
+uint32_t receive_SPI() {
+ uint32_t bits = 0;
-bool
-check_TI_CDCE18005(enum TI_Input_10_MHz which_input, enum CDCE18005 which_register) {
- // USART_Transmit(CR, Control); USART_Transmit(LF,Control); //reset_TI_CDCE18005();
- if(which_input == Primary_GPS){
- u32 read_value = get_TI_CDCE18005(which_register);
- return read_value == table_Pri_Ref[which_register];
- }
- else {
- u32 read_value = get_TI_CDCE18005(which_register);
- return read_value == table_Sec_Ref[which_register];
- }
-};
-// This could obviously be done more elegantly to share more code; but this is
-// simple and easy to understand
+ set_bit(CE_, Hi); // Make sure we're inactive
+ set_bit(CLK, Lo); // and clk line is inactive, too
+ set_bit(MOSI,Lo); // Make our bit output zero, for good measure
+ set_bit(CE_, Lo); // Start SPI transaction with TI chip; MOSI is don't care
+ // For each bit we are receiving, prep, clock in the bit LSB first
+ for (uint8_t i=0; i<32; i++){
+ bits >>= 1;
+ set_bit(CLK, Hi);
+ if( get_bit(MISO) ) bits |= 0x80000000;
+ set_bit(CLK, Lo);
+ }
+ // OK, transaction is over
+ set_bit(CE_, Hi);
+ // Ditch the lower 4 bits, which only contain the address
+ return (uint32_t)(bits >> 4);
+}
+uint32_t get_TI_CDCE18005(enum CDCE18005 which_register){
+ uint32_t get_reg_value = 0;
+ get_reg_value = (0xf0 & which_register << 4) | Read_Command;
+ // This tells the TI chip to send us the reg. value requested
+ send_SPI(get_reg_value);
+ return receive_SPI();
+}
+bool check_TI_CDCE18005(enum TI_Input_10_MHz which_input,
+ enum CDCE18005 which_register) {
+ if(which_input == Primary_GPS){
+ uint32_t read_value = get_TI_CDCE18005(which_register);
+ return read_value == table_Pri_Ref[which_register];
+ } else {
+ uint32_t read_value = get_TI_CDCE18005(which_register);
+ return read_value == table_Sec_Ref[which_register];
+ }
+}
-void
-Setup_Atmel_IO_Ports(){
-
-
-/////////////////////////////////////////////////////////////////////////////
+void Setup_Atmel_IO_Ports() {
/*
* PORT A
- *
- *pin# Sig Our Functional Name
*
- * p51 PA0 CLK_CDCE to U205 pin 24 -- L-->H edge latches MOSI and MISO in CDCE18005
- * p50 PA1 CE_CDCE Low = Chip Enabled for SPI comm to U205 pin 25
- * p49 PA2 MOSI_CDCE Goes to CDCE18005 - U205 pin 23
- * p48 PA3 MISO_CDCE Input Comes from U205 pin 22
- * p47 PA4 PD_CDCE Low = Chip is in Power-Down state; is Hi for normal operation U205 pin 12
- * p46 PA5 SYNC_CDCE Low = Chip is sync'd with interal dividers; Hi for normal operation U205 pin 14
- * p45 PA6 PPS_SEL Low --> PPS_EXT selected; Hi -> PPS_GPS selected; to U203 pin 1
- * p44 PA7 gps_lock Input Comes from M9107 - U206 pin 3
+ * pin# Sig Our Functional Name
+ *
+ * p51 PA0 CLK_CDCE to U205 pin 24 -- L-->H edge latches MOSI and MISO in CDCE18005
+ * p50 PA1 CE_CDCE Low = Chip Enabled for SPI comm to U205 pin 25
+ * p49 PA2 MOSI_CDCE Goes to CDCE18005 - U205 pin 23
+ * p48 PA3 MISO_CDCE Input Comes from U205 pin 22
+ * p47 PA4 PD_CDCE Low = Chip is in Power-Down state; is Hi for normal operation U205 pin 12
+ * p46 PA5 SYNC_CDCE Low = Chip is sync'd with interal dividers; Hi for normal operation U205 pin 14
+ * p45 PA6 PPS_SEL Low --> PPS_EXT selected; Hi -> PPS_GPS selected; to U203 pin 1
+ * p44 PA7 gps_lock Input Comes from M9107 - U206 pin 3
*
*/
-// Bit #: 76543210
-PORTA = Bits_8(00110010); // /pd_cdcd, /sync_code, /ce need to be 1 (disabled) to start
-DDRA = 1<<DDA6 | 1<<DDA5 | 1<<DDA4 | 1<<DDA2 | 1<<DDA1 | 1<<DDA0; //// all bits are outputs, except PA7 (gps_lock) and PA3 (MISO_CDCE) are inputs
+// /pd_cdcd, /sync_code, /ce need to be 1 (disabled) to start
+// all bits are outputs, except PA7 (gps_lock) and PA3 (MISO_CDCE) are inputs
+PORTA = Bits_8(00110010);
+DDRA = 1<<DDA6 | 1<<DDA5 | 1<<DDA4 | 1<<DDA2 | 1<<DDA1 | 1<<DDA0;
-
-
-/////////////////////////////////////////////////////////////////////////////
/*
* Port B
*
- *pin# Sig Our Functional Name
+ * pin# Sig Our Functional Name
*
- * p10 PB0 Ethernet /SEN
- * p11 PB1 Ethernet SCLK
- * p12 PB2 Ethernet MOSI
- * p13 PB3 Ethernet MISO
- * p14 PB4 Not connected, set as output with value 0
- * p15 PB5 Ethernet /RESET -- Set to HI for normal use, weak input
- * p16 PB6 Ethernet /WOL --- Wake on LAN -- set, weak input
- * p17 PB7 Not connected, set as output with value 0
+ * p10 PB0 Ethernet /SEN
+ * p11 PB1 Ethernet SCLK
+ * p12 PB2 Ethernet MOSI
+ * p13 PB3 Ethernet MISO
+ * p14 PB4 Not connected, set as output with value 0
+ * p15 PB5 Ethernet /RESET -- Set to HI for normal use, weak input
+ * p16 PB6 Ethernet /WOL --- Wake on LAN -- set, weak input
+ * p17 PB7 Not connected, set as output with value 0
*
*/
-
-
- PORTB = Bits_8(01100001); // Initial Value is all zeros
- DDRB = 1<<DDB2 | 1<<DDB4 | 1<<DDB7; // MOSI is an output; the Not Connected pins are also outputs
+PORTB = Bits_8(01100001); // Initial Value is all zeros
+DDRB = 1<<DDB2 | 1<<DDB4 | 1<<DDB7; // MOSI is an output; the Not Connected pins are also outputs
-
-/////////////////////////////////////////////////////////////////////////////
/*
* Port C
*
- *pin# Sig Our Functional Name
+ * pin# Sig Our Functional Name
*
- * p34 PC0 Not connected, set as output with value 0
- * p35 PC1 Reference Select Switch INPUT
- * p36 PC2 Not connected, set as output with value 0
- * p37 PC3 Not connected, set as output with value 0
- * p38 PC4 Not connected, set as output with value 0
- * p40 PC5 "Top LED" of D103 3-stack of green LEDs
- * p41 PC6 "Middle LED"
- * p43 PC7 "Bottom LED"
+ * p34 PC0 Not connected, set as output with value 0
+ * p35 PC1 Reference Select Switch INPUT
+ * p36 PC2 Not connected, set as output with value 0
+ * p37 PC3 Not connected, set as output with value 0
+ * p38 PC4 Not connected, set as output with value 0
+ * p40 PC5 "Top LED" of D103 3-stack of green LEDs
+ * p41 PC6 "Middle LED"
+ * p43 PC7 "Bottom LED"
*
*/
-PORTC = 0; // Initial Value is all zeros
-DDRC = ~( 1<<DDC1 ); // All bits are outputs, except PC1. including the 5 Not Connected bits
-
+PORTC = 0; // Initial Value is all zeros
+DDRC = ~( 1<<DDC1 ); // All bits are outputs, except PC1. including the 5 Not Connected bits
-/////////////////////////////////////////////////////////////////////////////
/*
* Port D
*
- *pin# Sig Our Functional Name
+ * pin# Sig Our Functional Name
*
- * p25 PD0 Ethernet /INT input
- * p26 PD1 GPS NMEA bit, output
- * p27 PD2 GPS Serial Out (RXD; INT1) INPUT
- * p28 PD3 GPS Serial In (TXD) OUTPUT
- * p29 PD4 GPS Present, INPUT hi = Present
- * p30 PD5 Not connected, set as output with value 0
- * p31 PD6 Not connected, set as output with value 0
- * p32 PD7 Not connected, set as output with value 0
+ * p25 PD0 Ethernet /INT input
+ * p26 PD1 GPS NMEA bit, output
+ * p27 PD2 GPS Serial Out (RXD; INT1) INPUT
+ * p28 PD3 GPS Serial In (TXD) OUTPUT
+ * p29 PD4 GPS Present, INPUT hi = Present
+ * p30 PD5 Not connected, set as output with value 0
+ * p31 PD6 Not connected, set as output with value 0
+ * p32 PD7 Not connected, set as output with value 0
*
*/
-PORTD = 0; // Initial Value is all zeros
-DDRD = 1<<DDD3;
-
+PORTD = 0; // Initial Value is all zeros
+DDRD = 1<<DDD3;
-/////////////////////////////////////////////////////////////////////////////
/*
* Port E
*
- *pin# Sig Dir Our Functional Name
+ * pin# Sig Dir Our Functional Name
*
- * p2 PE0 In avr_rxd (Also MOSI [PDI] when used for SPI programming of the chip)
- * p3 PE1 Out avr_txd (Also MISO [PDO] when used for SPI programming of the chip)
- * p4 PE2 In avr_cts
- * p5 PE3 Out avr_rts DUE TO MOD, make this an input, too (as we go direct GPSDO to FPGA via level translators)
- * p6 PE4 In PPS_GPS
- * p7 PE5 In PPS_EXT_n
- * p8 PE6 In Not Connected
- * p9 PE7 In Not Connected
+ * p2 PE0 In avr_rxd (Also MOSI [PDI] when used for SPI programming of the chip)
+ * p3 PE1 Out avr_txd (Also MISO [PDO] when used for SPI programming of the chip)
+ * p4 PE2 In avr_cts
+ * p5 PE3 Out avr_rts
+ * p6 PE4 In PPS_GPS
+ * p7 PE5 In PPS_EXT_n
+ * p8 PE6 In Not Connected
+ * p9 PE7 In Not Connected
*
*/
+
PORTE = 0;
DDRE = 1<<DDE1; // make outputs, set to zero. PE1 is usart0 TXD
-
-/////////////////////////////////////////////////////////////////////////////
/*
* Port F
*
- * Split into 2 nibbles; goes to Amp/Filter board to select ENABLE and two bits to select band
- * one bit per nibble is not connected.
+ * Split into 2 nibbles; goes to Amp/Filter board to select ENABLE and two bits
+ * to select band one bit per nibble is not connected.
*
- * pin Sig Dir Our Functional Name
- * num
+ * pin Sig Dir Our Functional Name
*
- * p61 PF0 Out J117 pin 3 (J117 pins 1 and 2 are GND)
- * p60 PF1 Out J117 pin 4
- * p59 PF2 Out J117 pin 5
- * p58 PF3 Out J117 pin 6
- * p57 PF4 Out J118 pin 3 (J118 pins 1 and 2 are GND)
- * p56 PF5 Out J118 pin 4
- * p55 PF6 Out J118 pin 5
- * p54 PF7 Out J118 pin 6
+ * p61 PF0 Out J117 pin 3 (J117 pins 1 and 2 are GND)
+ * p60 PF1 Out J117 pin 4
+ * p59 PF2 Out J117 pin 5
+ * p58 PF3 Out J117 pin 6
+ * p57 PF4 Out J118 pin 3 (J118 pins 1 and 2 are GND)
+ * p56 PF5 Out J118 pin 4
+ * p55 PF6 Out J118 pin 5
+ * p54 PF7 Out J118 pin 6
*
*/
-
-
-PORTF = 0; // Initial Value is all zeros; be sure ENABLE bits are active high!!!!
-DDRF = 0xff; // All bits are outputs
-
+PORTF = 0; // Initial Value is all zeros; be sure ENABLE bits are active high!!!!
+DDRF = 0xff; // All bits are outputs
-
led(Middle,On);
-setup_TI_CDCE18005(Primary_GPS); // 10 MHz from Internal Source
-
-led(Top,On);
-PORTA |= (1<<PA6); // PPS from Internal source
-
+setup_TI_CDCE18005(Primary_GPS); // 10 MHz from Internal Source
+led(Top,On);
+PORTA |= (1<<PA6); // PPS from Internal source
}
-/////////////////////////////////////////////////////////////////////////////
+// NOT PRESENT unless proven so...
+bool Global_GPS_Present = (bool)FALSE;
+bool Global_Ext_Ref_Is_Present = (bool)FALSE;
-//enum TI_Input_10_MHz {Primary_GPS, Secondary_Ext};
-
-//setup_TI_CDCE18005(enum TI_Input_10_MHz);
-
-bool Global_GPS_Present = (bool)FALSE;
-bool Global_Ext_Ref_Is_Present = (bool)FALSE; // NOT PRESENT unless proven so...
-// This was initially global becasue it was to be set in an interrupt routine
-// But it turned out interrupts were not needed. But kept this in because
-// although it's a Global, it is the only one, and it makes it easier to
-// go back and use interrupts if absolutely necessary. It could be
-// removed and replaced with some local variable that gets passed
-// around, but, really, it seems OK to me like this.
-
-
-
-void
-LEDs_Off(){
- led(Top,Off);
- led(Middle,Off);
- led(Bottom,Off);
+void LEDs_Off(){
+ led(Top,Off);
+ led(Middle,Off);
+ led(Bottom,Off);
}
+void Force_Internal(){
+ led(Top,On);
+ led(Middle,Off);
+ led(Bottom,On);
-void
-Force_Internal(){
- // led(Middle,On);
- led(Top,On);
- led(Middle,Off);
- led(Bottom,On);
+ setup_TI_CDCE18005(Primary_GPS);
- setup_TI_CDCE18005(Primary_GPS);
-
- // Set PPS to Primary (1) n.b.: "1" in general means "Internal" for all such signals
- PORTA |= (1<<PA6); // PPS from Internal source
+ // Set PPS to Primary (1) n.b.: "1" in general means "Internal" for all
+ // such signals
+ PORTA |= (1<<PA6);
}
+void Force_External(){
+ led(Top, Off);
+ led(Middle, On);
+ led(Bottom, On);
-void
-Force_External(){
- // led(Middle, Off);
- led(Top, Off);
- led(Middle, On);
- led(Bottom, On);
-
- setup_TI_CDCE18005(Secondary_Ext);
-
- // Set PPS to External (0
- PORTA &= ~(1<<PA6); // PPS from External source
-}
-
-
-/////////////////////////////////////////////////////////////////////////////
-
-void
-Prefer_Internal(){
-
- if(Global_GPS_Present)
- Force_Internal();
- else if(Global_Ext_Ref_Is_Present)
- Force_External();
- else
- LEDs_Off();
-}
-
-
-
-
-
-void
-Prefer_External(){ // IF EXTERNAL IS OK, then do this stuff
- // if external is NOT OK, then force Internal
- if(Global_Ext_Ref_Is_Present)
- Force_External();
- else if(Global_GPS_Present)
- Force_Internal();
- else
- LEDs_Off();
-}
-
-
-
-// Turns out, we don't need interrupts
-
-
-#if 0
-//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
-u8 Global_Tick_Counter = (u8)0;
-u8 Global_Ext_Ref_Detect_Counter = (u8)0;
-
-// External Reference Detect interrupt; nominally at 610 Hz (10 MHz / 2**14 )
-ISR ( _VECTOR(1)){
- asm("cli"); // Global Interrupt Disable --- enable with SEI if desired later
-
+ setup_TI_CDCE18005(Secondary_Ext);
- Global_Ext_Ref_Detect_Counter++ ; // We reset this elsewhere
-
- asm("sei"); // Global Interrupt Enable
+ // Set PPS to External
+ PORTA &= ~(1<<PA6);
}
+void Prefer_Internal(){
-// Timer 0 Overflow Handler
-ISR ( _VECTOR(16)){
- static u8 led_state = Off;
-
- asm("cli"); // Global Interrupt Disable --- enable with SEI if desired later
-
- led_state = (led_state ? Off : On);
-
- asm("sei"); // Global Interrupt Enable
+ if(Global_GPS_Present)
+ Force_Internal();
+ else if(Global_Ext_Ref_Is_Present)
+ Force_External();
+ else
+ LEDs_Off();
}
-//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-
-
-
-void
-Setup_Atmel_Interrupts(){
- // Timer 0 is all we need -- but simplest if both Timer 0 AND IRQ1 (ext_ref_detect 610 Hz signal) also
- // Nah, don't need this...
+void Prefer_External(){
+ // if external is NOT OK, then force Internal
+ if(Global_Ext_Ref_Is_Present)
+ Force_External();
+ else if(Global_GPS_Present)
+ Force_Internal();
+ else
+ LEDs_Off();
}
-#endif
+bool Check_What_Is_Present(){
+ // See if +5 scaled to 3.3 from GPSDO is there
+ Global_GPS_Present = (PIND & (1<<DDD4)) != 0;
+ volatile uint8_t portE = PINE;
+ volatile uint8_t prev, now;
-bool
-Check_What_Is_Present(){
+ // Get PREVIOUS state of the input
+ prev = ( portE & (1 << DDE7) ? 1 : 0);
- Global_GPS_Present = (PIND & (1<<DDD4)) != 0; // See if +5 scaled to 3.3 from GPSDO is there
+ for(uint16_t c=1; c; c++){
+ portE = PINE;
+ now = ( portE & (1 << DDE7) ? 1 : 0);
+ if(prev != now){
+ Global_Ext_Ref_Is_Present = (bool)TRUE;
- volatile u8 portE = PINE;
- volatile u8 prev, now;
-
- prev = ( portE & (1 << DDE7) ? 1 : 0); // Get PREVIOUS state of the input
- for(u16 c=1; c; c++){
- portE = PINE;
- now = ( portE & (1 << DDE7) ? 1 : 0);
- if(prev != now){
- Global_Ext_Ref_Is_Present = (bool)TRUE;
- return (bool)TRUE;
+ return (bool)TRUE;
+ }
}
- }
+
// Else, if it didn't wiggle in that time, then it didn't wiggle
// So ext. is NOT present
-
Global_Ext_Ref_Is_Present = (bool)FALSE;
return (bool)FALSE;
-
}
-bool
-get_Switch_State(){
- u8 portC = PINC;
+bool get_Switch_State(){
+ uint8_t portC = PINC;
- // return (bool)(portC & (1<<DDC1) ? On : Off);
- return (bool)(portC & (1<<DDC1) ? Off : On); // UP is prefer internal,
- // DOWN is prefer external
+ // UP is prefer internal,
+ // DOWN is prefer external
+ return (bool)(portC & (1<<DDC1) ? Off : On);
}
-
-/////////////////////////////////////////////////////////////////////////////
-/////////////////////////////////////////////////////////////////////////////
-// M A I N //
-/////////////////////////////////////////////////////////////////////////////
-/////////////////////////////////////////////////////////////////////////////
-
-
-int
-main(void){
-
- bool Old_Switch_State, Current_Switch_State, Old_Global_Ext_Ref_Is_Present = FALSE;
-
-
-
- asm("cli"); // Global Interrupt Disable --- enable with SEI if desired later
-
- Setup_Atmel_IO_Ports();
-
- // Setup_Atmel_Interrupts();
-
-
- /*
- * DO THIS FOREVER:
- *
- *
- * get_switch_state
- *
- * if SWITCH_CHANGED:
- *
- *
- * if PREFER_INTERNAL:
- * if INTERNAL_PRESENT do_internal
- * else if EXTERNAL_PRESENT do_external
- * else LEDs OFF
- *
- * if PREFER_EXTERNAL:
- * if EXTERNAL_PRESENT do_external
- * else if INTERNAL_PRESENT do_internal
- * else LEDs OFF
- *
- */
-
-
-
-
- Old_Switch_State = ! get_Switch_State();
-
- // Because down below, we use this to get state swap...
- // So we arbitrarily set the PREVIOUS state to be the "other" state
- // so that, below, we trigger what happens when the switch changes
- // This first "change" is therefore artificial to keep the logic, below, cleaner
-
- while(TRUE) {
- Check_What_Is_Present(); // Set "Global_Ext_Ref_Is_Present" and "Global_GPS_Present"
-
- // Off means "Prefer External" -- DOWN
- // On means "Prefer Internal" -- UP
-
- Current_Switch_State = get_Switch_State();
-
- if( (Current_Switch_State != Old_Switch_State) ||
- (Global_Ext_Ref_Is_Present != Old_Global_Ext_Ref_Is_Present) ) {
-
- Old_Switch_State = Current_Switch_State;
- Old_Global_Ext_Ref_Is_Present = Global_Ext_Ref_Is_Present;
-
- if(Current_Switch_State == On)
- Prefer_Internal();
- else
- Prefer_External();
- } // if() checking for different switch status
-
-
- } // WHILE() loop
-
-
-} /*end "main" of Program 'OctoClock.c */
+/*******************************************************************************
+* Main Routine
+*******************************************************************************/
+
+int main(void){
+
+ bool Old_Switch_State, Current_Switch_State, Old_Global_Ext_Ref_Is_Present = FALSE;
+
+ // Global Interrupt Disable --- enable with SEI if desired later
+ asm("cli");
+
+ Setup_Atmel_IO_Ports();
+
+ /*
+ * DO THIS FOREVER:
+ *
+ * get_switch_state
+ *
+ * if SWITCH_CHANGED:
+ *
+ * if PREFER_INTERNAL:
+ * if INTERNAL_PRESENT do_internal
+ * else if EXTERNAL_PRESENT do_external
+ * else LEDs OFF
+ *
+ * if PREFER_EXTERNAL:
+ * if EXTERNAL_PRESENT do_external
+ * else if INTERNAL_PRESENT do_internal
+ * else LEDs OFF
+ *
+ */
+
+ Old_Switch_State = ! get_Switch_State();
+
+ // Because down below, we use this to get state swap So we arbitrarily set
+ // the PREVIOUS state to be the "other" state so that, below, we trigger
+ // what happens when the switch changes This first "change" is therefore
+ // artificial to keep the logic, below, cleaner
+ while(TRUE) {
+ // Set "Global_Ext_Ref_Is_Present" and "Global_GPS_Present"
+ Check_What_Is_Present();
+
+ // Off means "Prefer External" -- DOWN
+ // On means "Prefer Internal" -- UP
+ Current_Switch_State = get_Switch_State();
+
+ if( (Current_Switch_State != Old_Switch_State) ||
+ (Global_Ext_Ref_Is_Present != Old_Global_Ext_Ref_Is_Present) ) {
+
+ Old_Switch_State = Current_Switch_State;
+ Old_Global_Ext_Ref_Is_Present = Global_Ext_Ref_Is_Present;
+
+ if(Current_Switch_State == On)
+ Prefer_Internal();
+ else
+ Prefer_External();
+ }
+ }
+}