Shop OBEX P1 Docs P2 Docs Learn Events
1st timer needs a bit of help — Parallax Forums

1st timer needs a bit of help

jstjohnzjstjohnz Posts: 91
edited 2010-09-02 22:15 in Propeller 1
Thanks in advance, first go-round with the prop.

I am using a DMX receiver object from the library. It receives a serial stream and fills a 513-byte array. My problem is I want to be able to access this array directly from ASM code running in another cog.

The array is defined in the VAR block of the DMX object as:
byte DMXDATA [513]

I added a new entry point (prob not correct nomenclature) in the DMX object called array:

PUB array : value
value := @DMXdata

My thinking is this will return the long address of the 1st byte of the array in main memory.

I start my ASM code with:
dmxarrayadrs := DMX.array
cognew (@mycode,dmxarrayadrs)

If I am understanding correctly, this will pass the address of the 1st byte of the array in PAR.

In my ASM code I have:
mov bufradrs,par

Then to read the 1st data byte in the array I would do:

rdbyte temp,bufradrs

Unfortunately it doesn't seem to be working. Is there something wrong with my method or is there a better way? Is there a way to display a memory dump from Viewport? Am I correct in my thinking that viewport isn't much help in debugging ASM code?

Again, all help appreciated. I am making some pretty good headway, but I haven't found a good way to debug assembly code yet.

-jim-

