|
|
View previous topic :: View next topic |
Author |
Message |
thibow
Joined: 11 Apr 2012 Posts: 30
|
|
Posted: Thu Apr 12, 2012 1:59 pm |
|
|
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
|
|
Posted: Thu Apr 12, 2012 2:20 pm |
|
|
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
|
|
Posted: Thu Apr 12, 2012 2:31 pm |
|
|
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
|
|
Posted: Fri Apr 13, 2012 3:38 am |
|
|
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
|
|
Posted: Fri Apr 13, 2012 7:02 am |
|
|
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
|
|
Posted: Fri Apr 13, 2012 7:51 am |
|
|
Just tested and approved
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
|
|
Posted: Fri Apr 13, 2012 8:18 am |
|
|
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
|
|
Posted: Fri Apr 13, 2012 9:15 am |
|
|
Yes it does, you're right, I forgot to removed it |
|
|
thibow
Joined: 11 Apr 2012 Posts: 30
|
|
Posted: Fri Apr 13, 2012 3:29 pm |
|
|
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... ?
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
|
|
Posted: Fri Apr 13, 2012 4:23 pm |
|
|
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
|
|
Posted: Fri Apr 13, 2012 4:26 pm |
|
|
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
|
|
Posted: Fri Apr 13, 2012 4:36 pm |
|
|
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
|
|
Posted: Mon Apr 16, 2012 9:52 am |
|
|
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
|
|
Posted: Mon Apr 16, 2012 10:00 am |
|
|
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
|
|
Posted: Mon Apr 16, 2012 10:13 am |
|
|
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. |
|
|
|
|
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
|