|
|
View previous topic :: View next topic |
Author |
Message |
tom.ayars
Joined: 23 Jun 2008 Posts: 14
|
SPI slave response |
Posted: Thu Jul 17, 2008 10:52 am |
|
|
Can someone point me to an example of a master device sending data then waiting some time before the slave sends a response back to the master? |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Jul 17, 2008 11:26 am |
|
|
Typically this would be done by the master polling a status register
in the SPI slave. It waits until the "busy" bit goes low. Then the
master does a read to the slave's data register. Or, the slave might
also provide an interrupt to the master (on a dedicated \INT pin
coming from the slave and connected to the EXT INT pin on the master). |
|
|
tom.ayars
Joined: 23 Jun 2008 Posts: 14
|
|
Posted: Thu Jul 17, 2008 11:40 am |
|
|
So the master would receive an interrupt saying there is data available in the slave's register and at that point the master would do a in=spi_read() and would the slave do a spi_write(data) or would it do a garbage=spi_read(data)?
thanks |
|
|
Ttelmah Guest
|
|
Posted: Thu Jul 17, 2008 1:09 pm |
|
|
When the master, writes to the slave, it receives _back_ the data already in the SPI data register on the slave PIC.
All actual transfers have to be performed by the master.
You write a byte into the slave data register, set a signal on the slave to say 'I have something to send', and when the master writes a byte to the slave (dummy byte), it receives back, the waiting byte.
You can do it without having a separate signal, by regularly 'polling' with the master, but using a line, gives the faster trigger.
Best Wishes |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Jul 17, 2008 2:27 pm |
|
|
You had a question about the difference between spi_write and spi_read
when used in slave code. To check this, make a test program:
Code: | #include <16F877.H>
#fuses XT,NOWDT,NOPROTECT,BROWNOUT,PUT,NOLVP
#use delay (clock=4000000)
//#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)
#define SPI_MODE_0 (SPI_L_TO_H | SPI_XMIT_L_TO_H)
#define SPI_MODE_1 (SPI_L_TO_H)
#define SPI_MODE_2 (SPI_H_TO_L)
#define SPI_MODE_3 (SPI_H_TO_L | SPI_XMIT_L_TO_H)
//=================================
void main()
{
setup_spi(SPI_SLAVE | SPI_MODE_0);
spi_read(0x55);
spi_write(0x55);
while(1);
} |
Then look at the .LST file. Here's part of it:
Code: | ... spi_read(0x55);
0026: BCF 03.5
0027: MOVF 13,W // Read SSPBUF into W
0028: MOVLW 55
0029: MOVWF 13 // Load SSPBUF with 0x55
002A: BSF 03.5
002B: RRF 14,W // Rotate BF bit into CY
002C: BTFSS 03.0 // Wait in loop until BF = 1
002D: GOTO 02B
...
... spi_write(0x55);
002E: BCF 03.5
002F: MOVF 13,W // Read SSPBUF into W
0030: MOVLW 55
0031: MOVWF 13 // Load SSPBUF with 0x55
0032: BSF 03.5
0033: RRF 14,W // Rotate BF bit into CY
0034: BTFSS 03.0 // Wait in loop until BF = 1
0035: GOTO 033
...
|
Conclusion: They do the same thing.
Here's the code where it puts the return value
into a variable. It does the same thing as above
but it also does a read of SSPBUF at the end.
Code: | ... c = spi_read(0x55);
002E: BCF 03.5
002F: MOVF 13,W // Read SSPBUF into W
0030: MOVLW 55
0031: MOVWF 13 // Load SSPBUF with 0x55
0032: BSF 03.5
0033: RRF 14,W // Rotate BF bit into CY
0034: BTFSS 03.0 // Wait in loop until BF = 1
0035: GOTO 033
0036: BCF 03.5
0037: MOVF 13,W // Read SSPBUF into W
0038: MOVWF 21 // Put W into 'c' variable |
|
|
|
tom.ayars
Joined: 23 Jun 2008 Posts: 14
|
|
Posted: Mon Jul 28, 2008 8:30 am |
|
|
Thanks for the help guys. I now have another question maybe one of you can help me with. I have a pic set up as a slave device on the line and a separate device acting as the master. I am using the spi_read() command inside the SSP interrupt and I am having success reading data coming in. The problem arises when I go to read from the MISO line on the other device, all I can see is 0xFF. I have hooked up a probe to the MISO line and can confirm this. Also, I look at the SSPBUF register and the data is there.
I guess my question is, what exactly is happening in the SSPSR shift register when I issue a spi_read() command that would cause me to only be able to see 0xFF on the MISO line? |
|
|
Ttelmah Guest
|
|
Posted: Mon Jul 28, 2008 8:52 am |
|
|
Nothing....
However, if you have glance at some other threads, you will find, that I am 'not alone', in preferring to use my own code, for the SPI. The CCS code, is poorly documented, with regards to how it does work, and unnecessarily complex, when using the SPI, especially in interrupt driven environments.
For myself, on a 18 chip, I use:
Code: |
#byte SSPBUF = 0xFC9
#byte SSPCON = 0xFC6
#byte SSPSTAT = 0xFC7
#bit BF = SSPSTAT.0
/* Now the SSP handler code. Using my own, since the supplied routines test the wrong way round for my needs */
#DEFINE READ_SSP() (SSPBUF)
#DEFINE WAIT_FOR_SSP() while(!BF)
#DEFINE WRITE_SSP(x) SSPBUF=(x)
#DEFINE CLEAR_WCOL() SSPCON=SSPCON & 0x3F
|
In the interrupt handler, I can just use 'READ_SSP' at the start of the handler, when I want to read the SSPBUF register, and 'WRITE_SSP', when I want to load it.
One thing that could cause your problem though is just how slow the slave can be. The interrupt is only called once the byte has sent. The slave then takes typically perhaps about 40 instructions (even if it is not in another interrupt to actually 'reach' the handler. If the handler puts the read byte into a buffer, you can easily be talking another 20 to 30 instructions to do this, If yor byte you want to write back, itself comes from an array, you can easily be talking the same again, before it is actually loaded into the buffer register. Easily over 100 instruction times, before the master can start to clock data, and actually get back what is expected. If the slave is already in another interrupt, it gets even worse...
0xFF, is though an unusual combination. You would normally expect to get back the last byte transferred, even if it has been read. Are you sure something else is not changing the TRIS on the SPI line, or setting this high?.
Best Wishes |
|
|
bright
Joined: 24 Apr 2011 Posts: 14
|
this is not a reply merely just a question |
Posted: Tue May 03, 2011 1:44 pm |
|
|
PCM programmer I have seen the ccs program and also the assembly programs that you have posted, I have just 1 question from your assembly program for spi_write function, the last two lines don't they make this assembly code stay in an infinite loop. It is just that I have tried to use this function in my program and it seems as if when my program reaches this line it goes into an infinite loop, even took your code and simulated it with MPLAB SIM and it does the same thing. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue May 03, 2011 1:53 pm |
|
|
1. Post a very short test program that shows the problem. The program
should be 10 lines of code or less. It must compile without errors if
I copy and paste it into MPLAB.
2. Post your compiler version.
3. Post a description of how you know it's in an infinite loop.
What test are you doing, to prove that it happens ? Describe the test.
Describe the test setup (hardware board, RS-232 link to a terminal
program on the PC, etc.). |
|
|
bright
Joined: 24 Apr 2011 Posts: 14
|
|
Posted: Tue May 03, 2011 2:14 pm |
|
|
This is the code I have written to test my spi if it works:
Code: |
#include <16F690.H>
#use delay (clock=8000000)
#define SPI_MODE_0 (SPI_L_TO_H | SPI_XMIT_L_TO_H)
#define SPI_MODE_1 (SPI_L_TO_H)
#define SPI_MODE_2 (SPI_H_TO_L)
#define SPI_MODE_3 (SPI_H_TO_L | SPI_XMIT_L_TO_H)
//=================================
void main()
{
setup_spi(SPI_SLAVE | SPI_MODE_0);
spi_write(0x67);
OUTPUT_BIT(PIN_C0, 1);
} |
I am using the CCS_PICC_CP_4084 version.
To answer your third question, I went to debugger menu and then selected then went to select tool and then from there I chose the MPLAB SIM to check what happens to my code line by line, then I kept on pressing F7 on my keyboard to keep on moving from 1 line to another until I got to the line: spi_write(0x67); and then no matter how many times I pressed F7 it just stood there. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
|
bright
Joined: 24 Apr 2011 Posts: 14
|
1 more question |
Posted: Wed May 04, 2011 7:17 am |
|
|
I am sorry for being a nuisance but can I ask you 1 more question. If want to change few lines from the assembly code that you have given for spi_write function, how can I achieve that with the version I am using? |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed May 04, 2011 11:53 am |
|
|
I assume you want to get rid of the test at the end of the spi_write() code.
You can do it as shown below. For a debugging session, just uncomment
the "#define DEBUG" line as show below. This will enable the macro
replacement for spi_write(), which is also shown below. This macro does
not have the test at the end. It only loads SSPBUF with a value. I think
this is what you want for your MPLAB simulator testing.
Just remember that when you're done running it in the simulator and
you're ready to test it in real hardware, to comment out the "#define
DEBUG" line, so the normal code will be put back in your program.
And re-compile it, of course.
Code: |
#include <18F452.h>
#fuses XT,NOWDT,PUT,BROWNOUT,NOLVP
#use delay(clock=4000000)
#define DEBUG
#ifdef DEBUG
#byte SSPBUF = getenv("SFR:SSPBUF")
#define spi_write(x) SSPBUF=(x)
#endif
//======================================
void main(void)
{
spi_write(0x55);
while(1);
} |
|
|
|
bright
Joined: 24 Apr 2011 Posts: 14
|
|
Posted: Wed May 04, 2011 2:32 pm |
|
|
Ok thank you PCM programmer, you have been a great help. |
|
|
|
|
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
|