/*********************************************************************
 *
 *                  SPI to  MCP4822 dual channel 12-bit DAC
 *
 *********************************************************************
 * Bruce Land Cornell University
 * Spet 2015
 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
#include <stdlib.h>
#include <plib.h>
#include <xc.h> // need for pps


// Configuration Bit settings
// SYSCLK = 40 MHz (8MHz Crystal/ FPLLIDIV * FPLLMUL / FPLLODIV)
// PBCLK = 40 MHz
// Primary Osc w/PLL (XT+,HS+,EC+PLL)
// WDT OFF
// Other options are don't care
//                       8MHZ                          4MHz               80MHz            40      <---    40MHz
#pragma config FNOSC = FRCPLL, POSCMOD = OFF, FPLLIDIV = DIV_2, FPLLMUL = MUL_20, FPBDIV = DIV_1, FPLLODIV = DIV_2
#pragma config FWDTEN = OFF
#pragma config FSOSCEN = OFF, JTAGEN = OFF, DEBUG = OFF

// core frequency we're running at // peripherals at 40 MHz
#define	SYS_FREQ                    40000000
#define I2C_CLOCK_FREQ              100000

#define I2C 1
#define GPIO 1
#define SPI 0 //can help regardless

/* ====== MCP4822 control word ==============
bit 15 A/B: DACA or DACB Selection bit
1 = Write to DACB
0 = Write to DACA
bit 14 ? Don?t Care
bit 13 GA: Output Gain Selection bit
1 = 1x (VOUT = VREF * D/4096)
0 = 2x (VOUT = 2 * VREF * D/4096), where internal VREF = 2.048V.
bit 12 SHDN: Output Shutdown Control bit
1 = Active mode operation. VOUT is available. ?
0 = Shutdown the selected DAC channel. Analog output is not available at the channel that was shut down.
VOUT pin is connected to 500 k???typical)?
bit 11-0 D11:D0: DAC Input Data bits. Bit x is ignored.
*/
// A-channel, 1x, active
#define DAC_config_chan_A 0b0011000000000000

//== Timer 2 interrupt handler ===========================================
volatile unsigned int DAC_data ;// output value
volatile unsigned char count = 0;
volatile SpiChannel spiChn = SPI_CHANNEL2 ;	// the SPI channel to use
volatile int spiClkDiv = 16 ; // 20 MHz max speed for this DAC

void __ISR(_TIMER_2_VECTOR, ipl2) Timer2Handler(void)
{
    mT2ClearIntFlag();
    
    // generate  ramp
     DAC_data = (DAC_data + 1) & 0xfff ; // for testing
    
    // CS low to start transaction
     mPORTBClearBits(BIT_4); // start transaction
     //mPORTBClearBits(BIT_0);
    // test for ready
     while (TxBufFullSPI2());
     // write to spi2
     //WriteSPI2(DAC_config_chan_A | DAC_data);
     WriteSPI2(count++);
    // test for done
    while (SPI2STATbits.SPIBUSY); // wait for end of transaction
     // CS high
     //mPORTBSetBits(BIT_0); // end transaction
    mPORTBSetBits(BIT_4);
}


