Shop OBEX P1 Docs P2 Docs Learn Events
Smart Pin NCO Example — Parallax Forums

Smart Pin NCO Example

In @JonTitus 's Smart Pins doc, he has the following program:

        dirl    #20                 
        wrpin   NCO_Config,#20      
        wxpin   #1, #20             
        dirh    #20                 

        qfrac   ##123, ##_clkfreq   ' Calculate number of 25-MHz cycles for 8ms period

        getqx   pa                  'Save in PA register
        wypin   pa,#20              'Send pulse count to Y register

.myloop nop                         'Delay two clocks for IN to drop
        jmp     #.myloop            'Wait forever

NCO_Config  long %0000_0000_000_000_000000000_01_00110_0

My confusion is with the qfrac line. I've worked at this for an hour trying to figure out what is going on here, and how [123 << 32 ] / [25_000_000] (_clkfreq defined elsewhere) gives the number of clock cycles for an 8ms period! I think I'm missing something (and a line that mysterious should certainly have more explanation).

My thoughts so far: 123<<32 / 25M ~= 20k, the number of actual clock cycles for a full period is 200k, so maybe that means something. If we did 25M / 125 (qdiv ##_clkfreq, ##125) it would come out to exactly 200k, so I'm not sure why we're bothering with the qfrac instruction like this..

But it works! The example, runs, and the period is 8ms, so there's something to this.

Comments

  • AribaAriba Posts: 2,690
    edited 2021-02-09 00:38

    Normally you want to output a certain NCO frequency, independent of the system clock frequency someone have chosen.
    So you calculate the Y value at runtime from the current clkfreq.
    QFRAC is the simplest way to calculate the Y value with full resolution,and without needing 64 bit calculation:

      NCOfreq = clkfreq / 2^32 * Y
    
      Y = NCOfreq * 2^32 / clkfreq  =  NCOfrq<<32 / clkfreq  =  NCOfrq FRAC clkfrq
    
    

    Andy

  • @Ariba Where does the NCOfreq = clkfreq / (2^32 * Y) part come from? I think that's the part I missed, Im still new to Smart Pins.

  • cgraceycgracey Posts: 14,152

    Well, 2^32 means '2 XOR 32' which is 34. The intent, I see, was to express $1_0000_0000, which is too big for a long.

    'X QFRAC Y' divides X<<32 by Y, but this 64-bit action (x<<32) happens in the CORDIC. QFRAQ is great for getting a huge fraction that is less than one, effectively. X must be less than Y. QFRAC will return the 32 bits to the right of the decimal point. It's great for computing NCO values.

  • @cgracey said:
    Well, 2^32 means '2 XOR 32' which is 34. The intent, I see, was to express $1_0000_0000, which is too big for a long.

    Oh I see, some confused notations, Ive been thinking 2 ** 32, you know, pow(2,32), 1<<32.

    @cgracey said:
    QFRAC will return the 32 bits to the right of the decimal point. It's great for computing NCO values.

    Does 'to the right of the decimal point' mean for the everday decimal encoding (e.g. 34.824 => 824) or for floating point (e.g. 0.34824E+02 => 34824)? (Maybe I should actually make myself an example, but I havent learned the debugging or TACHOZ tools yet and I dont know how.)

  • AribaAriba Posts: 2,690
    edited 2021-02-09 02:53

    @Ariba Where does the NCOfreq = clkfreq / (2^32 * Y) part come from? I think that's the part I missed, Im still new to Smart Pins.

    No it's: NCOfreq = (clkfreq / 232) * Y, if you want parentheses.
    See the wikipedia article about NCO: https://en.wikipedia.org/wiki/Numerically-controlled_oscillator

    The Z register is the phase accumulator, and Y is the frequency control word. Y gets added to Z on every sysclock*. The NCO frequency is the overflow rate of the Z register.
    If Y=1 then we have the lowest frequency possible, which is clkfreq / 232 (because Z is a 32bit register). If Y is higher, you get a proportional frequency : clkfreq / 232 * Y.

    *only true if the precounter in X[15..0] is 1, but that's the normal case, you want it as fast as possible to reduce jitter.

  • cgraceycgracey Posts: 14,152
    edited 2021-02-09 02:40

    Sjgallagher2, consider this:

  • Oh it's all making a lot more sense now. I hadnt thought to look up NCOs outside of P2 docs, and with the parentheses your expression makes much more sense. Thanks for the help guys, much appreciated.

Sign In or Register to comment.