From 9fefb30f210f86c8c5964ca8ee80f63ad8856d02 Mon Sep 17 00:00:00 2001 From: Nicholas Corgan Date: Fri, 7 Jun 2013 13:04:51 -0700 Subject: OctoClock support --- firmware/octoclock/OctoClock.c | 844 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 844 insertions(+) create mode 100644 firmware/octoclock/OctoClock.c (limited to 'firmware/octoclock/OctoClock.c') 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 +#include + + +#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<> 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<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>= 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<