/* 
 * File:   si570-vfo-encoder.c
 * Author: Ramiro Aceves, EA4NZ
 *
 * Created on 20 de diciembre de 2013, 8:51
 */

#include <xc.h>
#include <stdio.h>
#include <math.h>
#include <plib/delays.h>
#include <plib/i2c.h>

#pragma config FOSC = HS
#pragma config PLLEN = ON
//#pragma config CPUDIV = CLKDIV4
#pragma config CPUDIV = NOCLKDIV
#pragma config USBDIV = OFF
#pragma config WDTEN = OFF
#pragma config MCLRE = ON
#pragma config IESO = OFF
#pragma config HFOFST = OFF
#pragma config XINST = OFF

#pragma config LVP = OFF

#define MAX_FDCO_FREQ 5670.0
#define MIN_FDCO_FREQ 4850.0
#define FXTAL 114.242835695880
//#define FXTAL 114.327438

float FRECUENCIA=50.0;
float DELTA=0.25;


void write_si570_regs (float RFREQ, unsigned char HS_DIV, unsigned char N1);
void prog_si570 (float FOUT);

void interrupt pulsaboton(void){

    Delay1KTCYx(40    );
     if (RABIE && RABIF && PORTBbits.RB7==1 && PORTBbits.RB5==0){

         FRECUENCIA=FRECUENCIA+DELTA;
                prog_si570 (FRECUENCIA);
                char x=PORTBbits.RB7;
                RABIF=0;
                return;
        }

      if (RABIE && RABIF && PORTBbits.RB7==0 && PORTBbits.RB5==0){

          FRECUENCIA=FRECUENCIA-DELTA;
               prog_si570 (FRECUENCIA);
               char x=PORTBbits.RB7;
               RABIF=0;
               return;
      }

    char x=PORTBbits.RB7;
    RABIF=0;
    return;
}


void main (void)
{

        TRISC=0b00000000; /*RC0-RC7 salidas*/
        TRISB=0b11110000;/*RB6=SCL, RB4=SDA, RB7=RB5=INPUTs*/
        WPUB= 0b10100000;/*RB7, RB5, WEAK PULLUP ENABLED*/
        WDTCON=0x00;/*DESHABILITAR WATCHDOG*/
        INTCON2=0b11110101;
        //INTCON2=0b01110101; /habilita los pullup
        ANSELH=0x00;
        PORTC=0b00000000;/*reset del puerto C*/
        
        
             
        
        RABIE=1;
        
        IOCB7=1;
        //IOCB5=1;


        prog_si570 (FRECUENCIA);

        GIE=1;

            

        while(1){

            Delay10KTCYx(255);
            }
         


        }

        


    



void write_si570_regs (float RFREQ, unsigned char HS_DIV, unsigned char N1)

