PDA

View Full Version : Need some help with Assembly



Jennifer
04-01-2009, 09:49 PM
Hi,

I'm using the "spi_engine.spin" and I want to make a connection between two propellers. One should be the master and one should be the slave. Could someone help me writing SHIFTINSLV and SHIFTOUTSLV??

Maybe a lot to read but the purple code is what I use for the slave. What I'm most concerned about is the Clock2 part. Could someone help me with this.

Thanks a lot!




This is what I've done so far:



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.
wrlong zero,par 'zero command to signify command received
ror t1,#16+2 'lookup command address
add t1,#jumps
movs :table,t1
rol t1,#2
shl t1,#3
:table mov t2,0
shr t2,t1
and t2,#$FF
jmp t2 'jump to command
jumps byte 0 '0
byte SHIFTOUT_ '1
byte SHIFTIN_ '2
byte SHIFTOUTSLV_ '3
byte SHIFTINSLV_ '4
byte NotUsed_ '5
NotUsed_ jmp #loop
'################################################# ################################################## #############
SHIFTOUT_ 'SHIFTOUT Entry
mov t4, arg3 wz ' Load number of data bits
if_z jmp #Done ' '0' number of Bits = Done
mov t1, #1 wz ' Configure DataPin
shl t1, arg0
muxz outa, t1 ' PreSet DataPin LOW
muxnz dira, t1 ' Set DataPin to an OUTPUT
mov t2, #1 wz ' Configure ClockPin
shl t2, arg1
muxz outa, t2 ' PreSet ClockPin LOW
muxnz dira, t2 ' Set ClockPin to an OUTPUT
sub LSBFIRST, arg2 wz,nr ' Detect LSBFIRST mode for SHIFTOUT
if_z jmp #LSBFIRST_
sub MSBFIRST, arg2 wz,nr ' Detect MSBFIRST mode for SHIFTOUT
if_z jmp #MSBFIRST_
jmp #loop ' Go wait for next command
'------------------------------------------------------------------------------------------------------------------------------
SHIFTIN_ 'SHIFTIN Entry
mov t4, arg3 wz ' Load number of data bits
if_z jmp #Done ' '0' number of Bits = Done
mov t1, #1 wz ' Configure DataPin
shl t1, arg0
muxz dira, t1 ' Set DataPin to an INPUT
mov t2, #1 wz ' Configure ClockPin
shl t2, arg1
muxz outa, t2 ' PreSet ClockPin LOW
muxnz dira, t2 ' Set ClockPin to an OUTPUT
sub MSBPRE, arg2 wz,nr ' Detect MSBPRE mode for SHIFTIN
if_z jmp #MSBPRE_
sub LSBPRE, arg2 wz,nr ' Detect LSBPRE mode for SHIFTIN
if_z jmp #LSBPRE_
sub MSBPOST, arg2 wz,nr ' Detect MSBPOST mode for SHIFTIN
if_z jmp #MSBPOST_
sub LSBPOST, arg2 wz,nr ' Detect LSBPOST mode for SHIFTIN
if_z jmp #LSBPOST_
jmp #loop ' Go wait for next command
'------------------------------------------------------------------------------------------------------------------------------
SHIFTOUTSLV_ 'SHIFTOUT_slave Entry
mov t4, arg3 wz ' Load number of data bits
if_z jmp #Done ' '0' number of Bits = Done
mov t1, #1 wz ' Configure DataPin
shl t1, arg0
muxz outa, t1 ' PreSet DataPin LOW
muxnz dira, t1 ' Set DataPin to an OUTPUT
mov t2, #1 wz ' Configure ClockPin
shl t2, arg1
muxz outa, t2 ' PreSet ClockPin LOW
muxz dira, t2 ' Set ClockPin to an INPUT
sub LSBFIRST, arg2 wz,nr ' Detect LSBFIRST mode for SHIFTOUT_slave
if_z jmp #LSBFIRST2_
sub MSBFIRST, arg2 wz,nr ' Detect MSBFIRST mode for SHIFTOUT_slave
if_z jmp #MSBFIRST2_
jmp #loop ' Go wait for next command
'------------------------------------------------------------------------------------------------------------------------------
SHIFTINSLV_ 'SHIFTIN_slave Entry
mov t4, arg3 wz ' Load number of data bits
if_z jmp #Done ' '0' number of Bits = Done
mov t1, #1 wz ' Configure DataPin
shl t1, arg0
muxz dira, t1 ' Set DataPin to an INPUT
mov t2, #1 wz ' Configure ClockPin
shl t2, arg1
muxz outa, t2 ' PreSet ClockPin LOW
muxz dira, t2 ' Set ClockPin to an INPUT
sub MSBPRE, arg2 wz,nr ' Detect MSBPRE mode for SHIFTIN
if_z jmp #MSBPRE2_
sub LSBPRE, arg2 wz,nr ' Detect LSBPRE mode for SHIFTIN
if_z jmp #LSBPRE2_
sub MSBPOST, arg2 wz,nr ' Detect MSBPOST mode for SHIFTIN
if_z jmp #MSBPOST2_
sub LSBPOST, arg2 wz,nr ' Detect LSBPOST mode for SHIFTIN
if_z jmp #LSBPOST2_
jmp #loop ' Go wait for next command
'------------------------------------------------------------------------------------------------------------------------------
MSBPRE_ ' Receive Data MSBPRE
MSBPRE_Sin test t1, ina wc ' Read Data Bit into 'C' flag
rcl t3, #1 ' rotate "C" flag into return value
call #Clock ' Send clock pulse
djnz t4, #MSBPRE_Sin ' Decrement t4 ; jump if not Zero
jmp #Update_SHIFTIN ' Pass received data to SHIFTIN receive variable
'------------------------------------------------------------------------------------------------------------------------------
LSBPRE_ ' Receive Data LSBPRE
LSBPRE_Sin test t1, ina wc ' Read Data Bit into 'C' flag
rcr t3, #1 ' rotate "C" flag into return value
call #Clock ' Send clock pulse
djnz t4, #LSBPRE_Sin ' Decrement t4 ; jump if not Zero
mov t4, #32 ' For LSB shift data right 32 - #Bits when done
sub t4, arg3
shr t3, t4
jmp #Update_SHIFTIN ' Pass received data to SHIFTIN receive variable
'------------------------------------------------------------------------------------------------------------------------------
MSBPOST_ ' Receive Data MSBPOST
MSBPOST_Sin call #Clock ' Send clock pulse
test t1, ina wc ' Read Data Bit into 'C' flag
rcl t3, #1 ' rotate "C" flag into return value
djnz t4, #MSBPOST_Sin ' Decrement t4 ; jump if not Zero
jmp #Update_SHIFTIN ' Pass received data to SHIFTIN receive variable
'------------------------------------------------------------------------------------------------------------------------------
LSBPOST_ ' Receive Data LSBPOST
LSBPOST_Sin call #Clock ' Send clock pulse
test t1, ina wc ' Read Data Bit into 'C' flag
rcr t3, #1 ' rotate "C" flag into return value
djnz t4, #LSBPOST_Sin ' Decrement t4 ; jump if not Zero
mov t4, #32 ' For LSB shift data right 32 - #Bits when done
sub t4, arg3
shr t3, t4
jmp #Update_SHIFTIN ' Pass received data to SHIFTIN receive variable
'------------------------------------------------------------------------------------------------------------------------------
LSBFIRST_ ' Send Data LSBFIRST
mov t3, arg4 ' Load t3 with DataValue
LSB_Sout test t3, #1 wc ' Test LSB of DataValue
muxc outa, t1 ' Set DataBit HIGH or LOW
shr t3, #1 ' Prepare for next DataBit
call #Clock ' Send clock pulse
djnz t4, #LSB_Sout ' Decrement t4 ; jump if not Zero
mov t3, #0 wz ' Force DataBit LOW
muxnz outa, t1
jmp #loop ' Go wait for next command
'------------------------------------------------------------------------------------------------------------------------------
MSBFIRST_ ' Send Data MSBFIRST
mov t3, arg4 ' Load t3 with DataValue
mov t5, #%1 ' Create MSB mask ; load t5 with "1"
shl t5, arg3 ' Shift "1" N number of bits to the left.
shr t5, #1 ' Shifting the number of bits left actually puts
' us one more place to the left than we want. To
' compensate we'll shift one position right.
MSB_Sout test t3, t5 wc ' Test MSB of DataValue
muxc outa, t1 ' Set DataBit HIGH or LOW
shr t5, #1 ' Prepare for next DataBit
call #Clock ' Send clock pulse
djnz t4, #MSB_Sout ' Decrement t4 ; jump if not Zero
mov t3, #0 wz ' Force DataBit LOW
muxnz outa, t1

