Sharing Locks Between Spin and PASM
coryco2
Posts: 107
After working with Spin for a while, I recently decided to start delving into Propeller assembly, and am a bit confused on how locks (semaphores) can be implemented so Spin and PASM running in separate cogs can access global variables in a mutually exclusive way.
Here is a quick demo I wrote up to test my understanding:
The PASM is supposed to increment the values of three variables from zero up by steps of one, waiting for the Spin in another cog to display the values on the terminal once per second. As is, the code will now will display a set of values only once and stall, and they are 1428597 and not 1 as I would expect. If I remove the delay, it does increment and display more values, but in much larger jumps than one.
What am I getting wrong here, please?
Here is a quick demo I wrote up to test my understanding:
CON _clkmode = xtal1 + pll16x ' System clock settings _xinfreq = 5_000_000 HOME = 1 ' Parallax Serial Terminal constants CRSRXY = 2 CR = 13 CLREOL = 11 CLS = 16 OBJ debug : "FullDuplexSerial" ' Declare FullDuplexSerial object VAR '(4 contiguous longs) long variable[3] long SemID 'ID# of lock checked out by PASM PUB Start cognew(@entry, @variable[0]) 'Start cog and pass the address of variable[0] from Spin to PASM cog SpinLoop PUB SpinLoop debug.start(31, 30, 0, 57600) ' Start serial connection for debug terminal waitcnt(clkfreq + cnt) ' Wait 1 s before starting repeat IF lockset(SemID) <> true 'If this locks the resource by not getting back TRUE as the previous state debug.dec(variable[0]) debug.str(string(CR)) debug.dec(variable[1]) debug.str(string(CR)) debug.dec(variable[2]) debug.str(string(CR, CR)) lockclr(SemID) 'unlock the variables to allow PASM to update them waitcnt(clkfreq + cnt) DAT 'Assembly language code org ' Entry entry mov l,par 'par value here is the variable[0] address passed from Spin in the Start method mov v1, #0 mov v2, #0 mov v3, #0 locknew SemIDa 'check out a lock, store ID in register SemIDa add l,#3*4 'Calculate address in main memory 3 four-byte longs from variable[0] (i.e. Spin variable SemID) wrlong SemIDa,l 'copy lock number from PASM variable to Spin variable to give both access to the same lock ' Update values update lockset SemIDa wc ' Set lock, set c flag to previous state of the lock if_nc jmp #$+3 'if c indicates previous state of lock was clear, jump ahead three instructions if_c lockset SemIDa wc 'if lock previously set, set lock and loop back three instructions to test previous state again jmp #$-3 if_nc add v1, #1 'Increment variable values add v2, #1 add v3, #1 mov p,par wrlong v1,p add p, #4 wrlong v2,p add p, #4 wrlong v3,p lockclr SemIDa jmp update ' ' Data ' p res 1 l res 1 v1 res 1 v2 res 1 v3 res 1 SemIDa res 1 'lock ID#
The PASM is supposed to increment the values of three variables from zero up by steps of one, waiting for the Spin in another cog to display the values on the terminal once per second. As is, the code will now will display a set of values only once and stall, and they are 1428597 and not 1 as I would expect. If I remove the delay, it does increment and display more values, but in much larger jumps than one.
What am I getting wrong here, please?
Comments
Could you please explain how your pause works?
rdlong cnt, #0
add cnt, cnt
waitcnt cnt, #0
I thought "cnt" was a read-only register containing the current system counter value, but it appears the rdlong instruction writes to it?
Basically, one cog sets "the" lock to indicate that it is reading about 8 bytes of data via I2C from a touchscreen controller (to hub RAM); the lock is cleared after it's finished. In the event that the lock is already checked out, it simply skips reading the touchscreen controller; the main loop will come back around before long.
Meanwhile, the Spin code that reads the values from hub RAM, waits to check out the lock, reads several registers, and then releases the lock.
If I use the code as written above, the Spin side immediately locks up (pardon the pun), and as the lock is checked out, the PASM side doesn't read the touch controller, either.
I use locks elsewhere, but only in Spin code, so multiple subroutines accessing the same shared resource have to wait on each other; they work just fine. What is going on here when introducing PASM to the mix?
-Phil