Shared variables and communication between cogs
ThePenguinMaster
Posts: 89
Hey, first off, thanks for taking the time to read this thread. So far i have spent a lot of time playing with the propeller, but only single cogs and pre-made objects that utilize other cogs. I'm getting to the point where i need to better understand how memory is shared between cogs. i want to be able to start a routine in a cog, and have a shared buffer between the cogs where status flags can be set and maybe a chunk of space for data to be transferred. Also, what if both cogs need to read and write to the location in memory? are there any objects in the object exchange you might be able to recommend for a reference?
Comments
Use pointers (pointer := @varibale) - pointer should be word sized or larger. If you need to share variables from different objects.
Otherwise, all cogs started up in a single object file have acess to all variables and data sections very easily. The same as if you were using just one cog.
As for reading and writing to the same location, you need to use status flags and a data register. Its different depending on what application you want.
For example: You want to have a flag variable which controls the synchronization between the processors and a data register or set or registers that hold the information you wish to share between the cogs.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Nyamekye,
Basically it seems there is no really pretty way to do it, compared to C.
The way used by Parallax, for example in TV.spin is probably the best option.
From a 'master' object, pass in a pointer to an array to the 'slave' object.
The Master can then use DAT, VAR, stack variables, or even a manually allocated pointer.
The slave object stores this pointer.
The consequence is that the 2 (or more) objects need to agree on the layout of the buffer, which means manually maintaining tight code coupling. In the slave objects, you have to use the typecast syntax.
The master could use VARS being the most maintainable.
The most intersting thing I found was that how the pointers were stored had a big influence on code size, and had some unexpected impacts. Access using a pointer in the STACK was best, closely followed by a pointer in a VAR. The worst was using a CONstant to hold a address.!
Not pretty but its here http://propeller.wikispaces.com/Referencing+Globals. Hack away to make it useful. I'd like it to end up more a set of design patterns really. (Even better would be tweaking spin to have a #include equivalent or some other mechanism! The current way is a maintenance nightmare)
Have a controll block (a struct in C, an array in SPIN) that keeps all the necessary information in a single place.
That information could be flags like "I'm ready", size of something, enum for what to do, etc. Further, that controll block might have an pointer to some array that needs processing and an information about the array's size.
In C, that might look like this:
If you pass a pointer to that controll block in the cognew, all is tidy, flexible, controllable and clear.
HTH,
Nick
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Never use force, just go for a bigger hammer!
The DIY Digital-Readout for mills, lathes etc.:
YADRO
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Nyamekye,
I find that problematic, as something, usually a few Objects and/or COGs measuring some raw values.
I then need to use it for a few things, in a number of places:
- in display logic to show on screen (and detect change of value)
- in monitoring logic to decide if needs to alert or do something else
- in logging logic to record historical stats
I originally had each sensor type object managing its own data, with a spin method to retrieve each value.
I then found I needed to use a master object to poll ALL the objects to copy the values somewhere else,
then they were calling other objects with lots of parameters, for example to display a screenfull of different measurements.
I was thinking either:
A wrapper would be nice, but lots of overhead involved.
·
VAR
··········· Long theList···· ‘this is intended to be an array of stored strings
··········· Long Stack[noparse][[/noparse]10]
PUB start | i
··········· i:=0
··········· Cognew(GetList(@thelist, stack[noparse][[/noparse]0])
··········· ‘There is some code to wait for the other cog here
··········· Repeat while theList[noparse][[/noparse]i] > 0
······················· Terminal.str(theList[noparse][[/noparse]i])
······················· i++
·
PUB GetList(list)
··········· Repeat until AFunctionThatReturnsAString returns nothing
··········· ··········· Long[noparse][[/noparse]list] := AFunctionThatReturnsAString
··········· ··········· List++
·
It is what happens in GetList that I am unsure about, now what I’m thinking is that you want to create a long containing the string that ‘AFunctionThatReturnsAString’ returns and increment the address to the long and do it again to create an array. Now I know that the repeat statement will not work as typed, because there is no returns nothing statement, but the idea is that I don’t know how many strings the function is going to return, and I need to store them into an array that both cogs can access. So using the pointers is a huge help. Now when I read the values they are not what I expect. Any suggestions? I know this may be a simple problem, but I’m new to this and some of the simple concepts are proving to be difficult. It’s a little different than C++, but once I get the basic concepts down, I should be good to go. If necessary, I can post the exact code I wrote last night after I get home.
Pointers are not typed like in c. Incrementing the pointer only incremented one byte.
Better to use the array indexing syntax (generated code is smaller in spin, not sure if its faster though)
As for waiting for the 2nd cog... as the example stands, not much point using 2nd cog at all.
Edit: Edit: Grrr how do you post unmolested code????
Post Edited (matb) : 7/1/2009 10:43:55 PM GMT
It isn't that hard. It is an ever repeating pattern: Pass a pointer to a controll-block.
In the ASM-code, I first write the sequence and size of the parameters as a comment. Read the parameters with rdlong/rdword/rdbyte, store them in local vars and then you go ..
In the meantime, I like that pattern a lot. I'd even use it when only passing one parameter.
Nick
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Never use force, just go for a bigger hammer!
The DIY Digital-Readout for mills, lathes etc.:
YADRO
what i am trying to do is make a function that will grab a file list and place it into an array, this array needs to be accessible from any cog, so i have that part down, but the storing of a register location into a list is what is not working now. @tbuf is a pointer to a location in mem that holds the file name, so what happens is that when i print the elements of the array, i get the last value that was stored in tbuf as many times as files are on my SD card. I need to store the value into the array and not the pointer. This is simple im sure, but once i get these concepts i will be in the clear.
fileList := @tbuf
Should be
LONG[noparse][[/noparse] fileList ][noparse][[/noparse] i ] := @tbuf
Secondly, you are over-writing the string in tbuf each time. You need more than one buffer, or to manage it some other way.
Thirdly, which is not a bug, the pointers need not be longs, a word is a big enough.