Shop OBEX P1 Docs P2 Docs Learn Events
Counter and ASM Question — Parallax Forums

Counter and ASM Question

MightorMightor Posts: 338
edited 2007-08-30 16:32 in Propeller 1
Hey there,

I'm trying to learn ASM for the prop. Right now I'm going through the Propeller Counters document. As far as I can understand you basically have two counters per cog. Does that mean that you could have two separate PWM generators per cog? I'd like to know if it is possible before I embark on my journey to modify the below into something that generates two different PWM signal on two separate pins. I don't want to strand my (asm)-ship before I've even set sail. So if it's doable, please let me know. I am not looking for the code, I'd like to try that myself, only to know if it can be done [noparse]:)[/noparse]

{{
  Demonstration of scaling Duty Cycle

}}

CON
  _clkmode = xtal1 + pll16x
  _xinfreq = 5_000_000

VAR
  long parameter

PUB go | x
  cognew(@entry, @parameter)
  repeat
    'parameter := 50
    repeat x from 0 to period                   ' linearly advance parameter from 0 to 100
      parameter := x                            ' a constant here locks to x percent high
      waitcnt(1000 + cnt)                  ' wait a little while before the next update

DAT
        org

entry   mov dira, diraval                       ' set APIN to output
        mov ctra, ctraval                       ' establish counter A mode and APIN
        mov frqa, #1                            ' set counter to increment 1 each cycle

        mov time, cnt                           ' record current time
        add time, period                        ' establish next period

:loop   rdlong value, par                       ' get an up to date duty cycle
        waitcnt time, period                    ' wait until next period
        neg phsa, value                         ' backup up phsa so that it
        jmp #:loop                              ' loop for next cycle

diraval long |< 0                               ' APIN direction (0)
ctraval long %00100 << 26 + 0                   ' NCO/PWM APIN=0 {BPIN=1} <- not used
period  long 100                                ' 800kHz period ( clkfreq / period )
time    res 1
value   res 1




Gr,
Mightor

▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
| To know recursion, you must first know recursion.

