Propeller Cog Problem
Discovery
Posts: 606
in Propeller 1
My application uses Cogs for independent operation but one Cog is not operating.
Cog 0 should be the main program
Cog 1 should be rational number calculation
Cog 2 should be the Z axis control
Cog 3 should be the X axis control
Cog 4 should be the Y axis control
But Cog 3 will not operate. Cog 3 and Cog 4 are the same identical code. The only difference is Cog 3 operates on a global file of numbers contained in X[500] while Cog 4 operates on a global file of numbers contained in Y[500].
If I send the X[500] file to Cog 4 it works fine. If I try to set a test global variable in Cog 3...the main program does not get the value. The same test global variable put into Cog 4 is read correctly by the main program. It appears that Cog 3 is not operating.
The global variables are all static volatile types.
static volatile int X[500], Y[500];
void Xaxis(void* par);
void Yaxis(void* par);
void Zaxis(void* par);
unsigned int stack[400+25];
cogstart(&Xaxis, NULL, stack, sizeof(stack);
cogstart(&Yaxis, NULL, stack, sizeof(stack);
cogstart(&Zaxis, NULL, stack, sizeof(stack);
Any ideas?
Sincerely,
Discovry
Cog 0 should be the main program
Cog 1 should be rational number calculation
Cog 2 should be the Z axis control
Cog 3 should be the X axis control
Cog 4 should be the Y axis control
But Cog 3 will not operate. Cog 3 and Cog 4 are the same identical code. The only difference is Cog 3 operates on a global file of numbers contained in X[500] while Cog 4 operates on a global file of numbers contained in Y[500].
If I send the X[500] file to Cog 4 it works fine. If I try to set a test global variable in Cog 3...the main program does not get the value. The same test global variable put into Cog 4 is read correctly by the main program. It appears that Cog 3 is not operating.
The global variables are all static volatile types.
static volatile int X[500], Y[500];
void Xaxis(void* par);
void Yaxis(void* par);
void Zaxis(void* par);
unsigned int stack[400+25];
cogstart(&Xaxis, NULL, stack, sizeof(stack);
cogstart(&Yaxis, NULL, stack, sizeof(stack);
cogstart(&Zaxis, NULL, stack, sizeof(stack);
Any ideas?
Sincerely,
Discovry
Comments
So, I need three different stack declarations.
Thank you.
Discovery
Discovery
Thank you.
Discovery
I used the code supplied by Jason Dorie above in my upgraded plotting machine and the machine went crazzy.
So, I made a COG tester program to investigate the COGs. The attached code runs three COGs (X,Y,Z). The results of calculations should produce TestX = 45, TestY = 55, and TestZ = 66. Only COGs Y and Z compute values. Both COGs Y and Z compute correctly. COG X does not compute at all.
Code is attached. I cannot find anything wrong. What is the problem?
Discovery
The previously attached C file is not the correct file. The attached C file below is correct. XCog does not compute. The output should be TestX = 45, TestY = 55, and TestZ = 66.
Discovery
cogstart(&Yaxis, NULL, Ystack, sizeof(Ystack));
cogstart(&Zaxis, NULL, Zstack, sizeof(Zstack));
If your eventual goal is to run a motor on each cog, you'all need to synchronize them somehow.
Your code works fine for me, however you need to wait for the cogs to complete before working on the data they modify. Add a delay of 1 second (just to be sure) before printing the values. Actual code needs to account for the time needed for a cog to compute the values before working on them, use a flag variable to indicate when the data are ready. Something like this:
Thanks you.
Discovery
Thank you.
Discovery
I thought that global variables were defined by static variable statements prior to the main program. Variables used in Cogs were local variables. What am I missing?
Discovery
In other words, a static local is really a global variable that is only visible from the {} scope it is declared in.
Sorry, but I am confused.
In my application code, not my test code, I use a variable Ops in two Cogs to wait for the Ops to go to "1" then the Cogs set digital outputs to control two stepper motors (X and Y) in the plotter machine..
In the X Cog...
while(Ops==0)
{
}
{
for j=1;j<w+1;J++)
{
X=x[J];
stepperX();
}
and in the Y Cog...
while(Ops==0))
{
}
{
for(j=1;j<z+1;j++)
{
Y= y[j];
stepperY();
}
So, the j variable should be declared int j in each Cog and the Ops, X[500], and Y[500] variables should be declared just
int in the main program code. Is that correct?
Once the Ops variable in the main program goes to 1, both Cogs call the stepperX() and StepperY() subroutines to clock the two steppers very rapidly emptying the contents of the values in the X and Y arrays and moving the plotting head.
I there anything wrong here?
Sincerely,
Discovery
If you want a suggestion to better understand the variables visibility, separate the different "tasks" your code does into different source files. One source would be the "main" source with the entry point and all global variables and functions, then one source for each task running in a separate cog. I hope that the IDE you are using (if any) doesn't merge the code to simplify things.
When you do that, you'll find that variables and functions defined in a source are not immediately visible from other sources, you need to declare them as extern in each source where you are using them. If you don't declare them extern then the linker will throw an error (duplicated symbol). Variables defined as static are visible only from the source where are declared, even if you declare them extern in another source, the linker will throw a symbol not found error. I assume that you already know that variables declared in a function are visible by that function only, even if static.
Aside from learning, separating the source code is a good pratice and helps maintaining the code clear.
About your code, it should work as described. I'm not sure when the Ops variable is cleared. As described both cogs should start but you don't know when they finish, you need something else to signal that the cogs have finished the work otherwise resetting the Ops variable may cause troubles (one code may not see the new state and believe that it should start the stepper fuction again, maybe with incorrect data.
Also, defining volatile the variables used by concurrent code is a good practice because tells the compiler to not optimize them and always use the correct value.
Hope this helps.
Discovery
There is a single DIRA/OUTA register for each cog and in C you can modify the single bits using the bitwise or, and, xor operators:
I think there are helper functions in simple libraries to make it work more like Spin, but in the end the above is what they do.
See the Propeller manual about how the registers are then combined to produce the actual pin states.
The one thing I think you will have a problem with is that two independent cogs controlling steppers is not a simple thing. Picture a line with a 30 degree slope. For each two steps you take in X, you take one step in Y. How do you make sure that the two motors advance at the right time so your line stays straight? It's actually easier to do this in a single cog with one loop controlling both motors. Look up DDA (digital differential analyzer) and Bresenham algorithms. Stepper motors can be treated very much like pixels on a graphics display, so graphics rasterization algorithms can be used with very few changes.
My current controller uses a single Cog to operate the Z axis stepper to keep the plasma cutter head at a distance of 1.6 mm from the base metal throughout the cut. The main program Cog does the calculating for X axis steps and Y axis steps and works well but it must be faster. That brought up the thought to put the X axis and Y axis control in each of two Cogs. The other option that I found is to replace the slow steppers with high speed high power units and keep the control as is. The decision is to order replacement Steppers.
Sincerely,
Discovery