Tuesday, October 20, 2015

A bipolar analog I/O for Arduino Due

Giovanni Carrera rev. 20/10/15
The aim of this work is to convert the unipolar AD and DA converters of Arduino Due into bipolar with appropriate circuits. Bipolar analog inputs and outputs are required in those cases in which the signals can take on also negative values; they have as reference a more stable zero voltage or ground and not the half of the supply voltage or something like that.
With the use of the proposed circuits, an Arduino Due system can be easily employed in replacing an analog PID type controller, with greater potentiality and flexibility. Acquisition systems, low frequency oscilloscopes or spectrum analyzers and waveform generators are examples of additional applications.

ADC input bipolar

We begin to see how to convert a unipolar analog input into bipolar. A simple voltage divider, such as that illustrated in Figure 1, does this job well.  Using the Ohm’s law we can easily obtain the following formulas:
Assuming that the output current is zero, the current through R1 and R2 will be that shown in the formula (1). In these conditions, the output voltage Vo is that of the formula (2).
Suppose you want an input voltage V2 of ± 3.3V which should correspond to 0 and 3.3 V of output voltage. It can be shown that this statement is satisfied if you put V1 equal to 3.3 V. By the formula (2), in fact, we have that if V2 = -3.3 V, V0 = 0 only if R1 = R2  and in the case where V2 = +3.3 V, V0 = 3.3 V. So that the circuit meets our conditions if we set V1 = + 3.3V = Vref, V2 = Vi (bipolar input) and R1 = R2. In order to get closer to the theoretical model of the divider we must use an operational amplifier with high input impedance and unity gain, like the one shown in Figure 2.
This type of operational amplifier can also work with single power supply up to output voltage ​​close to zero, although starts to saturate to about 1 .5 V below the supply voltage, namely + 3.5V in our case. This non-linearity becomes a merit because we want to limit the input of the ADC. The voltage on input pins with respect to ground, as we can see on CPU datasheet, must be in the range: -0.3V to +4.0 V, otherwise a permanent damage can happen. For additional safety, a resistor of 100 was also added in series to the output, as shown in Figure 7.

DAC output became bipolar
To produce a bipolar signal is used a non-inverting operational amplifier connected in a particular way, as shown in Figure 3, i.e. with an offset Vr on the inverting input. In fact, a non-inverting amplifier has the end of R1 connected to ground and, in the case R1 = R2, has a gain G = 2.
The theory says that we can’t generate negative signals without a negative generator, so this op amp requires also a complementary negative supply.
Applying the theoretical model of the operational amplifiers is obtained the following relation:
Vo = Vi – I*R2  = Vi*(1 + K) – K*Vr
Where K = R2 /R1. Our conditions are as follows: if Vi = 0  than Vo = -Vr = -3.3 V and if Vi = + 3.3V than Vo = Vr = +3.3 V. They are satisfied only if K = 1, that is, with equal resistors that give a gain G = 2.

The Arduino Due DAC
Arduino Due does not have an analog output voltage from 0 V to Vref,  this topic has been widely discussed in my post “How to modify analog output range of Arduino Due”. The circuit of figure 5, with a gain equal to G = 3.3/2.2 = 1.5, reaches the desired output range from 0 to 3.3V.
Anti-aliasing filter
A useful thing is to put to the input a low-pass filter to prevent noise aliasing which may arise if the input signal is not band-limited. In figure 6 we can see the scheme of an active low-pass Sallen-Key filter, second order and unity gain and the formula to calculate its cut-off frequency.

In figure 7 we see the complete circuit scheme, from left to right we can see: the low-pass filter (R1, R2, C1, C2 and U2B), the bipolar to unipolar input circuit (R3, Rp1, R4 and U1A) , the differential amplifier (R8, R9, R10, R11, R6, Rp2, R7 and U1B), the unipolar to bipolar output circuit and the negative power supply (C7, C6 and U3).
The low pass filter, with the values shown in the diagram has a cut-off frequency of approximately 220 Hz. The capacitor C1 = 2*C2 is realized with two parallel capacitors, everyone with the capacity equal to C2.
The trimmer Rp1 must be adjusted to obtain on the U1A output a voltage equal to Vref/2 = 1.65V with zero input. The typical value of Arduino Due Vref is 3.3 V, but should be measured with a precise DVM.
To calibrate the trimmer Rp2, it is necessary to output to the DAC the minimum value, that is zero, and act on Rp2 until bringing to a minimum the output voltage of U1B. These operational, powered with single power supply, fail to give a zero output true, but there are very close (a few mV).
Using battery power, the simpler and more economical solution to generate the negative voltage of -5 V is to use an ICL7660 which is a DC/DC charge pump converter. It has the advantage of requiring only a pair of electrolytic capacitors, but has as a disadvantage that the output voltage is not controlled and is reduced by increasing the current. In our case, the dual op amp LM358, in addition to the advantages already described, have also low power consumption.

The practical realization
In Figure 8  you can see the prototype realized on a breadboard card.

The filters require passive components of good precision, a tolerance of ± 1% is readily available for resistors but the capacitors have tolerances around 10-20%, so they should be selected using a capacitance meter.

The tests

