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 support@ccsinfo.com

SPI PIC to PIC 16F690 read from slave problem

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



Joined: 19 Apr 2011
Posts: 7

View user's profile Send private message

SPI PIC to PIC 16F690 read from slave problem
PostPosted: Thu Apr 21, 2011 1:15 am     Reply with quote

Hi,

I write some SPI PIC to PIC interface and success data write to slave but master can't get data from slave

Are anyone have some sample code for PIC16F for example or any suggestion ?

Best regards,

my code

master

Code:
#include <16f690.h>

#fuses INTRC,NOWDT,NOPROTECT
#use delay (clock=8000000)

#use rs232(baud=9600,xmit=PIN_B7,rcv=PIN_B5, errors)

#define SS_PIN PIN_C6

void main() {

   int data;
   //The next statement sets up the SPI hardware, with this PIC as a master using mode 1
   //SPI_CLK_DIV_64 sets the speed of the SPI clock pulses--this is the slowest speed
   setup_spi(SPI_MASTER | SPI_L_TO_H | SPI_CLK_DIV_16);
   delay_ms(100);
   output_high(SS_PIN);
   
   while(true) {
     
       output_low(PIN_C6);
       data=0;
       spi_write(0x18);
       spi_write(1);
       data=spi_read(0);
       output_high(PIN_C6);
       delay_ms(1000);
       printf("V1=%x\n\r",data);
   }

}


slave

Code:
#include <16f690.h>
#fuses INTRC,NOWDT,NOPROTECT
#use delay (clock=8000000)

#use rs232(baud=9600,xmit=PIN_B7,rcv=PIN_B5, errors)

int8 memory[80], data, instr, address;

void write_data(void)
{
   while(!spi_data_is_in());
   
   data = spi_read();
   
   if(address >= 0 || address <= 80)
   {
      memory[address] = data;
   }
}

void main(void)
{
   setup_spi(spi_slave | spi_l_to_h | spi_ss_disabled);

   while(true)
   {
      while(!spi_data_is_in());
      instr = spi_read();
     
      while(!spi_data_is_in());
      address = spi_read();

      if (instr == 0x18)
      {
         instr = spi_read(18);
      }
      else if(instr == 0xa)
      {
         write_data();
      }
   }
}
Ttelmah



Joined: 11 Mar 2010
Posts: 19366

View user's profile Send private message

PostPosted: Thu Apr 21, 2011 2:10 am     Reply with quote

Enable Slave select, and have the master send a select signal.

Problem is that without SS, it is very difficult to synchronise the two chips when they wake up. If the master wakes earlier or latter than the slave, there is a very good chance of a 'random' extra clock bit at the start of the transmission. Once you have this, the buses will remain permanently 'out of sync'.
Without SS. you need to have the clock line biased to a level (say high), and have the master pull it low for a period when it wakes, then start the SPI peripheral. On the slave, you need to have it watch the line, and wait for it to go low, and only then start the SPI peripheral. You also need to have something like a checksum in the data, and the slave respond with a bit pattern to the master. If the master sees the wrong bit pattern, and the slave sees the wrong checksum, you re-initialise the bus.
SPI without SS, is quite hard to do.

Best Wishes
natapongw



Joined: 19 Apr 2011
Posts: 7

View user's profile Send private message

PostPosted: Thu Apr 21, 2011 2:31 am     Reply with quote

Thank you very much Ttelmah

I try for many code but still can't get data from slave.
Now I remove "spi_ss_disabled" and it not work.

Screen not show anything when run but when send data to slave it's work.
natapongw



Joined: 19 Apr 2011
Posts: 7

View user's profile Send private message

PostPosted: Thu Apr 21, 2011 2:59 am     Reply with quote

Do I need some resistor in bus line ?
natapongw



Joined: 19 Apr 2011
Posts: 7

View user's profile Send private message

PostPosted: Thu Apr 21, 2011 6:01 am     Reply with quote

I can get value now !

I use "output_high(PIN_C6);" that is ss pin before loop in slave PIC.

But my new problem when I try to get data from array in slave it is incorrect more than correct data.
natapongw



Joined: 19 Apr 2011
Posts: 7

View user's profile Send private message

PostPosted: Thu Apr 21, 2011 6:11 am     Reply with quote

I found that every 3 loops data will correct here is my code

Master :

Code:
#include <16f690.h>
#fuses INTRC,NOWDT,NOPROTECT
#use delay (clock=8000000)

