Shop OBEX P1 Docs P2 Docs Learn Events
How to? Create an array of arrays — Parallax Forums

How to? Create an array of arrays

SteveWoodroughSteveWoodrough Posts: 190
edited 2014-01-08 18:35 in General Discussion
Given my low experience level, this may seem like a peculiar question. Can I create an array of arrays? I am trying to start several of the same type objects in different cogs.

The brute force method looks like this, and works just fine. It starts as many cogs as remain and blinks LED’s:
var

  byte Cog [8]
  long LED16Stack[10],LED17Stack[10],LED18Stack[10],LED19Stack[10],LED20Stack[10],LED21Stack[10],LED22Stack[10],LED23Stack[10] 


pub cog_counter 

'' starts blink led in each remaining cog

  start16                                               'Launched into cog  1
  start17                                               'Launched into cog  2
  start18                                               'Launched into cog  3 
  start19                                               'Launched into cog  4 
  start20                                               'Launched into cog  5 
  start21                                               'Launched into cog  6 
  start22                                               'Launched into cog  7 
  start23   

 
pub blink_led(pin)

  dira[Pin]~~                                           ' make pin output
  repeat
    !outa[pin]
    waitcnt(clkfreq/(pin-15)+cnt)                       'Subtracting 15 makes the cogs blink at a rate you can observe 


pub start16

  stop16
  Cog[1]:= cognew(blink_led(16),@LED16Stack)+1

   
pub stop16

  if cog[1]
    cogstop(cog[1]~ - 1)

    
pub start17

  stop17
  Cog[2]:= cognew(blink_led(17),@LED17Stack)+1

   
pub stop17

  if Cog[2]
    cogstop(cog[2]~ - 1)

    
pub start18

  stop18
  Cog[3]:= cognew(blink_led(18),@LED18Stack)+1

    
pub stop18

  if Cog[3]
    cogstop(Cog[3]~ - 1)
    
pub start19

  stop19
  Cog[4]:= cognew(blink_led(19),@LED19Stack)+1

   
pub stop19

  if Cog[4]
    cogstop(Cog[4]~ - 1)

    
pub start20

  stop20
  Cog[5]:= cognew(blink_led(20),@LED20Stack)+1

    
pub stop20

  if Cog[5]
    cogstop(cog [5]~ - 1)
pub start21

  stop21
  Cog[6]:= cognew(blink_led(21),@LED21Stack)+1

  
pub stop21

  if Cog[6]
    cogstop(cog [6]~ - 1)

    
pub start22

  stop22
  Cog[7]:= cognew(blink_led(22),@LED22Stack)+1

    
pub stop22

  if Cog[7]
    cogstop(cog [7]~ - 1)

    
pub start23

  stop23
  Cog[8]:= cognew(blink_led(23),@LED23Stack)+1

    
pub stop23

  if cog [8]
    cogstop(cog [8]~ - 1)



So I decided to tighten it up a bit and began to write:
  byte Cog [8]
  long LED16Stack[10],LED17Stack[10],LED18Stack[10],LED19Stack[10],LED20Stack[10],LED21Stack[10],LED22Stack[10],LED23Stack[10] 


pub cog_counter | n,startpin

'' starts blink led in each remaining cog

  startpin := 16
  repeat n from 1 to 8
    dira[n+(startpin-1)]~~                              'set pin to output
    if cog[n]                                           'standard cogstop routine
      cogstop(cog[n]~ -1)
  Cog[n]:=cognew(blink_led(n+(startpin-1)),@???)+1    'start next cog 


When I got to the point where I wrote ??? I realized I was in a pickle. I need an array of arrays, I think. Can that be done?

Best Regards,
Steve

