/* *************SOURCE FILE******************** File saved as main.c Compiler: XC8 v1.38 CCI compliant? Yes Software function Si5351a i2c programmer utilizing the Silabs 'Clockbuilder' generated .h file Written by Russell E. Tribe Date 8/10/2016 For (PIC type) PIC16F1459 Resonator Internal 16Mhz CPU clock 16MHZ (48 MHz PLL output divided by 3 in CPU divider) Instruction clock 4MHz T = 0.25µS (4MIPS) Other information Other information LED on pin2 (RA5) SDA on pin 13 (RB4) SCL on pin 11 (RB6) ********* NB: Follow instructions in the file 'register_map.h' ********* */ /** C O N F I G U R A T I O N B I T S ******************************/ // CONFIG1 #pragma config FOSC = INTOSC // Oscillator Selection Bits (INTOSC oscillator: I/O function on CLKIN pin) #pragma config WDTE = OFF // Watchdog Timer Enable (WDT disabled) #pragma config PWRTE = OFF // Power-up Timer Enable (PWRT disabled) #pragma config MCLRE = OFF // MCLR Pin Function Select (MCLR/VPP pin function is digital input) #pragma config CP = OFF // Flash Program Memory Code Protection (Program memory code protection is disabled) #pragma config BOREN = OFF // Brown-out Reset Enable (Brown-out Reset disabled) #pragma config CLKOUTEN = OFF // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin) #pragma config IESO = OFF // Internal/External Switchover Mode (Internal/External Switchover Mode is disabled) #pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is disabled) // CONFIG2 #pragma config WRT = OFF // Flash Memory Self-Write Protection (Write protection off) #pragma config CPUDIV = CLKDIV3 // CPU System Clock Selection Bit (divide by 3 = 16Mhz) #pragma config USBLSCLK = 48MHz // USB Low SPeed Clock Selection bit (System clock expects 48 MHz, FS/LS USB CLKENs divide-by is set to 8.) #pragma config PLLMULT = 3x // PLL Multipler Selection Bit (3x Output Frequency Selected) #pragma config PLLEN = ENABLED // PLL Enable Bit (3x or 4x PLL is enabled - see above) #pragma config STVREN = OFF // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will not cause a Reset) #pragma config BORV = LO // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.) #pragma config LPBOR = OFF // Low-Power Brown Out Reset (Low-Power BOR is disabled) #pragma config LVP = OFF // Low-Voltage Programming Enable (High-voltage on MCLR/VPP must be used for programming) /** I N C L U D E S **************************************************/ #include //Provides PIC header file and is required for CCI compliance #include "i2c.h" #include "register_map.h" //This is the data generated by Silabs 'Clockbuilder' /** FUNCTION PROTOTYPES **********************************************/ void intialSetUp (void); //Manages the initialization of all PIC functions void programSi5351a (void); void sendRegister (unsigned char, unsigned char); void wait (unsigned char); void flashLED (unsigned char); /** DECLARATIONS******************************************************/ #define _XTAL_FREQ 16000000 //Used by library delay routines AND i2c baud setting #define LED LATAbits.LATA5 //Pin 2 #define OFF 0 #define ON 1 #define BAUD_RATE 100000 //Speed of I2C clock - either 100kHz ('Standard Speed') or 400 kHz ('High Speed') #define SI5351A_ADDRESS 0xC0 /** GLOBAL VARIABLES *************************************************/ //**************************************** int main(void) { unsigned char sync_mode, slew; intialSetUp (); //Initializes the PIC flashLED (1); //Say "Hi!" __delay_ms(50); //Allow time for the si5351a to initialize //Initialize the I2C module for MASTER mode with 100kHz clock CloseI2C(); //Close i2c if it was operating earlier sync_mode = MASTER; slew = SLEW_OFF; SSP1ADD = (_XTAL_FREQ/(4*BAUD_RATE))-1; //Determines speed of the I2C bus - using this formula instead of entering a number //is convenient when changing oscillator speed eg when migrating to a different PIC OpenI2C(sync_mode,slew); programSi5351a (); //Terminate communication from MASTER side CloseI2C(); //Close I2C module flashLED (2); //Say "Goodbye!" SLEEP (); //Shut down the PIC in order to prevent RFI and to save power while(1); //Wait here - end of program } //main //**************************************** void intialSetUp (void) { /* Firstly, set up the oscillator. (I have kept the settings I used for an earlier USB project) These oscillator settings are required for FS USB operation and will deliver a 16MHz system clock */ OSCCONbits.SCS = 0b00; //Clock source determined in Config words OSCCONbits.IRCF = 0b1111; //16Mhz internal oscillator frequency selected OSCCONbits.SPLLMULT = 1; //PLL x 3 selected while (OSCSTATbits.HFIOFS == 0); //Wait until int osc is stable to 5% ACTCONbits.ACTSRC = 1; //Active tuning derived from FS USB ACTCONbits.ACTEN = 1; //Active clock tuning is enabled //Cannot use this next line until a USB connection has been made! //while (ACTCONbits.ACTLOCK == 0); //Wait until active tuning is locked ANSELBbits.ANSB4 = 0; //Select digital mode for the SDA pin (Pin 13) WPUBbits.WPUB4 = 0; WPUBbits.WPUB6 = 0; //Set up pin 2 (RA5) as the LED output TRISAbits.TRISA5 = 0; //Pin 2 (RA3) is an output pin LED = OFF; } //**************************************** //The si5351a requires re-programming at every power-up //Refer to Silabs Si5251a data sheet section 5.1 and figure 12 for i2c Programming Procedure. //Refer to Silabs AN619 for register details void programSi5351a (void) { unsigned char counter; Reg_Data current; //The following procedures comply with Silabs Si5251a data sheet section 5.1 and //figure 12 for i2c Programming Procedure. sendRegister (3,0xFF); //Disable outputs sendRegister (16,0x80); //Power down output drivers sendRegister (17,0x80); //Power down output drivers sendRegister (18,0x80); //Power down output drivers sendRegister (19,0x80); //Power down output drivers sendRegister (20,0x80); //Power down output drivers sendRegister (21,0x80); //Power down output drivers sendRegister (22,0x80); //Power down output drivers sendRegister (23,0x80); //Power down output drivers //Now send the register data from register_map.h for(counter = 0; counter < NUM_REGS_MAX; counter++) { current = Reg_Store[counter]; sendRegister (current.Reg_Addr, current.Reg_Val); } sendRegister (177,0xAC); //Apply PLLA and PLLB soft reset sendRegister (3,0xFE); //Enable Channel 0. Others disabled } //**************************************** /*This function follows the description in Silabs Si5251a data sheet section 4 in particular, figure 9 for i2c write operation. NB 'Burst Mode' writing cannot be used as the required register addresses are not contiguous*/ void sendRegister (unsigned char reg, unsigned char data) { StartI2C (); masterSendI2C (SI5351A_ADDRESS | 0x00); //Sends si5351a address and 'write' bit masterSendI2C (reg); masterSendI2C (data); StopI2C (); } //**************************************** //A delay function void wait (unsigned char iterations) { while (iterations) { __delay_ms(100); iterations --; } } //**************************************** void flashLED (unsigned char iterations) { while (iterations) { LED = ON; __delay_ms(500); LED = OFF; __delay_ms(500); iterations --; } } //****************************************