Comments

  • kuronekokuroneko Posts: 3,623
    edited 2010-09-01 22:01
    Welcome! The only thing I can think of immediately is that the returned address (from DMX.array) is not long aligned (4n). The parameter to PASM code is limited to 14bit, therefore has to be long aligned (bottom two bits are %00). Can you verify the alignment of the DMX buffer? If that doesn't solve it we need to see some code :)
  • jmspaggijmspaggi Posts: 629
    edited 2010-09-02 09:12
    Hi kuroneko,

    How can we verify that a variable is alligned?

    I'm also having same kind of issues with the long-alligned rule :(

    And when it's not alligned, does it mean we "just" need to define some dummy byte variables before it, and lost some space?

    JM
  • jstjohnzjstjohnz Posts: 91
    edited 2010-09-02 11:20
    kuroneko wrote: »
    Welcome! The only thing I can think of immediately is that the returned address (from DMX.array) is not long aligned (4n). The parameter to PASM code is limited to 14bit, therefore has to be long aligned (bottom two bits are %00). Can you verify the alignment of the DMX buffer? If that doesn't solve it we need to see some code :)

    It appears to be aligned, my variable that points to the head of the buffer has a value of $CCC. BTW, if you are familiar with Viewport, is there a way to display contents of main memory? And is there a way to get a listing of the compiled code that shows what's being put where?

    -jim-
  • Beau SchwabeBeau Schwabe Posts: 6,568
    edited 2010-09-02 12:05
    I suspect that it's the way you are moving the address into your Pasm code. Typically the par variable within Pasm is long aligned, but if you are trying to reference a BYTE it won't necessarily be aligned properly.

    If you provide more code details it might be easier to see what's going on.

    Typically when I start a PAsm program I reference the par with a long, If I need to point to a BYTE array I do it by reference, especially if there are mixed variables containing long,word, and byte because the compiler will most likely re-order them by size. i.e. longs first, then words, followed by bytes

    Here is a code example:
    VAR
    
    long    Argument0, Argument1
    
    
    PUB Pasm
        Argument1 := @ByteData      '<-- Argument1 contains the address of ByteData
                                    '    if the @ sign were omitted, then Argument1
                                    '    would equal the value of the first element
                                    '    of ByteData        
        cognew(@Entry,@Argument0)   
    
    DAT
    
    ByteData      byte      %01100110, %11100111
    
    
    DAT
    
    Entry
    
            mov             temp,                   par  'PAR+0 ; temp contains the address of Argument0
            rdlong          _Argument0,             temp '_Argument0 now contains the value of Argument0
    
            add             temp,                   #4   'PAR+4 ; temp contains the address of Argument1    
            rdlong          _Argument1,             temp '_Argument1 now contains the value of Argument1
                                                         'which in this case is the address of the Byte
                                                         'array we want.  So since it's an address we
                                                         'want to read it again only this time with rdbyte
                                                         'since the data is byte aligned.
    
            rdbyte          temp,                   _Argument1 'temp equals the First element of BYTE array
            add             _Argument1,             #1   '_Argument1+1 ; get the next address for the BYTE
                                                         'array
                                                         
            rdbyte          temp,                   _Argument1 'temp equals the second element of BYTE array
    
                                                            'Each time you increment _Argument1 you advance
                                                            'to the next BYTE in the array.
    
    temp          long      0
    _Argument0    long      0
    _Argument1    long      0
    
  • kuronekokuroneko Posts: 3,623
    edited 2010-09-02 16:41
    jstjohnz wrote: »
    It appears to be aligned, my variable that points to the head of the buffer has a value of $CCC.

    Yes, I also checked the object in question and the byte array sits directly behind a number of longs ($0CCC = %00001100_11001100). As the way you get this address down into your PASM code looks OK I suspect it's something else entirely.

    You say it's not working. A rdlong/rdword/rdbyte always reads something so I assume you get wrong/unexpected values. For further assistence we (I at least) need to see some code. Can you verify somehow that par gets there intact?

    Sorry, I'm not a Viewport user. Hanno?!
    jstjohnz wrote: »
    And is there a way to get a listing of the compiled code that shows what's being put where?

    This kind of list feature is only available in bst[c].

    Example code (which works as intended, demoboard). Object zwei encapsulates a byte array the address of which is queried from object eins and passed to PASM. Then the top object forces 1Hz updates of the first array element which are displayed by the PASM code.
    '' eins.spin
    ''
    OBJ
      child: "zwei"
    
    PUB null : n
    
      cognew(@entry, child.array)                   ' get array address, start cog
      repeat                                        ' |
        child.init(n++)                             ' |
        waitcnt(clkfreq + cnt)                      ' | modify array at 1Hz
    
    DAT             org     0
    
    entry           mov     dira, mask              ' activate demoboard LED bank
    
                    rdbyte  outa, par               ' get byte from byte[child.array][0]
                    rev     outa, #8                ' reverse and move up to bit 16..23
                    jmp     #$-2                    ' repeat
    
    ' initialised data and/or presets
    
    mask            long    $00FF0000               ' demoboard LED bank
    
    ' uninitialised data and/or temporaries
    
                    fit
    
    DAT
    
    '' zwei.spin
    ''
    CON
      length = 13
      
    VAR
      long  padding[3]
      byte  data[length]
    
    PUB null
    '' This is not a top level object.
    
    PUB init(pattern)
    
      data[0] := pattern            ' only fill first byte
      
    PUB array : value
    
      value := @data{0}             ' actually @data[0], @data is the same
    
    DAT
    
  • kuronekokuroneko Posts: 3,623
    edited 2010-09-02 16:52
    jmspaggi wrote: »
    How can we verify that a variable is alligned?

    And when it's not alligned, does it mean we "just" need to define some dummy byte variables before it, and lost some space?
    PRI isLongAligned(address)
    
      return not (address & %11)
    

    Effectively, in order to be long aligned the lower two bits have to be zero, i.e. the value has to be dividable by 4 without remainder (value // 4 == 0). So either you do the // 4 business or for powers of 2 (faster) do & (po2 - 1).

    If your byte array is unaligned then you need to introduce padding (1..3 bytes), arrange your variables in a way that you put the right number of single byte variables in front (no loss) or store the address itself in a long and read the address from said long (rdlong followed by rdbyte). The last is worst so I'd rather waste 3 bytes padding than 2 longs (address + PASM code).
  • jstjohnzjstjohnz Posts: 91
    edited 2010-09-02 22:15
    kuroneko wrote: »
    Yes, I also checked the object in question and the byte array sits directly behind a number of longs ($0CCC = %00001100_11001100). As the way you get this address down into your PASM code looks OK I suspect it's something else entirely.

    You say it's not working. A rdlong/rdword/rdbyte always reads something so I assume you get wrong/unexpected values. For further assistence we (I at least) need to see some code. Can you verify somehow that par gets there intact?

    Sorry, I'm not a Viewport user. Hanno?!



    This kind of list feature is only available in bst[c].

    Example code (which works as intended, demoboard). Object zwei encapsulates a byte array the address of which is queried from object eins and passed to PASM. Then the top object forces 1Hz updates of the first array element which are displayed by the PASM code.
    '' eins.spin
    ''
    OBJ
      child: "zwei"
    
    PUB null : n
    
      cognew(@entry, child.array)                   ' get array address, start cog
      repeat                                        ' |
        child.init(n++)                             ' |
        waitcnt(clkfreq + cnt)                      ' | modify array at 1Hz
    
    DAT             org     0
    
    entry           mov     dira, mask              ' activate demoboard LED bank
    
                    rdbyte  outa, par               ' get byte from byte[child.array][0]
                    rev     outa, #8                ' reverse and move up to bit 16..23
                    jmp     #$-2                    ' repeat
    
    ' initialised data and/or presets
    
    mask            long    $00FF0000               ' demoboard LED bank
    
    ' uninitialised data and/or temporaries
    
                    fit
    
    DAT
    
    '' zwei.spin
    ''
    CON
      length = 13
      
    VAR
      long  padding[3]
      byte  data[length]
    
    PUB null
    '' This is not a top level object.
    
    PUB init(pattern)
    
      data[0] := pattern            ' only fill first byte
      
    PUB array : value
    
      value := @data{0}             ' actually @data[0], @data is the same
    
    DAT
    

    well it turns out that I was getting the data passed properly, I just wasn't loading the buffer with the right data to give my expected results. FWIW, what I am doing is reading DMX lighting data and using those values to drive a string of RGB led pixels. One cog runs the DMX receiver object that loads the received data into a 512 byte buffer, then another cog runs an ASM routine to extract the date, reformat it for the RGB LEDs, and output serial data and clock to the LED string.

    As of right now it looks pretty good. I need to add the actual DMX receiver hardware to my breadboard so that I can try it with real DMX data. Up to now I have been faking it by stuffing values into the DMX buffer.

    Thanks for all of the help.
Sign In or Register to comment.