Test of input circuits
In addition to the theory, necessary for the development of a project, it is often required to make even the experimental tests. Static measurements carried out on the prototype, with the purpose of seeing his behaviour at the limits of the input/output range, have given very interesting results.
For test purposes, I wrote a dedicated program (see the software section), which is used also to calibrate the analog output. The supply voltages measured on my system are: Vref = 3.310, V+5 = 5.032 and V-5 = -4.975 volts.
The first tests have been quite disastrous in regard to voltage values below one volts output I saw numbers that varied greatly and randomly. From a search on the Internet, I discovered that the problem was caused by the IDE Arduino (version 1.5.3), which had bugs in their function analogRead () for Arduino Due. I recompiled my program with the latest version 'nightly' and, fortunately, things are back to normal.
Overcome the drawbacks mentioned, the results of the linear regression were very good with a correlation of 0.9999981. With the calibration results, we can convert the number N output from the converter:
Vi = N* 0.001609 – 3.3097 (3)
This is precisely the formula to be used in the program to obtain the input voltage expressed in volts. With it one can easily derive the actual input range that goes from -3.310 V (N = 0) to 3.278 V (N = 4095). To make these calculations I used Excel, but that's okay any spreadsheet or least squares program.

Tests of output circuits
With a Vref = 3.31 V, and the power supply of 5.032 V, I measured a minimum voltage output by the DAC of 0.553 V and a maximum of 2,766 V, values very close to 1/6 and 5/6 of the Vref.
The measures on my Arduino Due of the output circuits formed by the differential amplifier U1B, and the unipolar to bipolar converter U2a also gave very good results with a correlation of 0.9999998. With the calibration results, we can get the number to be sent to the DAC to obtain the output voltage Vo:
N = INT(Vo*623.0613 + 2053.7584) (4)
Obviously the formulas (3) and (4) are valid for my system and are obtained with the calibration measurements.
At the software level we must treat the signals to be sent to the DAC or to be read by the ADC as 12 bits unsigned integers, with a minimum of zero, corresponding to -Vo and a maximum of 212-1 = 4095, corresponding to +Vo. The ideal zero volts will be equal to 2048. In essence, we have to work on integers: from -2048 (-Vo) to +2047 (+ Vo) and add 2048 before sending them to DAC or subtract 2,048 readings of ADC. If we want to be more precise it is necessary to use the formulas (3) and (4) obtained by linear regression of a number of measures that, in my case, ranged from 7 for the DAC  to 10-16 for ADC.

The software
For tests on Arduino Due AD and DA converters, I wrote a simple program that sends to the DAC0 values of N according to the table: {0,512,1024,2048,3072,3584,4095}. They are generated in succession, each time we press the button SSbutton connected to pin 32. At the same time are printed on the LCD display of my system both the number sent to the DAC, both the number read from the ADC on the channel A0. In the absence of the display, with minor changes to the program, these data can be printed on the monitor of the Arduino IDE via serial communication.

  1. "Active Low-Pass Filter Design”, Texas Instruments application Report SLOA049B - September 2002
  2. “Atmel ARM Cortex-M3 Product Family (SAM3)”, Atmel application note 42187A−SAM−10/2013


  1. Isn't it possible to combine the input low-pass filter (U2B) and offset (U1A), so only a single op amp is required? And also possible to combine the output offset (U1B) and low pass (U2A), so it also uses only a single op amp?

  2. Dear Mr.Carrera,
    i try to figure out how to push up DAC output from the esp32 0-3.3v to 0.8-4.1V range. so to increase (or plus offset) DAC output by 0.8V permanently. sorry i'm not being trained in electrical terms. i would like to control e-bike hub motor with it and the motor controller (throttle input) requires this 0.8-4.1v range.
    thanks, levente

  3. liklev, simply set Vp = 0 volts (ground it, or you may choose to retain the ability to adjust the 0.8 volt offset slightly by omitting only R7 = 0 ohms and retaining R6 and Rp2.)

  4. thanx Rod, i suppose you talk about Fig.5 with the single opamp setup.
    by this i should remove just the 1.3kohm R7 and leave the rest as it is?
    would it be linear all along and just shift up the DAC by set voltage on VP?
    anyhow i will start to read up my books on opamps, till now i had no idea this is the tool i need.

  5. hi Rod,
    meanwhile i found the op-amp setup i guess accurate fit to my purpose.
    a 2-stage "summing amplifier" where the 1st stage doing the adding-up of DAC and 0.8V, while the 2nd stage inverting back the result to positive voltage.
    it does not "stretch" the range, just a+b=c.
    simulation show me that i need higher than 5V supplies (+10/-10) for op-amps to work accurately and may be can use all resistor 10k or even 100k.
    i found some charge-pump circuitry as well which can invert positive voltage to negative to feed the op-amps +/- from batteries.
    thanx again

  6. liklev, note that Figure 7 above includes an ICL7660 charge-pump voltage converter supplying +5 and -5 volts to the LM358 op amps, so they have an output voltage range of +4.25 to -4.25 volts (the output voltage range Vcc-1.5 volts specified on the Texas Instruments LM358 spec sheet). This accurately covers the 0.8 to 4.1 volt range you state you need. So it is not necessary to further increase their supply voltage.