Homebuilt Hardware


dspicVCDO

Posted in Synth DIY by ryan on the August 14th, 2008

Update: After playing with this VCO for a while and thinking about the design. I think the idea is good, but the implementation could use some work. This design provides some tuning assistance but a complete autotune feature would be much nicer. The main problem I have is the high power consumption. I have been working with the NXP LPC1700 and LPC2000 controllers a lot and think that those would be a much better choice. In the future, i also plan to build my digital modules to use a third +5V power supply rather than regulating a 15V down to 5V. If anyone is considering building this as is, know that I am currently not using this in my synth.

This is a digital VCO built with a dspic30f3013. It is a numerically controlled oscillator (NCO) with the exponential conversion performed in the dspic using a lookup table. The NCO phase is used to lookup a triangle waveform. The triangle wave is output through an 8bit R2R DAC. The normal VCO waveforms, sine, sawtooth, and PWM, are generated using analog circuitry. For this first version, I wanted to create a traditional VCO, but future versions may include additional waveforms. The inputs are 1V/Octave, exponential FM, sync, and PWM. There are three frequency controls. A coarse, and fine exponential control are summed with the 1V/Oct and exponential FM inputs. A linear fine control is also provided using the dspic’s built in ADC.

Both of the dspic’s accumulators are used. Accumulator A acts as a 32bit phase accumulator for the NCO. Accumulator B stores a 24bit tuning word. The NCO operates at 500khz. The high sample rate is used to reduce aliasing. There is still a small amount of aliasing audible, I can hear it with my headphones but not so much on my speakers.

The control voltage comes into a 16bit ADC and is sampled at about 100khz. The ADC reading is then passed through a first order digital filter. This filter is very inexpensive and is implemented without the dsp instructions. The lower 12 bits of the filtered ADC reading index a lookup table which provides a 24bit tuning value. The upper 4 bits of the ADC reading are used to lookup an octave multiplier value. The multiplication is done in two steps using MAC dsp instructions.

The analog waveshapers are similar to most triangle core VCOs. I have done something a bit different with the sine shaper. This circuit works wonderfully. It uses an OTA with negative feedback. A description of this circuit can be seen in the paper I wrote a few years back (here). The resistor values for the sine shaper came from one that Ian Fritz built. The saw shaper was also adapted from Ian Fritz’ triangle VCO.

The performance of the VCO is as good as I’d hoped. It tracked over several octaves as well as my meter could measure and it was tracking better than my kenton midi-CV converter. There is some frequency jitter caused by noise at the ADC input. That is the reason I added the digital filter which I had originally had hoped to avoid.

One my favorite things about having a VCDO is the ease of tuning. I don’t expect to need to tune it often. When needed, very close tuning can be achieved without a reference frequency or frequency meter. I included a calibrate button and trim pot on the ADC reference. When the button is held and the lower 12 bits of the ADC reading are 0, a LED is lit. This has the effect of visibly showing when the VCO is set to an exact multiple of octaves.

The design is stable, but I still have one concern. That is the power consumption of the dspic while running at 120MHz. The dspic gets quite warm but not so hot that It burns my finger. The regulator however does get quite hot. I am certain it is within spec with a current headroom of 20-50mA depending on the ambient temperature. But It would have been a good idea to drop the input voltage through some diodes. The whole circuit draws 120mA from the +15V supply, so there is a price to pay for the stability that comes with being digital. A better solution would be to use a processor with a more efficient architecture. The dspic requires 4 clock cycles for the fastest instructions and I don’t think I’m using the dsp instructions enough to use a dspic.

I will probably build one more of this version, then use it as a base for a future design. The future design will have more features that are difficult to achieve with analog VCOs. The main goals for version 2 will be reduced power consumption and ADC cost.

Detailed NCO Operation

My oscillator is an NCO. This is the same thing that DDS ICs use. you can find lots of information about them from analog devices’ web site. it basically adds a constant *tuning* value to an accumulator at some
sample rate. the value of the tuning word determines the frequency. if you look at the accumulator value over time, it will increase until it overflows then repeats. the accumulator value is the oscillator phase.
it is a ramp wave form but can be used to lookup any other wave form from a lookup table. the tuning word can be any number up to 1/2 the maximum phase accumulator value. In practice, it should stay much less than this to avoid aliasing. A 32bit phase accumulator will give good frequency resolution.

the frequency of a NCO can be calculated as:

f=\dfrac{tuning\_word}{2^{num\_accumulator\_bits}}f_s

