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

SPI slave receives bits shifted to right

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



Joined: 16 Sep 2005
Posts: 138
Location: The Netherlands

View user's profile Send private message Send e-mail Visit poster's website MSN Messenger

SPI slave receives bits shifted to right
PostPosted: Tue Dec 18, 2007 10:05 am     Reply with quote

Hello,

I searched this forum, but I couldn't get an answer to my question.

I use 2 PIC18F8722 connected with SPI. I have a the following code running on them:
Master:
Code:
#include "18F8722.h"
#device *=16 ADC=10
#case
#FUSES NOWDT       //No Watch Dog Timer
#FUSES H4          //High speed Osc (> 4mhz)
#FUSES NOPROTECT   //Code not protected from reading
#FUSES NOLVP       //Low Voltage Programming on B3
#FUSES NOCPD       //No EE protection
#FUSES NOWRT       //Program memory not write protected
#use delay(clock=40000000)
#use rs232(baud=9600, BRGH1OK, parity=n, bits=8, xmit=PIN_C6, rcv=PIN_C7, ERRORS, stream=ZIGBEE)
#use rs232(baud=9600, BRGH1OK, parity=n, bits=8, xmit=PIN_G1, rcv=PIN_G2, ERRORS, stream=GPS)

char c_spi = 0;

void spi_init()
{
   setup_spi(SPI_MASTER | SPI_H_TO_L | SPI_CLK_DIV_16);
}

void spi_send(int8 data)
{
   int8 result;
   
   result = spi_read(data);
   
   if (result > 0)
      c_spi = result;
   
   delay_ms(1);
   
   output_high(SCK_SPI1);
   
   delay_ms(100);
}

void main()
{
   spi_init();

   delay_ms(1000);
   spi_send('H');
   spi_send('e');
   spi_send('l');
   spi_send('l');
   spi_send('o');
   spi_send(' ');
   spi_send('W');
   spi_send('o');
   spi_send('r');
   spi_send('l');
   spi_send('d');
   spi_send('!');
   
   while (1)
   {
         delay_ms(100);
         output_toggle(PIN_H1); //toggle LED
   }
}


Slave:
Code:
#include "18F8722.h"
#device *=16 ADC=10
#case
#FUSES NOWDT       //No Watch Dog Timer
#FUSES H4          //High speed Osc (> 4mhz)
#FUSES NOPROTECT   //Code not protected from reading
#FUSES NOLVP       //Low Voltage Programming on B3
#FUSES NOCPD       //No EE protection
#FUSES NOWRT       //Program memory not write protected
#use delay(clock=40000000)
#use rs232(baud=9600, BRGH1OK, parity=n, bits=8, xmit=PIN_C6, rcv=PIN_C7, ERRORS, stream=USB)
#use rs232(baud=9600, BRGH1OK, parity=n, bits=8, xmit=PIN_G1, rcv=PIN_G2, ERRORS, stream=UWEAVE)

void spi_init()
{
   setup_spi(SPI_SLAVE | SPI_H_TO_L | SPI_CLK_DIV_16 | SPI_SS_DISABLED);
}

void main()
{
   char c_master = 0;

   spi_init();

   while(1)
   {
      c_master = spi_read(0);
      if (c_master > 0)
      {
         fputc(c_master, USB);
         c_master = 0;
      }
   }
}


when I use this, I get from the USB port the string "$2Â67É+À╣62►"

when I add the following line to the slave:
Code:

   while(1)
   {
      c_master = spi_read(0);
      if (c_master > 0)
      {
         c_master <<= 1;    // I ADDED THIS LINE
         fputc(c_master, USB);
         c_master = 0;
      }
   }
I receive: "Hdlln Vnrld " which says me there could be some timing problem or such. But whatever I do to the declaration of the SPI bus I can't seem to get it working.

Does anybody have an idea what my problem could be?
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Tue Dec 18, 2007 12:31 pm     Reply with quote

To me this looks like a synchronization problem. At program start the master and slave are not synchronized and it is very well possible that a random clock pulse is introduced. For example your spi_setup() differs from the power-on default, if the master and slave don't change the setup at exactly the same time you will have generated 1 or 2 clock pulses. Another possible cause of errors are the omission of pull-up / pull-down resistors for a defined power-on state.

The easiest way to fix this is to use a Chip Select signal which is used to tell the Slave it must be ready for communications. For added confusion Microchip has decided to call this Slave input line 'Slave Select'. Just before transmission you activate the Slave Select input and when communication is finished you disable the signal again.

If you don't have the spare pins to implement the Slave Select signal there are other synchronisation methods but these require more program memory and are slower.

A bug in your slave code:
Code:
   setup_spi(SPI_SLAVE | SPI_H_TO_L | SPI_CLK_DIV_16 | SPI_SS_DISABLED);
For the slave never set a clock speed! Get rid of the SPI_CLK_DIV_16. You are lucky it is working now because the defined value for SPI_CLK_DIV_16 is 1, which is by chance equal to the defined value for SPI_SS_DISABLED.

Another luring problem is in the speed the slave can handle the incoming data. The master is sending the data at a speed of SPI_CLK_DIV_16, i.e. a single bit is sent every 16 clock cycles and a byte in 16*8=128 clock cycles.
The slave is running at the same clock speed as the master and receives a whole byte in 128 clock cycles. The processor uses 4 clock cycles to execute a single instruction, so in your while-loop there is only time to execute 128/4=32 assembly instructions. This is a bit tight.... Cool
Give the slave a bit more time by slowing down the transmission from the master, insert a delay between the bytes or use SPI_CLK_DIV_64.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Tue Dec 18, 2007 12:33 pm     Reply with quote

In your slave setup, you're specifying a clock divisor constant. Slaves
don't supply a clock. The master supplies it. You don't need that divisor.
Also in your slave code, you're giving the spi_read() function a
parameter. In CCS, that signifies that the spi module should supply a
clock. But slaves don't supply a clock.

CCS has an SPI slave example file that shows how to do the read
in the slave.
Code:

while(!spi_data_is_in());

data = spi_read();

Quote:

c:\program files\picc\examples\ex_spi_slave.c
Foppie



Joined: 16 Sep 2005
Posts: 138
Location: The Netherlands

View user's profile Send private message Send e-mail Visit poster's website MSN Messenger

PostPosted: Wed Dec 19, 2007 3:55 am     Reply with quote

I implemented the Slave Select signal as CKielstra said and also changed the setup to setup_spi(SPI_SLAVE | SPI_H_TO_L);
Further more I changed spi_read(0); in spi_read(); as PCMprogrammer said.

And now it is working flawless. Many thanks!
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