Shop OBEX P1 Docs P2 Docs Learn Events
[FYI] clkfreq/2n — Parallax Forums

[FYI] clkfreq/2n

kuronekokuroneko Posts: 3,623
edited 2011-08-14 00:50 in Propeller 1
This post has been triggered by a [post=1021211]recent 8MHz requirement[/post] (serial transfer, clkfreq/10). It didn't really need the clock generation but I did it anyway. In general, dividing by powers of two is easily done with an NCO but sometimes you may need the odd (2n) divider but not the associated (counter) jitter. What are our options?
  • plain code
  • waitcnt usage
  • (mis)using an NCO as a monoflop
  • waitvid usage (for the time being I consider that cheatingA and it's not everyone's cup of tea anyway despite being one of the most flexible solutions)
Let's start with point 2 which effectively covers everything above (and including) clkfreq/28.
CON
  pin = 16
  
DAT             org     0

[COLOR="blue"]entry[/COLOR][COLOR="orange"]_28[/COLOR]        mov     dira, :mask
                mov     cnt, #5{14} +4
                add     cnt, cnt
                
:loop           xor     outa, :mask             ' toggle pin
                waitcnt cnt, [COLOR="orange"]#14[/COLOR]
                jmp     #:loop

:mask           long    |< pin

                fit
Which leaves range 8..26. Let's cover plain code examples first (there are less, 8/16/20/24). I'm aware that 8 and 16 are powers of two, they are included here for completeness.
CON
  pin = 16
  
DAT             org     0
                                       
[COLOR="blue"]entry_08[/COLOR]        mov     dira, :mask

                neg     outa, dira              ' !dira +1
                djnz    outa, #$-1              ' outa -= 1
                          
:mask           long    |< pin

                fit

DAT             org     0

[COLOR="blue"]entry_16[/COLOR]        mov     dira, :mask

                xor     outa, :mask             ' toggle pin
                jmp     #$-1

:mask           long    |< pin

                fit

DAT             org     0

[COLOR="blue"]entry_20[/COLOR]        mov     dira, :mask
                
:loop           waitpne $, #0
                neg     outa, dira              ' !dira +1
                waitpne $, #0
                djnz    outa, #:loop            ' outa -= 1

:mask           long     |< pin

                fit

DAT             org     0

[COLOR="blue"]entry_24[/COLOR]        mov     dira, :mask

:loop           xor     outa, :mask             ' toggle pin
                nop
                jmp     #:loop

:mask           long    |< pin

                fit
And finally, an NCO based example (clkfreq/26, the remainder is listed in the attached SPIN file).
CON
  pin = 16

DAT             org     0

[COLOR="blue"]entry_26[/COLOR]        mov     dira, :mask

                movs    ctra, #pin
                movi    ctra, #%0_00100_000     ' NCO
                movi    frqa, #%0000_0001_0
                                                ' SDeRSDwm-RSDwm-RSDwm-RSDeRSDeR
:loop           movi    phsa, #%1111_0011_0     ' XXX#                      ___#
                waitpne $, #0                   '     ######
                waitpne $, #0                   '           ######
                waitpne $, #0                   '                 ______
                jmp     #:loop                  '                       ____

:mask           long    |< pin

                fit
Bean's bean [thread=123170]frequency counter[/thread] has been used to verify the generated waveforms.


A As in not exercising your brain enough :)

