/* * Copyright 2013 Ettus Research LLC * * 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. * * 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 . */ /* * Welcome to the firmware code for the USRP Octoclock accessory product! * * 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). * * 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) * */ #include #include #include #include #ifdef On #undef On #endif #ifdef Off #undef Off #endif #define Off (0) #define On (!Off) #ifdef FALSE #undef FALSE #endif #ifdef TRUE #undef TRUE #endif #define FALSE (0) #define TRUE (!FALSE) // 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(uint16_t u=14000; u; u--) asm("nop"); #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}; enum Levels {Lo, Hi}; void led(enum LEDs which, int turn_it_on) { // selects the proper bit uint8_t LED = 0x20 << which; if(turn_it_on) PORTC |= LED; else PORTC &= ~LED; } /******************************************************************************* * SPI routines *******************************************************************************/ /* All macros evaluate to compile-time constants */ /* 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) /* 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 */ 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 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 }; // 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 // extra error in Table 9, for bits 24 and 25 int table_size = sizeof (table_Pri_Ref) / sizeof(uint32_t); void set_bit(uint8_t bit_number, enum Levels bit_value) { if(bit_value == Hi) PORTA |= 1< 0 ? TRUE : FALSE; } // Send 32 bits to TI chip, LSB first. // 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<>= 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() { /* * 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 * */ // /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<