Shop OBEX P1 Docs P2 Docs Learn Events
2 or more COG's running assembler — Parallax Forums

2 or more COG's running assembler

Richard MorrisonRichard Morrison Posts: 8
edited 2006-07-11 18:29 in Propeller 1
I want to launch 2 COG's that each toggle different I/O pins ad infinitum at different frequencies in assembler using consecutive Spin statements

coginit(6,@routine1,var)
coginit(7,@routine2,var)

Not particularly useful (given the counters) but just want to demonstrate that it works OK (in assembler) before attempting something more interesting....

My routine1 and 2 work fine with 1 COG operating but not 2.

Can someone out there tell me how the DAT section of my program should be structured to get this to work properly ?

Thanks

Comments

  • SSteveSSteve Posts: 808
    edited 2006-07-07 14:44
    Until someone more knowledgeable replies: This is a shot in the dark based on a vague recollection, but try putting an ORG directive just before the routine2 label. If that doesn't work, please post your code and tell us what's not working.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    OS-X: because making Unix user-friendly was easier than debugging Windows

    links:
    My band's website
    Our album on the iTunes Music Store
  • Richard MorrisonRichard Morrison Posts: 8
    edited 2006-07-08 00:32
    Sorry I didn't post the code earlier.· Here it is.·

    The second org is commented out at the moment.· When·this code·runs P0 has the expected square wave.

    If I include the second org·only P1·appears to produce output, at a lower frequency, of course.· I am running this on a PropStick.

    So how do we make both·COG's run simultaneously ?

    A related·question would be - what happens if one's assembler segment needs to exceed 512 longs ??·- OK we could use a second, or third COG but how then should the DAT segment of the program be structured ?

    Can't wait for the assembler manual to appear - who knows when this might be ?
  • JLBSheckyJLBShecky Posts: 6
    edited 2006-07-08 02:46
    I would like to offer some real help, but the best that I can do is to say the I just noticed that they now have the manual online as of the last time i checked just a few minutes ago. they have a link on the propellor download page, or you can just go to http://www.parallax.com/dl/docs/prod/prop/WebPM-v1.0.pdf
    I havent had a chance to get to the assembly section myself, I am still enjoying reading over the tutorial at this moment.

    -JLBShecky

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    -JLBShecky
  • Richard MorrisonRichard Morrison Posts: 8
    edited 2006-07-08 02:55
    Yes indeed - and more than 400 pages too !!

    Fantastic to see this made available. Thanks Parallax !! Hopefully should shed light on this issue.
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2006-07-08 04:34
    The data used by an assembly cog has to be governed by the same ORG as its code. You need to separate delay1 from delay2, data1 from data2, and t1 from t2, so that each resides in its proper code segment.

    -Phil
  • Beau SchwabeBeau Schwabe Posts: 6,568
    edited 2006-07-08 06:08
    Richard,

    I think this is what Phil is trying to describe, only I did not seperate t1 from t2..... I tested this code, and on pin0 I read a 500kHz square and on pin1 I read a 50kHz square.
    Note: You don't need the second DAT, I just did this as visual symetry.



    ' 2 COG assembler program, July 8th, 2006
    ' Produce square waves on pins P1, P0
    
    '
    ' Pin Utilization
    '
    ' P0            controlled by COG 6
    ' P1            controlled by COG 7
    
    [b]CON[/b]
    
    [b]_clkmode[/b] = [b]xtal[/b]1 + [b]pll[/b]16x
    [b]_xinfreq[/b] = 5_000_000
      
    [b]VAR[/b]
    
    [b]long[/b] param
    
    [b]PUB[/b] start
    
    param := 0
          
    [b]coginit[/b](6,@cog6, param)    'launch assembly program in 1st COG
    [b]waitcnt[/b]([b]cnt[/b] + 2_000)
    
    [b]coginit[/b](7,@cog7, param)    'launch assembly program in 2nd COG
    [b]waitcnt[/b]([b]cnt[/b] + 2_000)
    
    
    [b]DAT[/b]
                  [b]org[/b]
    
    cog6          [b]or[/b]              [b]dira[/b],#$01
    
                  [b]mov[/b]             t1,[b]cnt[/b]                                       
                  [b]add[/b]             t1,delay1
            
    [b]repeat[/b]1       [b]waitcnt[/b]         t1,delay1
                  [b]xor[/b]             [b]outa[/b],data1                     
                  [b]jmp[/b]             #[b]repeat[/b]1
    
    ' Initialized data
    
    delay1        [b]long[/b]            80
    data1         [b]long[/b]            1
    
    
    [b]DAT[/b]
                  [b]org[/b]
                       
    cog7          [b]or[/b]              [b]dira[/b],#$02
    
                  [b]mov[/b]             t2,[b]cnt[/b]                                       
                  [b]add[/b]             t2,delay2
            
    [b]repeat[/b]2       [b]waitcnt[/b]         t2,delay2
                  [b]xor[/b]             [b]outa[/b],data2                      
                  [b]jmp[/b]             #[b]repeat[/b]2
                 
    ' Initialized data
    
    delay2        [b]long[/b]            800
    data2         [b]long[/b]              2
      
    ' Uninitialized data
    
    t1            [b]res[/b]             1
    t2            [b]res[/b]             1
    
    
    

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Beau Schwabe

    IC Layout Engineer
    Parallax, Inc.
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2006-07-08 06:35
    Beau,

    I believe your solution will work so long as cog6's code is no longer than cog7's. But if it's longer, t1 will have an address that collides with cog6's code, because it's referenced to the second org. This is one place where the "put all res statements last" rule needs to be broken. t1 belongs after data1. It won't interfere with cog7 there because cog7 will be loaded into a different cog. (Referencing addresses accross org boundaries is something the assembler ought to be flagging with a warning.)

    Richard, I would encourage you to use cognew instead of coginit, BTW. Your programs will be more portable if they don't depend on which cogs actually contain your code.

    -Phil
  • Richard MorrisonRichard Morrison Posts: 8
    edited 2006-07-08 07:37
    Thanks Beau and Phil

    I confirmed Beau's modification works but also proved that Phil is correct too - adding just one NOP after the first XOR instruction while having both t1 and t2 in the same uninitialized data section at the very end of the program after the second org causes the high frequency square wave to get clobbered - so do separate all variables used by different COG's as Phil suggests (sounds like one for the Tricks and Traps Phil)

    Thanks for the heads up on merits of COGNEW vs COGINIT too...
  • henkvbeekhenkvbeek Posts: 11
    edited 2006-07-11 18:22
    I hope to present hereby two more sophisticated examples how using SPIN and
    assembly parts with their interactions trough the PAR register.

    SPIN_vs_ASM:
    CON
    'Set clock speed to 80 MHz
      _clkmode = xtal1 + pll16x
      _xinfreq = 5_000_000
    
    OBJ
      Usart: "Simple_Serial"
      Numbr: "Simple_Numbers"
      
    VAR
      long  LNum1, LNum2
       
    PUB Start                                                             
      Usart.start(-1, 0, 19_200)
      WaitCnt(50_000_000 + Cnt)
      Usart.str(string("Usart object started",13,10))
    
      LNum1 := $123456
      LNum2 := $654321
      Usart.str(Numbr.ihex(LNum1, 6))
      Usart.tx(13)
      Usart.tx(10)
      Usart.str(Numbr.ihex(LNum2, 6))
      Usart.tx(13)
      Usart.tx(10)
    
      cognew(@TestAsm, @LNum1)                      'Start new cog with address of var
      waitcnt(cnt + 200_000)                        'Wait for cog to run        
    
      Usart.str(Numbr.ihex(LNum1, 6))
      Usart.tx(13)
      Usart.tx(10)
      Usart.str(Numbr.ihex(LNum2, 6))
      Usart.tx(13)
      Usart.tx(10)
    
    DAT
                  org       0
    
    TestAsm       mov       ParPtr, PAR             'Get address of SPIN var into local ParPtr
                  RdLong    Num, ParPtr             'Read Value of SPIN var into local var Num
                  add       Num, #5                 'Add local 5 into local var Num
                  WrLong    Num, ParPtr             'Write local var Num back into SPIN var
                  add       ParPtr, #4              'Prepare for getting next SPIN var
                  RdLong    Num, ParPtr             'Read Value of SPIN var into local var Num
                  add       Num, #3                 'Add local 3 into local var Num
                  WrLong    Num, ParPtr             'Write local var Num back into SPIN var
    Wt            jmp       #Wt                     'Wait infinitely
                                  
    ' Uninitialized data
    
    ParPtr        res             1
    Num           res             1
    
    



    TwoPinsToggleWithTwoCogs.spin:

    CON
    'Set clock speed to 80 MHz
      _clkmode = xtal1 + pll16x
      _xinfreq = 5_000_000
    
    OBJ
      Usart: "Simple_Serial"
      Numbr: "Simple_Numbers"
      
    VAR
      long  LNum1, LNum2
       
    PUB Start                                                             
      Usart.start(-1, 0, 19_200)
      WaitCnt(50_000_000 + Cnt)
      Usart.str(string("Usart object started",13,10))
    
      LNum1 := $123456
      LNum2 := $654321
      Usart.str(Numbr.ihex(LNum1, 6))
      Usart.tx(13)
      Usart.tx(10)
      Usart.str(Numbr.ihex(LNum2, 6))
      Usart.tx(13)
      Usart.tx(10)
    
      cognew(@TestAsm, @LNum1)                      'Start new cog with address of var
      waitcnt(cnt + 200_000)                        'Wait for cog to run        
    
      Usart.str(Numbr.ihex(LNum1, 6))
      Usart.tx(13)
      Usart.tx(10)
      Usart.str(Numbr.ihex(LNum2, 6))
      Usart.tx(13)
      Usart.tx(10)
    
    DAT
                  org       0
    
    TestAsm       mov       ParPtr, PAR             'Get address of SPIN var into local ParPtr
                  RdLong    Num, ParPtr             'Read Value of SPIN var into local var Num
                  add       Num, #5                 'Add local 5 into local var Num
                  WrLong    Num, ParPtr             'Write local var Num back into SPIN var
                  add       ParPtr, #4              'Prepare for getting next SPIN var
                  RdLong    Num, ParPtr             'Read Value of SPIN var into local var Num
                  add       Num, #3                 'Add local 3 into local var Num
                  WrLong    Num, ParPtr             'Write local var Num back into SPIN var
    Wt            jmp       #Wt                     'Wait infinitely
                                  
    ' Uninitialized data
    
    ParPtr        res             1
    Num           res             1
    
    



    These two programs are only ment to show using cognew with parameter passing.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    What God wants, God gets . . .
  • henkvbeekhenkvbeek Posts: 11
    edited 2006-07-11 18:29
    Sorry, I posted the same code twice.
    Her is the other one:

    TwoPinsToggleWithTwoCogs.spin:
    ' 4 COG assembler program, July 11th, 2006
    ' Produce square waves on pins P16+17,18+19,20+21 and 22+23
    
    CON
    
     _clkmode = xtal1 + pll16x      ' 80 MHz
     _xinfreq = 5_000_000
    
      P16 = |< 16
      P17 = |< 17
      Del1 = 500                    ' millisec
    
      P18 = |< 18
      P19 = |< 19
      Del2 = 2000
    
      P20 = |< 20
      P21 = |< 21
      Del3 = 4000
    
      P22 = |< 22
      P23 = |< 23
      Del4 = 8000
    
    VAR
      long  HPins1, HDlay1
      long  HPins2, HDlay2
      long  HPins3, HDlay3
      long  HPins4, HDlay4
    
    PUB start
    
      HPins1 := P16 | P17
      HDlay1 := CLKFREQ / 1000 * Del1
    
      HPins2 := P18 | P19
      HDlay2 := CLKFREQ / 1000 * Del2
    
      HPins3 := P20 | P21
      HDlay3 := CLKFREQ / 1000 * Del3
    
      HPins4 := P22 | P23
      HDlay4 := CLKFREQ / 1000 * Del4
    
      cognew(@cogBlink, @HPins1) 'launch assembly program in new COG
      waitcnt(cnt + 2_000)
    
      cognew(@cogBlink, @HPins2)
      waitcnt(cnt + 2_000)
    
      cognew(@cogBlink, @HPins3)
      waitcnt(cnt + 2_000)
    
      cognew(@cogBlink, @HPins4)
      waitcnt(cnt + 2_000)
    
    
    DAT
                  org       0
    
    CogBlink      mov       ParPtr, PAR
                  RdLong    Pins, ParPtr
                  add       ParPtr, #4
                  RdLong    Dlay, ParPtr
                    
                  mov       dira, Pins
    
                  mov       Tmp, cnt                                             
                  add       Tmp, Dlay
            
    RptBlink      xor       outa, Pins
                  waitcnt   Tmp, Dlay
                  jmp       #RptBlink
    
    ' Uninitialized data
    
    ParPtr        res       1
    Pins          res       1
    Dlay          res       1
    Tmp           res       1
    
    

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    What God wants, God gets . . .
Sign In or Register to comment.