Status Lights to Indicate Activity of Cogs

Hello, I am making a spin program to turn on and off the VGA LEDs on the PropBOE according to the active status of each cog.

Cog 0 starts up, Sets pins 0..7 as outs, then low, then turns on LED 0 to indicate that it is active, then generates two random numbers. Cog 0 then starts a cog according to random number a, then stops a cog according to random number b, also setting the corresponding LED low. As Each Cog is activated, it turns on an LED to indicate it's activity, then generates the random numbers to start and stop the other cogs.

What I need help with is the syntax of Coginit and the random operator, Thanks!


  • 24 Comments sorted by Date Added Votes
  • Mike GreenMike Green Posts: 22,753
    edited May 29 Vote Up0Vote Down
    You’re going to have some problems. Each cog has its own copy of the DIR and OUT registers and they’re OR’d together to produce the values actually used to determine the I/O pin states. You’ll be ok with DIR since any cog that will affect I/O pins 0-7 will have DIRA[0-7] := %11111111 as part of its initialization code. The problem will be that you can’t turn off an LED from a cog different from the one that turns on the LED (and keeps it on). You have one cog with a bit of OUTA set to 1 and there’s no way to get PinOUTA = OUTAcogA OR OUTAcogB to have a zero value when OUTAcogA is a one.

    Look in the Propeller Manual for the syntax of COGINIT and the random operation.
  • AwesomeCronkAwesomeCronk Posts: 316
    edited May 29 Vote Up0Vote Down
    I had attached the Program(sort of) that used Dira[0..7] ~~ to set all pins as outputs. Did you guys see the Spin file? Because I don't.
    I see it now.
  • AwesomeCronkAwesomeCronk Posts: 316
    edited May 29 Vote Up0Vote Down
    I have been reading through the Kit Labs Fundamentals PDF and reading examples for syntax assistance. Didn't find anything on random there. Thanks for the Idea on the Manual.
  • Here is the updated code:
  • Look at page 159 of the Manual for the "?" operator. This takes a 32 bit value (the "seed") and runs it through a "linear feedback shift register" to get a new pseudo-random value. If you have a long variable called Seed, you'd do Seed := ?Seed every time you want a new pseudo-random value. During your program's initialization, you'd first set Seed to some arbitrary value, ideally based on something that changes each time you run your program. For debugging, you could use a fixed value and your pseudo-random sequence would repeat each time you run the program.
  • AwesomeCronkAwesomeCronk Posts: 316
    edited May 29 Vote Up0Vote Down
    Ok. I tried testing my attempts by debugging via PST, using the Parallax Serial Terminal Object, but did not recieve anything via PST. The red and blue RX/TX LEDs don't come on(they do come on during programming, and RX flashes for a brief moment at powerdown). Updated code is shown. The Parallax Serial Terminal Object is functional, it works through the demo object, and I used the same initialization techniques(as far as I know).
  • Mike, to your first comment.
    Only Cog 0 wil run the Private method Init.
  • Alas, you can't call PST from multiple cogs. The problem is that PST has only one buffer and its associated variables. If one cog calls a method in PST and another cog calls any method in PST, the first cog might be changing a PST variable while the 2nd cog also attempts to change to same variable to something else.

    You can use a "lock" to reserve access to a shared resource to fix this problem. There are examples in the Propeller Manual for the LOCKNEW, LOCKSET, LOCKCLR, and LOCKRET starting at pg 120.
  • AwesomeCronkAwesomeCronk Posts: 316
    edited May 29 Vote Up0Vote Down
    Hey, I just thought of something! I read that there must be at least 2 lines of Spin in order to have any PASM. Perhaps there may be a similar limit applied to this.
    I changed the Private method "Init" to a Public method, AND IT WORKED!! :lol: :cool:
    All but the LEDs, that is.
  • I will be removing the PST code when this goes multi-cog.
  • I am having issues with the forums. I am not seeing your comments unless I refresh the page, sorry about that.
  • Yes, the LEDs. You can't turn them off from another cog because of the OR. As long as one cog has its corresponding bit of DIR and OUT set to 1, the I/O pin will be high (on). Somehow one cog (that generates the random 'turn off' number) has to communicate to the other cog (that has its DIR and OUT bit set to 1). I prefer using a variable that both cogs can access.
  • The cog that powers on LED 6(for example) will be shut down. Then the cog that stopped cog 6 will turn off LED 6, no competition. When running in cog 0, however, the LED for cog 1 blinked. I debugged the MyID variable to the PST and found that cog 0 pulls up as cog 1. According to the Manual, CogID should be returning 0-7, not 1-8
  • The COGID instruction and Spin function does indeed return the current cog’s number as a value from 0-7. Most software by convention adds 1 to this so a value from 1-8 gives the cog number (+1) and zero indicates that a cog was never started, usually due to the lack of an available cog
  • So I could solve this by subtracting 1 from the MyID variable?

    What do I do about the LEDs only being on for a moment? I would like them to be on for the entire duration of the cog's active status.
  • Have each cog turn on a corresponding LED when the cog starts with

    OUTA[COGID] := 1 { Set corresponding OUTA bit to high }
    DIRA[COGID] := 1 { and enable I/O pin output state }

    Whenever the cog stops, whether the cog stops itself or it's stopped by another cog, the LED will turn off because a stopped cog zeroes all of its control registers including DIRA and OUTA.
  • Code to start a cog looks somewhat like this:
    IF MyID := COGNEW(cogLoop,@cogStack)+1
       { cog started successfully }

    Then you'd have:
    pub cogLoop
      outa[cogid] := 1
      dira[cogid] := 1
      { LED turned on, now do something }
      [ when method ends, cog stops and LED turns off }

    You can use an array for MyID and make cogStack big enough for 8 cog stacks. Usually I'd allow 100 longs, but that's way more than you'd really need for one cog. Try 50 per cog with VAR LONG cogStack[400]

    You can put the IF in a REPEAT loop with i going from 1 to 7. You'd have

    MyID[ I ] := COGNEW(cogLoop,@cogStack+I*200)+1
  • AwesomeCronkAwesomeCronk Posts: 316
    edited May 30 Vote Up0Vote Down
    That may be the issue with my LEDs. My stack is too small. Also. I will try to adapt your Cognew to work with Coginit. I need to start by ID(RandomStart, RandomStop) so that it is random.
  • You can also use COGINIT which allows you to specify the cog number (0-7) to be used. Keep in mind that cog 0 is probably your main cog containing your initialization routine. Also, whenever you start up a cog with either COGNEW or COGINIT, it will take around 500us for the cog to start executing. You also have to do a COGSTOP before you do a COGINIT to make sure the cog involved stops executing before the stack space to be used gets reinitialized. You'll need a check to make sure the cog to be restarted isn't the one running the code that comes up with its own cog number.
  • You might first try a program that only works with 7 of the 8 cogs and the controlling code is completely in cog 0. You won't be able to use PST because that requires a 2nd cog for the serial I/O routines. You could limit yourself to 6 cogs and LEDs if you want to debug with PST called from the main cog.
  • Parallel processing is complicated because several things can be happening at the same time. The Propeller is actually a nicely designed device for this. Try first using only 6 cogs for the random start/stop stuff. Once you get that working, it's pretty easy to strip out the debugging code and use all 8 cogs.

    You probably will want to put delays in the code for all but the initialization cog so the initialization cog can finish its work before one of the other cogs reuses the initialization cog before it's done.
  • AwesomeCronkAwesomeCronk Posts: 316
    edited May 31 Vote Up0Vote Down
    Okay. Delays are one thing which have confused me. I almost always mess up with the syntax and it doesn't work.
  • Mike GreenMike Green Posts: 22,753
    edited May 31 Vote Up0Vote Down
    For a fixed delay, you want a constant like this:

    CON ms = CLKFREQ / 1000

    This gives the number of system clock cycles for a millisecond and adjusts it as needed when a program is recompiled with a different system clock speed. Then you can do:


    to get a 150ms pause. The total delay in clock cycles must be less than 2^31 or you'll run into problems with overflow since calculations are done with 32 bit numbers. Be careful with delays on the order of tens of microseconds or less. That's getting near the execution time for primitive Spin operations. Such situations probably should be handled using assembly language.

    You can also define

    CON us = CLKFREQ / 1000000


    CON sec = CLKFREQ
Sign In or Register to comment.