jmp #loop ' Go wait for next command
'------------------------------------------------------------------------------------------------------------------------------
MSBPRE2_
MSBPRE2_Sin test t1, ina wc ' Read Data Bit into 'C' flag
rcl t3, #1 ' rotate "C" flag into return value
call #Clock2 ' Send clock pulse
djnz t4, #MSBPRE2_Sin ' Decrement t4 ; jump if not Zero
jmp #Update_SHIFTIN ' Pass received data to SHIFTIN receive variable
'------------------------------------------------------------------------------------------------------------------------------
LSBPRE2_ ' Receive Data LSBPRE
LSBPRE2_Sin test t1, ina wc ' Read Data Bit into 'C' flag
rcr t3, #1 ' rotate "C" flag into return value
call #Clock2 ' Send clock pulse
djnz t4, #LSBPRE2_Sin ' Decrement t4 ; jump if not Zero
mov t4, #32 ' For LSB shift data right 32 - #Bits when done
sub t4, arg3
shr t3, t4
jmp #Update_SHIFTIN ' Pass received data to SHIFTIN receive variable
'------------------------------------------------------------------------------------------------------------------------------
MSBPOST2_ ' Receive Data MSBPOST
MSBPOST2_Sin call #Clock2 ' Send clock pulse
test t1, ina wc ' Read Data Bit into 'C' flag
rcl t3, #1 ' rotate "C" flag into return value
djnz t4, #MSBPOST2_Sin ' Decrement t4 ; jump if not Zero
jmp #Update_SHIFTIN ' Pass received data to SHIFTIN receive variable
'------------------------------------------------------------------------------------------------------------------------------
LSBPOST2_ ' Receive Data LSBPOST
LSBPOST2_Sin call #Clock2 ' Send clock pulse
test t1, ina wc ' Read Data Bit into 'C' flag
rcr t3, #1 ' rotate "C" flag into return value
djnz t4, #LSBPOST2_Sin ' Decrement t4 ; jump if not Zero
mov t4, #32 ' For LSB shift data right 32 - #Bits when done
sub t4, arg3
shr t3, t4
jmp #Update_SHIFTIN ' Pass received data to SHIFTIN receive variable
'------------------------------------------------------------------------------------------------------------------------------
LSBFIRST2_ ' Send Data LSBFIRST
mov t3, arg4 ' Load t3 with DataValue
LSB2_Sout test t3, #1 wc ' Test LSB of DataValue
muxc outa, t1 ' Set DataBit HIGH or LOW
shr t3, #1 ' Prepare for next DataBit
call #Clock2 ' Send clock pulse
djnz t4, #LSB2_Sout ' Decrement t4 ; jump if not Zero
mov t3, #0 wz ' Force DataBit LOW
muxnz outa, t1
jmp #loop ' Go wait for next command
'------------------------------------------------------------------------------------------------------------------------------
MSBFIRST2_ ' Send Data MSBFIRST
mov t3, arg4 ' Load t3 with DataValue
mov t5, #%1 ' Create MSB mask ; load t5 with "1"
shl t5, arg3 ' Shift "1" N number of bits to the left.
shr t5, #1 ' Shifting the number of bits left actually puts
' us one more place to the left than we want. To
' compensate we'll shift one position right.
MSB2_Sout test t3, t5 wc ' Test MSB of DataValue
muxc outa, t1 ' Set DataBit HIGH or LOW
shr t5, #1 ' Prepare for next DataBit
call #Clock2 ' Send clock pulse
djnz t4, #MSB2_Sout ' Decrement t4 ; jump if not Zero
mov t3, #0 wz ' Force DataBit LOW
muxnz outa, t1