Comments

  • Mike GreenMike Green Posts: 23,101
    edited 2014-01-05 14:00
    Typically, you use a single array of an appropriate size and specify an offset like this. You only need 7 stack areas since there's a default stack area from the end of the program to the end of memory.

    var long StackArea[7 * 10]

    cog[ n ] := cognew( blink_led( n + startpin ), @StackArea + 4*10*n )

    Note that n has to range from 0 to 6 for this to work
  • Duane DegnDuane Degn Posts: 10,588
    edited 2014-01-05 14:33
    I think Parallax Semiconductor has an appnote on two dimensional arrays (what you're trying to do).

    I curious about why you want so many cogs to blink LEDs?

    I have an object which uses one cog to blink up to 32 LEDs all at different rates.

    If the LEDs are just being used to learn about using multiple cogs then have at it.

    However, if this is really about blinking LEDs, you shouldn't need more than one cog to do so. Let me know if there's anything about the LED object you don't understand.
  • RforbesRforbes Posts: 281
    edited 2014-01-05 15:00
    I'm not exactly sure if this would help, but it's a working example of "2 dimensional" arrays taken from one of the example strategies in the appnote that parallax put out some time ago.

    Here's the appnote:
    http://www.parallaxsemiconductor.com/sites/default/files/appnotes/AN003-AbstractDataStructures-v1.0_1.pdf
  • SteveWoodroughSteveWoodrough Posts: 190
    edited 2014-01-05 15:50
    Duane Degn wrote: »
    I think Parallax Semiconductor has an appnote on two dimensional arrays (what you're trying to do).

    I curious about why you want so many cogs to blink LEDs?

    Thank you for the responses. I am taking some quiet time here between episodes of shoveling the driveway to create a template object for my own use and get a better understanding of ViewPort and FullDuplexSerial4Port. To that template I decided to add a "cogs remaining" method. I originally did this with my robomagellan project to determine how many cogs I had remaining. The brute force approach works but I thought I could do it in a more "elegant" manner.
    Best Regards,
    Steve
  • SteveWoodroughSteveWoodrough Posts: 190
    edited 2014-01-05 20:02
    Mike suggestion works just fine, thank you! I’m trying to solidify my understanding, and in the process I am confused on a matter I really thought I already understood.

    First, I presume the statement StackArea[7*10] essentially means the we are creating 7 arrays each of 10 longs. Makes sense, but why @StackArea + 4*10*n? The 4 works, but I don’t know why.

    Second, and this is what really has me confused, I originally created byte Cog[7] assuming that I would need the 7 bytes for the cog names. Just for giggles I reduced it to Cog[6], with no effect, and kept reducing to just byte Cog. Same effect each time, all the led’s blink for the remaining cogs. I thought I understood this, but clearly I do not.

    Thanks
    Steve

    var
    
      byte Cog'[0]                                           ' create 7 byte size variables named cog[0] - cog[6]
                                                                
      long StackArea[7*10]                                  ' create 7-10 long sized arrays named StackArea 
    
    pub cog_counter | n,startpin
    
    '' starts blink led in each remaining cog
     
      startpin := 16
      repeat n from 0 to 6
        dira[n+startpin]~~                                  ' set pin to output
        if Cog[n]                                           ' standard cogstop routine
          cogstop(cog[n]~ -1)
        Cog[n]:=cognew(blink_led(n+startpin),@StackArea + 4*10*n)+1    ' start next cog
    
         
    
  • tonyp12tonyp12 Posts: 1,951
    edited 2014-01-05 20:11
    >we are creating 7 arrays each of 10 longs.
    No not really, Spin/Pasm use absolute addressed for variables that never move or have gaps.
    So when you pass an address along with cognew , it's simple the start address of a block of the hub ram of your choice.
    So you really are creating 70 longs reserved space (on big block) and it's up to you how you want to treat it.
    You could interleave or space each sub-block 10 longs apart etc.
  • macmini706macmini706 Posts: 2
    edited 2014-01-05 20:31
    Thanks very much
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2014-01-05 20:31
    but why @StackArea + 4*10*n?
    byte address of nth subarray = base address + 4 bytes/long * 10 longs/subarray * nth subarray

    -Phil
  • Duane DegnDuane Degn Posts: 10,588
    edited 2014-01-05 20:41
    why @StackArea + 4*10*n? The 4 works, but I don’t know why.

    The "4" is because there are four bytes in a long. Hub RAM is addressed as bytes. While you have seven groups of 10 longs, you also have seven groups of 40 bytes.


    Second, and this is what really has me confused, I originally created byte Cog[7] assuming that I would need the 7 bytes for the cog names. Just for giggles I reduced it to Cog[6], with no effect, and kept reducing to just byte Cog. Same effect each time, all the led’s blink for the remaining cogs.

    There is a lot of empty RAM with a small program. Your six extra variables where in the memory located right after where "Cog" is stored. Theres a good chance writing to this memory wouldn't have a noticeable effect on the program. But this is not a good idea. It can easily cause you trouble.

    Did you see my recent thread on stack space? There's a program there that dumps the contents of the stack space assigned to a cog. I found the exercise very instructive.
  • RforbesRforbes Posts: 281
    edited 2014-01-06 05:55
    @Duane

    Did you see my recent thread on stack space? There's a program there that dumps the contents of the stack space assigned to a cog. I found the exercise very instructive.
    [/quote

    Thanks for pointing to this thread. Very informative!
  • SteveWoodroughSteveWoodrough Posts: 190
    edited 2014-01-06 19:00
    Thank you Tony, Phil, and Duane for your responses. It's beginning to come into focus, and I think I am beginning to see the error in my understanding. The byte sized variable, Cog, need only be declared once since it is used once per COG. If multiple COG’s are started the Prop will manage which is which, therefore there is no need to declare an array Cog[7] to anticipate the need for multiple COG ID’s.

    Likewise the StackArea variable array need only be sized to run in one COG. StackArea[10] is sufficient given the simple nature of the method and there is no need to try and anticipate 7 instances of the method call in the form StackArea[70].

    Best Regards
    Steve
  • Duane DegnDuane Degn Posts: 10,588
    edited 2014-01-06 21:36
    The byte sized variable, Cog, need only be declared once since it is used once per COG. If multiple COG’s are started the Prop will manage which is which, therefore there is no need to declare an array Cog[7] to anticipate the need for multiple COG ID’s.

    If I understand you correctly then you do not understand correctly.

    I don't have time to explain. Hopefully someone else can jump in.
  • Mike GreenMike Green Posts: 23,101
    edited 2014-01-06 21:53
    Each time you start a new cog with COGNEW or COGINIT, you need to supply a unique stack area, one area per cog. The only way you can use the same area is if you stop the cog that's been using it. In other words, only one cog can use a stack area at any given time. In the case of the example I gave, the single array variable is effectively split up into 7 stack areas of 10 longs (40 bytes) each.
  • SteveWoodroughSteveWoodrough Posts: 190
    edited 2014-01-08 18:35
    I SINCERELY appreciate everyone’s time on this matter. I think part of the problem (me being the larger part) was that as I reduced the stack space or the CogID bytes, I mistook a few flashing LED’s for a functioning program. The program “looked” like it was working, but really was not.

    I’ve reread all the posts and as an educational exercise, I decided to create a few experiments each with the intention of accomplishing the same task of starting COG's. The programs can be run without modification on demo or QuickStart boards.

    The first is pretty straight forward with seven stack arrays and seven cog ID’s to support the starting of the seven remaining cogs. Size: 83 Longs program 72 Longs variables.
    var
    
      long Cog0Stack[10], Cog1Stack[10],Cog2Stack[10], Cog3Stack[10], Cog4Stack[10], Cog5Stack[10], Cog6Stack[10]
      
      byte CogID_0, CogID_1, CogID_2, CogID_3, CogID_4, CogID_5, CogID_6
    
    
    pub main  
    
      start16                                               ' launched into cog  1
      start17                                               ' launched into cog  2
      start18                                               ' launched into cog  3 
      start19                                               ' launched into cog  4 
      start20                                               ' launched into cog  5 
      start21                                               ' launched into cog  6 
      start22                                               ' launched into cog  7 
      
         
    pub blink_led(pin)
    
      dira[Pin]~~                                           
      repeat
        !outa[pin]
        waitcnt(clkfreq/(pin-15)+cnt)                        
    
    
    pub start16
    
      stop16
      CogID_0:= cognew(blink_led(16),@Cog0Stack)+1
    
       
    pub stop16
    
      if CogID_0
        cogstop(CogID_0~ - 1)
    
        
    pub start17
    
      stop17
      CogID_1:= cognew(blink_led(17),@Cog1Stack)+1
    
       
    pub stop17
    
      if CogID_1
        cogstop(CogID_1~ - 1)
    
        
    pub start18
    
      stop18
      CogID_2:= cognew(blink_led(18),@Cog2Stack)+1
    
        
    pub stop18
    
      if CogID_2
        cogstop(CogID_2~ - 1)
        
    pub start19
    
      stop19
      CogID_3:= cognew(blink_led(19),@Cog3Stack)+1
    
       
    pub stop19
    
      if CogID_3
        cogstop(CogID_3~ - 1)
    
        
    pub start20
    
      stop20
      CogID_4:= cognew(blink_led(20),@Cog4Stack)+1
    
        
    pub stop20
    
      if CogID_4
        cogstop(CogID_4~ - 1)
    pub start21
    
      stop21
      CogID_5:= cognew(blink_led(21),@Cog5Stack)+1
    
      
    pub stop21
    
      if CogID_5
        cogstop(CogID_5~ - 1)
    
        
    pub start22
    
      stop22
      CogID_6:= cognew(blink_led(22),@Cog6Stack)+1
    
        
    pub stop22
    
      if CogID_6
        cogstop(CogID_6~ - 1)
     
    
    The second program is intended to do the same thing in a more streamlined manner, and incorporates Mike Green’s recommendation regarding the allocation of the reserved stack space. If I understand, each subsequent Cog[n] runs in an @StackArea memory location offset by 40*n bytes from the previous. Size: 23 Longs program 72 Longs variables.
    pub cog_counter | n,startpin
    
    '' starts blink led in each remaining cog
     
      startpin := 16
      repeat n from 0 to 6
        dira[n+startpin]~~                                   
        if Cog[n]                                            
          cogstop(cog[n]~ -1)
        Cog[n]:=cognew(blink_led(n+startpin),@StackArea + 4*10*n)+1    ' start next cog
        
    
          
    pub blink_led(pin)
    
      dira[Pin]~~                                            
      repeat
        !outa[pin]
        waitcnt(clkfreq/(pin-15)+cnt)                       
    
    

    The last is a pair of programs; the second is called by the first seven times. I will not risk trying to explain why it works! Size: 37 Longs program 77 Longs variables.

    Anyway, I think I’ve developed a bit better understanding, and maybe this might just help someone else along.
    Regards,
    Steve
    obj
    
      c0 : "Cog3"
      c1 : "Cog3"
      c2 : "Cog3"
      c3 : "Cog3"
      c4 : "Cog3"
      c5 : "Cog3"  
      c6 : "Cog3"
      
    pub Main  
    
      c0.start(16)
      c1.start(17)
      c2.start(18) 
      c3.start(19) 
      c4.start(20) 
      c5.start(21) 
      c6.start(22)
      
    
    var
    
      long CogStack[10]
      
      byte Cog
    
    
    pub start(pin)  
    
      stop(pin)
      Cog:= cognew(blink_led(pin),@CogStack)+1
    
         
    pub blink_led(pin)
    
      dira[pin]~~                                           
      repeat
        !outa[pin]
        waitcnt(clkfreq/(pin-15)+cnt)                       
    
    
    pub stop(pin)
    
      if Cog
        cogstop(Cog~ - 1)
    
    
Sign In or Register to comment.