#use rs232(baud=9600,xmit=PIN_B7,rcv=PIN_B5,bits=8, errors)

#define SS_PIN PIN_C6
//————————————————————————————————————————————————————————————
void main() {

   int8 data,inp,loop;
   //The next statement sets up the SPI hardware, with this PIC as a master using mode 1
   //SPI_CLK_DIV_64 sets the speed of the SPI clock pulses--this is the slowest speed
   setup_spi(SPI_MASTER | SPI_L_TO_H | SPI_CLK_DIV_16);
   delay_ms(100);
   output_high(SS_PIN);
   data=0x00;
   while(true) {
     
     for(loop=0;loop<=1000;loop++){
      for(data=0;data<10;data++){

       output_low(SS_PIN);    //pull the slave select line low to select the slave
       delay_us(10);          //give the slave time to notice this (may be unnecessary)
       
       spi_write(data);        //send the value
       //if(spi_data_is_in())
       delay_us(loop);
       inp=spi_read(0);
       
       delay_us(10);          //(may be unnecessary)
       output_high(SS_PIN);   //deselect the slave.
       
       
       
       delay_ms(200);
       printf("V%d=%d\n\r",loop,inp);
     }
    }
   }
}


Slave

Code:
#include <16f690.h>
#fuses INTRC,NOWDT,NOPROTECT
#use delay (clock=8000000)

#use rs232(baud=9600,xmit=PIN_B7,rcv=PIN_B5, errors)

int8 gps[10]={1,3,3,6,122,1,2,4,7,3};
int val;

#int_ssp
void ssp_isr(void)
{
   disable_interrupts(INT_SSP); 
   val = spi_read(0);
   while(!spi_data_is_in())
   spi_write(18);
   enable_interrupts(INT_SSP);
}

void main(void)
{
   //printf("Begin\n\r");
   setup_spi(SPI_SLAVE | SPI_L_TO_H);
   clear_interrupt(INT_SSP);
   enable_interrupts(INT_SSP);
   enable_interrupts(GLOBAL);
   output_high(PIN_C6);
   while(true)
   {
      //val = spi_read(0); //spi_read must be passed an argument. The argument value is sent
                          //back to the master whenever the master sends us a message again.
                          //This allows two-way communication, but here the master ignores
                    //whatever the slave sends back, so just send a 0.
      //spi_write(gps[val]);

       //display the value read:
       //printf("Data : %u\n\r", val);

   }
}


And this is my result

V0=18
V0=3
V0=4
V0=18
V0=6
V0=7
V0=18
V0=9
V1=0
V1=18
V1=2
V1=3
V1=18
V1=5
V1=6
V1=18
.
.
.
.
Ttelmah



Joined: 11 Mar 2010
Posts: 19366

View user's profile Send private message

PostPosted: Thu Apr 21, 2011 10:13 am     Reply with quote

Don't disable the interrupt in the handler. Not needed, the hardware disabled interrupts for you.
You are mishandling the byte order. When the slave interrupt triggers, _one_ byte is waiting to be read. You are attempting to read this, then write another byte 'out', then waiting for a second byte to arrive.
Code:

//slave
#int_ssp
void ssp_isr(void)
{
   val = spi_read(); //Do _not_ try to send a value here on a slave
   spi_write(val+1); //This is the byte that will be received by the master on
   //it's _next_ transaction
}




Code:

//master
#define SS_PIN PIN_C6
//————————————————————————————————————————————————————————————
void main() {

   int8 data=0,inp;
   //The next statement sets up the SPI hardware, with this PIC as a master using mode 1
   //SPI_CLK_DIV_64 sets the speed of the SPI clock pulses--this is the slowest speed
   setup_spi(SPI_MASTER | SPI_L_TO_H | SPI_CLK_DIV_16);
   output_high(SS_PIN);
   delay_ms(1);
   do {
    //You declared loop as an int8. How can it count to 1000?....
    for(data=0;data<10;data++){

      output_low(SS_PIN);    //pull the slave select line low to select the slave
      spi_write(data);        //send the value
      output_high(SS_PIN);
      delay_us(70); //Allow time for the interrupt to be serviced - typically
      //60+ instructions
      output_low(SS_PIN);
      inp=spi_read(0);
      output_high(SS_PIN);
      delay_ms(200);
      printf("V%d=%d\n\r",inp);
    }
   }while(TRUE); //avoids warning message
}

Should give 1 to 11 as replies.

Best Wishes
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