My SPI communication is taking a long time... can't figure out why. I am measuring elapsed time
in Propeller 1
Hey guys,
I am measuring elapsed time over various functions and displaying it through the Parallax Serial Terminal.
I noticed that my SPI functionality is taking a long time (it takes 105 milliseconds to execute the SPI function below).
Here is my method for measuring elapsed time:
Inside the ReadPayload function I started commenting stuff out so I could see what is taking so long, turns out the "Read RX Payload" part is what takes 105 milliseconds! Both the "Low(SPI_Ce)" and the "High(SPI_Ce)" take only 82 us (microseconds) each to execute.
So I dug into the "SpiReadWrite" function:
So I don't understand what the problem is here? Shouldn't this be executing like a 100 times faster? Thanks and any help is greatly appreciated!
I am measuring elapsed time over various functions and displaying it through the Parallax Serial Terminal.
I noticed that my SPI functionality is taking a long time (it takes 105 milliseconds to execute the SPI function below).
Here is my method for measuring elapsed time:
Time := -cnt
'Functions to time go here
nRF.ReadPayload
Time += cnt - 544
PST.Str(string(13,"Time to read payload: "))
PST.Dec(Time / (clkfreq / 1000)) 'Display in milliseconds
Inside the ReadPayload function I started commenting stuff out so I could see what is taking so long, turns out the "Read RX Payload" part is what takes 105 milliseconds! Both the "Low(SPI_Ce)" and the "High(SPI_Ce)" take only 82 us (microseconds) each to execute.
PUB ReadPayload | idx, fifoRegister
'Stop receiving
Low(SPI_Ce)
'Read RX payload
Low(SPI_Csn)
SpiReadWrite(R_RX_PAYLOAD)
repeat idx from 0 to 31
payload[idx] := SpiReadWrite(NOOP)
High(SPI_Csn)
'Start receiving
High(SPI_Ce)
So I dug into the "SpiReadWrite" function:
PUB SpiReadWrite(byte_out) : byte_in | bit
{{
SPI read-write procedure (8-bit SPI mode 0)
Read and write are synced, i.e. for each byte in it is one byte out
For deatails see: http://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus
}}
byte_in := byte_out
repeat bit from 0 to 7
'Write MOSI on trailing edge of previous clock
if (byte_in & $80)
High(SPI_Mosi)
else
Low(SPI_Mosi)
byte_in <<= 1
'Half a clock cycle before leading/rising edge
TIME.PauseUSec(1)
High(SPI_Sck)
'Half a clock cycle before trailing/falling edge
TIME.PauseUSec(1)
'Read MISO on trailing edge
byte_in |= Read(SPI_Miso)
Low(SPI_Sck)
return byte_in
PUB PinDelay(Pin)
if Pin == SPI_Ce
waitcnt(clkfreq / CE_DELAY + cnt) 'CE_DELAY = 100_000
elseif Pin == SPI_Csn
waitcnt(clkfreq / CSN_DELAY + cnt) 'CSN_DELAY = 100_000
PUB High(Pin)
dira[Pin]~~
outa[Pin]~~
PinDelay(Pin)
PUB Low(Pin)
dira[Pin]~~
outa[Pin]~
PinDelay(Pin)
PUB Read(Pin)
dira[Pin]~
return ina[Pin]
So I don't understand what the problem is here? Shouldn't this be executing like a 100 times faster? Thanks and any help is greatly appreciated!
Comments
It would also be worth moving the contents of High and Low into your read/write function, and only setting dira[Pin]~~ once, instead per iteration in the loop.
So it looks like I really need to get my hands on a SPI object thats written in assembly, and use that in place of my functions? I'm still shocked that its that much slower... so even the wait instructions are probably not accurate either.
EDIT:
So if I am reading the datasheet correctly for the nRF24L01+, it looks like it can handle an 8Mhz SPI clock speed.
I found the SPI_Asm.spin object, but I am a little confused what value to use for start(Delay,state). So state should be 0 so the Clock starts low.... but what is an appropriate delay to use? So 8 mhz is 0.125 microseconds correct? it says if I use a delay of 5 that is 500 nanoseconds, and a delay of 15 is 1000 nanoseconds. So it seems I could use the smallest delay e.g. 1 for the fastest speed?
Thanks again for the advice!
If you want, I will post some code that just increments. It's only one byte at a time but it has no delays.
Sure that sounds good. So you are saying the CE or CNS does not need a delay? I was under the impression that it did. The CE is cycled high then low to trigger the nRF to transmit.
outa[pin]~~ outa[pin]~
takes on the order of 10 us. So just drop the delay, and use back to back output assignments.If that's too short, turn the pin on two or three times, without turning it off, just to waste time.
Whenever csn goes low sck cycles high and low eight times. In mode zero data is read(clocked in) when sck is high. Then there will be a short pause before the next byte begins.
The four spi pins are mosi, miso, csn and sck.
Irq signals that data has been sent or received and ce controls the radio.
There is no 'Shockburst' since it slows things down noticeably.