note: tuning values higher than 1/2 the max phase accumulator value actually generate negative frequencies, or a phase that decreases instead of increasing. to negate a frequency the new tuning word is max_accumulator_value - tuning_word. this is useful for through-zero oscillators.

To go from a linear ADC value to exponential tuning word for an NCO, an exp() and log() function is needed. the calculation is like this:

octave\_scale=2^\dfrac{num\_adc\_bits}{num\_octaves}

f=base\_frequency*e^{\dfrac{adc\_value}{octave\_scale}\ln{2}}}

tune\_word=f*2^\dfrac{num\_accumulator\_bits}{sample\_rate}

where:

  • octave_scale: calculated from the number of octaves you want your adc range to cover.
  • base_frequency: the frequency with adcvalue=0.
  • adc_value/octave_scale: the value read from the adc divided by the octave scaling. this ends up incrementing by 1 for each octave. the exponential will double when this ratio increases by 1.
  • f: the desired NCO output frequency in hz
  • num_accumulator_bits: number of bits in the phase accumulator.

As the NCO is running, the top n bits of the phase accumulator can be used to lookup the wave table data. To avoid the terrible aliasing sound, a high sample rate is used with a bit of low pass filtering at
the output. Alternatively, the wave tables can be many bits and band limited but that requires a many bit DAC.

The tuning word calculation is to complicated for a small microcontroller to perform at a rate fast enough for audio FM. It can be simplified by pre-calculating the tuning word for every possible ADC reading then storing that value in a lookup table. This will end up using a huge amount of memory. As an example, a 16bit ADC and 32bit tuning word would require 256KB of storage for the tuning table.

Since audio is exponential and the frequency doubles for each octave. The tuning table memory requirements can be reduced by storing only a single octave. To keep the microcontroller calculations simple, I recommend storing the lowest octave (the highest octave can also be used). to calculate the tuning word of a higher octave simply multiply octave 0’s tuning word by (2^octave). Another way to reduce the table size is by using a sample rate such that the maximum frequency’s tuning word uses less bits than the phase accumulator has. I have found that a good size is 32bit for the phase accumulator and 24bits for the tuning word.

so, the calculation to determine a tuning word at run time is:

tune\_word=tune\_table[{adc\_val}\bmod{octave\_scale}]*2^\dfrac{adc\_val}{octave\_scale}

Where mod is modulus and the division result is an integer. The requirements for multiplication, division, and modulus can be removed if the processor can handle values with enough bits to represent the tuning word. For a 32bit processor and 32bit phase accumulator (up to 32bit tuning word):  the octave scale can be taken as a power of 2. the modulus operation (adc_value%octave_scale) is now accomplished by clearing some number (adc_bits-octave_scale_bits) of the high bits in the adc_value. the division is done by shifting adc_value right by the number of remaining adc bits. The final multiplication is multiplying by a power of 2 so it can just be a left shift.

An example calculation with a 16bit ADC, octave_scale = 4096 (0×1000), covering 16 octaves would be like this:

tune\_word=tune\_table[adc\_val\ \&\ 0x0fff]<<(adc\_val>>12)

The above calculation is essentially what my dspicVCDO does. But with the dspic, a 16bit processor, it doesn’t work out so well. It cannot hold the 24bit tuning word in memory to do the shift so easily.  I had
to separate the 24bit tuning word into a value holding the upper 16bit and another holding the lower 8bits. The dspic does have a multiplier which can operate quickly so I used that. I put the octave multiplier
in a lookup table as well. I then calculate the tuning word in a way similar to:

tune\_word=tune\_table\_MSW[adc\_val\ \&\ 0x0fff]*octave\_table[adc\_val>>12]<<16+

tune\_table\_LSB[adc\_val\ \&\ 0x0fff]*octave\_table[adc\_val>>12]

I do this all with the dspic’s accumulator which is not designed for such operations. but it works out ok by doing a multiply to accumulator operation with the lower 8bits. Then a shift. Then a multiply and accumulate operation with the upper 16bits. Then another shift. Using a 32bit processor would work best since the simplest calculation would work out. The trouble with the dspic comes from the accumulators not being able to load values in easily. That, and they are designed for fixed point fractional values.

if anyone reading this sees a better way to do it with the dspic, I’d be glad to hear about it.

Sound tests

dspic-vcdo-octaves.mp3 - The triangle output playing on several octaves

dspic-vcdo_fm-test.mp3 - the sine output with exponential FM from an Oakley VCO

Schematic

dspic-vcdo_schem-2008-08-26.pdf

Firmware (assembly)

dspic-vcdo_firmware-2008-08-17.zip

Software (lookup table generators)

dspic-vcdo_table_generators-2008-08-12.zip