diff options
Diffstat (limited to 'firmware/octoclock/OctoClock.c')
| -rw-r--r-- | firmware/octoclock/OctoClock.c | 844 | 
1 files changed, 844 insertions, 0 deletions
| diff --git a/firmware/octoclock/OctoClock.c b/firmware/octoclock/OctoClock.c new file mode 100644 index 000000000..07397601d --- /dev/null +++ b/firmware/octoclock/OctoClock.c @@ -0,0 +1,844 @@ +/* + * 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 + * + * + * V1.02 -- Make LEDs consistent with Chassis - Top LED is INTERNAL; middle is EXTERNAL; bottom is STATUS + * + * STATUS is ON if the 10 MHz external input is present.   19 April 2013 + * + * + * 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. + * + * + * New Version that supports CLOCK board Version 1.0 + * + * Author: Michael@Cheponis.Com with code borrowed liberally from + * previous AVR projects + * + */ + +/* + * 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 <avr/io.h> +#include <avr/interrupt.h> + + +#ifdef On +#undef On +#endif + +#ifdef Off +#undef OFf +#endif + +#define Off	(0) +#define On (!Off) + + +// Important for the Serial Port, not used at the moment +#define	FOSC	(7372800) +#define BAUD	(115200) + +#define MYUBRR FOSC/16/BAUD-1 + + +#define wait() for(u16 u=14000; u; u--) asm("nop"); + + + +enum LEDs {Top,Middle,Bottom}; // Top is 0, Mid is 1, and Bottom is 2 + +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; +	 +} + + +enum TI_Input_10_MHz {Primary_GPS, Secondary_Ext}; + +void setup_TI_CDCE18005(enum TI_Input_10_MHz); + + + + +/***************************************************************************************** + +			SPI routines + +******************************************************************************************/ + + + +/* 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 + */ + #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)) +  +/* Sample usage: + 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 + +// 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 +}; + + +// 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 +}; + +//; 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(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. + + +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); +} + + +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 +} + + +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. + +/* +#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); +} + +// 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. +// + + + + + + +// 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 +} + +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(); +}; + + +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	 + + + + + + + + +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 + * + */ + +// 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 + + +					 +/////////////////////////////////////////////////////////////////////////////					 +/* + * Port B + * + *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 + * + */ +  + + 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 + * + * 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 + +  + +/////////////////////////////////////////////////////////////////////////////					 +/* + * Port D + * + *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 + * + */ +PORTD = 0;		// Initial Value is all zeros +DDRD =  1<<DDD1 | 1<<DDD3; + +					 + +/////////////////////////////////////////////////////////////////////////////					 +/* + * Port E + * + *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 + * + */ +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. + * + * pin Sig Dir		Our Functional Name + * num + * + * 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 + + + +	 +led(Middle,On); +setup_TI_CDCE18005(Primary_GPS);	// 10 MHz from Internal Source + +led(Top,On);  +PORTA |= (1<<PA6);	// PPS from Internal source + + +} + +///////////////////////////////////////////////////////////////////////////// + +//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 +Force_Internal(){ +  // led(Middle,On); + led(Top,On); + led(Middle,Off); + led(Bottom,On); + + 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 +} + + +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 + + +  Global_Ext_Ref_Detect_Counter++ ;  // We reset this elsewhere + +  asm("sei");	// Global Interrupt Enable +} + + +// 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 +} + +//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +//;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + + +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... +} + +#endif + + + +bool +Check_What_Is_Present(){ + +  Global_GPS_Present = (PIND & (1<<DDD4)) != 0; // See if +5 scaled to 3.3 from GPSDO is there + + +  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; +    } +  } +  // 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; + + // return (bool)(portC &  (1<<DDC1) ? On : Off);  + return (bool)(portC &  (1<<DDC1) ? Off : On);  // UP is prefer internal, +                                                // DOWN is prefer external +} + + +///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// +//                            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 */ | 