Comments

  • kuronekokuroneko Posts: 3,623
    edited 2011-08-11 19:02
    While looking for it myself (currently verifying) can someone please come up with a non-waitvid based clkfreq/6?
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2011-08-11 19:21
    'You mean exactly clkfreq / 6 and jitter-free? You're dreaming, right? (One of my favorite machine shops always asked, "Okay, which of these tolerances are BS?")

    -Phil
  • kuronekokuroneko Posts: 3,623
    edited 2011-08-11 19:30
    Yes (not the dreaming bit)! I mean 3 cycles high and 3 cycles low which (@80MHz) comes down to a period of 75ns (13.33MHz = 80MHz/6).
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2011-08-11 19:47
    Are you barring external circuitry from the solution? (This has got to be one of your best puzzles, EVER!)

    -Phil
  • kuronekokuroneko Posts: 3,623
    edited 2011-08-11 19:52
    Now I'm getting a little scared. I already double checked my math (Bean's counter tells me 13.33MHz) in that /6 means what I think it does. All I needed was a demoboard (no extra h/w) and I didn't use waitvid. Everything else is allowed. Are we talking about the same thing here?
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2011-08-11 19:57
    kuroneko wrote:
    Are we talking about the same thing here?
    I'm not sure. If you're doing anything with a PLL-mode counter and expect a precise, jitter-free division down to clkfreq / 3, you will see a phase glitch sooner or later. 'Care to show your code?

    -Phil
  • kuronekokuroneko Posts: 3,623
    edited 2011-08-11 20:02
    CON
      pin = 16
      
    DAT             org     0
    
    [COLOR="blue"]entry_06[/COLOR]        mov     dira, :mask
    
                    movs    ctra, #pin
                    movi    ctra, #%0_00100_000     ' NCO
                    movi    frqa, #%0011_0000_0
                                                    ' SDeRSDeRSDeRSDeRSDeRSDeRSDeR
    :loop           movi    phsa, #%1000_0000_0     ' XXX#                    ___#
                    nop                             '     ##__
                    movi    phsa, #%1101_0000_0     '         _###
                    nop                             '             ___#
                    movi    phsa, #%0010_0000_0     '                 ##__
                    jmp     #:loop                  '                     _###
    
    :mask           long    |< pin
    
                    fit
    
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2011-08-11 20:03
    Come to think of it, it could probably be done with two cogs, each providing an output of three clocks on and nine off. Is that your approach?

    -Phil
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2011-08-11 20:15
    Okay, I'm looking at the output from your code now on the scope. I have to say, it's damn clever! :)

    -Phil
  • jmgjmg Posts: 15,185
    edited 2011-08-12 01:13
    kuroneko wrote: »
    CON
      pin = 16
      
    DAT             org     0
    
    [COLOR="blue"]entry_06[/COLOR]        mov     dira, :mask
    
                    movs    ctra, #pin
                    movi    ctra, #%0_00100_000     ' NCO
                    movi    frqa, #%0011_0000_0
                                                    ' SDeRSDeRSDeRSDeRSDeRSDeRSDeR
    :loop           movi    phsa, #%1000_0000_0     ' XXX#                    ___#
                    nop                             '     ##__
                    movi    phsa, #%1101_0000_0     '         _###
                    nop                             '             ___#
                    movi    phsa, #%0010_0000_0     '                 ##__
                    jmp     #:loop                  '                     _###
    
    :mask           long    |< pin
    
                    fit
    

    Impressive - can you generalise that, for other divisions ? and include cases where Hi counts can be 1 different from low counts ?
  • kuronekokuroneko Posts: 3,623
    edited 2011-08-12 01:38
    jmg wrote: »
    ... can you generalise that, for other divisions ? and include cases where Hi counts can be 1 different from low counts ?
    Haven't thought about it yet. Wouldn't video h/w (mis)use be more flexible for that or is there a specific reason for not using it? Anyway, what range are you after? 6..27 I presume (28+ should be obvious as you have direct control over both halves).
  • jmgjmg Posts: 15,185
    edited 2011-08-12 02:37
    kuroneko wrote: »
    Haven't thought about it yet. Wouldn't video h/w (mis)use be more flexible for that or is there a specific reason for not using it? Anyway, what range are you after? 6..27 I presume (28+ should be obvious as you have direct control over both halves).

    Yes, those small number frequencies that are not easily reached with a simple SW loop make the most sense.
    If course, if a general form for higher divides exists that is still small, then > 28+ can still be useful.
  • Andrey DemenevAndrey Demenev Posts: 377
    edited 2011-08-12 05:52
    jmg wrote: »
    Impressive - can you generalise that, for other divisions ? and include cases where Hi counts can be 1 different from low counts ?

    No problem. CLKFREQ/3 :
    CON
      pin = 0
    
        
    DAT             org     0
    
    entry_03        mov     dira, :mask
    
                    movs    ctra, #pin
                    movi    ctra, #%0_00100_000     ' NCO
                    movi    frqa, #335
    :loop           movi    phsa, #80
                    nop
                    jmp     #:loop
    
    :mask           long    |< pin
    
                    fit
    
  • kuronekokuroneko Posts: 3,623
    edited 2011-08-12 21:08
    I was halfway through doing a waitvid based driver so I finished it off. The setup sequence is rather verbose (can be cut down to the essential register setup, i.e. pre-calculated ctra/frqa/vcfg/vcsl etc). It's all down to how friendly you want to be to the caller.

    The driver allows you to send custom wave forms with a period of 1..32 cycles. Required parameters are period, pin and bit pattern.

    In the end it is the most flexible way of sending out (custom) wave forms for this frequency range.
  • kuronekokuroneko Posts: 3,623
    edited 2011-08-14 00:50
    jmg wrote: »
    ... can you generalise that, for other divisions ? and include cases where Hi counts can be 1 different from low counts ?
    OK, I did the numbers on this one and for dividers 2..27 the following generic loop works:
    • setup an NCO
    • set the top 12bit of frqx to ($1000_0000/period) >> 16
    • preset phsx with frqx
    • close the loop after period*4 cycles
    High time for 2n+1 dividers is n+1, if you need opposite polarity just use a differential NCO and swap the pins. HTH
Sign In or Register to comment.