CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

Problem with SPI slave

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
cbarberis



Joined: 01 Oct 2003
Posts: 172
Location: Punta Gorda, Florida USA

View user's profile Send private message Send e-mail

Problem with SPI slave
PostPosted: Wed Apr 07, 2010 7:49 pm     Reply with quote

Hi,
I am getting rather frustrated as I cannot seem to see why my approach for what I am trying to do just does not work! I have two PIC's on separate boards; the first one is a master SPI (PIC18F2480) that gets data from an RS232 serial line, once it decodes the entry value for an address and a numeric value for a dac it sends this information via the SPI port to a second PIC (PIC16F88) that acts as a slave spi device, the second pic uses the hardware spi in slave mode and then uses a software I2C master mode to communicate to 5 separate dacs (MCP4725) the I2C seem to work perfectly and the spi data comming from the master spi pic also appear to be correct if one was to look at it on a logic analyzer that uses the spi logic protocol. In actuality; when I first wrote the code for both of these it appeared to work fine on the Proteus VSM simulation, however in the real world the slave spi does not seem to work.

My data to the slave is as follows: spi mode 1,1 3 bytes as shown below, the first byte is an address for the dac and the second and third byte form the 12 bit data for the dac.
Code:

   byte1(address)   byte2(MSB)   byte(LSB)
______        ______        _____        _______
      ||||||||      ||||||||     ||||||||


sorry for the lousy text diagram above!

Looking at the data and timing everything looks correct on an SPI logic analyzer, but for some silly reason I cannot seem to get anything more than the first byte (address) received by the slave. I am sure that I am overlooking something or doing something stupid, but after staring at this for a long time, i can't seem to see the problem, perhaps someone else might see the real issue or have a better approach as to how to propperly receive these three bytes correctly. I have included most of my code for both devices, except for the header files. I am using V4.106 of the CCS compiler. Both PIC's are running on internal oscillator @ 8MHz, NWDT,NOMCLR.

Any help or hints would be greatly appreciated! (I believe the actual problem is in the slave code)



Code:
////// Master SPI Code  on a PIC18F2480 //////////////////////////////////////////////////////////////////////


#define SLAVECOMMAND 0x80
#define clrscr() puts( "\x1b[2J")
#define home()   puts( "\x1b[H")
#define DACVFACTOR 0.0012
#define RVAL 82.5


#define RS232_BUFFER_SIZE  50      // allow for max number of chars

float volts,current;


int1 InBufferFlag = 0, CommandFlag = 0;

unsigned int8  channel;
unsigned int16 DacValue;
char rs232_buffer[RS232_BUFFER_SIZE];
char Function;
int8 rs232_nextin=0, rs232_nextout=0, rs232_lastin =0;

#int_RDA
void  RDA_isr(void)
{char c;
   c=getc();
   rs232_buffer[rs232_nextin++] = c;
   if(c == '\r')
   InBufferFlag = 1;
 if( (c == 'x') | (c == 'y') | (c == 'b')| (c == 'r'))     
     { CommandFlag = 1; Function = c;}
   if (rs232_nextin >= RS232_BUFFER_SIZE) {rs232_nextin=0;}
}


char bgetc(void)
 { char c;
   while (rs232_nextout == rs232_nextin) {restart_wdt();}
   c=rs232_buffer[rs232_nextout++];
   if (rs232_nextout >= RS232_BUFFER_SIZE) {rs232_nextout=0;}
   return(c);
}



void ClearBuff()  // clear serial char buffer
{ unsigned int i;
   disable_interrupts(INT_RDA);
   rs232_nextin=0;
   rs232_nextout=0;
   InBufferFlag = 0;
   CommandFlag = 0;
   for(i=0;  i< RS232_BUFFER_SIZE; i++)
         rs232_buffer[i]=0;
         restart_wdt();
      enable_interrupts(INT_RDA);  }



