SPI Engine faster ?
Hi all .
I was looking for an SPI engine object, and I've found, Beau Schwabe·code object.
Is avoiding the "setcommand(cmd, argptr)" method in the engine, and passing data by command directly·?
Or are you refering, another way, to get 2.5M in assembly ?
If I could do a caller in assembly....how to call SPI Object ?? If I'll do in spin, just your demo code !! it's did·...sorry that's confusing me.
This is a part of the engine for reference:
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
I was looking for an SPI engine object, and I've found, Beau Schwabe·code object.
How to call SPI through assembly faster ?.Beau said...
Notes:
Consecutive SHIFTIN/SHIFTOUT updates through Spin at 80 MHz is about 14kHz (Bit rate about 112k)
Consecutive SHIFTIN/SHIFTOUT updates through Assembly at 80 MHz is about 310kHz (Bit rate about 2.5M)
Is avoiding the "setcommand(cmd, argptr)" method in the engine, and passing data by command directly·?
Or are you refering, another way, to get 2.5M in assembly ?
If I could do a caller in assembly....how to call SPI Object ?? If I'll do in spin, just your demo code !! it's did·...sorry that's confusing me.
This is a part of the engine for reference:
CON
#1,_SHIFTOUT,_SHIFTIN
VAR
long cog, command, Flag
PUB SHIFTOUT(Dpin, Cpin, Mode, Bits, Value) 'Once called from Spin, SHIFTOUT remains running in its own COG.
if Flag == 0 'If SHIFTOUT is called with 'Bits' set to Zero, then the COG will shut
start 'down. Another way to shut the COG down is to call 'stop' from Spin.
setcommand(_SHIFTOUT, @Dpin)
PUB SHIFTIN(Dpin, Cpin, Mode, Bits)|Value 'Once called from Spin, SHIFTIN remains running in its own COG.
if Flag == 0 'If SHIFTIN is called with 'Bits' set to Zero, then the COG will shut
start 'down. Another way to shut the COG down is to call 'stop' from Spin.
setcommand(_SHIFTIN, @Dpin)
result := Value
'------------------------------------------------------------------------------------------------------------------------------
PUB start : okay
'' Start SPI Engine - starts a cog
'' returns false if no cog available
stop
Flag := 1
okay := cog := cognew(@loop, @command) + 1
PUB stop
'' Stop SPI Engine - frees a cog
Flag := 0
if cog
cogstop(cog~ - 1)
command~
PRI setcommand(cmd, argptr)
command := cmd << 16 + argptr 'write command and pointer
repeat while command 'wait for command to be cleared, signifying receipt
'################################################################################################################
DAT org
'
' SPI Engine - main loop
'
loop rdlong t1,par wz 'wait for command
if_z jmp #loop
movd :arg,#arg0 'get 5 arguments ; arg0 to arg4
mov t2,t1 ' │
mov t3,#5 '───┘
:arg rdlong arg0,t2
add :arg,d0
add t2,#4
djnz t3,#:arg
mov address,t1 'preserve address location for passing
'variables back to Spin language.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔

