Shop OBEX P1 Docs P2 Docs Learn Events
My 1st PASM Snippet (which doesn't work). Help? — Parallax Forums

My 1st PASM Snippet (which doesn't work). Help?

RumpleRumple Posts: 38
edited 2012-10-23 16:15 in Propeller 1
But at least it compiles...

I'm working on a routine that interprets 24 bits of gated synchronous serial data. Spin doesn't seem to be fast enough to catch the clock edges so I thought I'd try to do the input side in PASM before wimping out and adding a hardware shift register.

After browsing and swiping a lot of the examples found here, I came up with this:
VAR

long datin                      '24 bits of incoming serial data

'lots more variables

Pub main                        'Main loop

  dira[3]~
  dira[9]~
  dira[10]~

  cognew(@input,@datin)         'launch data input routine (ASM)

'oodles of non-relevant code

'the datin variable gets sent out via RS-232.

dat
              org 0                    'Begin at cog addr 0
input         mov p,par                'p=address of datin variable in hub
:loop         waitpeq state0, #mask0   'wait for A0 (P3) to go high
              mov count, #24           'set loop counter to 24
              mov in, #0               'reset input variable
              jmp #:loop1              'do the loop1 routine.  Necessary?

:loop1        shl in, #1               'shift input variable left 1 bit
              waitpeq state1, #mask1   'wait for clock (P9) to go high
              add in, ina&mask3        'capture level of data pin (P10)
              waitpeq state1, #mask2   'wait for clock (P9) to go low
              djnz count, #:loop1      'loop until count=0
              jmp #:writemem           'do writemem routine.  Necessary?

:writemem     wrlong in, p             'write input data to datin variable
              waitpeq state0, #mask2   'wait for A0 (P3) to go low
              jmp #:loop               'goto beginning of loop



state0  long  %0000_0000_0000_0000_0000_0000_0000_1000
mask0   long  %0000_0000_0000_0000_0000_0000_0000_1000
state1  long  %0000_0000_0000_0000_0000_0010_0000_0000
mask1   long  %0000_0000_0000_0000_0000_0010_0000_0000
mask2   long  %0000_0000_0000_0000_0000_0000_0000_0000
mask3   long  %0000_0000_0000_0000_0000_0100_0000_0000 

p       res   1
count   res   1
in      res   1           


The glitch is that datin is forever 0. The ADD line is definitely suspect, but the whole attempt may be riddled with mistakes and misinterpretations...can't tell.

If someone could kindly point out the folly of my ways, I'd be ecstatic. Any other comments or criticisms would certainly be welcome too.

As an aside, I sure wish that the ASM section of the manual contained as many command usage examples as the SPIN section. But I think I understand why it doesn't...

Comments

  • tonyp12tonyp12 Posts: 1,951
    edited 2012-10-18 09:26
    for starters, can not have this
    >add in, ina&mask3

    You can not use pre calculation in pasm, the ide will do the math on this and put a number there.
    One of the pitfall of learning Pasm is what is pre inline math and what is runtime math.
  • RumpleRumple Posts: 38
    edited 2012-10-18 09:46
    Thanks, Tony. I see it now. That's an attempt to AND ina with a mask and add the result to a variable. In one line. Let me see if I can find an elegant alternative approach...
  • JonnyMacJonnyMac Posts: 9,108
    edited 2012-10-18 10:03
    You can do it like this -- but not in one line:
    test    mask3, ina              wc
            if_c            add     in, #1
    
  • RumpleRumple Posts: 38
    edited 2012-10-18 10:06
    When using waitpeq with initialized masks should I be using

    waitpeq state, #mask

    or

    waitpeq state, mask

    ?
  • ChrisGaddChrisGadd Posts: 310
    edited 2012-10-18 10:23
    Rumple wrote: »
    When using waitpeq with initialized masks should I be using

    waitpeq state, #mask

    or

    waitpeq state, mask

    ?
    The second one; placing a # in front gives you the address of the mask rather than the contents.
    You can do it like this -- but not in one line:

    test mask3, ina wc
    if_c add in, #1
    wouldn't that count the number of bits set in the input? - Edit: nevermind, I spaced out on the shl command.

    Here's my very quick and untested take on the problem:
    DAT		org
    input
    		mov	count,#24		' count 24 bits
    		mov	in,#0			' initialize the in register
    		waitpeq	P3,P3			' wait for P3 to go high
    :loop
    		waitpeq	P9,P9			' wait for P9 to go high
    		test	ina,P10	     wc		' test the state of P10, set C if input is high
                    rcl	in,#1			' rotate C into the in register
    		waitpne	P9,P9			' wait for P9 to go low
    		djnz	count,#:loop		' loop 24 times
    :writemem
    		wrlong	in,par			' write the in register to the address in par
    		waitpne	P3,P3			' wait for P3 to go low
    		jmp	#input			
    
    P3		long	1 << 3
    P9		long	1 << 9
    P10		long	1 << 10
    count		res	1
    in		res	1
    
  • RumpleRumple Posts: 38
    edited 2012-10-18 10:26
    Thanks, Jon, your approach is certainly more efficient than what I came up with. Educational too.

    I implemented it but the routine still doesn't function as desired.

    Is it time to procure a copy of ViewPort? Will that tell me what's going on in there?
  • Mark_TMark_T Posts: 1,981
    edited 2012-10-18 13:18
    You need to explain the signals you're receiving in more detail if you want us to work out if the code's DTRT... For instance how are you expecting to sync on P3 - the first time in you fail to sync to its edge.
  • RumpleRumple Posts: 38
    edited 2012-10-18 13:27
    Success!

    Using Chris's myriad of tricks and shortcuts and architectural finesse, and Jon's pin level detection snippet, it works. Probably. I'll know when I start to parse the data at the other end. But it certainly works better than it did. Here's what I ended up with:
    DAT           org                       'get 24 bits of serial in
    input
                  mov     count,#24         ' count 24 bits
                  mov     in,#0             ' initialize the in register
                  waitpeq P3,P3             ' wait for P3 to go high
    :loop
                  shl in, #1                'shift input long left 1 bit
                  waitpeq P9,P9             'wait for P9 to go high
                  test P10, ina  wc         'check level of data pin (P10)
                  if_c add in, #1           'if it's high, add 1 to input variable
                  waitpne P9,P9             'wait for P9 to go low
                  djnz    count,#:loop      'loop 24 times
    :writemem
                  wrlong  in,par            'write the in register to the address in par
                  waitpne P3,P3             'wait for P3 to go low
                  jmp     #input            'back to beginning      
    
    P3              long    1 << 3
    P9              long    1 << 9
    P10             long    1 << 10
    count           res     1
    in              res     1      
    
    

    Thanks, guys.
  • HannoHanno Posts: 1,130
    edited 2012-10-23 16:15
    Howdy,
    I had some fun seeing what I could do with ViewPort and your code....
    Here's your code with some additional spin code to repeatedly send data to be decoded.
    var
      long out   'data sent out
      long inp  'result decoded in pasm
    pub main
      cognew(@input, @inp)
      repeat
        repeat out from 0 to 10
          send(out)
          waitcnt(cnt+clkfreq)
    pub send(x)   'output 24 bits using p3,p9,p10
      dira[3]~~
      dira[9..10]~~
      outa[3]~~   'indicated 24 bits are coming
      repeat 24
        if(x & (1<<23)) 'ready data bit
         outa[10]~~
        else
         outa[10]~
        x<<=1
        outa[9]~~  'pulse data is there bit
        outa[9]~
      outa[3]~
    DAT           org                       'get 24 bits of serial in
    input
                  mov     count,#24         ' count 24 bits
                  mov     in,#0             ' initialize the in register
                  waitpeq P3,P3             ' wait for P3 to go high
    :loop
                  shl in, #1                'shift input long left 1 bit
                  waitpeq P9,P9             'wait for P9 to go high
                  test P10, ina  wc         'check level of data pin (P10)
                  if_c add in, #1           'if it's high, add 1 to input variable
                  waitpne P9,P9             'wait for P9 to go low
                  djnz    count,#:loop      'loop 24 times
    :writemem
                  wrlong  in,par            'write the in register to the address in par
                  waitpne P3,P3             'wait for P3 to go low
                  jmp     #input            'back to beginning      
    
    P3              long    1 << 3
    P9              long    1 << 9
    P10             long    1 << 10
    count           res     1
    in              res     1
    

    This is what it looks like in ViewPort:
    dso.png


    Pressing "Run" will run the code and show you variables "inp" and "out":
    code.png


    So far we haven't instrumented our code for ViewPort. You can confirm that your code is successfully decoding different numbers by seeing both inp and out change in realtime.
    You can use the LSA view already to look at the pin activity, but by letting ViewPort instrument our code and using quickstart we view the pin activity at a faster rate- up to 80msps.
    Here's the instrumented code:
    code1.png

    Here's the LSA view showing p3 being high, p10 corresponds to the data, and p9 clocking out the data:
    lsa.png


    Hanno
    811 x 714 - 119K
    811 x 714 - 91K
    811 x 714 - 103K
    811 x 714 - 101K
Sign In or Register to comment.