{
unsigned char Si570_REG_7;
unsigned char Si570_REG_8;
unsigned char Si570_REG_9;
unsigned char Si570_REG_10;
unsigned char Si570_REG_11;
unsigned char Si570_REG_12;
unsigned char Si570_REG_135;
unsigned char Si570_REG_137;

unsigned int entera_de_RFREQ;
float decimal_de_RFREQ;
unsigned long resto;

unsigned char sync_mode;
unsigned char slew;
unsigned char add1;
unsigned char w;
unsigned char data;
unsigned char status;

Si570_REG_7=((HS_DIV-4) << 5) | ((N1-1) >> 2);
entera_de_RFREQ = floor(RFREQ);
Si570_REG_8= (((N1-1) << 6 ) | (entera_de_RFREQ >> 4));
decimal_de_RFREQ=RFREQ-entera_de_RFREQ;
resto=floor(decimal_de_RFREQ *268435456);
Si570_REG_9=((entera_de_RFREQ << 4) | (resto >> 24));
Si570_REG_10=(resto >> 16);
Si570_REG_11=(resto >> 8);
Si570_REG_12=(resto);

sync_mode=MASTER;
slew=SLEW_OFF;
add1=0xAA;                              //Si-570 address 0x55*2

OpenI2C(sync_mode, slew);
SSPADD=0x1D;                            //100kHz SCL clock @ 12 MHz

    IdleI2C();                          //read 137 register for DCO freezze
StartI2C();
    IdleI2C();
WriteI2C( add1 | 0x00 );
    IdleI2C();
WriteI2C((unsigned char) 137 );
    IdleI2C();
RestartI2C();
    IdleI2C();
WriteI2C( add1 | 0x01 );
    IdleI2C();
Si570_REG_137=ReadI2C();
    IdleI2C();
NotAckI2C();
    IdleI2C();
StopI2C();

Si570_REG_137=(Si570_REG_137 | 0x10);   //set bit 4 of 137 reg to freezze DCO

    IdleI2C();                          //write 137 register
StartI2C();
    IdleI2C();
WriteI2C( add1 | 0x00 );
    IdleI2C();
WriteI2C( (unsigned char)137 );
    IdleI2C();
WriteI2C(Si570_REG_137);
    IdleI2C();
StopI2C();


    IdleI2C();                          //write 7 register
StartI2C();
    IdleI2C();
WriteI2C( add1 | 0x00 );
    IdleI2C();
WriteI2C( (unsigned char) 7 );
    IdleI2C();
WriteI2C(Si570_REG_7);
    IdleI2C();
StopI2C();


    IdleI2C();                          //write 8 register
StartI2C();
    IdleI2C();
WriteI2C( add1 | 0x00 );
    IdleI2C();
WriteI2C( (unsigned char) 8 );
    IdleI2C();
WriteI2C(Si570_REG_8);
    IdleI2C();
StopI2C();

    IdleI2C();                          //write 9 register
StartI2C();
    IdleI2C();
WriteI2C( add1 | 0x00 );
    IdleI2C();
WriteI2C( (unsigned char) 9 );
    IdleI2C();
WriteI2C(Si570_REG_9);
    IdleI2C();
StopI2C();

    IdleI2C();                          //write 10 register
StartI2C();
    IdleI2C();
WriteI2C( add1 | 0x00 );
    IdleI2C();
WriteI2C( (unsigned char) 10 );
    IdleI2C();
WriteI2C(Si570_REG_10);
    IdleI2C();
StopI2C();


    IdleI2C();                          //write 11 register
StartI2C();
    IdleI2C();
WriteI2C( add1 | 0x00 );
    IdleI2C();
WriteI2C( (unsigned char) 11 );
    IdleI2C();
WriteI2C(Si570_REG_11);
    IdleI2C();
StopI2C();

    IdleI2C();                          //write 12 register
StartI2C();
    IdleI2C();
WriteI2C( add1 | 0x00 );
    IdleI2C();
WriteI2C( (unsigned char) 12);
    IdleI2C();
WriteI2C(Si570_REG_12);
    IdleI2C();
StopI2C();

    IdleI2C();                          //read 137 register for DCO unfreezze
StartI2C();
    IdleI2C();
WriteI2C( add1 | 0x00 );
    IdleI2C();
WriteI2C( (unsigned char)137 );
    IdleI2C();
RestartI2C();
    IdleI2C();
WriteI2C( add1 | 0x01 );
    IdleI2C();
Si570_REG_137=ReadI2C();
    IdleI2C();
NotAckI2C();
    IdleI2C();
StopI2C();

Si570_REG_137=(Si570_REG_137 & 0xEF); //clear bit 4 of 137 reg to freezze DCO

    IdleI2C();
StartI2C();
    IdleI2C();
WriteI2C( add1 | 0x00 );
    IdleI2C();
WriteI2C( (unsigned char)137 );
    IdleI2C();
WriteI2C(Si570_REG_137);
    IdleI2C();
StopI2C();

    IdleI2C();
StartI2C();
    IdleI2C();
WriteI2C( add1 | 0x00 );
    IdleI2C();
WriteI2C( (unsigned char)135 ); // set bit 6 of 135 register for NewFreq to be applied
    IdleI2C();
WriteI2C( (unsigned char) 0x40 );
    IdleI2C();
StopI2C();




return;
}



unsigned char check_and_prog(unsigned char HS_DIV,unsigned char N1, float FOUT)
{
        float RFREQ;
        float FDCO;
        FDCO=FOUT * HS_DIV*N1;
	if ( (FDCO <= MAX_FDCO_FREQ) && (FDCO >= MIN_FDCO_FREQ) )
	{
			RFREQ=(FDCO)/FXTAL;
			write_si570_regs (RFREQ, HS_DIV, N1);
                        return 0;
	}
        return 1;
}
void prog_si570 (float FOUT)
{
	
	unsigned char HS_DIV[6]={11,9,7,6,5,4};
	unsigned char N1;
        unsigned char i;
        
        N1=1;
        for (i=0;i<=5;i++)
        {
            if(check_and_prog(HS_DIV[i],N1,FOUT)==0) return;
        }

        for (N1=2;N1<=128;N1=N1+2)
        {
        
            for (i=0;i<=5;i++)
            {
            if(check_and_prog(HS_DIV[i],N1,FOUT)==0) return;
            }
        }
        
    return;
}
       

