Global Variables shared between 2 cogs.
Shawna
Posts: 508
in Propeller 1
I am missing something here and I am not sure what it is. It is probably obvious, but not too me.
I am trying to read the raw gyro values from a lsm9ds1 module.
This code works and it all runs in a single cog.
When I try fire up a second cog to read the module, I display all 0's for gX, gY and gZ. I don't understand what is going on. According to the learn site in order to share global variables they need to be declared as volatile.
This code displays 0's.
I would imagine I am missing something simple but I can't figure it out.
On a side note, I am not sure why when reading the IMU this is the proper call to the function.
I originally tried this and it does not work properly. This returns 0's.
Thanks for the help!
Shawn A.
I am trying to read the raw gyro values from a lsm9ds1 module.
This code works and it all runs in a single cog.
#include "simpletools.h"
#include "lsm9ds1.h"
void Read_Gyro(void);
volatile int gX;
volatile int gY;
volatile int gZ;
int main() // Main function
{
imu_init(1, 2, 3, 4);
//cog_run(Read_Gyro, 256);
while(1)
{
Read_Gyro();
term_cmd(CLS);
print("gX = %d\r", gX);
print("gY = %d\r", gY);
print("gZ = %d\r", gZ);
pause(10);
}
}
Read_Gyro(){
imu_readGyro(&gX, &gY, &gZ);
}
When I try fire up a second cog to read the module, I display all 0's for gX, gY and gZ. I don't understand what is going on. According to the learn site in order to share global variables they need to be declared as volatile.
This code displays 0's.
#include "simpletools.h" // Include simple tools
#include "lsm9ds1.h"
void Read_Gyro(void);
volatile int gX;
volatile int gY;
volatile int gZ;
int main() // Main function
{
imu_init(1, 2, 3, 4);
cog_run(Read_Gyro, 256);
while(1)
{
term_cmd(CLS);
print("gX = %d\r", gX);
print("gY = %d\r", gY);
print("gZ = %d\r", gZ);
pause(10);
}
}
void Read_Gyro(){
while(1){
imu_readGyro(&gX, &gY, &gZ);
}
}
I would imagine I am missing something simple but I can't figure it out.
On a side note, I am not sure why when reading the IMU this is the proper call to the function.
imu_readGyro(&gX, &gY, &gZ);
I originally tried this and it does not work properly. This returns 0's.
imu_readGyro(gX, gY, gZ);
Thanks for the help!
Shawn A.
Comments
Tom
Your are calling mu_init() on one cog and imu_readGyro() on another cog. Are you sure that this second cog knows which pins to use and are the dira bits set correctly by his cog?
Your second point about having to call imu_readGyro() with addresses is simple. C uses call by value. So when you write imu_readGyro(gX, gY, gZ) this function gets only the values of these variables, but you want the function to to write into these vars. Therefor imu_readGyro(9 needs the addresses.
IMU_INIT() is called from the main thread. This causes those pins to be allocated to the main cog. Another cog can not use those pins.
You are also reading the gyro as fast as possible and not waiting for the sensor to have updated information. zero is normal for this sensor.
Mike
Thanks Tom
The learn site says what you just said, but it didn't sink in properly until now. Sometimes I just have too hear things a certain way before my brain will pickup on it.
Thanks rbehm
@Mike
Thanks for the example. I have a couple questions.
1) Why is the " * " required in the declaration of the function Read_Gyro? I think it is a pointer.
2) Why " *par " in the actual function Read_Gyro? Is par a variable that stores the address of where the function Read_Gyro actually starts in memory?
3)Why the " & " in the start new cog statement? It works without the " & ".
4) Is it necessary to use local variables to read the gyro data into and then load the data into global variables? What are the advantages to doing it this way? Thanks for the help.
Shawn A.
Since the cog_run is calling your function you need to pass the address of the function. In the background it copies it into cog memory and then runs it.
In the case of local variables in this case it is not necessary but in some cases you want the variables to be updated at the same time as they are running asynchronous to the main function.
Mike
I wrote a program that collected joystick data from an android bluetooth app in one cog and used it to control an activitybot in an other cog. When I was developing the code I ran tests just printing the x & y data each loop. But I saw that the y value was not from the same data pair as the x value. It was from the previous pair.
So in the bluetooth cog I collected x & y ascii digits, converted them to numbers in local variables (xval & yval) (9 bits each), then packed them together into one 32 bit integer global (joydata). The control cog unpacked the global maintaining the synchronization.
The code in the bluetooth cog was:
(note in the bluetooth app the joystick values were from -100 to +100, but it added 200 to that value when sending so there was no need to have to deal with sign bits when sending or receiving. But since I wanted to use -100 to +100 I subtracted 200 from each value.)
The code in the control cog was:
The full program is developed in this thread:
https://forums.parallax.com/discussion/156970/bluetooth-app-to-control-activitybot
Hope this helps.
Tom
I wrote an SBUS driver and used this to make sure that it had all the channels value converted before it would allow reading of the values. SBUS has 8 or 16 channel values
Mike
That's a neat project Tom!
https://parallax.com/sites/default/files/downloads/P8X32A-Propeller-Datasheet-v1.4.0_0.pdf
It looks like only 1 cog can access the hub at a time. If global variables are stored in the hub this would make me think that locks are not necessary. However, on page 8 the document says................... To me this sounds like locks are important. Maybe this is why I have had problems in the past with programs with multiple cogs sharing variables.
Anyways, I started playing with Locks in what I thought would be the most basic place to start and the results are strange.
I expected to see the value of _Lock to change from 0 to 1 when displayed, or maybe even a -1. The only thing that is displayed is a 1. Not sure what i am missing here.
In Mikes example above, I do not see where the lock is actually set. I see where it is cleared. From what I have read, when locknew() is called the initial state is random, or maybe that is when the lock is returned. I will have to try and find that again.
Thanks
Shawn A.
If you are updating a group of bytes/words/longs in hub with one cog just use a hub position as a flag to indicate its done. Don't update that flag until its all copied in, and likewise when another cog takes it out, don't update the flag til its done.
Enjoy!
Mike
That will only show the lock number not its state. There are 8 locks available you have lock 1.
I like locks as you can set and for get them. efficient instructions that don't take up any space.
Mike
The state of the variable is returned by the lockset/lockclr functions. This is actually important; calling "lockset(n)" is a request to set lock number "n", but it is not guaranteed to do so (another COG may have already done that). So you need to test in a loop. lockset() returns the old state, so loop until we get 0 (meaning no other COG has it locked):
Finally, a minor nit: the name "_Lock" that you chose for your lock variable is reserved in C for the system (all names starting with an underscore then a capital letter are reserved). You could break the C library by using a name like that.
Eric
C# wants capital letters first then lower case. Java wants lower case first followed by Uppercase. Python wants underscores between names.
I give up.
Mike
+1
It's all the minor nits like this that make using multiple languages such a PITA, not the actual language differences. That's why I like to stick to a few languages whenever possible.
Mixed case style guidelines are nothing to do with the language, they are a human invention to
try to improve readability and uniformity in a large code base that's worked on by many people.
Unless you have a need for this, ignore it and just use well chosen names and lots of whitespace,
those are always the most important style guidelines.
Some of the case conventions are there to try to make visually obvious the difference between
constant, variable, class, keyword, etc etc. Unfortunately there are a variety of conflicting conventions
and some languages aren't case sensitive which causes more confusion!
[ and anyway these days any good programming editor can colour-code the different kinds of names
for you, making the case conventions entirely superfluous ]
I was bound to work for a while as a 'fix it man'. So when some stuff was hitting the fan, I was send in to - hmm - take over the project and tame a horde of cats/programmers.
Code conventions are just that. 'conventions'. It is a agreement between the programmers working on a project together so that the code base is someway conforming to a common style.
This has nothing to do (or say mostly nothing) with the language used, it is more important that it makes reading/refactoring/reviewing the code more easy. Usually there is (or should be) a document describing how the code should look like and where, when and how one is supposed to use CamelCase Underscores or pre/post addons to names.
This varies from company to company, sometimes even from project to project. C# does not want capital letters first, you can do whatever you want, but most Microsoft examples are written in a common MS code style and people adapt to it to have consistency between self written code and that copy and paste stuff you find in every program.
I also was teaching COBOL in the late 1980's. I visited a friend of mine, just dropping by at his workplace. He did offered me the job and I basically declined two weeks earlier. So he tricked me into it. While walking over the campus we went into a building and he opened the door to a classroom. And stated to the class 'Here is Michael Sommer he is your new teacher' then he padded me on the back and left the room.
I never ever wanted to stay in front of a group and teach. Gosh I am a Code Monkey, I don't do PEOPLE ok? But one has to do what one has to do, so I took the class over, the last teacher had a car accident and those guys and girls needed to pass their class in fall.
Programming COBOL for at least a decade at that time knowledge was not the point, teaching was. What a experience. For weeks I was barely one day ahead with producing course material for the next days.
But I learned a lot about coding styles. Every programmer has a handwriting. Even with strict coding rules, formatting rules and language restrictions. COBOL is very good at the last one.
At every test they had to pass I was reviewing their code. And two members of the group where helping out others to pass their tests. I could see their handwriting all over the place. This one had problems with the menu, all other code from him but the menu code definitely written by Paul, that listing clearly shows Laura's handwriting in the SCREEN SECTION and so on.
I had 35 students for half a year and in at least 75% of the code I reviewed - there was Paul and Laura involved somewhere.
Coding style is very important, the best example here is @JonnyMac, he is just brilliant and all his Objects in the OBEX are super clean and well written. I wish I could do that, but I am still fighting to get there.
How you name things is 'coding convention' for the project/company, but how to dissect a problem into routines and subroutines, how to solve things elegant and/or efficient is the Art of programming.
I do not just put @JonnyMac out here, @kuroneko's code is a joy to read, @"Mike Green", @"Phil Pilgrim (PhiPi)", @lonesock and others.
I am sadly not really good at that. Always unhappy with my own code, convoluted, compressed, efficient but somehow ugly(?) to read. But I try to learn from other coders...
Enjoy!
Mike
The problem is that underscored variable names are reserved for the system and compiler, and so they get used a lot in system header files. Programmers look at the header files and think that's good style, and so start using underscores themselves. But the underscore in the header file isn't a matter of style, it's to avoid conflicts with user code. If users start putting underscores at the start of variables it defeats the purpose of having the reserved names.
by an uppercase letter, as that may clash with a macro/ifdef
In fact leading underscores in C++ constructor arglists is common practice in order to be able to name
both instance variables and arguments similarly.
But these are all still conventions. See the obfuscated C contest for examples of what to avoid at all costs!
Now C++ may have different conventions. I wouldn't know about that.
Since we are talking about locks...... would it be possible to read the LSM9DOF module with 2 cogs if locks were used?
The code below is an outline of how I think it might work. It obviously won't compile. In theory I think it might work, but I have know idea.
What do you guys think?
Mike
So if you read the sensor at every 10 milliseconds and then multiple by 100 you could get degrees per second change.
Mike
I have the calculations working to determine degrees of rotation for the gyro. However I am using floating point math to do it. I would like to switch to integers only, but at this point in time its not a big deal. I can read the gyro and do the math in a separate cog, but there is no time left to read the acc.
So I am going to try and use a lock and do the math in a cog dedicated just for math.
I am not quite there yet. Getting close.
@Shawna
try this I wrote this tutorial for a C library. Let me know if it helps.
Propeller c Library tutorial
Follow the link.
http://forums.parallax.com/discussion/download/123134/Propeller C library tutorial.docx
http://forums.parallax.com/discussion/download/123135/libgps10.zip
this should help you go between cogs. Took me a while but it works. First take the raw program then follow the steps. to create a library of your own if you like.