Arduino Nano based DCO

Motivated by the thread The Design of the Roland Juno Digitally Controlled Oscillators I dug more into this topic and built an Arduino Nano based DCO. The frequency it produces is quite accurate over several octaves. Frequency is controlled by a 16-bit timer overflow interrupt that counts every cycle of the 16 mhz clock. Amplitude compensation is done by DAC MCP4728. Ramp output is buffered and amplified to 10Vpp.

Note: it only works on Arduino Nano/Atmega 328p because of the timer interrupts

Currently MIDI and CV control is missing, I will add this later on. I uploaded the source code and schematics to GitHub - polykit/dco: Arduino based DCO

Maybe I will build a module for my Kosmo setup. It clearly has some advantages regarding frequency stability on temperature changes. Also some additional waveshaping would be nice.

Happy oscillating (and a happy new year)!

Edit: updated schematics, corrected to 10Vpp

15 Likes

Nice! I wonder how many voices a nano could output in parallel using this approach. Have you tried to use all 4 channels of the MPC4728 at the same time?

Quite a few arduino-s support interrupts, so I would be surprised if one could not run this on another one, like an Uno or Mega.

3 Likes

No, not yet. There is only one 16-bit timer interrupt so it needs to be handled all by one overflow counter. Also calculation of cycles has to be adjusted and all frequencies need to be taken into account. Sounds a bit complicated but doable. I would say limitation is amount of I/O pins or calculation gets too heavy.

Yes, but they all work a bit different. One need to check the datasheet of the microcontroller and adjust the routine that handles the overflow.

3 Likes

Woah, this is really great! Low part count as well. Where does the v/oct input go in that circuit, I don’t see it labelled.

It’d be absolutely amazing if you could drive 3/4/5 of these oscillators off of a single Arduino, then you could add a small “spread” knob to build really thick supersaws in a single circuit.

Although I could be wrong, I wouldn’t worry about including waveshaping inside the circuit itself since that can be done by other modules in the setup.

If you want to make this into a Kosmo board/panel, sign me up for one!

3 Likes

I now added simple 1V/oct control but I’m not very happy with it. The built-in 10-bit ADC of the Arduino is not really suited for this task. I will add some 12-bit or even 16-bit ADC. It makes no sense to have an accurate oscillator when control voltage is flappy.

5 Likes

cool work,

given that a Nano is cheaper than a 3340 and requires a lot less parts, it would be easy to justify just using multiple nanos and keeping it simple rather than trying to do it all in one…

Gona keep a close eye on this one :wink:

3 Likes

Interesting project and I look forward to how it develops — not sure it’ll end up being “a lot less parts” than a 3340 though. Once you figure in the CV inputs, tuning controls, external ADC, and the shaping circuitry to add pulse and triangle outputs, it’ll look a lot less simple.

@jkb, are you doing the exponential conversion in hardware or software? Added: Guess it has to be in software, otherwise you’d need way more than even 16 bit digitization for decent pitch resolution.

2 Likes

Yes, it’s done in software. That is exactly the hard part when it’s done in hardware.

I will at least add pulse out because there is one op-amp not in use. I ordered some ADS1x15 ADCs for CV input, let’s see where it goes from there.

4 Likes

I added proper voltage control with ADC ADS1115, it’s a 16-bit AD-converter, input covers a range from 0-10V. There is also pulse out added, all four op-amps are now in use.
I also played with driving multiple oscillators (they are not really oscialltors, I don’t know how to call them) with one Arduino but it’s tricky. I will give an update when there is any progress on this topic.

6 Likes

Looks great so far!

Inspired me to have a play and I thought it would be a good challenge to try to copy the idea “blind”.

I didn’t have the ADC/DAC parts on hand (they have arrived today though so when I get time I’ll play) so I thought I’d see what I could do with the internal 10 bit ADC.

Due to lack of time I have only focused on the arduino side - getting the square wave output from it but not building the actual DCO part yet. Since I had the low resolution to play with I tried using just 0-5V control, but adding in switchable octaves. Since I didn’t want to play around with the interrupts too much myself, I used the TimerOne library to simplify it.

Pretty happy with what I got so far, though I will definitely change to use the ADC and DAC like you have. I was thinking of using the extra channels of the ADC to add control knobs and possibly a second CV input, avoiding the need to do analogue mixing of the voltages. Two CV inputs and one “course” and one “fine” tuning knobs would be good. Perhaps one CV could be 0-10V and the other a full +/-10V(?). Just thinking out loud really.

Anyone interested, here is my code so far: https://github.com/porl/duiCO.git

NOTE: I use PlatformIO to upload the code to the Arduino, but if you use the Arduino IDE you should be able to just take the src/main.cpp file and rename it to main.ino or whatever and remove the #include <Arduino.h> line from the top. Make sure you have the TimerOne library available to the IDE.

Designed with an Arduino Micro. It takes a 0-5V CV input on pin A0 and outputs the pulses on pin 9 (50% duty cycle). Pin 2 is octave up and 3 is octave down. Switching both essentially cancels each other out, but I intended to use an On-Off-On SPDT switch between them, with pull-down resistors to ground.