Comments
have the cog always running, and give it a status byte to determine it's current status (you can use locks as well if you wish to have halting calls)
Something like
VAR byte count, status byte buffer[noparse][[/noparse]data]Have the cog running the SPI routines poll count... if it is non zero, set the lock, and set status to logical true. Have it progressively shift out the buffer, while shifting in to the same buffer. After it's done, release the lock and set status to zero.
That way, you main application can do other things while it's running, and you can spi out multiple bytes.
Also, avoiding generic SPI calls would aid you in avoiding large delays. You my also consider just writting it in spin. Although the execution time is relatively low, you would avoid wasting a cog and there is no need for excessive load times.
Remember that booting a cog takes ~8000 cycles, so spin would most likely be faster.
First·of all, thanks so much fo the suggests.
I'm totally agree with you, about to have the cog always running, I don't know that, but 8000 clocks is too much time while booting a cog.
Just I need to send packets of data (of 192 Bit each) to a SPI peripheral, it is important to do that, and maintain those packets in a buffer, so you're poiting exactly in my future application.
Perhaps, I can not express me correctly, and could be a missunderstanding in my questions (or I don't understand your explanation...).
Tha byte that you name "status" ....is not the same as Flag, in the example that I post. ?? (Supoosing the cog is running and the "start' line is not write there....)
If I have the cog running all time, How to pass the values to the SPI engine ?? or.. how to get the comand variable actualized, with a new value from outside the SPI driver..?
PRI setcommand(cmd, argptr) command := cmd << 16 + argptr 'write command and pointer repeat while command 'wait for command to be cleared, signifying receiptCould I avoid this part of spin code ?? and be replaced with some using command := buffer[noparse][[/noparse]data1] etc. ?
Regards and Happy New Year !!
Alberto.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
You just want to have the cog that would be doing the SPI code constantly polling a value (command), and when it sees a non-zero command, have it start it's shift in / shift out code. flags / status would just be a method of determining the status.
You would also want the cog to clear the command value so it doesn't auto repeat after everything is said and done.
I went ahead and slapped this together. It's basically the most efficient method of doing SPI transfers if the buffers are largeish.
The SPI code is missing because I'm not 100% sure on the asm syntax, but it should at least give you an idea of what I'm thinking of.
CON CLK_PIN = %0000_0000_0000_0001 DIN_PIN = %0000_0000_0000_0010 DOU_PIN = %0000_0000_0000_0100 PUB start command := 0 ' Initalize to zero bytes to copy spi_lock := LOCKNEW ' Create a new lock spi_cog := COGNEW( @entry, spi_stack ) ' Start our cog PUB stop COGSTOP( spi_cog ) PUB shift(bytes, count) | i repeat until not LOCKSET( spi_lock ) repeat i from 0 to count buffer[i] := byte[noparse][[/noparse] bytes ][noparse][[/noparse] i ] command := count PUB getStatus return LOCKSET( spi_lock ) DAT ORG entry MOV outa, 0 MOV dira, #(DOU_PIN | CLK_PIN) ' Set output pins wait_loop RDBYTE bytes_copy, command WC ' Loop until we have a buffer to scan out IF_Z JMP #wait_loop spi_out LOCKSET spi_lock MOV buff_start, @buffer start_byte MOV byte_in, 0 MOV bits_left, 8 RDBYTE byte_out, 0 ADD buff_start, #1 shift_out ' TODO: SPI OUT DJNZ bits_left, shift_out DJNZ bytes_copy, #start_byte LOCKCLR spi_lock ' Local memory for the SPI cog bytes_copy LONG 0 byte_temp LONG 0 bits_left LONG 0 buff_start LONG 0 ' Global memory for the SPI cog command LONG 0 spi_cog LONG -1 spi_lock LONG -1 buffer BYTE $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF BYTE $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF BYTE $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF BYTE $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF BYTE $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF BYTE $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF BYTE $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF BYTE $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF BYTE $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF BYTE $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF BYTE $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF BYTE $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF BYTE $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF BYTE $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF BYTE $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF BYTE $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF spi_stack LONG 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 [/i]because this includes some assembly SPI code that is for the secure digital cards. There is one Spin version
and two assembly versions. They are not the absolute fastest but they are not bad.
Sorry, I haven't replied sooner, I have been busy over the Christmas and New Year holidays.
The two statements...
Consecutive SHIFTIN/SHIFTOUT updates through Spin at 80 MHz is about 14kHz (Bit rate about 112k)
Consecutive SHIFTIN/SHIFTOUT updates through Assembly at 80 MHz is about 310kHz (Bit rate about 2.5M)
...are simply indicating a measured thru-put based on an 8-byte data value. If you are using Spin and send
data in a continuous stream. You can expect a thru-put of about 14kHz. If you strip down the assembly code
essentials and use the assembly portion that performs SHIFTIN/SHIFTOUT routines and never leave the assembly
environment, then the thru-put increases to about 310kHz.
http://forums.parallax.com/showthread.php?p=602056
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Beau Schwabe
IC Layout Engineer
Parallax, Inc.
I'll be trying your suggests, after a new post.
Regards.
Alberto.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