Shop OBEX P1 Docs P2 Docs Learn Events
Using a buffer in PSAM — Parallax Forums

Using a buffer in PSAM

BobbyVBobbyV Posts: 19
edited 2012-03-02 13:23 in Propeller 1
Hello All,

I'm trying to implement a buffer in cog ram using PSAM. What I want to do is take 128 samples using an ADC incrementally saving them into the buffer and after the sample process read each sample in the buffer for data processing. The reason for this is so I can quickly take a bunch of samples at a high sample rate, then post process each sample. The processing for each sample takes longer than the time period between each sample, which leaves me with the choice to either lower my sample rate (which would be no good) or use a buffer.

I found a method which I have seen others use, but I don't completely understand how it works. It uses the "movd" instruction which is used for "self modifying code" according to the propeller manual. Since I don't understand how the registers are being changed (and what happens when I try to loop back to a previous place), I see visions of catastrophic failures with code being unintentionally written over and loops going crazy!

I posted the code I would used based on forum wisdom using movd. I also added the approach that I first thought of, using a spin thought process which I'm not too sure would translate into PSAM.

Could someone please explain how this changing the destination field stuff works? or if my method would work?
DAT

''  A buffer method I have seen others use:

'' Write 128 samples to a buffer in cog ram
                        org     0
entry
                        mov     count, #128
                        movd    :FILBUF, Buffer

:SAMPLOOP               ''
                        ''ADC Sample code here
                        ''
:FILBUF                 mov     0-0, sample
                        add     :FILBUF, #$100
                        djnz    count, #:SAMPLOOP

'' Next, read a sample from the buffer, do something with the sample, increment and loop
                        mov     count, #128
                        movd    :READBUF, Buffer
:PRLOOP                 ''
                        '' Process code here
                        ''
:READBUF                mov     temp,0-0
                        add     :READBUF, #$100
                        ''
                        '' Processing code here
                        ''
                        djnz    count,#:PRLOOP


'' The buffer method I thought of to write to buffer (reading would be similar), but not sure if it works
                        mov     count, #128
                        mov    BUFADR, #Buffer
:SAMPLOOP               ''
                        ''ADC Sample code here
                        ''
                        mov     BUFADR, sample
                        add     BUFADR, #1
                        djnz    count, #:SAMPLOOP

'' variables
count                   long 0
sample                  long 0
temp                    long 0 
BUFADR                  long 0

Buffer                  res 128
                        fit    

Comments

  • RaymanRayman Posts: 13,850
    edited 2012-03-01 08:43
    I think you have the right idea...

    For the reading part though, it looks like you should modify the source and not the destination....
    So you'd need:
    movs :READBUF, Buffer
    and
    add :READBUF, #1

    Also, I think the number you need to add to destination, 512, is bigger than you can have as an explicit number and so you need to use a register for this value, like:
    d0 long 1 << 9
  • Mark_TMark_T Posts: 1,981
    edited 2012-03-01 08:48
    No, you are close but you need to know about the source and destination fields in instructions.

    The source field is the lower 9 bits of the (32 bit) long, the destination field is the next 9 bits.
    So in order to step the source field you need to add 1, not 256. To step the destination field you need to add 1<<9 (512) which is too large to be an immediate value.

    So you could add a value for the later:
    D1                   long  1<<9
    

    Also you must use immediate mode to pick up the addresses to load into the fields, so use
                            movd    :FILBUF, #Buffer
    
    (You don't want to read the contents of Buffer and put that into the instruction, you want the address of Buffer)

    And then the increments become
                            add     :FILBUF, D1 
    
                            add     :READBUF, #1
    

    Note that any write to cog ram will not be available as an instruction fetch till after the next instruction, so avoid doing
                            mov   :READBUF, #Buffer
    :loop
    :READBUF                mov   temp, 0-0  ' need an instruction between this and the previous to allow update to get through.
    
  • JonnyMacJonnyMac Posts: 8,918
    edited 2012-03-01 08:53
    I have a template file for PASM projects that includes read and write subroutines for PASM arrays/tables -- these might help as you can call them from any point in your code, you don't to install them inline.
    ' basepntr = address of array/table
    ' idx = index of element to read
    ' value = value that is read
    
    read                    mov     t1, basepntr
                            add     t1, idx
                            movs    rdval, t1
                            nop
    rdval                   mov     value, 0-0
    read_ret                ret
    
    
    ' basepntr = address of array/table
    ' idx = index of element to write
    ' value = value to write
    
    write                   mov     t1, basepntr
                            add     t1, idx
                            movd    wrval, t1
                            nop
    wrval                   mov     0-0, value
    write_ret               ret
    
  • JavalinJavalin Posts: 892
    edited 2012-03-02 07:17
    Also look at this sample - self-modifying code in PASM...

    http://obex.parallax.com/objects/268/

    James
  • BobbyVBobbyV Posts: 19
    edited 2012-03-02 07:28
    Thanks everyone for the help,

    So to make sure I understand correctly, from the following code:

    "movd" moves the address at #Buffer into the destination field of the register located at :FILBUF

    then, the '0-0' tells the 'mov' instruction located at register :FILBUF to move sample to the location already set in its the destination field by the previous "movd"?

    movd    :FILBUF, #Buffer  
    :SAMPLOOP               ''                        
                            ''ADC Sample code here                        
                            ''
    :FILBUF                 mov     0-0, sample
                            add     :FILBUF, D1                        
                            djnz    count, #:SAMPLOOP
    
    D1                      long    1<<9   
    
  • JonnyMacJonnyMac Posts: 8,918
    edited 2012-03-02 07:41
    the '0-0' tells the 'mov' instruction located at register :FILBUF to move sample to the location already set in its the destination field by the previous "movd"?

    The "0-0" is just a place-holder, you could have anything there -- that said, it's worth having something that will stick out to say, "this field is modified by something else" and "0-0" is what many use to do that. The movd instruction at the top of your code simply overwrites the destination field at :FILEBUF. This works because everything is sitting in the same RAM pool; you can modify anything, even instructions.
  • BobbyVBobbyV Posts: 19
    edited 2012-03-02 13:23
    Ahh, I get it now... learning has occurred!

    Thanks!
Sign In or Register to comment.