Shop OBEX P1 Docs P2 Docs Learn Events
PASM Problem — Parallax Forums

PASM Problem

PhilldapillPhilldapill Posts: 1,283
edited 2008-07-01 22:45 in Propeller 1
Oh for the love of god why won't it work...

I WAS trying to do something a little more complicated, but have narrowed the program down to a simplier form. I only want the PWM signal in my code to loop X amount of times, stored as an external variable in spin. I read the first long, that's the period - the second long, the duty cycle, and the third long, the number of times to repeat. It loops forever... It's not waiting for the counter to roll over since it's been sitting for 5 minutes now, repeating the same waveform.

DAT
org 0
entry   or      dira, pinOut
        mov     t1, #0
        mov     cnt1, #0
        'set the period        
        mov     addr1, par
        rdlong  period, addr1
        'set the onTime to next var
        add     addr1, #4
        rdlong  onTime, addr1
        'compute offTime
        mov     offTime, period  
        sub     offTime, onTime
        'get the next onTimeTable value - in spin code, just an array
        add     addr1, #4
        rdlong  cnt1, addr1
        'set the time and next flip-flop
        mov     time, cnt
        add     time, onTime
        'loop 1000 times
        mov     cnt1, #1000

        DJNZ    cnt1, #:loop
'        ret
 
:loop   waitcnt time, offTime
        andn    outa, pinOut 'turn pin OFF
        waitcnt time, onTime
        or      outa, pinOut 'turn pin ON
loopval_ret ret        


 
pinOut  long 1<<15
period  res 1
onTime  res 1
offTime res 1                     
time    res 1
t1      res 1
addr1   res 1
cnt1    res 1

fit 496  

Someone please help me... I've looked through tutorials and it SHOULD work! ARRRRRG.