void Init()
{     
   setup_adc_ports(NO_ANALOGS|VSS_VDD);
   setup_adc(ADC_OFF|ADC_TAD_MUL_0);
   setup_spi(SPI_MASTER|SPI_H_TO_L|SPI_CLK_DIV_16);  // mode 1,1 clock h when inactive data valid on clk lead edge
   setup_wdt(WDT_OFF);
   setup_wdt(WDT_ON);
   setup_timer_0(RTCC_INTERNAL);
   setup_timer_1(T1_DISABLED);
   setup_timer_2(T2_DISABLED,0,1);
   setup_timer_3(T3_DISABLED|T3_DIV_BY_1);
   setup_vref(FALSE);
   output_high(PIN_B0);
   enable_interrupts(INT_RDA);
   enable_interrupts(GLOBAL);   
 }

/************************* Routine I use to send to slave *****************************************************
void WriteToSlaveValue(unsigned int8 address, unsigned int16 data)
 { unsigned int8 data_in; // read dummy
   unsigned int8 highbyte, lowbyte;
   highbyte = data >>8;
   lowbyte = data;
   
     output_low(PIN_B0);
     delay_us(10);
     spi_write(address);
     data_in = spi_read();
     delay_ms(20);
     spi_write(highbyte);
     data_in = spi_read();
     delay_ms(20);
     spi_write(lowbyte);
     data_in = spi_read();
     delay_us(10);
     output_high(PIN_B0);
 }
/************************************************************************************************************

void main()
{
  Init();
 
  delay_ms(100);
  clrscr();
  home();
 
  printf("Ready for command: \r\n");
 
 
  while(1)
  {
     if(InBufferFlag || CommandFlag)
  {     
   if(CommandFlag && Function == 'x'){ClearBuff(); WriteToSlaveCmd(Function);
   printf(":%c\r\n",Function);}
   if(CommandFlag && Function == 'r'){ClearBuff(); printf("Resetting PIC\r\n"); delay_ms(1000); reset_cpu();
 }
   
   
   
   if(InBufferFlag && rs232_buffer[0]== 'a')
      {  rs232_buffer[0] <<= 8; //shift out the first byte char 'a' in this case
       if(rs232_nextin > 0)
         channel = bget_int8();
         ClearBuff();
          InBufferFlag = 0;
          CommandFlag = 0;
          //printf("DAC:%u = \r\n",channel);       
        }

       if(InBufferFlag && rs232_buffer[0]== 'v')
       { rs232_buffer[0] <<= 8; //shift out the first byte char 'o' in this case
       if(rs232_nextin > 0)
         {DacValue = bget_int16();         
          WriteToSlaveValue(channel,DacValue);}
        volts = DACVFACTOR * DacValue;
        current = volts / RVAL;
        current *= 1000;
       printf("\r\nDAC:%u = %Lu Cts,  Volts = %5.3g V,  Iled = %5.1g Ma\r\n",channel,DacValue,volts,current);
       ClearBuff();
       InBufferFlag = 0;
       CommandFlag = 0; }

      }
         restart_wdt();
  }
} ///////////////////////////// end of master code  ///////////////////////////////////////////////////


Code:

////// Slave Code  on a PIC16F88 //////////////////////////////////////////////////////////////////////

int8 SPIdataBuffer[3];
int1 DataCommandFlag = 0;
int1 FunctionFlag = 0;
int1 DacFlag = 0;
int1 SPIFlag =0;

#define COMMANDBYTE 0x80 
#define BYTE1 0
#define BYTE2 1
#define BYTE3 2

#int_SSP
void  SSP_isr(void)

SPIFlag =1;  // not using this
}


void Init()
{  SET_TRIS_A(0b11110011);
   SET_TRIS_B(0b11110011);
   setup_adc(ADC_OFF);
//  setup_spi(SPI_SLAVE|SPI_H_TO_L|SPI_CLK_DIV_16);
// ***the following lines set-up the SPI module did not trust CCS routines **
SSPEN = 1;
SSPM2 = 1;
SMP = 0;
CKE = 1;
CKP = 1;
BF = 0;

//***********************************
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
   setup_timer_1(T1_DISABLED);
   setup_timer_2(T2_DISABLED,0,1);
   setup_comparator(NC_NC_NC_NC);
   setup_vref(FALSE);
   //enable_interrupts(INT_SSP);
  // enable_interrupts(GLOBAL);
   output_low(PIN_B3);
}


void main()
{
 int8 DacAddress, ByteIndex =0;
 unsigned int16 DacDataValue;
 int8 i, DacMSB, DacLSB;
 
 Init();

 char cmd;
 

 while(1)
 {     
     /*    while(!input(SPI_SS))  // tried this, same outcome always gets first byte but not the rest
         { if(BF)
           {SPIdataBuffer[ByteIndex] = SSPBUF;
            ByteIndex++;  }
           if(ByteIndex == 3)
            { DataCommandFlag = 1;
              ByteIndex =0;    }
         }  */

       while(!input(SPI_SS))   // this does not do it either,always gets first byte but not the rest   
        {   if(spi_data_is_in())
           {SPIdataBuffer[ByteIndex] = spi_read(0);
             ByteIndex++;
             SPIFlag =0;}
             
            if(ByteIndex == 3)
            { DataCommandFlag = 1;
              ByteIndex =0;}
                                  }
         
        if(DataCommandFlag)
      {
        if(SPIdataBuffer[BYTE1]== COMMANDBYTE)              // if not a dac command
        { FunctionFlag = 1; cmd = SPIdataBuffer[BYTE3];}    // it must be a function get the function
        else
        { DacAddress = SPIdataBuffer[BYTE1];               // get the dac address
          DacMSB = SPIdataBuffer[BYTE2];                   // get the dac MSB value
          DacLSB = SPIdataBuffer[BYTE3];                   // get the dac LSB value 
          DacDataValue = make16(DacMSB,DacLSB);            // reconstruct 12 bit value for dac
          DacFlag =1;}                                     // means the data is just for the dac
          DataCommandFlag = 0;
       }
       
       
     if(FunctionFlag) {   
     switch (cmd)
     { case 'x':
       output_high(PIN_B3);
       break;
       case 'y':
       output_low(PIN_B3);
       break;
     }
      FunctionFlag = 0;
     }
     
     
     if(DacFlag)
     { //WriteToDacOnly(DacAddress,DacDataValue);
       WriteToDacAndEEprom(DacAddress,DacDataValue);
       DacFlag = 0;
     }
               
 }

}
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Thu Apr 08, 2010 1:33 am     Reply with quote