You can modify the constants at the top to change the response. I have a default frequency at 0V input CV (with no octave switching) as 27.5Hz. This corresponds to A0. I am reusing some of this code for a low speed clock for a sequencer module so it can in theory go down as far as you like. Not sure of its maximum frequency.

2 Likes

Very nice! Do you get an accurate frequency with the TimerOne library over the whole range? I needed to adjust that especially for low frequencies. I like the addition with the octave up/down switch.

I recently came up with another DCO based on the Raspberry Pi Pico using its PIO functionality: https://lookmumnocomputer.discourse.group/t/raspberry-pi-pico-dco

There I used PWM instead of a DAC for amplitude compensation. This should also work for the Arduino.

I also ommited ADC completely because of its inaccuracy and went for MIDI input instead. I even tried 16-bit ADC and moving average smoothing on the input signal but was not very happy with the results.

I’ll be honest, I’m not sure how accurate it is. In my current house I don’t have much room to play with this stuff, so it is pretty much just take-it-as-I-can on the dining table for playing with this. My eurorack synth is all boxed up away so I can’t really plug this into anything. I’ve just been using a small piezo speaker to listen to the raw output from pin 9 haha. At least to my ears things like the octave switch jump pretty well, so it is at least (to my ears) close for a few octaves. Don’t have a digital scope etc. to find the real frequency to check beyond that yet though. Interesting that you mentioned issues with the low range - I was expecting issues with the higher frequencies. If you have a chance, would you mind trying the code I did and see if you still have the inaccuracy?

I noticed a lot of issues with the tracking at first, but I believe that is largely due to being on a breadboard - touching some of the wires caused the frequency to jump around a fair bit so I believe it is sensitive to the connections moving and so on.

Did you try with the ADC on a stripboard or pcb? I wonder if the issues you had are related to the breadboard.

I hope that the Arduino DCO idea can still work - I’m happy to use MIDI for things like keyboard input, but I have an Analogue Systems “French Connection” Ondes Martenot style controller (https://www.soundonsound.com/reviews/analogue-systems-french-connection) which was what got me into the whole modular thing in the first place, and would love to use that through a full DIY system some day!

How does the Raspberry Pi Pico go for development so far? I’m definitely curious to play with it.

The timer interrupt only counts up to 65535 on an Arduino. So for small frequencies 16000000hz/frequency>65535 it needs to restart the timer interrupt which costs some additional CPU cycles and will change frequency unless you correct it. I will definitely look at the TimerOne library, from a first glimpse it looks very promising.

Yes, sure, I will definitely try it out and give you some feedback.

That might be a problem. But in general ADCs/DACs tend to be not that accurate. They often have gain or offset errors or problems with linearity. I tried something like this for smoothing input values: https://www.arduino.cc/en/Tutorial/BuiltInExamples/Smoothing
I also learned about gain/offset error correction: http://ww1.microchip.com/downloads/en/DeviceDoc/90003185A.pdf
And also using a lookup table for calibration is an option.
I mean small changes in the input readings will lead to a noticable frequency change.

I think it is very nice and brings a lot of features. PIO is a great addition and is even more accurate than the timed interrupts. I had problems with the ADC though, I found it not usable, see Raspberry Pi Confirms It Is Investigating a Flaw in the Raspberry Pi Pico, RP2040 ADC - Hackster.io
Also USB HID/MIDI support is very good. I definitely recommend adding a reset button to programm the Pico.

What a shame about the flaw found in their ADC! Such a new platform, I bet that must feel like a letdown to them.

Wondering if there is a better way to go about things. It feels like we have access to chips far more powerful and flexible than they did during the design of the Juno, but it feels like we are likely to keep hitting road blocks with this approach. It seems like there should be something that can be used to build a “simple” DCO for the Kosmo format (or Eurorack etc. of course).

Any ideas on another approach if you feel these platforms might not work in that way?

For sure the engineers designing the Juno were brilliant if you see what components they had and no internet at the time. But I think the input signal path (keyboard, arpeggiator, midi) of the Juno 106 is all digital so they didn’t had that problems. I doubt there were good ADCs/DACs at that time compared to today.

In general I think it can be done even with what we have now. It just means a lot of fiddling and testing. A lot can be done in software because we have powerful processors.

Ah, good point - I didn’t consider the fact that the Juno didn’t need to worry about converting from an analogue voltage first before doing its digital stuff.

I was all spec’d up just now to hook up my old oscilloscope to the output to look properly at the timing etc. as I just got the replacement probes in the mail today. Unfortunately the scope has been in storage so long that I got that distinctive burning electronics smell and sad smoke coming out of it. So long story short, I still don’t know how accurately this thing is tracking.

My next step will be to make some buffer to try to get the signal into a state I can record it on my computer then look at the wave there.

1 Like

Quick update:

Added the AD51115 to the input and things seem to track reasonably well on my 1V/oct keyboard for at least the four octaves it uses.

Note that I haven’t done anything “scientific”, this was just using my ears.

So now I have the basic “core” of the oscillator. Next I will try to get the MCP4728 working and then try to drive a “real” oscillator core rather than just listening to the Arduino’s square output directly.

Fingers crossed!

3 Likes