Frequency calculation for NCO counter
Andrew E Mileski
Posts: 77
My Christmas 2015 present to myself was a frequency counter (TTi TF960), as I've been fiddling a lot with oscillator design & RF lately.
Like getting a new set of tools, I'm going around the house and fixing measuring everything whether it needs it or not. This of course lead me to my Propeller boards.
The math for NCO frequency initially looks like it is a 32-bit divisor and a 64-bit dividend. I wanted to avoid that, and keep things limited to SPIN's 32-bit signed integers.
The following is the result, but of course I'd love to hear if there is a faster or simpler method that I'm overlooking that is also accurate. I excel at finding the most complex solutions to simple problems (e.g. I considered successive approximation).
Like getting a new set of tools, I'm going around the house and fixing measuring everything whether it needs it or not. This of course lead me to my Propeller boards.
The math for NCO frequency initially looks like it is a 32-bit divisor and a 64-bit dividend. I wanted to avoid that, and keep things limited to SPIN's 32-bit signed integers.
The following is the result, but of course I'd love to hear if there is a faster or simpler method that I'm overlooking that is also accurate. I excel at finding the most complex solutions to simple problems (e.g. I considered successive approximation).
PUB NCO(_ctr, _freq, _pin) | _frqx {{ Purpose: Set a counter to output at the specified frequency. Results: Always succeeds. Parameters: _ctr The counter to use (0 = counter 'A', 1 = counter 'B'). _freq The frequency to output, in Hertz. _pin The pin to output on. }} ' Set pin to output DIRA[_pin]~~ _frqx := 0 ' _frqx = (_freq << 32) / CLKFREQ repeat 32 _freq := (_freq // CLKFREQ) << 1 _frqx := (_frqx << 1) + (_freq / CLKFREQ) ' Round to nearest (round quotient up if remainder > half of divisor) if ((_freq << 1) => CLKFREQ) _frqx++ ' Start counter if (_ctr) CTRB := 0 PHSB := 0 FRQB := _frqx CTRB := (%00100 << 26) | _pin else CTRA := 0 PHSA := 0 FRQA := _frqx CTRA := (%00100 << 26) | _pin
Comments
For a fixed propeller clock of 80 MHz and 1 hertz resolution, I use this simple formula:
Andy
That uses only shift/add so it will be faster than the method that uses division / and remainder //. Note that 2^32 / 80_000_000 = 53.687, which is close to 161/3.
That 'close' is ~ 381ppm error, which may be good enough for many applications.
Another approach is to use 2^32/64 =67.108864MHz and a 4.194304MHz Xtal, and then you have an exact and simple 64 ( << 6).