Comments

  • SteelSteel Posts: 313
    edited 2007-08-28 19:27
    yup. You are correct. There are 2 timers, and you can set each of them to the correct mode and have 2 PWM per cog...thus making 16 possible pwm signals. THANK YOU PARALLAX!
  • MightorMightor Posts: 338
    edited 2007-08-29 19:35
    Well I figured it out and it works quite nicely now. I'd really like it if someone could have a look at the code and tell me if this is indeed the proper way to do it. Now, I know TIMTOWTDI (yeah, deSilva, I know Perl [noparse]:)[/noparse], but some input would be greatly appreciated. I'd really like to know if there are clever tricks do this kind of thing. The counter application notes mention the ability use the counters so you can make the cog do other stuff as well. However, I am not sure how that would be possible since I seem to be in a loop most of the time.

    {{
      Demonstration of scaling Duty Cycle
    
    }}
    
    CON
      _clkmode = xtal1 + pll16x
      _xinfreq = 5_000_000
    
    VAR
      long parameter
    
    PUB go | x
      cognew(@entry, @parameter)
      repeat
        'parameter := 50
        repeat x from 0 to period                   ' linearly advance parameter from 0 to 100
          parameter[noparse][[/noparse]0] := x                            ' a constant here locks to x percent high
          parameter := period - x
          waitcnt(1000 + cnt)                  ' wait a little while before the next update
    
    DAT
            org
    
    entry   mov dira, diraval                       ' set APIN to output
            mov ctra, ctraval                       ' establish counter A mode and APIN
            mov frqa, #1                            ' set counter to increment 1 each cycle
            mov ctrb, ctrbval                       ' establish counter B and
            mov frqb, #1 
    
            mov time, cnt                           ' record current time
            add time, period                        ' establish next period
    
    :loop   rdlong value, par                       ' get an up to date duty cycle
            mov value2, par
            add value2, #4                          ' Get the address for the 2nd long
            rdlong value2, value2                   ' read the 2nd argument from the HUB
            waitcnt time, period                    ' wait until next period
            neg phsa, value                         
            neg phsb, value2
            jmp #:loop                              ' loop for next cycle
    
    diraval long |< 2 + |< 3                         ' APIN direction (0)
    ctraval long %00100 << 26 + 2                    ' NCO/PWM APIN=3
    ctrbval long %00100 << 26 + 3                    ' NCO/PWM APIN=4
    period  long 1000                                ' 800kHz period ( clkfreq / period )
    time    res 1
    value   res 1
    value2  res 1
    
    



    Also, this is running at a breakneck speed of 800kHz, which is great when you're running this program in GEAR, but what kind of frequency should I be looking at when using PWM for a motor? 800kHz seems a little excessively fast. I am also going to need some diodes apart from the H bridge. What kind should I get? The max current the motors draw when stalled is about 1A. I saw on voti.nl (a local-ish online electronic shop) that the UF4007 is fast and can deal with 1A. Would this do the trick for me?

    Gr,
    Mightor

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    | To know recursion, you must first know recursion.
  • deSilvadeSilva Posts: 2,967
    edited 2007-08-29 20:17
    Mightor said...
    The counter application notes mention the ability use the counters so you can make the cog do other stuff as well. However, I am not sure how that would be possible since I seem to be in a loop most of the time.
    Well, the PWM feature is indeed the worst example for this claim... But you COULD could do something else before WAITCNT... Having just 8 COGs can never compensate for the wealth of possibilties you have with a good interrupt system smile.gif


            mov time, cnt                           ' record current time
            add time, period                        ' establish next period
    



    Why "period" .. this is highly irrelevant in this place...
    When you enter the loop you will first wait THIS time before any PHS is set.

    diraval long |< 2 + |< 3                         ' APIN direction (0)
    ctraval long %00100 << 26 + 2                    ' NCO/PWM APIN=3
    ctrbval long %00100 << 26 + 3                    ' NCO/PWM APIN=4
    
    


    I should use constant NAMES rather "1" and "2"

    period  long 1000                                ' 800kHz period ( clkfreq / period )
    


    You can read the ckfreq value also in "PASM" - do you know how?
  • MightorMightor Posts: 338
    edited 2007-08-30 03:58
            mov time, cnt                           ' record current time
            add time, period                        ' establish next period
    

    deSilva said...

    Why "period" .. this is highly irrelevant in this place...
    When you enter the loop you will first wait THIS time before any PHS is set.
    Well, to be honest with you, I copied most of this code from the Propeller counter application notes code examples. I merely tweaked to be able to handle two PWM signals [noparse]:)[/noparse] Why is it highly irrelevant? What would be more appropriate?


    period  long 1000                                ' 800kHz period ( clkfreq / period )
    

    deSilva said...
    You can read the ckfreq value also in "PASM" - do you know how?
    No, I do not. What would that allow me to do in this case? I picked 1000 because it allows me to see the waves very nicely in the GEAR simulator when it runs at 80MHz. In the Prop manual I see this:
    Propeller manual said...
    After issuing a CLKSET instruction, it is important to update the System Clock Frequency value by writing to its location in Main RAM (long 0): WRLONG freqaddr, #0. If the System Clock Frequency value is not updated, other objects will misbehave due to invalid clock frequency data.
    My guess is that this has something to do with it, although tbh, I am not sure yet in what way [noparse]:)[/noparse]

    Thanks for looking at this stuff and giving me feedback, it's highly appreciated.

    Gr,
    Mightor

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    | To know recursion, you must first know recursion.
  • deSilvadeSilva Posts: 2,967
    edited 2007-08-30 16:32
    Mightor said...

    Why "period" .. this is highly irrelevant in this place...
    When you enter the loop you will first wait THIS time before any PHS is set.
    Well, to be honest with you, I copied most of this code from the Propeller counter application notes code examples. I merely tweaked to be able to handle two PWM signals [noparse]:)[/noparse] Why is it highly irrelevant? What would be more appropriate?[noparse][[/noparse]/code]

    You see, you are entering the main loop at its WAIT-instruction, without presetting the PWM mechanism. So what is the use of waiting? Or how long? Why "period". Well it's a value as any value... Nevertheless it can also be a shorter or a longer time - what I wanted to say: No connection with the "period " in any way here. I myself would have coded:
            mov time, cnt                           ' record current time
            add time, period                        ' establish next period
            JMP #:loopEntry
    
    :loop   rdlong value, par                       ' get an up to date duty cycle
            mov value2, par
            add value2, #4                          ' Get the address for the 2nd long
            rdlong value2, value2                   ' read the 2nd argument from the HUB
            waitcnt time, period                    ' wait until next period
    :loopEntry
            neg phsa, value                         
            neg phsb, value2
            jmp #:loop 
    
    



    But as it is generally frowned upon using "unstructured" constructs, you can now reshape the loop:
            mov time, cnt                           ' record current time
            add time, period                        ' establish next period
    
    :loop
            rdlong value, par                       ' get an up to date duty cycle
            mov value2, par
            add value2, #4                          ' Get the address for the 2nd long
            rdlong value2, value2                   ' read the 2nd argument from the HUB
            neg phsa, value                         
            neg phsb, value2 
            waitcnt time, period                    ' wait until next period
    
            jmp #:loop 
    
    




    Using the clock frequency stored in HUB cell 0 is easy
    [noparse][[/noparse]code]
    RDLONG t0, #0 ' read clock frequency
    MOV t1, reqFreq
    CALL #divide
    MOV period, t0


    reqFreq LONG 80_000 ' 80 kHz
    I think it's 80kHz you are using, not 800...
    You of course have to insert the standard 32/16 bit division routine..

    However the values have now be harmonized with the values read from memory... At the moment you use "per thousend" which is quite transparent and will work (the duty cycle at least) independent of the clock speed.

    But it is always a good idea to set the _PLLX to 4 from time to time , just to see whether one's program still runs with another clock...
Sign In or Register to comment.