Wednesday, April 10, 2013

ADIS16209 sensor & dspiC33FJ128MC802 & SPI

The task is my first hands-on experience with PIC programming(dspic33FJ). In my opinion, dspiC33FJ128MC802 is a powerful and flexible PIC since it has re-mappable I/Os. This particular feature has also imposed some difficulties for a PIC newbie like me.
So, here is the task : make ADIS16209 sensor work with dspiC33FJ128MC802 via SPI.
Connections:
PIN 6 <---> MOSI (Master out slave in)
PIN 7 <---> MISO (Master in slave out)
PIN 22 <---> CS (Chip select)
PIN 11 <---> CLK (Clock)

Biggest problem I have faced was setting correct clock edge and clock polarity for SPI.(I needed an oscilloscope to debug this)
Sample code that works :
 /*  
  * File:  main.c  
  *  
  * Created on February 9, 2010, 10:53 AM  
  */  
 #include <stdio.h>  
 #include <stdlib.h>  
 #include <p33Fxxxx.h>  
 _FOSCSEL(FNOSC_FRC);  
 _FOSC(FCKSM_CSECMD & OSCIOFNC_OFF & POSCMD_XT);  
 _FWDT(FWDTEN_OFF);  
 _FICD(JTAGEN_OFF & ICS_PGD3);  
 short temp;  
 /*  
  *  
  */  
 void delay(void) {  
   long i = 5242;  
   while (i--)  
     ;  
 }  
 void Init_SPI(void) {  
   SPI1STATbits.SPIEN = 0; //Disable SPI1  
   _SPI1IE = 1;  
   _SPI1IF = 0;  
   //*******  
   SPI1CON1bits.MSTEN = 1;  
   SPI1CON1bits.MODE16 = 1;  
   SPI1CON1bits.PPRE = 0;  
   SPI1CON1bits.SPRE = 2;  
   SPI1CON1bits.CKE = 0;  
   SPI1CON1bits.CKP = 1;  
   SPI1CON1bits.SMP=0;  
   SPI1STATbits.SPIEN = 1;  
   _SPI1IF = 0;  
 }  
 void turnLEDDebugOFF() {  
   LATAbits.LATA0 = 0;  
 }  
 void __attribute__((__interrupt__, __auto_psv__)) _SPI1Interrupt(void) {  
   SPI1STATbits.SPIROV = 0;  
   temp = SPI1BUF;  
   temp&=0b0011111111111111; //mask out   
   _SPI1IF = 0;  
    LATBbits.LATB11 = 1; // raise the slave select line}  
 }  
 void write_SPI(short command) {  
   LATBbits.LATB11 = 0; // lower the slave select line  
   // temp = SPI1BUF; // dummy read of the SPI1BUF register to clear the SPIRBF flag  
   SPI1BUF = (command); // write the data out to the SPI peripheral  
  //  while (!SPI1STATbits.SPITBF);     // wait for the data to be sent out  
 //            
  // while (SPI1STATbits.SPIRBF);     // wait for the data to be sent out  
 //  
 }  
 int main(int argc, char** argv) {  
   RCONbits.SWDTEN = 0; /* Disable Watch Dog Timer*/  
   // Configure Oscillator to operate the device at 40Mhz  
   // Fosc= Fin*M/(N1*N2), Fcy=Fosc/2  
   PLLFBD = 38; // M=154  
   CLKDIVbits.PLLPOST = 0; // N2=2  
   CLKDIVbits.PLLPRE = 0; // N1=10  
   OSCTUN = 0; // Tune the FRC  
   // Clock switching to incorporate PLL  
   __builtin_write_OSCCONH(0x01); // Initiate Clock Switch to Internal  
   // FRC with PLL (NOSC=0b001)  
   __builtin_write_OSCCONL(0x01); // Start clock switching  
   while (OSCCONbits.COSC != 0b001); // Wait for Clock switch to occur  
   AD1PCFGL = 0xFFFF; // Pins to digital  
   LATAbits.LATA0 = 1;  
   TRISAbits.TRISA0 = 0;  
   TRISBbits.TRISB12 = 0; //output RB12  
   LATBbits.LATB12=0;  
   LATBbits.LATB12=1;  
   TRISBbits.TRISB3 = 1; //input RB3  
   RPINR20bits.SDI1R = 3; //SDI1 input is associated to pin RP3 (pin 7 of the dsPIC)  
   RPOR2bits.RP4R = 8; //remappable pin RP4 (pin 11 of the dsPIC) is associated to SCK1  
   RPOR1bits.RP2R = 7; //remappable pin RP2 (pin 6 of the dsPIC) is associated to SDO1  
  // RPOR5bits.RP11R = 9; //CS RP11  
   Init_SPI();  
   TRISBbits.TRISB3 = 1; //input RB3  
   TRISBbits.TRISB2 = 0; //output RB2  
   TRISBbits.TRISB4 = 0; //output RB4  
   TRISBbits.TRISB11 = 0; //output RB11  
   LATBbits.LATB11 = 1;  
   while (OSCCONbits.LOCK != 1) {  
   };  
   while (1) {  
     int i = 0;  
     for (i = 0; i < 255; i++) {  
       write_SPI(0x4A00); //read product identification  
       delay();  
     }  
   }  
   return (EXIT_SUCCESS);  
 }  

2 comments: