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

2 PIC18 can't talk using SPI connection..
Goto page Previous  1, 2
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
thibow



Joined: 11 Apr 2012
Posts: 30

View user's profile Send private message

PostPosted: Thu Apr 12, 2012 1:59 pm     Reply with quote

I just read carefully the post you linked PCM, and what I can see is that the PIC used use a SPI buffer.. so the slave DOES NOT CALL spi_read...
This might be one thing, I can't find any spi buffer for PIC18LF2550
Ttelmah



Joined: 11 Mar 2010
Posts: 19539

View user's profile Send private message

PostPosted: Thu Apr 12, 2012 2:20 pm     Reply with quote

spi_read, _returns the contents of the SPI_BUFFER register_.
The code PCM programmer pointed you to, dated from before spi_read worked reliably, so the code instead, reads the hardware buffer register directly. You don't need to do this - just use spi_read.
If you want to read the buffer you can access it with:
Code:

#byte SPI_BUFFER=getenv("SFR:SSPBUF")

and then use 'SPI_BUFFER' as a variable name to access it.

Best Wishes
thibow



Joined: 11 Apr 2012
Posts: 30

View user's profile Send private message

PostPosted: Thu Apr 12, 2012 2:31 pm     Reply with quote

Thank you Ttelmah, I manage to do something with "#byte SSPBUF = 0x0FC9" but as you said, it is old and obsolete..

Now it is so confusing, I feel like everything is so unpredictable.. I saw that PCM examples work with "spi_xmit_l_to_h" in setup_spi.. so I added that too.

Then, I get so confusing output even with a simple interrupt..

=====MASTER=====
Code:
#include <18F2550.H>

#fuses HSPLL,NOWDT,NOPROTECT,NOLVP,NODEBUG,PLL2,CPUDIV4,NOVREGEN,NOMCLR
#use delay(clock=16000000)

#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C5,bits=8,STOP=1)
#define SPI_SS pin_A5

signed int data;   

void main (void){

   //configure the device to be a master, data transmitted on H-to-L clock transition
   setup_spi(spi_master | spi_l_to_h | spi_clk_div_16 | spi_xmit_l_to_h);
   output_HIGH(pin_A1); //Led à 0
   output_HIGH(pin_A0); //Led à 0   
   output_HIGH(SPI_SS); // SS initialized


   while(1){
   
   output_LOW(SPI_SS);
   spi_write(13);
   output_HIGH(SPI_SS);
   
   delay_ms(250);

   output_LOW(SPI_SS);
   data=spi_read(0);
   output_HIGH(SPI_SS);

   printf("data :%d\r\n",data);
   output_toggle(pin_A0);
   output_toggle(pin_A1);

   delay_ms(250);
   }
}


=====SLAVE=====
Code:
#include <18F2550.H>

#fuses HSPLL,NOWDT,NOPROTECT,NOLVP,NODEBUG,PLL2,CPUDIV4,NOVREGEN,NOMCLR
#use delay(clock=16000000)
signed int received;
signed int i=1;



#int_ssp
void ssp_isr(void) {
// while(!spi_data_is_in());
   received=spi_read();
   //delay_us(100);
   spi_write(received+i);
   output_toggle(pin_A1);
}
void main (void){
   
   //configure the device to be a slave, data transmitted on H-to-L clock transition
   setup_spi(spi_slave | spi_l_to_h | spi_xmit_l_to_h );

   enable_interrupts(INT_SSP);
   enable_interrupts(global);


   output_HIGH(pin_A1); //Led à 0
   output_HIGH(pin_A0); //Led à 0   
   
   while(1){
     }
}


====Output====
Code:
data :13
data :1
data :1
data :1
data :1
data :1
data :1


It woks well once.. and then write 1.. can't figure out why..
Ttelmah



Joined: 11 Mar 2010
Posts: 19539

View user's profile Send private message

PostPosted: Fri Apr 13, 2012 3:38 am     Reply with quote

The problem is the SPI_WRITE in the slave.

Use the code that talks directly to the SSP buffer.

Historically, CCS's SPI_READ, and SPI_WRITE functions had problems when used in interrupts. SPI_READ performing an unnecessary test for data being available, and SPI_WRITE waiting till the data was sent. I had in the past always used my own versions directly accessing the buffer because of this.

A few CCS versions ago, there was a thread here saying that this had been fixed, and a quick test of SPI_READ, showed that this looked to be true, with in now just reading directly from the buffer without testing the 'full' bit, when used in an interrupt - hurrah....

However a quick test of the assembly produced by SPI_WRITE, in 4.114, shows that it still waits for the write to complete, before exiting:
Code:

.................... #int_ssp
.................... void ssp_isr(void) {
.................... // while(!spi_data_is_in());
....................    received=spi_read();
00AE:  MOVF   FC9,W    //Directly read SSPBUF - perfect
00B0:  MOVWF  19
....................    //delay_us(100);
....................    spi_write(received+i);
00B2:  MOVF   1A,W
00B4:  ADDWF  19,W
00B6:  MOVWF  1B
00B8:  MOVF   FC9,W
00BA:  MOVFF  1B,FC9 //Write to SSPBUF
00BE:  RRCF   FC7,W //UUrgh - sits and waits for the transfer to complete
00C0:  BNC   00BE

Unfortunately, this is not what is wanted in an interrupt.... :(

So, CCS have 'half fixed' the functions for use in interrupts, and they will still give problems here.

Best Wishes
thibow



Joined: 11 Apr 2012
Posts: 30

View user's profile Send private message

PostPosted: Fri Apr 13, 2012 7:02 am     Reply with quote

Hello Ttelmah, thank's a lot for this full explanation, so what you advise me to do if I get it right is to forget SPI_WRITE in the slave, and use instead
Code:
SSPBUF = whatever_var
to talk to the Master.

Now why only in the slave and not in master as well ? Do you advise me not to use any ccs spi_read / write function at all ? (I mean it's not so painful to use SSBUF once one know how to use it..)

I'll have a look at this.

Thank's a lot
thibow



Joined: 11 Apr 2012
Posts: 30

View user's profile Send private message

PostPosted: Fri Apr 13, 2012 7:51 am     Reply with quote

Just tested and approved Very Happy
Thank you very much, now I can use interrupt and it works the way it should using in the slave :

Code:
#byte SSPBUF=getenv("SFR:SSPBUF")
...
signed int received;
signed int i=1;
...
#int_ssp
void ssp_isr(void) {

   received = SSPBUF;
   delay_us(100);
   if (received==13){
         SSPBUF = received+i;
      i++;
   }


(as far as I've seen, we can use spi_read/_write in the master without any issue)

Thank you for your help
jeremiah



Joined: 20 Jul 2010
Posts: 1354

View user's profile Send private message

PostPosted: Fri Apr 13, 2012 8:18 am     Reply with quote

Does it work without the delay in the ISR? If at all possible, you want to avoid using delays there. You want ISR's to be as fast as they possibly can.
thibow



Joined: 11 Apr 2012
Posts: 30

View user's profile Send private message

PostPosted: Fri Apr 13, 2012 9:15 am     Reply with quote

Yes it does, you're right, I forgot to removed it
thibow



Joined: 11 Apr 2012
Posts: 30

View user's profile Send private message

PostPosted: Fri Apr 13, 2012 3:29 pm     Reply with quote

I'm getting back to you as I face problem now sending characters..

The code is almost the same, except that I'm dealing with strings now.

Here is what I want to do: Send character from slave to master.

There is 2 ways:

-Slave sends continuously, and hope for the master to catch everything
-Slave sends one character once the Master has sent him a random thing

I tried both ways, the first was given random results, some times I could read exactly what I was sending, depending on the delays I had between read and write,.

The second way seems to be safer.. but I have only One Character out of 2 that I printed.. Here is the simple code

==MASTER
Code:
#include <18F2550.H>

#fuses HSPLL,NOWDT,NOPROTECT,NOLVP,NODEBUG,PLL2,CPUDIV4,NOVREGEN,NOMCLR
#use delay(clock=16000000)

#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C5,bits=8,STOP=1)
#define SPI_SS pin_A5
#define LED1 pin_A1
#define LED0 pin_A0

char data;   

void main (void){

   //configure the device to be a master, data transmitted on H-to-L clock transition
   setup_spi(spi_master | spi_l_to_h | spi_clk_div_16 | spi_xmit_l_to_h);
   output_HIGH(LED1); //Led à 0
   output_HIGH(LED0); //Led à 0   
   output_HIGH(SPI_SS); // SS initialized


   while(1){

      output_LOW(SPI_SS);
      spi_write('b');         //write a random thing
      output_HIGH(SPI_SS);
      output_toggle(LED0);

      delay_us(500);      //wait for the SLave to respond

      output_LOW(SPI_SS);
      data=spi_read(0);   //read it in DATA
      output_HIGH(SPI_SS);
   
      printf("%c",data);   //Show me what you got through RS232
      
      output_toggle(LED1);   
   
      delay_ms(500);      //wait a bit
   }
}


==SLAVE
Code:
#include <18F2550.H>
#include <string.h>

#fuses HSPLL,NOWDT,NOPROTECT,NOLVP,NODEBUG,PLL2,CPUDIV4,NOVREGEN,NOMCLR
#use delay(clock=16000000)

#byte SSPBUF=getenv("SFR:SSPBUF")
#define  LED1 pin_A1
#define  LED0 pin_A0

char received;
signed int i=0;
char chaine[32]="Hello Thibow";
int length;


#int_ssp
void ssp_isr(void) {

     output_toggle(LED1);
   received = SSPBUF;  //read the random char
   if (i==length)
   {   i=0;
   }
   SSPBUF=chaine[i];//write the chaine
   i++;
}

void main (void){
   
   //configure the device to be a slave, data transmitted on H-to-L clock transition
   setup_spi(spi_slave | spi_l_to_h | spi_xmit_l_to_h );

   enable_interrupts(INT_SSP);
   enable_interrupts(global);


   length=strlen(chaine);

   output_HIGH(LED1); //Led à 0
   output_HIGH(LED0); //Led à 0   
   
   while(1){ }
}



===OUTPUT
Code:
H
l
o
T
i
o
H
l
o
T
i
o


I expect to have "Hello Thibow" but it goes too fast... I can't figure out why
Is there any simple way to be able to use this SPI... ? Rolling Eyes

EDIT: Sorry i posted the wrong code, now it's updated.


Last edited by thibow on Fri Apr 13, 2012 4:32 pm; edited 2 times in total
jeremiah



Joined: 20 Jul 2010
Posts: 1354

View user's profile Send private message

PostPosted: Fri Apr 13, 2012 4:23 pm     Reply with quote

It's a fundamental thing about SPI. Writes and reads happen at exactly the same time, so when you call spi_write('b');, you are also reading one of the characters the slave wrote (but of course not storing it), so you missing every other character.

Remember, in SPI, the slave device doesn't drive anything. The master device is in complete control of the communications. It generates the clock and pulls the data from the slave rather than the slave pushing data per say.

Comment out the code:
Code:

      //output_LOW(SPI_SS);
      //spi_write('b');         //write a random thing
      //output_HIGH(SPI_SS);
      //output_toggle(LED0);

      //delay_us(500);      //wait for the SLave to respond
thibow



Joined: 11 Apr 2012
Posts: 30

View user's profile Send private message

PostPosted: Fri Apr 13, 2012 4:26 pm     Reply with quote

Smile I obviously missed something, ok that's great, I'm away from the PICs right now but I'll try it out. That's as you said a fundamental thing, and this is one of the major problem I got from the bigenning.

But will the Slave got an interruption if the master asks to read ?
Thank you very much.
jeremiah



Joined: 20 Jul 2010
Posts: 1354

View user's profile Send private message

PostPosted: Fri Apr 13, 2012 4:36 pm     Reply with quote

When the master asks to read, it is actually writing data at the exact same time, so the slave will interrupt.

Here is a good set of diagrams for the process:
http://avrbeginners.net/architecture/spi/spi.html

The chip is different, but the process is the same. Notice how both the slave and the master change data at exactly the same time.

So when you call value=spi_read(0x00), what happens is the master "writes" the 0x00 to the slave and the slave "writes" whatever value it wants to the master, at the exact same time.

I would be willing to bet if you got a 4 port oscilloscope and scoped SCLK, SDO, SDI, and SS at the same time that you would see that.
thibow



Joined: 11 Apr 2012
Posts: 30

View user's profile Send private message

PostPosted: Mon Apr 16, 2012 9:52 am     Reply with quote

It is great it works the way I want. The weird thing is that If I write
spi_write() it writes only, and spi_read() writes and reads.. why is there a read then...
jeremiah



Joined: 20 Jul 2010
Posts: 1354

View user's profile Send private message

PostPosted: Mon Apr 16, 2012 10:00 am     Reply with quote

Well technically spi_write() also reads, BUT it never makes the read data available to you. That's why you were missing every other character. They were being "read" each time you called spi_write(), but not stored because the function didn't provide the data read by the SPI hardware.

If you look at all 4 lines on a scope and do some calls to spi_write() and spi_read(), you'll see that both excite the SPI interface the same way.
thibow



Joined: 11 Apr 2012
Posts: 30

View user's profile Send private message

PostPosted: Mon Apr 16, 2012 10:13 am     Reply with quote

The best way not to get confused is to use spi_read() for both read AND write and use the return value if needed... avoiding spi_write

Thank you very much for your explanation, it's clear now.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page Previous  1, 2
Page 2 of 2

 
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