View previous topic :: View next topic |
Author |
Message |
Birdasaur
Joined: 07 Oct 2003 Posts: 29
|
SPI PIC to PIC question |
Posted: Wed Dec 03, 2003 11:25 am |
|
|
With a 16f73 PIC SPI Master and a 16f73 PIC SPI Slave is it possible to send data in a "byte stream" fashion? I've searched for examples of this on this forum, and I've found that everyone:
selects the slave pic
reads/writes a byte
deselects the slave pic
for every byte, usually using an interrupt. This is cumbersome for me as I would like to transfer up to 20 bytes back and forth. (Almost like a binary packet) I'm trying to do several byte read/writes but the timing seems to be off. (Master requests two bytes of data, receives them in the wrong order). I'm so close now, is what I'm doing possible? My code should explain:
//Master code snippet
//Should request two bytes of data from slave and print them repeatedly
setup_spi(spi_master | spi_l_to_h | spi_clk_div_16 );
delay_ms(100);
while(1)
{
spi_write(byte1); //junk data
byte1 = spi_read(); //should receive 0xA4
delay_us(10);
spi_write(byte2); //junk data
byte2 = spi_read(); //should receive 0xA5
printf("byte1: %u\r\n",byte1);
//should print out 0xA4 but prints out 0xA5
printf("byte2: %u\r\n",byte2);
//should print out 0xA5 but prints out 0xA4
}
//Slave snippet
setup_spi(spi_slave | spi_l_to_h | spi_clk_div_16 );
while(1)
{
if(spi_data_is_in())
{
byte1 = spi_read();
spi_write(byte1); //byte1 is 0xA4
byte2 = spi_read();
spi_write(byte2); //byte2 is 0xA5
}
}
So as you can see I just want the Master to request multiple bytes from the slave in a linear stream fashion, but the bytes are out of order, implying that I'm not synched up. Am I doing anything wrong? I'm I not allowing for proper wait times between read and write calls?
Thanks for you help, if I can just get two bytes to come across correctly, I'll be able to run with this. |
|
|
Birdasaur
Joined: 07 Oct 2003 Posts: 29
|
Temporary fix for problem |
Posted: Wed Dec 03, 2003 12:08 pm |
|
|
I've temporarily fixed the problem with the following code:
while(1)
{
//if(spi_data_is_in())
//{
change. Apparently the spi_data_is_in() check was sucking up the first byte. Taking it out gets my order correct without flaw. I'm now able to send and receive 4 consecutive bytes without flaw. However, now how will my slave PIC know when there is a request from the Master? I want my slave PIC to do other things of course.
Could I just send a dummy value to get sucked up by the spi_data_is_in() call? Am I missing the real problem, ie... should I be using a delay in here somewhere that I'm not?
I know I could do this with the ssp interrupt but I don't think it would be wise to do 20 bytes worth of transfer in an interrupt function. I might be wrong about this though, maybe that is the best way...
Can anyone suggest? |
|
|
Birdasaur
Joined: 07 Oct 2003 Posts: 29
|
Narrowing the problem |
Posted: Wed Dec 03, 2003 12:28 pm |
|
|
I guess I'll keep posting because nobody else seems to know right now... :-)
When I replace the spi_data_is_in() check on the slave PIC, and have the master PIC make a dummy spi_write to pass the spi_data_is_in() check, it works! However only on the first try, every following message attempt causes the byte order to get shifted. (ie the timing is off) This would indicate to me that the spi_data_is_in() isn't necessarily "sucking up" the first byte sent out, but maybe I'm not giving somebody, somewhere enough time.
I don't know where this would be and I'd hate to have to go through all the combinations. I've read in the forum and the datasheets that I might have to clear the read register of the SPI hardware, but I don't quite understand how to do that. (If someone has a solution for this, please try to explain it to me a bit.)
Thank you. |
|
|
Neutone
Joined: 08 Sep 2003 Posts: 839 Location: Houston
|
Re: SPI PIC to PIC question |
Posted: Wed Dec 03, 2003 1:02 pm |
|
|
Birdasaur wrote: | With a 16f73 PIC SPI Master and a 16f73 PIC SPI Slave is it possible to send data in a "byte stream" fashion? | Yes
On the master Code: |
SPI_Buffer[0] = spi_read(SPI_Buffer[0]); delay_cycles( 8 );
SPI_Buffer[1] = spi_read(SPI_Buffer[1]); delay_cycles( 8 );
SPI_Buffer[2] = spi_read(SPI_Buffer[2]); delay_cycles( 8 );
SPI_Buffer[3] = spi_read(SPI_Buffer[3]); delay_cycles( 8 );
SPI_Buffer[4] = spi_read(SPI_Buffer[4]); delay_cycles( 8 );
SPI_Buffer[5] = spi_read(SPI_Buffer[5]); delay_cycles( 8 );
SPI_Buffer[6] = spi_read(SPI_Buffer[6]); delay_cycles( 8 );
SPI_Buffer[7] = spi_read(SPI_Buffer[7]); delay_cycles( 8 );
SPI_Buffer[8] = spi_read(SPI_Buffer[8]); delay_cycles( 8 );
SPI_Buffer[9] = spi_read(SPI_Buffer[9]); delay_cycles( 8 );
| In the slave
Code: | SPI_Buffer[0] = spi_read(SPI_Buffer[0]);
SPI_Buffer[1] = spi_read(SPI_Buffer[1]);
SPI_Buffer[2] = spi_read(SPI_Buffer[2]);
SPI_Buffer[3] = spi_read(SPI_Buffer[3]);
SPI_Buffer[4] = spi_read(SPI_Buffer[4]);
SPI_Buffer[5] = spi_read(SPI_Buffer[5]);
SPI_Buffer[6] = spi_read(SPI_Buffer[6]);
SPI_Buffer[7] = spi_read(SPI_Buffer[7]);
SPI_Buffer[8] = spi_read(SPI_Buffer[8]);
SPI_Buffer[9] = spi_read(SPI_Buffer[9]);
| Load the buffer in the master before each transmition. Unload after each transmition. Do the same in the slave. |
|
|
Birdasaur
Joined: 07 Oct 2003 Posts: 29
|
|
Posted: Wed Dec 03, 2003 1:04 pm |
|
|
On the master I called an spi_read(0) after the first spi_write to force the clock to go through. It accomplished the same as when I tried to write out dummy data with an spi_write().
I guess I'll have to try this with the interrupt service unless somebody out there can give me a nudge in the right direction. |
|
|
Neutone
Joined: 08 Sep 2003 Posts: 839 Location: Houston
|
|
Posted: Wed Dec 03, 2003 1:16 pm |
|
|
Birdasaur wrote: | I guess I'll have to try this with the interrupt service unless somebody out there can give me a nudge in the right direction. | If you manage to get it working within an interupt post your results.
You might be helped by readings the data sheet to understand the limitations of the hardware. The slave select line should stay held during the entire packet. The slave should be waiting for the select line to drop before accepting new packet data and then wait for the select line to rise after the packet is finished. This will keep master and slave in sync. |
|
|
Birdasaur
Joined: 07 Oct 2003 Posts: 29
|
Re to Neutone |
Posted: Wed Dec 03, 2003 1:19 pm |
|
|
Hey thanks for taking a few moments to help.
Well I tried your solution, and it caused the order of the byte "stream" to shift once per interation, similiarly to some of my previous attempts.
How did you determine the number of cycles to delay on the Master PIC?
Maybe I need more time between?
Shouldn't I have similiar delays in the Slave PIC code to give the SPI Hardware a chance to send the data? |
|
|
Birdasaur
Joined: 07 Oct 2003 Posts: 29
|
SS line held for entire packet |
Posted: Wed Dec 03, 2003 1:26 pm |
|
|
I saw that in the data sheet and on this forum. One of the things I decided to do was ground the SS line on the Slave PIC, effectively forcing it into a Slave Mode listen state all the time. (I'm not an EE guy, so please go easy on me.) If that isn't a good idea, let me know.
I figured that forcing it low all the time would keep the master and slave in sync. Remember I was able to do this perfectly when I took out the spi_data_is_in() check, (which leads me to believe that this is a timing issue...). That being said, how the heck do I know when the master wants to send data? (a real application wouldn't be set up like how i have it now!!)
I think if all else fails, I can just take out the spi_data_is_in() check, then do it all within the interrupt service. That would be perfect.
What am I waiting for? I just get nervous when interrupts are leaned upon. What do you think? |
|
|
Birdasaur
Joined: 07 Oct 2003 Posts: 29
|
BTW... |
Posted: Wed Dec 03, 2003 1:33 pm |
|
|
With your code solution, I removed the spi_data_is_in() check and it worked great, just like my way worked great. Still, the problem is how would my Slave PIC know when to perform this transaction?
I'm setting up the interrupt service function now and we'll see how it goes. If it goes well, then it would allow for my Slave to do other chores while waiting for Master requests. (which is what I ultimately want...) |
|
|
Neutone
Joined: 08 Sep 2003 Posts: 839 Location: Houston
|
Re: Re to Neutone |
Posted: Wed Dec 03, 2003 1:38 pm |
|
|
Birdasaur wrote: | Shouldn't I have similiar delays in the Slave PIC code to give the SPI Hardware a chance to send the data? |
It takes an fixed number of machine cycles to copy a byte from memory to the hardware buffer where it will then automaticly be shifted out. When the automatic shift operation is finished the data is ready bit is set. The data has been shifted out and in at the same time on the same clock so the recieved byte is ready as well. Because the master controls the clock it knows the transfer is complete before the slave does. I have been using this at 1Mbaud with excelent reliability. Interupts dont work at this data rate. You should tie the SS pin on the slave to a pin on the master and be done with it. Leaving the SS tied to ground is relying on luck that they come up in sync. |
|
|
Birdasaur
Joined: 07 Oct 2003 Posts: 29
|
Re: Re to Neutone |
Posted: Wed Dec 03, 2003 1:44 pm |
|
|
Quote: | You should tie the SS pin on the slave to a pin on the master and be done with it. Leaving the SS tied to ground is relying on luck that they come up in sync. |
I think I understand. If I tie the Slave's SS pin to the master, now I have control of the timing.
Correct me if this is wrong...
Select Slave SS pin
send data byte 1
...
send data byte n
Release Slave SS pin
That is how I interpret this. Or is it more like this:
Select Slave SS pin
send data byte 1
Release Slave SS pin
...
Select Slave SS pin
send data byte n
Release Save SS pin
Please advise, and thank you very much for this great advice. |
|
|
Neutone
Joined: 08 Sep 2003 Posts: 839 Location: Houston
|
Re: Re to Neutone |
Posted: Wed Dec 03, 2003 2:01 pm |
|
|
Birdasaur wrote: | If I tie the Slave's SS pin to the master, now I have control of the timing. |
I this of it as a data packet transfer.
In the master;
Load buffer.
SS to start the transfer.
Pause to allow slave to detect SS.
Transfer all bytes.
SS to stop the transfer.
Unload buffer.
Do other task.
Repeat.
When the slave is finished with the transfer it should do it's other task and then be waiting to send data before the master lowers the SS pin again. The master and slave will be in locked step. If you add another pin for data ready the master can skip the slave untill it is ready. |
|
|
Birdasaur
Joined: 07 Oct 2003 Posts: 29
|
Re: Re to Neutone |
Posted: Wed Dec 03, 2003 2:11 pm |
|
|
Quote: |
In the master;
Load buffer.
SS to start the transfer.
Pause to allow slave to detect SS.
|
What are we talking here, 10 us? I saw somewhere 50...
This pause is for the ssp_isr() right?
Quote: |
Transfer all bytes.
SS to stop the transfer.
Unload buffer.
Do other task.
Repeat.
|
I see where you're going. I won't have to do that, my plan is to make the slave PIC a sort of data collector that collects various data points but only reports what it currently has in its buffer and only when requested.
I'm trying this right now!! |
|
|
Birdasaur
Joined: 07 Oct 2003 Posts: 29
|
Somethings amiss... |
Posted: Wed Dec 03, 2003 2:23 pm |
|
|
I really thought this would work. But I don't receive the data I am supposed to receive. It is consistent however, which implies it might be almost working.
On the Master PIC I have:
while (1)
{
output_low(SlaveSelectPin);
delay_us(50);
byte1 = spi_read(byte1);
delay_us(8);
//....
byten = spi_read(byten);
delay_us(8);
output_high(SlaveSelectPin);
//print my results to RS232
}
on the Slave PIC:
#int_ssp
ssp_isr()
{
byte1 = spi_read(byte1);
//...
byten = spi_read(byten);
}
What am I missing? Let me guess, I can't do it this way or I'm way off right? |
|
|
Neutone
Joined: 08 Sep 2003 Posts: 839 Location: Houston
|
Re: Somethings amiss... |
Posted: Wed Dec 03, 2003 4:00 pm |
|
|
I suggest you keep it in lock step and scrap the interupt routine.
The slave waits for SS to go low
Collect data..
load buffer
While(!SS);
transfer...
While(SS);
repeate
It's the whiles that keep it in sync. If you querie the slave often enough the data will not be too old. |
|
|
|