Linearizing an RC Lowpass DAC
I recently worked on a project with my friend Jie to make a circuit sticker which can record and play back an analog signal that it has seen. With the goal of keeping the work as simple as possible we started from the existing microcontroller sticker, which is based around the ATtiny85 microcontroller. Since that microcontroller lacks a DAC I had to add one to get an analog signal out for playback.
A really simple way to make an analog signal from a fast digital signal is to feed it into an RC low-pass filter made from a resistor and capacitor like this:
On the left there is a pulse-width-modulated (PWM) signal from the microcontroller and on the right is the analog waveform we wanted. The capacitor and resistor are just the right size such that the capacitor cannot charge and discharge fast enough to follow the PWM waveform, but it can react fast enough to generate signals at the maximum frequency we care about. In the case of this sticker that frequency is about 1o hertz. I experimented and picked values of 390 Ohms for the resistor and 10 microfarads for the capacitor to meet that requirement.
Here is what the output looks like while linearly increasing the duty cycle of the PWM signal going in. Note the snake-like error. We need a flat ramp so that we can know the duty cycle is proportional to the output voltage. Let’s see if we can do something about that by being a tiny bit clever.
I started by taking the picture of the bad ramp waveform on my oscilloscope shown above with my phone. Then on my laptop I ran it through a few steps of manual cleanup in Gimp and wrote a quick program in Processing to generate this image:
With that done I wrote a new program to walk across this image and generate a lookup table in assembly code. Each value in the lookup table is a single byte corresponding to the PWM duty cycle which should be set to obtain the output voltage at the index. So to get an output at 50% of the supply voltage the code looks at entry 127 in the lookup table and sets the PWM duty cycle to the value there.
With the fancy new lookup table our linear lamp now looks mostly linear! Yay!
You can find the entire firmware for the sticker on GitHub here.