// ========================================================================
int	main(void)
{
	// Configure the device for maximum performance but do not change the PBDIV
	// Given the options, this function will change the flash wait states, RAM
	// wait state and enable prefetch cache but will not change the PBDIV.
	// The PBDIV value is already set via the pragma FPBDIV option above..
	SYSTEMConfig(SYS_FREQ, SYS_CFG_WAIT_STATES | SYS_CFG_PCACHE);

        // timer interrupt //////////////////////////
        // Set up timer2 on,  interrupts, internal clock, prescalar 1, toggle rate
        // at 30 MHz PB clock 60 counts is two microsec
        // 400 is 100 ksamples/sec
        // 2000 is 20 ksamp/sec
        OpenTimer2(T2_ON | T2_SOURCE_INT | T2_PS_1_1, 400*5);

        // set up the timer interrupt with a priority of 2
        ConfigIntTimer2(T2_INT_ON | T2_INT_PRIOR_2);
        mT2ClearIntFlag(); // and clear the interrupt flag

        // SCK2 is pin 26 
        // SDO2 (MOSI) is in PPS output group 2, could be connected to RB5 which is pin 14
        PPSOutput(2, RPB5, SDO2); 

        // control CS for DAC
        //mPORTBSetPinsDigitalOut(BIT_0);
        //mPORTBSetBits(BIT_0);
        mPORTBSetPinsDigitalOut(BIT_4);
        mPORTBSetBits(BIT_4);
        
        //setup up GPIO pin for toggling (need 4 pins_)
        //using RB0, RB1, RB8,R9
        mPORTBSetPinsDigitalOut(BIT_0);
        mPORTBSetPinsDigitalOut(BIT_1);
        mPORTBSetPinsDigitalOut(BIT_8);
        mPORTBSetPinsDigitalOut(BIT_9);
        
        //I2C bit bang
        mPORTBSetPinsDigitalOut(BIT_2);
        mPORTBSetPinsDigitalOut(BIT_3);
        //set them both high for idle
        mPORTBSetBits(BIT_2);//SDA
        mPORTBSetBits(BIT_3);//SCL
        int start = 0;
        
        //
        
        // divide Fpb by 2, configure the I/O ports. Not using SS in this example
        // 16 bit transfer CKP=1 CKE=1
        // possibles SPI_OPEN_CKP_HIGH;   SPI_OPEN_SMP_END;  SPI_OPEN_CKE_REV
        // For any given peripherial, you will need to match these
        SpiChnOpen(spiChn, SPI_OPEN_ON | SPI_OPEN_MODE8 | SPI_OPEN_MSTEN | SPI_OPEN_CKE_REV , spiClkDiv);

        UINT8               i2cData[10];
        I2C_7_BIT_ADDRESS   SlaveAddress;
        int                 Index;
        int                 DataSz;
        UINT32              actualClock;
        BOOL                Acknowledged;
        BOOL                Success = TRUE;
        UINT8               i2cbyte;


        // Initialize debug messages (when supported)
        //DBINIT();

        // Set the I2C baudrate
        //actualClock = I2CSetFrequency(I2C2, SYS_FREQ, I2C_CLOCK_FREQ);
        //if ( abs(actualClock-I2C_CLOCK_FREQ) > I2C_CLOCK_FREQ/10 )
       // {
        //    DBPRINTF("Error: I2C1 clock frequency (%u) error exceeds 10%%.\n", (unsigned)actualClock);
        //}

        // Enable the I2C bus
        //I2CEnable(I2C2, TRUE);
        
        
        // setup system wide interrupts  ///
        INTEnableSystemMultiVectoredInt();
        int count0 = 0;
        int flag0 = 0;
        int count1 = 0;
        int flag1 = 0;
        mPORTBClearBits(BIT_0);
        mPORTBClearBits(BIT_1);
        mPORTBClearBits(BIT_8);
        mPORTBClearBits(BIT_9);
        
        

	while(1)
	{
           // toggle a bit for ISR perfromance measure
            //mPORTBToggleBits(BIT_1);
        
        //Julia: toggle bit for gpio stuff
        
        if(GPIO==1){
            if(count0 == 1200 && flag0 == 0){
                mPORTBSetBits(BIT_0);
                count0 = 0;
                flag0 = 1;
            }
            if(count0 == 800 && flag0 ==1){
                mPORTBClearBits(BIT_0);
                flag0 = 0;
            }
            if(count0 == 750){
                mPORTBToggleBits(BIT_1);
            }
            
            
            if(count1 == 500 && flag1 == 0){
                mPORTBSetBits(BIT_8);
                mPORTBClearBits(BIT_9);
                count1 = 0;
                flag1 = 1;
            }
            if(count1 == 1000 && flag1 ==1){
                mPORTBClearBits(BIT_8);
                mPORTBSetBits(BIT_9);
                count1 = 0;
                flag1 = 0;
            }
            count0 = count0+1;
            count1 = count1+1;
        }
        if(I2C==1){
            //delay(10); // make a for loop
            //start command
            if(start==0) {
                int z;
                for(z=0; z<10000; z++){
                    // :)
                }
                mPORTBClearBits(BIT_2);
                int a;
                for(a=0; a<1000; a++){
                    // :)
                }
                mPORTBClearBits(BIT_3);
                start = 1;
                int b;
                for( b=0; b<1000; b++){
                    // :)
                }
            }else{ //toggle scl
                mPORTBSetBits(BIT_2);
                //send the data out
                int c;
                for(c = 0; c<8; c++){
                    mPORTBClearBits(BIT_3);
                    int d;
                    for(d=0; d<1000; d++){
                    // :)
                    }
                    mPORTBSetBits(BIT_3);
                    int e;
                    for(e=0; e<1000; e++){
                    // :)
                    }
                    mPORTBSetBits(BIT_2);
                }
                //ack/nack
                mPORTBClearBits(BIT_3);
                mPORTBClearBits(BIT_2);
                int f;
                for(f=0; f<1000; f++){
                    // :)
                }
                mPORTBSetBits(BIT_2);
                int g;
                for(g=0; g<1000; g++){
                    // :)
                }
                //stop condition
                mPORTBSetBits(BIT_3);
                int h;
                for(h=0; h<1000; h++){
                    // :)
                }
                mPORTBClearBits(BIT_3);
                mPORTBClearBits(BIT_2);
                int i;
                for( i=0; i<1000; i++){
                    // :)
                }
                mPORTBSetBits(BIT_3);
                mPORTBSetBits(BIT_2);
                start = 0;
               
            }
            
        }
        
 	}

}





