Shop OBEX P1 Docs P2 Docs Learn Events
cogs, threads, I need some help — Parallax Forums

cogs, threads, I need some help

spinbobspinbob Posts: 27
edited 2013-09-16 00:09 in Propeller 1
I'm just stuck here trying a bunch of things and nothing works. I have 8 spin files that I converted to C using spin2cpp.exe and the code doesn't run correctly. I need some clarification. Does the converter convert code and it will run? This text is from a post I posted in General topics.
****
First a few details. Program written in spin, converted to C with spin2cpp. 12K of code compiles without errors. Our unit (custom PCB) has a display on a I2C bus that I use for feedback as to code running. Here is the problem:
In the Main() I do this:
Call a spin_start function in another C file to init a new cog to gather data. In the new cog I init a couple variables then sit in a while(1) loop reading the A/D and storing values. This is where the trouble lies. If I remove the while loop then the rest of the code in my Main works fine but with the while loop in place the unit hangs up, no display. All this code runs fine in it's spin form.
****

Can someone give me a rock solid example of how to init a new cog and run the code using C in Simple IDE. Is it treads, cogs, asm....
Thank you.

Comments

  • Dave HeinDave Hein Posts: 6,347
    edited 2013-06-14 12:49
    The problem is that spin2cpp doesn't handle cognew of Spin methods. It tries to do something like this:
    thisobj.Cog = (cognew(Spin_Main(), (int32_t)(&thisobj.Stack)) + 1);
    
    spin2cpp should convert cognew to pthread_create when starting a Spin cog, but it doesn't do this. You can do this yourself as follows:
    #include <pthreads.h>
    
    pthread_t Spin_Main_Thread;
    
    ...
    
    pthread_create(&Spin_Main_Thread, 0, Spin_Main, 0);
    ...
    
    The default stack size is 500 bytes. If you want a different stack size you will have to do a few other things. If you look at the code in the "Threaded Chess" thread you can see how I set the stack size.
  • jazzedjazzed Posts: 11,803
    edited 2013-06-14 13:01
    Just follow the example here: https://sites.google.com/site/propellergcc/documentation/libraries/propeller-h-library#TOC-cogstart

    I would recommend avoiding pthread functions unless there is a good reason to use them. With pthreads we need to worry too much about yielding time like on single core processors and functions like waitcnt don't play very nicely with pthreads. That being said, pthreads with CMM/LMM memory models can do SMP processing on Propeller which is an advantage in the right hands.
  • Dave HeinDave Hein Posts: 6,347
    edited 2013-06-14 14:21
    I had forgotten about cogstart. That's probably a better way to go when porting Spin programs. The sample program shows a stack size of "sizeof(_thread_state_t)+sizeof(int)*3". That's the bare minimum, and more space should be added if the cog is going to call functions or declare stack variables. When porting Spin code, I would probably add a couple of hundred bytes to the stack just to be safe. It could be trimmed later if space is tight.
  • NumPyNumPy Posts: 27
    edited 2013-09-15 15:51
    In the propeller.h library link jazzed listed above, there is some code in cogstart_blinker.c:

    int stacksize1 = sizeof(_thread_state_t)+sizeof(int)*25; int *stack1 = (int*) malloc(stacksize1);

    I modified it to run three cogs and it just ran them all in one I think.

    When I added :
    int stacksize1 = sizeof(_thread_state_t)+sizeof(int)*25;

    int *stack1 = (int*) malloc(stacksize1);


    int stacksize2 = sizeof(_thread_state_t)+sizeof(int)*25;
    int *stack2 = (int*) malloc(stacksize2);


    int stacksize3 = sizeof(_thread_state_t)+sizeof(int)*25;
    int *stack3 = (int*) malloc(stacksize3);

    It worked I believe in three seperate cogs.

    Can someone point me in the right direction to understand the stack
    and how each cog relates to it? Maybe in the forums.
    I am wondering if this is poor coding and maybe I am using more
    memory than need be, etc.

    Full code below:
    (ps I don't know if the milliseconds are right in my debug, I just guessed based on clkfreq/20 being 50....




    /*
    
      * cogstart_blinker.c
      *
      * Make one cog blink a pin using the cogstart function.
      * This program should be compiled with the CMM or LMM memory model.
      */
     
    
     #include <stdio.h>
     #include <stdlib.h>
     #include <propeller.h>
     
    
     
    
     volatile unsigned int wait_time1;
     volatile unsigned int wait_time2;
     volatile unsigned int wait_time3;
     
    
     /*
      * toggle thread function gets started in a CMM or LMM COG.
      * param arg = pin number to toggle
      */
     void do_toggle(void *arg)
     {
         unsigned int nextcnt;
     
    
         int pin = (int) arg;
     
    
         int wait_time=0;
     
    
         if (pin==13)
         {wait_time=wait_time1;}
         else if (pin==14)
         {wait_time=wait_time2;}
         else if (pin==15)
         {wait_time=wait_time3;}
         
         DIRA |= (1 << pin);         // set pin to output
         nextcnt = wait_time + CNT;
         for(;;) {
             
             OUTA |=  (1 << pin);    // set pin high
             nextcnt = waitcnt2(nextcnt, wait_time);
             OUTA &= ~(1 << pin);    // set pin low
             nextcnt = waitcnt2(nextcnt, wait_time);
     
    
         }
         cogstop(cogid());
     }
     
    
     void main (void)
     {
         int pin1 = 13;
         int pin2 = 14;
         int pin3 = 15;
             
         int stacksize1 = sizeof(_thread_state_t)+sizeof(int)*25;
         int *stack1 = (int*) malloc(stacksize1);
     
    
         int stacksize2 = sizeof(_thread_state_t)+sizeof(int)*25;
         int *stack2 = (int*) malloc(stacksize2);
     
    
         int stacksize3 = sizeof(_thread_state_t)+sizeof(int)*25;
         int *stack3 = (int*) malloc(stacksize3);
     
    
         int cog1,cog2,cog3;
     
    
         // start the cog
         cog1 = cogstart(do_toggle, (void*) pin1, stack1, stacksize1);
         
         cog2 = cogstart(do_toggle, (void*) pin2, stack2, stacksize2);
         
         cog3 = cogstart(do_toggle, (void*) pin3, stack3, stacksize3);
     
    
         // initialize wait time to 50ms
         wait_time1 = CLKFREQ/10;
         wait_time2 = CLKFREQ/20;
         wait_time3 = CLKFREQ/40;
         
         
         printf("do_toggle started on COG %d\n", cog1);
         printf("wait_time = %d",(wait_time1/80000));
         printf(" milliseconds.\n");
         
         printf("do_toggle started on COG %d\n", cog2);
         printf("wait_time = %d",(wait_time2/80000));
         printf(" milliseconds.\n");  
     
    
         printf("do_toggle started on COG %d\n", cog3);
         printf("wait_time = %d",(wait_time3/80000));
         printf(" milliseconds.\n");
      
     }
     
    
    
  • jazzedjazzed Posts: 11,803
    edited 2013-09-15 16:21
    The wait-times should be set before doing any cogstart.

    It is possible that all cogs in your example are using wait_time=0, and that would make it look like one cog is doing all the work.
  • NumPyNumPy Posts: 27
    edited 2013-09-15 16:51
    Well,
    All three leds on pin 13..14 are flashing at different rates.
    I shortened the wait time to:
    wait_time1 = CLKFREQ/1000; wait_time2 = CLKFREQ/2000;

    wait_time3 = CLKFREQ/4000;

    and put a scope on the pins (attached).
    Pins 13 and 15.jpg


    I tried putting some debug in the loop:
    for(;;) {
    OUTA |= (1 << pin); // set pin high
    nextcnt = waitcnt2(nextcnt, wait_time);
    OUTA &= ~(1 << pin); // set pin low
    nextcnt = waitcnt2(nextcnt, wait_time);
    }


    I suppose that is the way I need to prove
    that different cogs are actually running different
    pieces of code.

    But it didn't work. Will try again.

    I am trying to figure out the relation ship between
    starting a cog, the cog id and the memory allocation that is
    in the code. I don't see anything stating what
    cog id to start, and all the allocation statements look identical.
    I was hoping there was some explanation of this inter-working
    that I could find.
    984 x 604 - 206K
  • NumPyNumPy Posts: 27
    edited 2013-09-15 17:23
    I found the "Sizing the Stack" section in the book
    Programming and Customizing the Multicore Propeller Microcontroller.
    hopefully that will shed some light on this...
  • NumPyNumPy Posts: 27
    edited 2013-09-15 17:34
    I'm going to keep reading, but my confusion on this started when
    I ran the blinkwithcogs.spin demo. In SPIN they all run at the same
    time on three leds.
    When I ran it through spin2cpp, it works but it runs them sequentially.
    One cog and one led run, then stop and then the next cog and led run.
    I don't see in the code, why the c version doesn't start all the cogs
    at the same time.
    //
    // automatically generated by spin2cpp v1.03 on Sun Sep 15 14:26:42 2013
    // spin2cpp -main blinkwithcogs.spin 
    //
    
    #include <propeller.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include "blinkwithcogs.h"
    
    #ifdef __GNUC__
    #define INLINE__ static inline
    #define PostEffect__(X, Y) __extension__({ int32_t tmp__ = (X); (X) = (Y); tmp__; })
    #else
    #define INLINE__ static
    static int32_t tmp__;
    #define PostEffect__(X, Y) (tmp__ = (X), (X) = (Y), tmp__)
    #endif
    
    int32_t blinkwithcogsSpin::Launchblinkcogs(void)
    {
      cognew(Blink(15, (CLKFREQ / 300), 10000), (int32_t)(&Stack[0]));
      cognew(Blink(14, (CLKFREQ / 700), 21000), (int32_t)(&Stack[10]));
      cognew(Blink(13, (CLKFREQ / 1000), 39000), (int32_t)(&Stack[20]));
      return 0;
    }
    
    int32_t blinkwithcogsSpin::Blink(int32_t Pin, int32_t Rate, int32_t Reps)
    {
      DIRA = ((DIRA & (~(1 << Pin))) | (1 << Pin));
      OUTA &= ~(1<<Pin);
      {
        int32_t _idx__0000;
        _idx__0000 = (Reps * 2);
        do {
          waitcnt(((Rate / 2) + CNT));
          OUTA ^= (1<<Pin);
          _idx__0000 = (_idx__0000 + -1);
        } while (_idx__0000 >= 1);
      }
      return 0;
    }
    
    
    blinkwithcogsSpin MainObj__;
    
    int main() {
      return MainObj__.Launchblinkcogs();
    }
    
  • jazzedjazzed Posts: 11,803
    edited 2013-09-15 18:06
    It's almost impossible to account for all SPIN and C differences. I suspect that running SPIN code within the C context would have just as many troubles.
    NumPy wrote: »
    int32_t blinkwithcogsSpin::Launchblinkcogs(void)
    {
    cognew(Blink(15, (CLKFREQ / 300), 10000), (int32_t)(&Stack[0]));
    cognew(Blink(14, (CLKFREQ / 700), 21000), (int32_t)(&Stack[10]));
    cognew(Blink(13, (CLKFREQ / 1000), 39000), (int32_t)(&Stack[20]));
    return 0;
    }

    This appears to be a case where spin2cpp fails. The blinkers are not getting enough stack because of the methodology. Your first post's example is better, although wrong as I mentioned in my previous post.
  • NumPyNumPy Posts: 27
    edited 2013-09-15 18:18
    If all the cogs were running the same wait time wouldnt the leds be blinking the same speed?
    Would you also tell me why the wait time needs to be specified before the cogstart.
    Thanks for your help earlier.
  • jazzedjazzed Posts: 11,803
    edited 2013-09-15 18:55
    NumPy wrote: »
    If all the cogs were running the same wait time wouldnt the leds be blinking the same speed?
    Sure, but neither of the examples you've shown will guarantee that. In the first case most of the COGs started before your wait_time assignments, although the last one (two, or even all) could have started after the wait_time assignments because it takes about 100us for a Propeller COG to start. In the other case, the C stack space was being abused.
    NumPy wrote: »
    Would you also tell me why the wait time needs to be specified before the cogstart.
    So that the value is guaranteed to be correct before the function starts? The main program runs in one COG, and thus one statement/instruction generally precedes another unless they are run in different cogs. A new COG that depends on some data should have the data set first.
  • NumPyNumPy Posts: 27
    edited 2013-09-16 00:09
    Thanks again.
Sign In or Register to comment.