Spin Refresher: read and store variable values between methods and procedures?
courtens
Posts: 101
This code illustrates what I am trying to do in a rudimentary simplistic way; but I forgot how to properly address variables. I intentionally left out variable declarations as to not confuse things ... global, and local; as I forgot how to syntax these.
CON _clkmode = xtal1 + pll16x _xinfreq = 5_000_000 High = 1 Low = 0 P2 = 2 VAR Long stack_0[20] 'Sets up a stack space for a Cog(processor) Long start_temp Long start_A Long start_B Long end_temp Long end_A Long end_B PUB Main CogNew(TimerCog, @stack_0) 'Starts a New Cog repeat ' do other stuff PUB TimerCog | stA, stB, stTemp, enA, enB, enTemp, duration set_pin_to_input(P2) repeat phsa := 0 repeat while phsa < 5_000_000 LogSignal stA := start_A ' do something with values stored in start_A, start_B ... enA := end_A duration = enA - stA ResetLogs PRI LogSignal if ina[P2] == Low and start_temp == 0 ' just dropped low start_temp := phsa if start_A == 0 start_A := start_temp elseif start_B == 0 start_B := start_temp if ina[P2] == High and start_temp <> 0 ' just went high end_temp := end := phsa start_temp := 0 ' reset if end_A == 0 end_A := end_temp elseif end_B == 0 end_B := end_temp PRI ResetLogs start_A := start_B := end_A := end_B := end_temp := start_temp := 0 PUB set_pin_to_input(pin) 'set pin to input dira[pin]~ outa[pin]~
How do I access (read) and save (write) variable values most effectively; locally or globally; and between routines, methods, and objects ... functions?
Comments
Do you want to write the values to the eeprom or a SD card?
You did forget "Long end" in your VAR
I would like to use the values to do some math in
PUB Main
, or any other procedure.Nice catch!
I do think I just found the section in the PDF manual for that, under "Parameters and Local Variables" page 184. This the section:
So it sounds like I could store variable values as a local variable, or a global variable. What is faster? Is the global using the hub to read and write values to the address? Or can the cog running that routine do it directly without waiting for it's turn?
I think you have a major miss understanding here.
Inside a procedure (PRI or PUB does not change anything) local Variables and Parameters are just saved on the stack, so are just valid as long you are inside the procedure.
If you define a variable in a DAT or VAR section it is per definition global, so accessible from any COG and any Procedure.
If you call a Procedure with parameters, they are copied onto the stack, any modification will not get pushed back (called by Value not by reference)
If you just access a global variable directly (not using as parameter) you modify the variable in HUB.
The Spin Stack is also in HUB so there is NO timing difference between local or global access. All of them are in HUB memory.
Avoiding the HUB access latency just works in PASM, there you can access the COG memory and avoid the HUB latency.
You CAN give the address of a variable as parameter to a procedure, but you very seldom need to, basically just if you have some PASM running in a COG, if working with Spin Cogs it is not needed at all.
start_B := 123
is the same as
LONG[@start_B] :=123
both modify the same location in HUB memory.
Since Spin is a Interpreter, every instruction needs a (lot of) couple of instructions so the 12 clock latency between HUB access of one COG does not really matter.
I hope this will help your understanding.
Mike
I was just rewording my first post when I saw your post pop in. Mike, thank you for your most helpful input!
This was the key:
I have been using local variables heavily (thinking apparently wrongly) that that would somehow avoid the HUB latency access timing issue.
So instead, I should better declare, read and write ALL variables globally. I think you just made my day!
Mike, is this really true? I am getting some terrible latency issues.
For instance, if I access a bunch of global variables held in the HUB, such as in this line of code using a different cog, it looks like I am bumping in some variable access timing issues. Note: all variables in this line of code are global variables:
if laser_state == 1 and hole_start_temp == 0 and hole_end + pop_delay < phsa and hole_end > 0 and hole_duration > hole_duration_last - movement
I think I do need to first pull all the values from the HUB and re-declare them locally to speed things up. Is this right?
no
if you read a variable directly from HUB (declared in VBAR or DAT) you need one HUB access.
if you pass that value into a procedure as parameter or move it to a local variable you have one HUB access for reading the variable another HUB access to write it into the parameter (on stack) or local variable (on stack) and then a third HUB access to finally read the local value from stack.
it would be slower.
One thing you need to keep in mind is that the COGs are real parallel working Cores. So if one Core reads the variable modifies it and writes it back and another Core is writing the same variable in between this change will be overwritten by the first Core and lost.
This is not a Propeller specific problem, all multi core systems have that issue with shared resources like RAM or PINs.
There are different ways to get around this problem, one (mostly used in Spin/Pasm) is to have some Protocol for access, say one Cog is writing the value, the other one is reading it - fine.
Often used with Spin to Cog parameters is on Cog writes a command >0 into the 'mailbox' in HUB variable, the other does what it needs to do and clears the value to 0 so the first Cog knows the transfer was successful before overwriting with a new command.
Another common way are Semaphores also called locks. The P1 has 8 of them. These are seldom used since they produce even more overhead and are not needed for the above methods of access.
If your program is not to large you could try to use FlexProp from @ersmith to compile your Spin Code to Pasm and speed everything up by at least factor 4.
Enjoy!
Mike
In FlexProp local variables are kept in COG memory (if possible... if you take the address of a variable with @ then it has to go in HUB). Also, even in the "official" Spin2 compiler I think access to the first 8 locals is slightly faster than access to general global variables (because the offset is encoded in the opcode). So in general @courtens original idea of keeping frequently used data in local variables is a good one. To copy between COGs though you will need to use globals.
The question is regarding Spin1, where the first 8 instance variables are just as fast as the first 8 locals.