View previous topic :: View next topic |
Author |
Message |
Sterngleiter
Joined: 07 Jan 2013 Posts: 90
|
SPI-Problem send multiple bytes |
Posted: Mon Sep 24, 2018 9:17 am |
|
|
Hello,
I would like to send 3 bytes via SPI, first and second Byte for the addressing and the third for data. However, I need answer from slave. I know that I can send one byte and have then one byte as answer. Somehow it does not work. When I rewrite my code just one byte I also get a byte. I have to send 3 bytes and possibly also receive 3. Can you tell me where I make a mistake.
Code Master:
Code: |
#include <main.h>
#use spi (MASTER, CLK=PIN_C3, DI=PIN_C4, DO=PIN_C5, ENABLE=PIN_C2, MODE=0, BITS=8, STREAM=SPI_1)
unsigned int8 eingang0=0;
int8 eingang1=0;
int8 eingang2=0;
void main()
{
port_b_pullups(0xFF);
output_high(pin_c2);
while(TRUE)
{
if(!input(pin_b0)){while(!input(pin_b0))
output_low(pin_c2);
spi_xfer(0x01);
eingang0=spi_xfer(0);
delay_us(5);
spi_xfer(0x02);
eingang1=spi_xfer(0);
delay_us(5);
spi_xfer(0x03);
eingang2=spi_xfer(0);
output_high(pin_c2);
}
}
}
|
Code Slave:
Code: |
#include <main.h>
#use spi (SLAVE,SPI1,MODE=1,bits=8, STREAM=SPI_1)
#byte SSP1BUF = 0xfc9
int8 value;
int8 eing;
int8 test[3];
int8 x=0;
void Ausgaenge(void);
#INT_SSP
void SSP_isr(void)
{
if (x>2){x=0;test[0]=0;test[1]=0;test[2]=0;}
test[x]=SSP1BUF;
x++1;
}
void main()
{
clear_interrupt(INT_SSP);
enable_interrupts(INT_SSP);
enable_interrupts(GLOBAL);
int8 zeit=100;
while(TRUE)
{
if (test[0]==0x01){SSP1BUF=0xff;}
if (test[1]==0x02){SSP1BUF=0xaa;}
if (test[2]==0x03){SSP1BUF=0xbb;}
}
} |
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19518
|
|
Posted: Mon Sep 24, 2018 10:02 am |
|
|
You should be loading your reply in the int_ssp. When this triggers the first time, load the reply you expect to receive for the second transfer.
Also you need to allow time. Problem is int_ssp triggers after the byte has transferred. Your slave needs to load the reply _before_ the master does the next transfer. You don't show your clock rates, but it will take typically about 40 instruction times before the slave can load the reply byte, so the master needs to pause for at least this long before issuing the second (and later) transfers. |
|
|
Sterngleiter
Joined: 07 Jan 2013 Posts: 90
|
|
Posted: Mon Sep 24, 2018 10:23 am |
|
|
8mhz internal clock is used. I have a waiting loop installed in master 5us after each send. How do I calculate something like that? do you have any suggestions for a program? |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19518
|
|
Posted: Mon Sep 24, 2018 10:31 am |
|
|
At 8MHz you are executing 2MIPS. 40 instructions is then 20uSec. You need a little more than this (30uSec), and that only if you load the bytes inside the interrupt. In your code, you don't, you have to get out of the interrupt and read/match the data bytes, which will take several times as long....
Also you don't have any delay after sending the header byte.
Just have a counter, reset by the header byte, and incremented each time the interrupt is called after this, and load the byte based on this counter. |
|
|
Sterngleiter
Joined: 07 Jan 2013 Posts: 90
|
|
Posted: Mon Sep 24, 2018 10:38 am |
|
|
How would you solve the problem? I also have to work outside of interrupt. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19518
|
|
Posted: Mon Sep 24, 2018 11:01 am |
|
|
Code: |
//slave
int8 send[]={0xFF, 0xAA, 0xBB, 0}; //load this with what you want
//to send.
#INT_SSP
void SSP_isr(void)
{
temp=spi_xfer_in(); //read the incoming
if (temp==1)
{x=0;test[1]=0;test[2]=0;}
test[x]=temp;
spi_prewrite(send[x]); //preload the reply bytes
x++;
}
//master
output_low(pin_c2);
spi_xfer(0x01);
delay_us(50);
eingang0=spi_xfer(0);
delay_us(50);
spi_xfer(0x02);
eingang1=spi_xfer(0);
delay_us(50);
spi_xfer(0x03);
eingang2=spi_xfer(0);
output_high(pin_c2);
|
|
|
|
Sterngleiter
Joined: 07 Jan 2013 Posts: 90
|
|
Posted: Mon Sep 24, 2018 11:16 am |
|
|
output_low(pin_c2);
spi_xfer(0x01);
delay_us(50);
eingang0=spi_xfer(0);
delay_us(50);
spi_xfer(0x02);
eingang1=spi_xfer(0);
delay_us(50);
spi_Xfer(0x03);
eingang2=spi_xfer(0);
output_high(pin_c2);
I thank you very much for the approach. With master code are the delay right?
Between first send and receive you have a delay, not between the others. that's wanted, right? |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19518
|
|
Posted: Mon Sep 24, 2018 11:23 am |
|
|
That's why it says //master.
I cut and pasted from your code. Added one extra delay on the first pair of transfers but missed one of the later pairs. Every pair of transfers need a delay between sending one byte and receiving the next. |
|
|
Sterngleiter
Joined: 07 Jan 2013 Posts: 90
|
|
Posted: Mon Sep 24, 2018 11:41 am |
|
|
Thanks, I will try tomorrow. Can we write if I have any questions? |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19518
|
|
Posted: Mon Sep 24, 2018 12:16 pm |
|
|
Yes, there are several people here who can help. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19518
|
|
Posted: Tue Sep 25, 2018 1:37 am |
|
|
Looking at it I realise you are missing one fundamental 'point' about SPI.
_Every_ SPI transaction, sends and receives a byte at the same time. You don't want to be clocking extra bytes out to receive the bytes back, use the transfers that are sending the bytes. So:
Code: |
//master
PostPosted: Mon Sep 24, 2018 5:16 pm Post subject:
output_low(pin_c2);
spi_xfer(0x01); //single 'send only' transfer to signal start
delay_us(50);
eingang0=spi_xfer(1); //Now each send clocks back a reply
delay_us(50);
eingang1=spi_xfer(2);
delay_us(50);
eingang2=spi_xfer(3);
output_high(pin_c2);
|
You use the transactions that are sending the bytes, as the transactions to clock the reply back. You don't want/need extra transactions between. I had not realised you were doing these extra transactions, which is why I missed the delays. |
|
|
Sterngleiter
Joined: 07 Jan 2013 Posts: 90
|
|
Posted: Wed Sep 26, 2018 1:44 pm |
|
|
Code:
//master
PostPosted: Mon Sep 24, 2018 5:16 pm Post subject:
output_low(pin_c2);
spi_xfer(0x01); //single 'send only' transfer to signal start
delay_us(50);
eingang0=spi_xfer(1); //Now each send clocks back a reply
delay_us(50);
eingang1=spi_xfer(2);
delay_us(50);
eingang2=spi_xfer(3);
output_high(pin_c2);
I do not understand red marked. I send 2 times the 1 in the int_ssp but I set x = 0 When temp==1. it will not be overwritten |
|
|
Sterngleiter
Joined: 07 Jan 2013 Posts: 90
|
|
Posted: Wed Sep 26, 2018 1:55 pm |
|
|
short question, why can not I simulate proteus spi. send runs but does not receive. the same code runs in the pic real time but not at proteus |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9229 Location: Greensville,Ontario
|
|
Posted: Wed Sep 26, 2018 2:01 pm |
|
|
short answer
Proteus is busted ! Has been for YEARS, please read PIC101 sticky. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19518
|
|
Posted: Wed Sep 26, 2018 2:08 pm |
|
|
Reason is the mode numbers are wrong. The SPI at both ends needs to have the same mode setting. Currently the slave has a different mode to the master resulting in it losing a bit of the transfer.... |
|
|
|