jmp #loop ' Go wait for next command
'------------------------------------------------------------------------------------------------------------------------------
Update_SHIFTIN
mov t1, address ' Write data back to Arg4
add t1, #16 ' Arg0 = #0 ; Arg1 = #4 ; Arg2 = #8 ; Arg3 = #12 ; Arg4 = #16
wrlong t3, t1
jmp #loop ' Go wait for next command
'------------------------------------------------------------------------------------------------------------------------------
Clock
mov t2, #0 wz,nr ' Clock Pin
muxz outa, t2 ' Set ClockPin HIGH
muxnz outa, t2 ' Set ClockPin LOW
Clock_ret ret ' return
'------------------------------------------------------------------------------------------------------------------------------
Clock2
and t2, ina wz,nr
if_z jmp #Clock2
Cup and t2, ina wz,nr
if_nz jmp #Cup
Clock2_ret ret ' return
'------------------------------------------------------------------------------------------------------------------------------
Done ' Shut COG down
mov t2, #0 ' Preset temp variable to Zero
mov t1, par ' Read the address of the first perimeter
add t1, #4 ' Add offset for the second perimeter ; The 'Flag' variable
wrlong t2, t1 ' Reset the 'Flag' variable to Zero
CogID t1 ' Read CogID
COGSTOP t1 ' Stop this Cog!
'------------------------------------------------------------------------------------------------------------------------------
{
########################### Defined data ###########################
}
zero long 0 'constants
d0 long $200
MSBPRE long $0 ' Applies to SHIFTIN
LSBPRE long $1 ' Applies to SHIFTIN
MSBPOST long $2 ' Applies to SHIFTIN
LSBPOST long $3 ' Applies to SHIFTIN
LSBFIRST long $4 ' Applies to SHIFTOUT
MSBFIRST long $5 ' Applies to SHIFTOUT
{
########################### Undefined data ###########################
}
'temp variables
t1 res 1 ' Used for DataPin mask and COG shutdown
t2 res 1 ' Used for CLockPin mask and COG shutdown
t3 res 1 ' Used to hold DataValue SHIFTIN/SHIFTOUT
t4 res 1 ' Used to hold # of Bits
t5 res 1 ' Used for temporary data mask
address res 1 ' Used to hold return address of first Argument passed
arg0 res 1 'arguments passed to/from high-level Spin
arg1 res 1
arg2 res 1
arg3 res 1
arg4 res 1