Comments

  • Cluso99Cluso99 Posts: 18,069
    edited 2008-07-01 06:09
    I see two possible problems

    1. You never set the ret address. You either fall into it or (firstly djnz to it).

    2. You are not executing the djnz loop at all.

    Hope this helps - didnt examine too closely

    Try this

    ········'loop 1000 times
    ······· mov···· cnt1, #1000

    :loop·· waitcnt time, offTime
    ······· andn··· outa, pinOut 'turn pin·OFF
    ······· waitcnt time, onTime
    ······· or····· outa, pinOut 'turn pin ON
    ······· DJNZ··· cnt1, #:loop

    :stop jmp #:stop 'loop here indefinately

    ·····



    Post Edited (Cluso99) : 7/1/2008 6:15:21 AM GMT
  • AleAle Posts: 2,363
    edited 2008-07-01 08:23
    There is no more than what Cluso99 said: The djnz will jump to :loop and the ret instruction (is a jmp) will have address 0 so it will jump to the beginning at address 0. If you have measured the on and off period you may have found that the offTime was a bit longer than what you set smile.gif (Remember that for waitcnt the dest variable contains the end of count for that waitcnt and the source for the next.

    This is easy to catch with a simulator wink.gif
  • PhilldapillPhilldapill Posts: 1,283
    edited 2008-07-01 16:59
    Well, I fixed it. I'm not sure if this is a proper way to do it, but it works.
            'loop x times
    :Choice DJNZ    cnt1, #:loop
            jmp     #:Continue
            
    :loop   waitcnt time, offTime
            andn    outa, pinOut
            waitcnt time, onTime
            or      outa, pinOut
            jmp   #:Choice
            
    :Continue               
            nop
    

    Are there any problems with this?
  • TimmooreTimmoore Posts: 1,031
    edited 2008-07-01 17:12
    There are 2 things to think about
    1. I would normally put the djnz at the bottom of the loop in place of the jmp #:choice, unless you specifically need to handle the cnt1 == 0 case. In asm the less jmping around you do the easier it is to understand the code. You tend to have more jmping is asm that spin but the less to add the better.
    2. when cnt1 gets to 0 you jmp to :continue, this will execute a nop and then execute whatever is in memory that the prop loaded from hub memory. Thats propably not what you want. Either put a cogstop or a jmp #:Continue so the cog just loops in place of the nop or something else for the cog to do.
  • PhilldapillPhilldapill Posts: 1,283
    edited 2008-07-01 17:35
    Ok, well I guess my next question is a general one.

    I want to be able to reuse a routine in different areas of my code. I'd like to be able to jump to it, do something, then continue on from where I left off in the original routine. How do you do this? I'm reading deSilva's tutorial, but I don't get this part.
  • AleAle Posts: 2,363
    edited 2008-07-01 17:49
    You have to use the "call/ret" combo. You cannot return from a ret that is not labeled as "xx_ret" when xx is the name of your routine. In that regard is less flexible than other processors due to the lack of a stack or a proper "link register".

    Edit: The best is to make small routines, so everything is easier to reuse.
  • PhilldapillPhilldapill Posts: 1,283
    edited 2008-07-01 17:54
    Whenever I do "call #:choice", it gives me an error saying "expected a DAT symbol". :choice is my routine [noparse]:([/noparse]
  • TimmooreTimmoore Posts: 1,031
    edited 2008-07-01 17:55
    First thing to understand is pasm has no stack. So what you do is store the address of the next instruction in a variable, jmp to the routine you want and at the end of it jmp using the vairable you saved the address (i.e. jmp variable without the #). The call/ret instruction automates this a bit. Call X saves the next address at the location called X_ret. You place this label on the ret instruction, i.e. the call will modify the ret instruction to jmp to the address it writes.

    call X

    X mov t0, #1
    X_ret ret

    so call X modifies the ret instruction with the address after the call instruction. Then jmps to X, executes the mov, then executes the ret which is now a jmp to the instruction after the call.
  • TimmooreTimmoore Posts: 1,031
    edited 2008-07-01 17:55
    You can't call to a :label, remove the :
  • PhilldapillPhilldapill Posts: 1,283
    edited 2008-07-01 17:58
    Arg, well scratch that last reply... I got it. You can only call global routines?

    Well, again, I'm stuck in the infinite loop. Ideas?

    :Choice call    #loop
            DJNZ    cnt1, #:choice
            jmp     #Continue
            
            
    loop   waitcnt time, offTime
            andn    outa, pinOut
            waitcnt time, onTime
            or      outa, pinOut
    loop_ret ret
     
    Continue               
            nop  
    
  • PhilldapillPhilldapill Posts: 1,283
    edited 2008-07-01 18:09
    Wow, well, again, scratch that I guess... I decreased the loops and it works after all. That's a relief... just when I thought I was getting it, I did! [noparse]:)[/noparse]
  • AleAle Posts: 2,363
    edited 2008-07-01 20:10
    good !... now you know that ret is a jump wink.gif I avoid local symbols as the plague ... Nothing like good old globals.
  • PhilldapillPhilldapill Posts: 1,283
    edited 2008-07-01 20:42
    Yeah, my problem was the XXX_ret ret part... I didn't understand it correctly, but now I do! Thanks guys!

    I'll probably be asking many more questions as I learn.
  • PhilldapillPhilldapill Posts: 1,283
    edited 2008-07-01 22:03
    Well - a new problem.
    Good news, is I've got my program working correctly(almost). I thought I would have a base frequency of 30.72kHz. The duty cycle of this frequency would vary, based on a table of sine values I made in Excel. These values are read in between pulses, and the duty cycle changes based on these. This SHOULD create a modified sine wave, and from my scope, it looks good. the pulses vary and due to the voltage rise time of the prop, it actually looks like two sinewaves on top of each other(the top being the ON times, and the bottom the OFF times).
    Now, the only problem to this is that the frequency reads 30.11kHz, not my target 30.72kHz. My period is a constant 2604 clocks which is rounded from 2604.1666. This rounding should in no way affect my frequency THIS much... Any thoughts?

    org 0
    entry   'set the output pin and temps
            or      dira, pinOut
            mov     t1, #0
            mov     cnt1, #0
    :main
            'set the period        
            mov     addr1, par
            rdlong  period, addr1
            'set cnt2 to zero
            mov cnt2, #64
            'set the onTime to next var
    :loop1  add     addr1, #4
            rdlong  onTime, addr1
            'compute offTime
            mov     offTime, period
            sub     offTime, onTime
            'set the time and next flip-flop
            mov     time, cnt
            add     time, onTime
            'set the counter to x
            mov     cnt1, #1
            'loop x times
    :Choice call    #OnOff
            DJNZ    cnt1, #:choice
            DJNZ    cnt2, #:loop1
            jmp     #:main
            
    OnOff   waitcnt time, offTime
            andn    outa, pinOut
            waitcnt time, onTime
            or      outa, pinOut
    OnOff_ret ret
    
    
  • TimmooreTimmoore Posts: 1,031
    edited 2008-07-01 22:20
    You haven't taken the time to run the code into account. The off time is longer from the or in onoff until the instruction to get cnt is missing from your calculation.
  • PhilldapillPhilldapill Posts: 1,283
    edited 2008-07-01 22:40
    Would you suggest I find the exact time that I want to turn the pin on and off, and just do a waitcnt time, #0? This way, 'time' is already calculated for the next loop?

    This would be similiar to the following code in spin

    time := cnt
    repeat
    time += x
    waitcnt(time)
    ...do something...
  • TimmooreTimmoore Posts: 1,031
    edited 2008-07-01 22:45
    I would check if the period/onetime have changed and if not skip the calculation of time and use the tme calculated by waitcnt
Sign In or Register to comment.