Shop OBEX P1 Docs P2 Docs Learn Events
LMM multi-COG programming questions — Parallax Forums

LMM multi-COG programming questions

mindrobotsmindrobots Posts: 6,506
edited 2011-11-21 05:04 in Propeller 1
I've been reviewing the lmm-c-toggle\toggle.c program and have some questions about the setup for multiple LMM cogs and also the .coguser0 and .coguser7 usage and setup.

The comments in the example code state
/*
 * function to start up a new cog running the toggle
 * code (which we've placed in the .coguser1 section)

but I don't see any explicit references to the sections in the code. The GAS and PASM examples do have explicit references to sections.

For a multi-cog LMM program, is it necessary to separate the code into sections? If so, how is this done?

Is there any documentation on how/when to use the .coguser sections? I found references to the sections but no details as to when they are needed.

The following is a modified toggle.c that starts up 2 additional LMM COGs. One to count up and one to count down. It's written for a Quickstart since it splits the LEDs (17-23) in half between the two COGs.
/*
source: lmm_c_toggle/toggle.c

This example builds upon the lmm_toggle example program.
In that program, the deault propgcc single LMM model 
was created. In that model, all code is running in a
single LMM VM under a single COG. The program
has the entire HUB ram available and visible to it for 
code and variable space.

In this example, a second and third LMM VM is started in a second and third COG. 
This shows you how to start using multiple COGs but maintains the 
LMM memory model, keeping all code and variables in HUB RAM. Each 
COG running an LMM VM can access the program variables as 
C variables without any special consideration for passing parameters 
or data between COGs.

This allows you to exploit the multi-core aspects of the Propeller
in relatively transparent manner.


The first started COG will toggle pins 16-19 at a decreasing duty 
cycle from 80,000,000 clock ticks per cycle down to 800,000 ticks per cycle.

The second started COG will toggle pins 20-23 at an increasing duty cycle
from 800,000 clock ticks per cycle up to 80,000,000 ticks per cycle.

COG0 is the initial LMM COG, it does basic housekeeping and the starts
a second COG to run the do_toggle function. After that it goes
into a loop where it divides/multiples the duty cycle by 2 every 2 seconds and 
stores the updated value in waiy_time. COG0 updates wait_time but 
doesn't use it to control the pins.

COG1 and COG2 run do_toggle which just checks the pins and then toggles 
the pins based on the value of wait_time1 or wait-time2. 
COG1 uses wait_time1 to control the pins but doesn't update it.
COG2 uses wait-time2 to control the pins but doesn't update it.


Copyright (c) 2011 Parallax, Inc.
MIT Licensed. See terms below.
*/


#include <stdio.h>  
#include <propeller.h>

#define STACK_SIZE 16

/*
 * function to start up a new cog running the toggle
 * code (which we've placed in the .coguser1 section)
 * "func" is the function to run, and
 * "stack_top" is the top of the stack to be used by
 * the new cog
 */
void start_lmm(void *func, int *stack_top)
{
    extern unsigned int _load_start_kernel[];

    /* push the code address onto the stack */
    --stack_top;
    *stack_top = (int)func;

    /* now start the kernel */
    cognew(_load_start_kernel, stack_top);
}

/* variables that we share between COG0 and COG1 */
volatile unsigned int wait_time1;
volatile unsigned int pins1;
/* variables that we share between COG0 and COG2 */
volatile unsigned int wait_time2;
volatile unsigned int pins2;

/* stack for COG1 and COG2 */
static int cog1_stack[STACK_SIZE];
static int cog2_stack[STACK_SIZE];


/*
 * the toggle code that runs in COG1
 */

void do_toggle(void)
{
  _DIRA = pins1;
  for(;;) {
    _OUTA ^= pins1; /* update the pins */
    /* sleep until _CNT == nextcnt, and return the new _CNT + wait_time */
    waitcnt(wait_time1+CNT);
  }
}

/*
 * the toggle code that runs in COG2
 */
void do_toggle2(void)
{
  _DIRA = pins2;
  for(;;) {
    _OUTA ^= pins2; /* update the pins */
    /* sleep until _CNT == nextcnt, and return the new _CNT + wait_time */
    waitcnt(wait_time2+CNT);
  }
}
/*
 * main code
 * This is the code running in the LMM cog (cog 0).
 * It launches two other cogs to actually run the 
 * toggling code
 */
#define MIN_GAP 800000

void main (int argc,  char* argv[])
{
    printf("hello, world!\n");

    /* set up the parameters for the LMM C cogs */
    // COG 1 parameters
    pins1 = 0x0f<<16;      // pins 16, 17, 18, 19
    wait_time1 = CLKFREQ;  /* start by waiting for 1 second */
    // COG 2 parameters
    pins2 = 0xF0<<16;      // pins 20, 21, 22, 23
    wait_time2 = MIN_GAP;  // start by waiting for minimum gap

    /* start the new cog */
    start_lmm(do_toggle, cog1_stack + STACK_SIZE);
    start_lmm(do_toggle2, cog2_stack + STACK_SIZE);
    printf("toggle cog has started\n");

    /* every 2 seconds update the flashing frequency so the
       light blinks faster and faster or slower and slower*/
    while(1) {
      sleep(2);
      wait_time1 =  wait_time1 >> 1;
      wait_time2 = wait_time2 << 1;
      if (wait_time1 < MIN_GAP)
    {
    wait_time1 = CLKFREQ;
    wait_time2 = MIN_GAP;
    }
    }
}

/* +--------------------------------------------------------------------
 * ¦  TERMS OF USE: MIT License
 * +--------------------------------------------------------------------
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files
 * (the "Software"), to deal in the Software without restriction,
 * including without limitation the rights to use, copy, modify, merge,
 * publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 * +--------------------------------------------------------------------
 */

The code above appears to run fine but I don't know if I should be doing something better or differently for multiple COG LMM code. If code needs to be explicitly sectioned off, I'd like to build a multi-cog template for the tutorials.

Thanks!

Comments

  • ersmithersmith Posts: 6,100
    edited 2011-11-21 05:04
    The comment about .coguser1 is a cut and paste artifact from the cog_c_toggle demo. When you're running LMM C code on another COG you do not have to place any code in .coguserN, that's only necessary for "native" COG C code.

    There are a few other things that are necessary for setting up threads on another COG; some of the library functions rely on per-thread data structures, and those need to be initialized. We'll be providing updated libraries and demos for threading shortly, you may want to hold off on this demo until those come out.

    Eric
Sign In or Register to comment.