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 question
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
Birdasaur



Joined: 07 Oct 2003
Posts: 29

View user's profile Send private message

SPI PIC to PIC question
PostPosted: Wed Dec 03, 2003 11:25 am     Reply with quote

Question

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

View user's profile Send private message

Temporary fix for problem
PostPosted: Wed Dec 03, 2003 12:08 pm     Reply with quote

Confused Rolling Eyes

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

View user's profile Send private message

Narrowing the problem
PostPosted: Wed Dec 03, 2003 12:28 pm     Reply with quote

Question

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

View user's profile Send private message

Re: SPI PIC to PIC question
PostPosted: Wed Dec 03, 2003 1:02 pm     Reply with quote

Birdasaur wrote:
Question 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

View user's profile Send private message

PostPosted: Wed Dec 03, 2003 1:04 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Wed Dec 03, 2003 1:16 pm     Reply with quote

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

View user's profile Send private message

Re to Neutone
PostPosted: Wed Dec 03, 2003 1:19 pm     Reply with quote

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

View user's profile Send private message

SS line held for entire packet
PostPosted: Wed Dec 03, 2003 1:26 pm     Reply with quote

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

View user's profile Send private message

BTW...
PostPosted: Wed Dec 03, 2003 1:33 pm     Reply with quote

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

View user's profile Send private message

Re: Re to Neutone
PostPosted: Wed Dec 03, 2003 1:38 pm     Reply with quote

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

View user's profile Send private message

Re: Re to Neutone
PostPosted: Wed Dec 03, 2003 1:44 pm     Reply with quote

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

View user's profile Send private message

Re: Re to Neutone
PostPosted: Wed Dec 03, 2003 2:01 pm     Reply with quote

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

View user's profile Send private message

Re: Re to Neutone
PostPosted: Wed Dec 03, 2003 2:11 pm     Reply with quote

Quote:

In the master;
Load buffer.
SS to start the transfer.
Pause to allow slave to detect SS.

Arrow What are we talking here, 10 us? I saw somewhere 50...
Question 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!! Smile
Birdasaur



Joined: 07 Oct 2003
Posts: 29

View user's profile Send private message

Somethings amiss...
PostPosted: Wed Dec 03, 2003 2:23 pm     Reply with quote

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

View user's profile Send private message

Re: Somethings amiss...
PostPosted: Wed Dec 03, 2003 4:00 pm     Reply with quote

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.
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 1, 2  Next
Page 1 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