Shop OBEX P1 Docs P2 Docs Learn Events
Sharing variables between COGS — Parallax Forums

Sharing variables between COGS

electric550electric550 Posts: 122
edited 2009-04-18 19:19 in Propeller 1
I thought I saw an example program of two cogs sharing variables through the central hub...but I cannot find it now...could someone point me to an example of two cogs sharing data between the two? Or post some code of this nature? for example cog A send value Z to cog B then CogB sends back value x to CogA?

I have read that cog A would send a value to the hub memory then cog B would read that value and vice verse but I am having trouble figuring it out.

Any help is appreciated

Comments

  • JonnyMacJonnyMac Posts: 9,194
    edited 2009-04-18 00:53
    One cog will usually define the variable and then pass the address of it (using @) to the other cog with the cognew function.
  • electric550electric550 Posts: 122
    edited 2009-04-18 01:01
    Is there a decent example of this occurring in one of the sample routines.
  • JonnyMacJonnyMac Posts: 9,194
    edited 2009-04-18 01:03
    I'm sure there are many -- what do you want to do, specifically? That would help others write you demo that would be meaningful.
  • ProcessingData...ProcessingData... Posts: 208
    edited 2009-04-18 01:15
    Is it okay if i jump in? I'm trying to do the same thing. I'm trying to send the [noparse][[/noparse]edit: Copied] DIR Register [noparse][[/noparse]edit: in a variable] from one cog to another.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Basic Stamp,···· Propeller,·· · SX,·· FUN!


    START:·
    >Proccessing Data. . . .··
    >Task Complete. . .·.
    >Saving Data. . . .
    >Entering SLEEP Mode. . . .
    >Signing OFF




    Post Edited (ProcessingData...) : 4/18/2009 1:44:56 AM GMT
  • electric550electric550 Posts: 122
    edited 2009-04-18 01:25
    I would like an example program like the one specified in the first post to see how the cog memory sharing works. I do not want to confuse the issue with all of the details.
  • jazzedjazzed Posts: 11,803
    edited 2009-04-18 01:30
    Unfortunately that's where the devil lives .... details details [noparse]:)[/noparse]

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    --Steve


    Propalyzer: Propeller PC Logic Analyzer
    http://forums.parallax.com/showthread.php?p=788230
  • Mike GreenMike Green Posts: 23,101
    edited 2009-04-18 01:32
    You're not really trying to do the same thing. The DIR register is a piece of hardware and there's a separate one for each of the cogs. There is no mechanism for one cog to control another cog except to stop and reset it (with COGSTOP) or to start it initially (with COGINIT). Two cogs can cooperatively communicate with each other, but that has to be built into both programs running on the cogs.

    Two cogs can communicate most easily using RDxxxx/WRxxxx instructions that access the same hub memory locations. The main issue is that the cogs have to communicate in such a way that they don't "mess each other up" by one cog changing a memory location while the other cog expects that the location won't be changed. For example, if you have two cogs, each with the statement "X := X + 1", this will sometimes work and sometimes it won't. If cog "A" starts this statement at time 1 and cog "B" starts the identical statement at time 2, cog "A" will fetch "X", add 1 to it, and store the result back into "X". At time 2, cog "B" will fetch "X", add 1 to it and store the result back into "X". Unfortunately, cog "A" will have stored its updated "X" while cog "B" is still adding 1 to it. Cog "B" will store its updated value right on top of the value just stored by the "A" cog. Instead of "X" being increment by 2, it's only incremented by 1.

    There are ways around this. The simplest is to use the LOCKxxx instructions to force one cog to wait until the other cog is done with its update. The Propeller Manual has some examples of this.
  • mojorizingmojorizing Posts: 249
    edited 2009-04-18 02:24
    Are you asking w/regard to asm?

    With regards to Spin language, here are 2 examles how to pass variables between cogs.

    CogObjectExample is from the PE Kit. It repeats each time and restarts Blinker with the current "time" variable. Nothing fancy there.

    CogObjectExample2 is my version to have Blinker2 start once and run until the 20 reps are done, rec'ving the current "time" in the process.

    Hopefully this helps, and furthermore, I believe the PE examples are where you saw the various ways cogs can communicate.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Bad spellers of the world untie!
  • electric550electric550 Posts: 122
    edited 2009-04-18 03:10
    This is so wrong but anyways this is how I think I would read a 32 bit value from address 500 in central hub and write to var[noparse][[/noparse]0] in cog

    RDLONG var[noparse][[/noparse]0], @500

    is this correct?
    below is what led me to assume this

    DAT
    org 'reset address pointer
    Loop rdlong t1, par WZ 'wait for command
    if_z jmp #Loop 'jump of zero
    movd :arg, #arg0 'get 8 arguments
    :arg mov t2, t1

    RDLONG
    Instruction: Read long of main memory.
    RDLONG Value, 〈#〉 Address
    Result: Long is stored in Value.
    • Value (d-field) is the register to store the long value into.
    • Address (s-field) is a register or a 9-bit literalwhose value is the main memory address
    to read from.
    –INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks
    000010 001i 1111 ddddddddd sssssssss Result = 0 --- Written 7..22
    Explanation
    RDLONG syncs to the Hub, reads the long of main memory at Address, and stores it into the
    Value register.
    If the WZ effect is specified, the Z flag will be set (1) if the value read from main memory is
    zero. The value from main memory will be written to Value unless the NR effect is specified.
    RDLONG is a Hub instruction. Hub instructions require 7 to 22 clock cycles to execute
    depending on the relation between the cog’s hub access window and the instruction’s moment
    of execution. See Hub on page 24 for more information.
  • Mike GreenMike Green Posts: 23,101
    edited 2009-04-18 03:22
    You could use "RDLONG 0,#500". This reads a long from hub address 500 to cog address 0. Since an immediate field can hold a value up to 511, you can put the hub address in as an immediate source value. If it's greater than 511, you have to use a separate memory location for the hub address.

    var[noparse][[/noparse] 0 ] doesn't mean anything in an assembly instruction.
  • electric550electric550 Posts: 122
    edited 2009-04-18 03:41
    Sounds good so I assume that WRLONG $10,#500 writes the 32bit value from cog address 10 to hub address 500?

    WRLONG
    Instruction: Write a long to main memory.
    WRLONG Value, 〈#〉 Address
    • Value (d-field) is the register containing the 32-bit value to write to main memory.
    • Address (s-field) is a register or a 9-bit literal whose value is the main memory
    address to write to.
    –INSTR– ZCRI –CON– –DEST– –SRC– Z Result C Result Result Clocks
    000010 000i 1111 ddddddddd sssssssss --- --- Not Written 7..22
    Explanation
    WRLONG synchronizes to the Hub and writes the long in Value to main memory at Address.
    WRLONG is a Hub instruction. Hub instructions require 7 to 22 clock cycles to execute
    depending on the relation between the cog’s hub access window and the instruction’s moment
    of execution. Hub on page 24 for more information.
  • Mike GreenMike Green Posts: 23,101
    edited 2009-04-18 03:46
    Yes

    Do keep in mind that $10 is hexadecimal while 500 is decimal.

    Post Edited (Mike Green) : 4/18/2009 4:06:40 AM GMT
  • electric550electric550 Posts: 122
    edited 2009-04-18 03:55
    well that is exciting.
  • electric550electric550 Posts: 122
    edited 2009-04-18 05:23
    This compiles but does not work, anyone know why?

    cognew(WriteMain(10,500), @stack[noparse][[/noparse]0])
    cognew(ReadMain(10,500),@stack[noparse][[/noparse]10])

    PUB WriteMain(cogaddress,hubaddress)
    dat
    MOVS 10, #$30
    WRBYTE 10,500

    PUB ReadMain(cogaddress,hubaddress)
    serial.start(31,30,0,9600)
    repeat
    cog := BYTE[noparse][[/noparse]0][noparse][[/noparse]500]
    serial.tx(cog)
    dat
    RDBYTE 10,500

    Theoretically it should send zeros out the serial port
  • jazzedjazzed Posts: 11,803
    edited 2009-04-18 05:31
    you've tried to mix spin and pasm. can't do that. you should have a look at a tutorial from the stickes. potatohead's tutorial is a good place to start.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    --Steve


    Propalyzer: Propeller PC Logic Analyzer
    http://forums.parallax.com/showthread.php?p=788230
  • electric550electric550 Posts: 122
    edited 2009-04-18 17:42
    This does not work and I don't know why. This is two cogs Prog1 writes a 1 or 0 to a hub variable based on input, then assemble reads it and jumps based on the value... The assembly code never jumps out of the non zero loop like the value is never zero. If someone knows why this does not work please let me know.

    Pub RAM1

    cognew(@assemble,@stack[noparse][[/noparse]0]) 'Start cog to pass through the servos
    cognew(Prog1,@stack[noparse][[/noparse]10]) 'Start cog for program to read pwm values

    PUB Prog1
    text.start(31,30,0,115200)
    repeat

    text.rx(pulseWidths[noparse][[/noparse]0])

    if pulseWidths[noparse][[/noparse]0] > 2000
    BYTEFILL(500,1,0) 'if 1 from serial port write 1 to ram location 500 in hub
    outa[noparse][[/noparse]7] := 0 'turn on LED --it is active low
    else
    outa[noparse][[/noparse]7] := 1 'turn off LED --it is active low
    BYTEFILL(500,0,0) 'if 0 from serial port write 0 to ram location 500 in hub
    waitcnt (counter)


    DAT
    org
    assemble
    mov dira, mask 'intialized pins
    mov 50, $0
    loop RDLONG 50, #500 'reads value from hub address 500??? and stores into 50??
    TJZ 50, #loop
    movd outa, ina 'mov pins 0 to 8 to pins 10
    jmp #loop

    mask long %00000000_00000000_11111111_10000000
    comp byte %00000000
  • Mike GreenMike Green Posts: 23,101
    edited 2009-04-18 18:07
    1) Assembly routines do not use a stack. The 2nd parameter to COGNEW is an arbitrary address that simply gets passed to the cog in the PAR register and can be anything you want (that's an address of a long or other 14 bit value).

    2) The "mov 50,$0" isn't necessary since location 50 is immediately changed using the RDLONG.

    3) The "outa[noparse][[/noparse] 7 ]" in Prog1 won't do what you expect since I/O pin 7 (in that cog) is in input mode. Each cog has its own private copy of DIRA and OUTA and changes to either are internal to that cog only. All of the DIRA and OUTA bits are combined as shown in the Propeller Manual to produce one I/O pin value for each bit. Look at that diagram for details.

    4) You have no idea what's contained in locations 500 to 503. The RDLONG reads 4 bytes starting at the address given. If you want to use only one byte, use RDBYTE instead. Location 500 might be somewhere in your program or in the stack space or variable space. It's generally not a good idea to use numeric addresses in the hub (shared) memory for that reason. It's easier to use PAR, so you'd have "RDBYTE 50,PAR". The COGNEW would then be "COGNEW(@assemble,@variable)" where "variable" is an ordinary byte variable in your program. You wouldn't need to use BYTEFILL. You could just write "variable := 0" or "variable := 1".

    5) Look at the examples for serial input. "text.rx(pulseWidths[noparse][[/noparse] 0 ])" doesn't mean anything and wouldn't compile anyway.
  • StefanL38StefanL38 Posts: 2,292
    edited 2009-04-18 19:19
    Hello Electric550,

    did you look into the Machine Language Tutorial
    from DeSilva ?

    and the Assembly, step by step
    from Graham Stabler

    best regards

    Stefan
Sign In or Register to comment.