Wednesday 15 April 2015

An 8-bit static DAC using only 4 digital I/O pins for the Arduino Uno (ATmega328P).

The Arduino Uno lacks a built in DAC, and a common project is to construct an R-2R resistor ladder DAC to output analog signals. The standard design is controlled by 8 I/O pins (8-bit) and can output up to 256 voltage levels. But using a few tricks it's possible to achieve the same number of output levels using only 4 pins.

The technique is to use all the states of a digital I/O pin, which as it's name suggests it can function both as an output and a high-impedance input. The input state also has an optional internal pull-up resistor. By selecting the right biasing circuit these extra pin states (input 'Z' and pull up 'PU') can be translated to additional output voltage levels. If these 4-state pins are connected together as part of a quaternary/4-ary resistor-ladder then the number of output levels grows as 4^n for n-inputs.

The 4-input example design can output approximately 4^4 = 256 levels (fewer after calibration). As always, it's a proof of concept. Don't use this circuit for anything serious (for a list of reasons scroll to the end).

The +12V and -12V are only necessary for the dated opamp.

The DAC Circuit



The basic unit of the circuit is a potential divider on the output of each pin which translates the four possible pin states to equally spaced voltage levels. These 4-level sources are then fed into a quaternary resistor ladder to produce the result.

One divider

The component selection must guarantee that the voltage levels at pinOutput are equally spaced. A shortcut is that if Rb1 and Rb2 are fixed as shown, Rp should be selected such that the voltage at the processor pin is 3.33V when the pull-up is enabled. (Note you can't use Arduino Uno digital pins 0,1 or 13 as these have other connections)

Output Pin States:
Logic mode DDRx PORTx v(pin) v(pinOutput)
'3' output '1' 1 1 5 2.23
'2' pull-up 0 1 3.33 1.95
'1' input (z) 0 0 1.67 1.67
'0' output '0' 1 0 0 1.39

The output from this divider is non-ideal because the equivalent source resistance varies depending on the logic level. To hide this effect the ladder should use much larger resistances, so that the variation constitutes a smaller percentage change.

The spice simulation (below) for the basic output ramp shows a number of discontinuities and glitches, even with exact component values. This is because the ratio between the two resistors in the ladder (680:330) is slightly below the ideal ratio for a quaternary DAC of 2.25:1. This mismatch is intentional, and results in a slight overlap when transitions of the most significant bits occur. These overlaps ensure that there are no large gaps in the output levels and result in better performance after calibration.



Breadboard prototype for the DAC


DC Performance

Measurements of the stable output levels using the internal ADC.


The initial run shows pretty poor linearly, but it's possible to fix most of this through calibration. The ATmega328P has sufficient RAM or flash to store a lookup table which translates between the desired output and the nearest available code.

To calibrate using the 10-bit ADC note that the readings will probably have some level of noise. I measured this to be about 3 LSB RMS for the prototype circuit. To reduce this I averaged 128 readings, resulting in a maximum variation between two successive readings of 0.7 LSB. (But it will only be as linear as the ADC.)

Its no longer possible to see the nonlinearity by eye, the Integral Non-Linearity (INL) plot is more helpful, showing an INL of ±10mV.

The DC performance can be described depending on the intended number of output levels

As an 8-bit DAC:
INL = ±0.65 LSB
DNL = -1 LSB to +0.25 LSB (duplicate codes)

As a 160-level (7.4bit) DAC:
INL = ±0.5 LSB
DNL = No duplicate codes


AC Performance

The AC performance of the DAC is fairly limited due to the parasitic capacitance of the pins and relatively large driving resistances, it's not exactly a candidate for Audio applications! The rise and fall times also vary depending on the transition, which results in visible output glitches. The following plots were produced with a samples rate of approximately 50kSPS.

Triangle waves, the left wave shows the effect of software glitch reduction from the previous post: Reducing glitches in the ladder-DAC.

Sine waves at 500Hz, 1kHz, 2kHz and 4kHz.

Square waves at 25kHz, 50kHz and 100kHz

The visible effect of the glitching can be reduced by RC-filtering the output of the DAC. The result appears much smoother when a filter with a time constant of 25uS is used. The cost of the filtering is bandwidth, square wave outputs above approximately 10kHz are significantly attenuated.




Reasons this DAC isn't practical

  1. Atmel don't want to specify the properties of the internal 'resistor' (it's not a true resistor), giving a wide range of 20k-50k. This circuit was constructed by measuring one particular chip (it's reasonably consistent between pins on the same chip, 2%).
  2. The resistor acts as if connected to a virtual source of 4.77V, not 5V. Unless the virtual source voltage scales linearly with the supply voltage any variation in the supply voltage will unset the calibration.
  3. Temperature drift is undefined.
  4. The useful bandwidth is quite limited.
The 2-pin version might have a use for a crude output level somewhere, maybe, unlikely!

1 comment:

  1. measuring the pull-up "resistors" and applying something like http://www.nerdkits.com/forum/thread/1815/ might provide a small improvement.

    ReplyDelete