Shop OBEX P1 Docs P2 Docs Learn Events
pasm help--timing isn't working right — Parallax Forums

pasm help--timing isn't working right

P!-RoP!-Ro Posts: 1,189
edited 2010-07-06 05:35 in Propeller 1
Today is actually the first day I've ever worked with pasm, so I'm very new. I've gone through a lot of documentation online as well as the propeller manual but now I've gotten stuck. I was trying to make a simple program to control a servo, but even though it is set up to send the correct 2ms pulse every 20 ms, it crashes to the end of it's range. I changed the values both directions but to no avail, but I shouldn't have to since the spin equivilent is running just fine. My only guess is I have the pause routines set up wrong, hovever I really can't tell. The code I have for sending the signals is below, the full code is attached.

:loop
········ mov···· clock,··· #0
········ add···· clock,··· cnt
········ add···· clock,··· #13
········
········ xor···· outa,···· servopin
········ waitcnt clock,··· duration
········ xor···· outa,···· servopin
········ mov···· clock,··· #0
········ add···· clock,··· cnt
········ add···· clock,··· #9
········ waitcnt clock,···· pause
········ jmp···· #:loop

Comments

  • Cluso99Cluso99 Posts: 18,069
    edited 2010-07-04 06:28
    In your code snippet you do not had DIRA set. Have you done this?

    BTW if you do a mov clock,cnt you do not need the preceeding mov clock,#0

    Next thing is that #9 may be just too fine to catch the cnt in waitcnt, in which case you will be waiting ~90sec for it go around the 32bit cycle.

    Next, you want 20ms. This is way faster than this. Presuming 80MHz clock, 12.5ns clock. mov+add+add+xor+waitcnt = 22+ clocks = ~275+ns. Your delay is only going to be ~0 clock ~(#9 - 4 - 6). Double this for your frequency of 1/450ns = ~2MHz.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Links to other interesting threads:

    · Home of the MultiBladeProps: TriBlade,·RamBlade,·SixBlade, website
    · Single Board Computer:·3 Propeller ICs·and a·TriBladeProp board (ZiCog Z80 Emulator)
    · Prop Tools under Development or Completed (Index)
    · Emulators: CPUs Z80 etc; Micros Altair etc;· Terminals·VT100 etc; (Index) ZiCog (Z80) , MoCog (6809)·
    · Prop OS: SphinxOS·, PropDos , PropCmd··· Search the Propeller forums·(uses advanced Google search)
    My cruising website is: ·www.bluemagic.biz·· MultiBlade Props: www.cluso.bluemagic.biz
  • TimmooreTimmoore Posts: 1,031
    edited 2010-07-04 06:29
    also res should be after any other stuff. you have longs after res
  • kuronekokuroneko Posts: 3,623
    edited 2010-07-04 07:28
    ATM your waitcnt's are setup for no delay (apart from their 6 cycle minimum). The first parameter should be the SPIN equivalent of now+delay. And as Tim noted, place all your res at the end. Try this:

    CON
      _clkmode = XTAL1|PLL16X
      _xinfreq = 5_000_000
    
    CON
      pin = 8
      
    PUB main
    
      cognew(@servo, 0)
    
    DAT             org     0
    
    servo           mov     dira, servopin
                    andn    outa, servopin
        
                    mov     clock, cnt              ' now
                    add     clock, #9               ' fall through
             
    :loop           waitcnt clock, pulse            ' wait for L/H target, set H/L target
                    xor     outa, servopin          ' set pin high
    
                    waitcnt clock, pause            ' wait for H/L target, set L/H target
                    xor     outa, servopin          ' set pin low
                    
                    jmp     #:loop
    
    ' initialised data and/or presets
    
    servopin        long    |< pin
    
    pulse           long    160_000                 ' 2ms @80MHz    high time
    pause           long    1_600_000 - 160_000     ' 18ms (20 - 2) low time
    
    ' uninitialised data and/or temporaries
    
    clock           res     1
    
                    fit
    
    DAT
    

    Post Edited (kuroneko) : 7/4/2010 9:12:24 AM GMT
  • JonnyMacJonnyMac Posts: 9,208
    edited 2010-07-04 13:50
    You can simplify your code a bit vis-a-vis waitcnt.

    dat
                    org     0
    
    servo           mov     dira, servopin                  ' pin is output
                    andn    outa, servopin                  ' and off
                    mov     clock, cnt                      ' create sync point
                    add     clock, duration                 ' setup for on timing
        
    :loop           or      outa, servopin                  ' pin on
                    waitcnt clock, pause                    ' hold, reload with off timing
                    andn    outa, servopin                  ' pin off
                    waitcnt clock, duration                 ' hold, reload with on timing
                    jmp     #:loop                          ' do it again
    
             
    servopin        long    |< 8                            ' pin mask
    
    duration        long    160_000                         ' on ticks
    pause           long    1_600_000 - 160_000             ' ticks in 20ms, less on ticks
    
    clock           res     1                               ' workspace for timer
    
    



    The key with waitcnt is that you must setup the target value (in clock) before the you use it; the second parameter in waitcnt is the new target (i.e., for the next waitcnt).

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Jon McPhalen
    Hollywood, CA

    Post Edited (JonnyMac) : 7/4/2010 2:49:35 PM GMT
  • kuronekokuroneko Posts: 3,623
    edited 2010-07-04 14:11
    @JonnyMac: FWIW, your on-time is 4 cycles short [noparse]:)[/noparse]

    And this doesn't fly:

    duration        [b]long[/b]    160_000                         ' on ticks
    pause           [b]long[/b]    1_600_000 - duration            ' ticks in 20ms, less on ticks
    

    Post Edited (kuroneko) : 7/5/2010 2:14:41 AM GMT
  • JonnyMacJonnyMac Posts: 9,208
    edited 2010-07-04 14:45
    You're right on the 4-cycles thing, but I guarantee that you'll never see that difference in the position of the servo! [noparse];)[/noparse]

    Yep, you're right (again), and I'll fix the other part of my listing.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Jon McPhalen
    Hollywood, CA
  • P!-RoP!-Ro Posts: 1,189
    edited 2010-07-04 17:38
    I tried the code, and it works great. I'm wondering about the waitcnt command now, however. So, in this code that flashes an led:

    ······ mov···· time, cnt
    ······ add···· time, #9
    :loop· waitcnt time, delay
    ······ xor···· outa, pin
    ······
    ······ jmp···· #:loop

    Is the first wait time·1 clock cycle, and the the second the delay time? If so, is there a way I can leave out the "delay" and just set a value for time? What is the reason for waitcnt adding a value for time for the next pause rather than the current pause?
  • Mike GreenMike Green Posts: 23,101
    edited 2010-07-04 17:46
    The WAITCNT instruction is designed for very precise repeated time intervals. The initial value for the destination operand ("time") is the system clock time for the 1st wait (the start of the repeated process). The source value ("delay") is the interval between subsequent processes. The WAITCNT waits for the first time to occur, then proceeds. It adds the interval time so that the next execution of the WAITCNT releases at precisely the interval requested. If you want the 1st cycle to start immediately, you'd do:
         mov   time,#9
         add   time,cnt
    


    I'm not sure exactly what value to use for the "9". I think it's a few clocks less, but I'd have to review some of the threads on WAITCNT timing. With this scheme, the time mark is the 2nd cycle (?) of the ADD instruction when the destination operand is fetched. The "9" accounts for the rest of the ADD instruction and the first few cycles of the WAITCNT until it compares the destination operand to the system clock.

    Post Edited (Mike Green) : 7/4/2010 5:53:03 PM GMT
  • P!-RoP!-Ro Posts: 1,189
    edited 2010-07-04 20:12
    Hover, that would be great but unfortunately it's for spin, which I'm already fairly familiar with.

    Mike, I think it has to be 9 or more because the add command takes 4 clock beats, and the the waitcnt takes 4 clock beats, leaving the minimum value of 1 clock beat for pausing. If you add an extra instruction between this, such as xor for toggling a pin, I found that the value needed to be 13+ giving an extra 4 clock cycles for the extra command.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    90 * 2 = Pi
  • pjvpjv Posts: 1,903
    edited 2010-07-04 20:40
    Hi Pi'd;

    The way I like to think of it is: WAITCNT Target, Reload

    When the WAITCNT is reached in your code, the cog waits at that point until the value in the system counter CNT reaches the value in Target. The cog then adds the value of Reload onto the value in Target (which at that instant was the same as the system counter CNT) and carries on with the program. If you then issue another WAITCNT, then execution is again halted until the previously loaded Target is reached. And a new Taget is again calculated.... and so on.

    So, another way of saying it is when a WAITCNT is encountered, it will wait until the previously loaded Target is reached.

    Hope that helps.

    Cheers,

    Peter (pjv)
  • kuronekokuroneko Posts: 3,623
    edited 2010-07-04 23:59
  • P!-RoP!-Ro Posts: 1,189
    edited 2010-07-05 05:05
    Thanks everyone for your help so far.

    Since I've been programming in assembly for two days now (yes, I know. A long time) I've decided to make some code that is actually useful. Since I got one of the penguins with a reset button problem at the expo, I decided to tether it up to the propeller and make it work. The code posted below allows it to walk forward, and with a little modding should be able to turn as well. Please go ahead and be as rough on my techniques as you want, I'd hate to be doing things wrong long enough to cement it in my mind!

    BTW--I have another question about my code. How come the second direction change will reset the first in this code?

    ·········mov····· dira, tiltpin
    ········ mov····· dira, stridepin

    It took me all day to figure out I had to use "or" instead!

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    90 * 2 = Pi
  • kuronekokuroneko Posts: 3,623
    edited 2010-07-05 05:27
    The servo loop is more efficiently written by using djnz, which also means you can remove the code for clearing time every time the sub routine is called. Initialising clock with cnt could also be done in the servo subroutine (outside the loop), i.e. mov clock, duration before the call and add clock, cnt in the sub routine.

    servoloop       mov     time, value             ' run servos
    
    :loop           or      outa, pin               ' pin on
                    waitcnt clock, pause            ' hold, reload with off timing
                    andn    outa, pin               ' pin off
                    waitcnt clock, position         ' hold, reload with on timing
    
                    djnz    time, #:loop
    servoloop_ret   ret
    

    Post Edited (kuroneko) : 7/5/2010 5:32:20 AM GMT
  • P!-RoP!-Ro Posts: 1,189
    edited 2010-07-05 06:12
    Thanks a lot, that's exactly what I needed!

    I've written a demo now where it moves forward-backward-turnleft-turnright-repeat. I implemented djnz a couple times, too. It's attached.

    Now I'm just thinking of what I should do tomorrow, start objects and to tasks such as play wav music?

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    90 * 2 = Pi
  • P!-RoP!-Ro Posts: 1,189
    edited 2010-07-06 01:22
    Is it possible to run objects using PASM? I haven't found a way yet, in fact I'm not even sure if it's possible to run spin at all in a cog once asm has been started. Any insight on this matter would be great.
  • kuronekokuroneko Posts: 3,623
    edited 2010-07-06 02:01
    pi'd said...
    Is it possible to run objects using PASM? I haven't found a way yet, in fact I'm not even sure if it's possible to run spin at all in a cog once asm has been started.
    The SPIN interpreter itself is a PASM blob. So either it runs or your code does (in the same cog that is). You might want to check out this thread Spin + LMM Pasm where effectively SPIN comes first and executes arbitrary blobs of PASM. If that's too scary then you'd better stick with separate SPIN/PASM cogs and communicate between them the old-fashioned way [noparse]:)[/noparse]
  • P!-RoP!-Ro Posts: 1,189
    edited 2010-07-06 05:35
    Wow, I've been spending all night figuring out the lmm thing, but code that works fine when launched in a different cog doesn't work with lmm. I went from all leds lighting when only 1 was supposed to having the leds light up in binary even though I was using decimal to now where it works fine but I seemingly have no control over pin 0. Also, loops don't seem to work worth a darn...I may be forced to just stick to the "old" method.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    90 * 2 = Pi
Sign In or Register to comment.