Numerically Controlled Oscillator (NCO)

I have finished an application note for a four channel numerically controlled oscillator (NCO). The documentation, library and sketch are at http://tinyurl.com/ydmz2su

The code runs on the Arduino compatible Wiblocks NB1A which has an 168P/328P and a TI TLV5620 four channel DAC. A timer interrupt is used to trigger periodic updates of the DAC channels.

The code documentation is sparse but I believe that the application note is complete. I document how the phase accumulator works and the relationship between the phase increment and frequency. I did not go into the details of the SNR calculations. The two references I used are listed at the bottom of the webpage.

Also, I just prototyped an NB1A MIDI interface that includes a midi-in, midi-out and four two-pole filters. The filters connect to the DAC outputs to smooth the stair-steps of the NCO.

(* jcl *)


www: http://www.wiblocks.com twitter: http://twitter.com/wiblocks blog: http://luciani.org

Nice project.

Just one question:

  if (nco_round(i)) {
    addr += 1;
    addr &= NCO_ADDR_MASK;
  }

Why not just add in the rounding bit?
The conditional is redundant surely?
If it’s a 1, it’ll round; if it’s a zero, it won’t.
Maybe squeeze a little more range out of it?

I believe I was originally worried about how the bit-fields in the phase accumulator structure would work with the wavetable address byte. Testing for a true value of the bit-field and then adding one to the addr byte seemed safer.

I believe you are correct that

addr += acc.acc_bits.round

will work. I just need to take a look at the asssembler output to verify it.

Thanks for the feedback.

(* jcl *)

On a second look, the bitwise-AND is redundant too, I think.

The and is necessary for this example. Only the lower six bits represent a valid address. Adding one to a value of 0x3F produces an invalid address.

When the 6bit bitfield is assigned to a byte it is right-justified.

(* jcl *)

P.S. I learned this bit-field lesson the hardway ;)

Ah! Yes - I used to use an eight bit phase accumulator (different processor, different architecture), so the AND was never necessary. Sorry!

Thanks for taking that close a look at the code!

(* jcl *)

I prefer to have a bigger table and keep all the conditional code out of the inner loop. My NCO code can be found here for reference: http://adrianfreed.com/content/arduino-sketch-high-frequency-precision-sine-wave-tone-sound-synthesis

It has the interpolation code you need to smoothly ramp frequency and amplitude if you want to make clean music synthesizer out of this idea. I also include the tables to map midi note numbers into phase increment values.