Try the SPI slave example in this thread and see it works with your
hardware:
http://www.ccsinfo.com/forum/viewtopic.php?t=39145
Ttelmah



Joined: 11 Mar 2010
Posts: 19552

View user's profile Send private message

PostPosted: Thu Apr 08, 2010 4:13 am     Reply with quote

Some comments though.

You are not sending mode 1,1.
Mode 1,1, requires:

SPI_H_TO_L | SPI_XMIT_L_TO_H

You are transmitting the data on the wrong edge, and currently running mode 1,0

Your receiver is also set for 1,0 though. Mode 1,1, requires CKP=1, CKE=0.

You can't clear the BF flag, by setting it to zero. You have to _read_ the data, which will clear the flag. This flag may well get set, when you first wake up. This is why it is marked in the data sheet as 'R', not 'R/W'.
On all flags like this, you must clear the condition, rather than just trying to change the flag.
Your initialisation, should use something like:
while(BF) spi_read();

to clear the BF flag.

Best Wishes
cbarberis



Joined: 01 Oct 2003
Posts: 172
Location: Punta Gorda, Florida USA

View user's profile Send private message Send e-mail

PostPosted: Thu Apr 08, 2010 5:01 pm     Reply with quote

Thank you all,

I did have the incorrect SPI mode selected as indicated, but even after fixing that nothing seemed to work with the SPI slave, I finally got it working by increasing the time between bytes to ~650 us which I think is ridicuosly long, but apparently one thing that seemed to fix the SPI transmission of data was to get rid of the ; spi_read(0); after doing the spi_write(XXXX); on the master spi code? I am not too sure why that would have such an impact.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group