Cluso99
04-01-2009, 09:57 PM
Jennifer: Did you mean to use SPI as there are simpler solutions such as the FullDuplexSerial object?

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Links to other interesting threads:

· Home of the MultiBladeProps: TriBladeProp (http://forums.parallax.com/showthread.php?p=786418), SixBladeProp (http://forums.parallax.com/showthread.php?p=780033), website (Multiple propeller pcbs) (http://bluemagic.biz/cluso.htm)
· Single Board Computer:·3 Propeller ICs·and a·TriBladeProp board (ZiCog Z80 Emulator) (http://forums.parallax.com/showthread.php?p=790917)
· Prop Tools under Development or Completed (Index) (http://forums.parallax.com/showthread.php?p=753439)
· Emulators: Micros eg Altair, and Terminals eg VT100 (Index (http://forums.parallax.com/showthread.php?p=778427))
· Search the Propeller forums (via Google) (http://search.parallax.com/search?site=parallax&client=parallax&output=xml_no_dtd&proxystylesheet=parallax&proxycustom=<HOME/>&ie=&oe=&lr=)
My cruising website is: ·www.bluemagic.biz (http://www.bluemagic.biz)·· MultiBladeProp is: www.bluemagic.biz/cluso.htm (http://www.bluemagic.biz/cluso.htm)

Jennifer
04-01-2009, 09:58 PM
Yes I want to use SPI

Beau Schwabe
04-02-2009, 02:57 AM
Jennifer,

This SPI driver that you reference does not allow you to configure one of the Clocks as an INPUT... Which is what you would need in order to do Prop to Prop communication.
I'm working on a dynamic SPI that would allow you to configure the clock this way, but this will take awhile for me to finish.


As Cluso99 points out there are other more efficient ways to communicate Prop to Prop. There is a high speed driver that I wrote, and there is a FullDuplex object already mentioned. In order to determine which method is best, we need to know what your ultimate communication goal is for your project.

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Beau Schwabe (mailto:bschwabe@parallax.com)

IC Layout Engineer
Parallax, Inc.

Jennifer
04-02-2009, 03:10 PM
Hi,

Thanks for your reply.

I'm working on a robot car that has a lot of sensors. The master needs to collect a lot of information and he will be communicating with a computer which decides what action should be taken. So the information needs to be send as fast as possible.

What is the high speed driver you refer to, Beau? Isn't the SPI engine in assembly the fastest way to do this? I also tried it with BS2_function (shiftout_slv en shiftin_slv) which worked perfect, but not fast enough.

All thoughts are welcome.

Jennifer

Cluso99
04-02-2009, 04:35 PM
There is an example on the forum of Beau's solution to high speed using 32bit serial + start and stop bits, with rates around 14Mbps which is much faster than SPI could ever achieve on a prop.

http://forums.parallax.com/forums/default.aspx?f=25&p=1&m=233212

Postedit: oops missed the "M" in Mbps http://forums.parallax.com/images/smilies/confused.gif· Thanks.

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Links to other interesting threads:

· Home of the MultiBladeProps: TriBladeProp (http://forums.parallax.com/showthread.php?p=786418), SixBladeProp (http://forums.parallax.com/showthread.php?p=780033), website (Multiple propeller pcbs) (http://bluemagic.biz/cluso.htm)
· Single Board Computer:·3 Propeller ICs·and a·TriBladeProp board (ZiCog Z80 Emulator) (http://forums.parallax.com/showthread.php?p=790917)
· Prop Tools under Development or Completed (Index) (http://forums.parallax.com/showthread.php?p=753439)
· Emulators: Micros eg Altair, and Terminals eg VT100 (Index (http://forums.parallax.com/showthread.php?p=778427))
· Search the Propeller forums (via Google) (http://search.parallax.com/search?site=parallax&client=parallax&output=xml_no_dtd&proxystylesheet=parallax&proxycustom=<HOME/>&ie=&oe=&lr=)
My cruising website is: ·www.bluemagic.biz (http://www.bluemagic.biz)·· MultiBladeProp is: www.bluemagic.biz/cluso.htm (http://www.bluemagic.biz/cluso.htm)

Post Edited (Cluso99) : 4/2/2009 12:37:43 PM GMT

MagIO2
04-02-2009, 05:11 PM
Hi Cluso99 ... 14bps is really FAST! ;o)

Jennifer
04-02-2009, 06:03 PM
Thx Cluso99.

I forgot to mention something. For now I'm trying to connect two propellers, but eventually there need to be 1 master and 2 slaves. With SPI I can use SlaveSelect to indicate which slave should listen. That's why I think I need SPI.

Jennifer

Post Edited (Jennifer) : 4/2/2009 11:19:09 AM GMT

Brian Fairchild
04-02-2009, 08:38 PM
Jennifer said...

...eventually there need to be 1 master and 2 slaves...


I have a system on the bench (not using props yet) which uses a serial port for one master to talk to 65,535 slaves. All you need to define is a simple protocol for the exchange of information.

The advantage of using 'standard' serial ports is that debugging is made a lot easier. Just hang a PC port on your interconnect and you can trace the data comms.

My master simply sends...

<start of packet><slave address hi><slave address lo><data 1>.....<data n><crc><crc><end of packet>

...the slaves receive every packet but only the addressed slave responds with a similar packet. It feels to me that it should be possible to encapsulate the whole packet sending and receiving routine inside a COG which will hide the nitty gritty from the main routines.

Post Edited (Brian Fairchild) : 4/2/2009 12:44:52 PM GMT

Cluso99
04-02-2009, 08:43 PM
I fixed the 14bps --> 14Mbps

Jennifer: I have to do exactly that with my TriBladeProp boards. I will use a different protocol because I dont need/want the clocking overhead. I've been thinking of using variable bit serial - 4/12/32/36 with the first 4 bits being a command. Even longer bit trains might be usable. Since you have a master, why not send out ultra high speed serial on P30 from the master to both slaves, and the slaves can send on P31 when instructed to.

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Links to other interesting threads:

· Home of the MultiBladeProps: TriBladeProp (http://forums.parallax.com/showthread.php?p=786418), SixBladeProp (http://forums.parallax.com/showthread.php?p=780033), website (Multiple propeller pcbs) (http://bluemagic.biz/cluso.htm)
· Single Board Computer:·3 Propeller ICs·and a·TriBladeProp board (ZiCog Z80 Emulator) (http://forums.parallax.com/showthread.php?p=790917)
· Prop Tools under Development or Completed (Index) (http://forums.parallax.com/showthread.php?p=753439)
· Emulators: Micros eg Altair, and Terminals eg VT100 (Index (http://forums.parallax.com/showthread.php?p=778427))
· Search the Propeller forums (via Google) (http://search.parallax.com/search?site=parallax&client=parallax&output=xml_no_dtd&proxystylesheet=parallax&proxycustom=<HOME/>&ie=&oe=&lr=)
My cruising website is: ·www.bluemagic.biz (http://www.bluemagic.biz)·· MultiBladeProp is: www.bluemagic.biz/cluso.htm (http://www.bluemagic.biz/cluso.htm)

Beau Schwabe
04-02-2009, 11:19 PM
Jennifer,

If you are looking for speed, you are much better off using synchronous communication such as Standard serial, or a high-speed derivative of Standard serial.

Either way, you can implement a serial protocol that allows anybody to be a master in turn. By defining a simple set of functions in the first couple of bytes that are sent in a way that everyone connected understands you can define transmitting, receiving, packet size, master requesting, etc. In hardware, one Propeller should be setup as the "default" master via a pin that can be tied to power or ground. From there the protocol can negotiate who can become a master.


With an 80MHz clock and 4 clock per instruction, SPI at it's best would be about 4MHz.

Loop:
read data bit (4)
set data bit (4)
toggle clock (4)
toggle clock (4)
jump to Loop (4)

Your talking 20 Clocks to shift out a single bit = 4MHz

You can stagger cogs to improve the efficiency and increase the frequency, and there are probably some counter tricks that you can do to shorten the code required to toggle the clock. Basically you set the counter to the Baud you want, and that's your clock... and then you begin transmitting the data as if it were Asynchronous data, but "step locked" to the counter so it effectively becomes synchronous data.

Loop:
read data bit (4)
set data bit (4)
jump to Loop (4)

12 Clocks to shift out a single bit ... 6.67MHz

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Beau Schwabe (mailto:bschwabe@parallax.com)

IC Layout Engineer
Parallax, Inc.