Home

Guide no. 84

The Adafruit 935 module gives the FireBeetle 2 ESP32-E, or an Arduino UNO, a real analog output: 4096 levels controlled over I²C, to measure with a multimeter and watch on the Serial Plotter.

By Ada Intelisano · informaticait.it technical team

Download the PDF (A4, 6 pages) Free to print and share, without changes — CC BY-ND 4.0
In short
  • Microchip's MCP4725 turns a number from 0 to 4095 into a steady voltage, not pulses like PWM.
  • The reference is the supply: VOUT = VDD × code ÷ 4096. At 3.3 V one step is about 0.8 mV.
  • It is controlled over I²C at address 0x62 with the Adafruit MCP4725 library; with the ESP32 the module goes on 3V3.
  • With setVoltage(code, true) the value stays in the EEPROM and the chip finds it again at every power-up.
Time: an hourLevel: next stepsBefore: guides no. 8, 14 and 22

Boards have an ADC to read a voltage, but almost never anything to produce one. The PWM in guide no. 37 switches the pin on and off very quickly and the multimeter sees an average, but the real voltage keeps jumping between zero and the maximum. A DAC, on the other hand, holds the voltage you ask for steady on its output. Microchip's MCP4725 does it with 4096 levels, takes its orders over I²C and remembers the last saved value even when it is switched off.

1The parts

  • the Adafruit 935 module with the MCP4725: it comes with a loose six-pin header that you have to solder. Adafruit warns that just pressing it into the holes without soldering does not work (guide no. 70);
  • the FireBeetle 2 ESP32-E with its pins already soldered, and five female-to-female jumper wires;
  • a multimeter (guide no. 8). Instead of the FireBeetle you can use an Arduino UNO, step 8.
New word: DACDigital-to-Analog Converter: it takes a number and turns it into a voltage. It does the opposite of the ADC, which measures a voltage and turns it into a number (guide no. 13).

2The module

  • VIN and GND: power, 2.7 to 5.5 V for the chip. Adafruit recommends the same voltage as the board that controls it: the 10 kΩ pull-up resistors take SDA and SCL up to VIN itself. So with the ESP32, 3.3 V.
  • SCL and SDA: the I²C bus (guide no. 22). The address is 0x62; it becomes 0x63 if you take A0 to VIN or close the “Addr” jumper on the back. This way two modules can share the same bus.
  • VOUT: the output. The same signals, except VOUT, also go through the two STEMMA QT connectors.
The Adafruit 935 board: six pins and two STEMMA QT portson−+optionalterminalMCP472512bitDACVINGNDSCLSDAA0VOUTVINGNDSCLSDAA0VOUTSTEMMA QTpower and I²CMCP472512 bit, I²C− and +: GND and VOUTmultimeter probes herepull-up 10 kΩon SDA and SCLon the back: “Addr” jumper (0x62 → 0x63)informaticait.it

3How much one step is worth

The output voltage follows the supply0 V1 V2 V3 V4 V5 V010242048307240951.252.505.00VDD 5 V (UNO)0.8251.653.30VDD 3.3 V (FireBeetle)code sent to the DACcalculation: VOUT = VDD × code ÷ 4096 (datasheet formula)informaticait.it

The chip has no reference of its own: it uses the supply. The datasheet formula is VOUT = VDD × code ÷ 4096, with the code from 0 to 4095. If VDD changes, the output changes too.

  • At 5 V one step is 1.22 mV (datasheet table); at 3.3 V about 0.8 mV (our calculation).
  • With 4095 the output gets to one step below VDD, not to VDD.
  • Near the ends of the range the accuracy drops: Microchip measures linearity between codes 100 and 4000, and the zero error is not calibrated at the factory.

4Connect and measure

  • Five straight wires: 3V3 → VIN, GND → GND, 22 → SCL, 21 → SDA, 35 → VOUT. Pin 35 is also A3, an analog input: this way the FireBeetle reads back the voltage it asked for.
  • VIN to 3V3, never to VCC: VCC carries the roughly 5 V from USB, the pull-ups would bring SDA and SCL to 5 V as well, and the ESP32 pins cannot take that (guide no. 21).
  • Multimeter on V⎓: black probe in the − hole and red probe in the + hole of the optional terminal block (they are GND and VOUT), or straight onto the GND and VOUT pins.
The wiring: five straight wires and the multimeterRST272−+ESPRESSIFESP32-WROOM-32ERST3V3GNDEN1823192221213140262513VCC3V3GND222115353439361241617on−+optionalterminalMCP472512bitDACVINGNDSCLSDAA0VOUT1.65VV⎓COMVΩ3V3 → VINGND → GND22 → SCL21 → SDA35 (A3) → VOUTAdafruit 935 (MCP4725)multimeter on V⎓FireBeetle 2 ESP32-Einformaticait.it
✓ A first testThe multimeter shows a reading even before the sketch: at power-up the chip loads the code saved in its EEPROM, which from the factory is half scale (datasheet). If nobody has changed it, you see about 1.65 V.

5Four voltages

// The MCP4725 DAC: four voltages, one every 4 seconds. Measure them with the
// multimeter between VOUT and GND; A3 reads them back. Library: Adafruit MCP4725.
#include <Arduino.h>
#include <Adafruit_MCP4725.h>

const byte ADDRESS = 0x62;      // Adafruit 935: 0x62 (0x63 with the jumper closed)
#ifdef ESP32
const float VDD = 3.3;          // FireBeetle 2 ESP32-E: module on 3V3
#else
const float VDD = 5.0;          // Arduino UNO: module on 5V
#endif
const int CODES[] = {0, 1024, 2048, 4095};   // from 0 to 4095: 12 bits

Adafruit_MCP4725 dac;

void setup() {
  Serial.begin(115200);
  if (!dac.begin(ADDRESS)) {
    Serial.println(F("MCP4725 not responding: check the wires and the address"));
    while (true) delay(1000);
  }
}

void loop() {
  for (int code : CODES) {
    dac.setVoltage(code, false);             // false: the EEPROM is left alone
    delay(50);
    Serial.print(F("code "));
    Serial.print(code);
    Serial.print(F("  about "));
    Serial.print(code * VDD / 4096, 2);      // the datasheet formula
    Serial.print(F(" V  A3: "));
#ifdef ESP32
    Serial.print(analogReadMilliVolts(A3));  // millivolts
    Serial.println(F(" mV"));
#else
    Serial.println(analogRead(A3));          // from 0 to 1023: about code / 4
#endif
    delay(4000);
  }
}

Install the Adafruit MCP4725 library. dac.begin(0x62) returns false if the chip does not answer; setVoltage(code, false) changes the output without touching the EEPROM. Open the Serial Monitor at 115200 baud: for each code you get the expected voltage and the one read on A3.

✓ What you should seeEvery four seconds the multimeter goes from almost 0 to about 0.83, 1.65 and 3.3 V (calculated with VDD at 3.3 V), and the Serial Monitor prints numbers close to those.
If it doesn't work
  • “MCP4725 not responding”: SDA and SCL swapped, VIN not connected, or the address is 0x63 because the “Addr” jumper is closed.
  • The multimeter reads a little less than expected: measure the 3V3 of the board and redo the sum with that value instead of 3.3.
  • A3 and the multimeter do not agree: the ESP32 ADC is less accurate than a multimeter (guide no. 14). Trust the multimeter.

6A wave on the Plotter

// A wave from the MCP4725 DAC and what A3 reads back, both on the Serial Plotter.
#include <Arduino.h>
#include <Adafruit_MCP4725.h>

const byte ADDRESS = 0x62;      // Adafruit 935
const bool SINE = false;        // true: sine wave; false: triangle wave
const int POINTS = 32;          // points in each period

Adafruit_MCP4725 dac;
int point = 0;

void setup() {
  Serial.begin(115200);
  if (!dac.begin(ADDRESS)) {
    Serial.println(F("MCP4725 not responding: check the wires and the address"));
    while (true) delay(1000);
  }
}

void loop() {
  int code;
  if (SINE) {
    code = 2048 + 2047 * sin(TWO_PI * point / POINTS);
  } else {                                     // up for half a period, then down
    int half = POINTS / 2;
    int rise = point < half ? point : POINTS - point;
    code = rise * 4095L / half;
  }
  dac.setVoltage(code, false);
  delay(2);
#ifdef ESP32
  Serial.print(F("Sent_mV:"));
  Serial.print(code * 3300L / 4096);           // module on 3V3
  Serial.print(F(",A3_mV:"));
  Serial.println(analogReadMilliVolts(A3));
#else
  Serial.print(F("Sent:"));
  Serial.print(code / 4);                      // in A3 counts: 1023 = 5 V
  Serial.print(F(",A3:"));
  Serial.println(analogRead(A3));
#endif
  point = (point + 1) % POINTS;
  delay(40);
}

About every 40 milliseconds the DAC takes a step: 32 points to go up and down. Open the Serial Plotter at 115200 baud. With SINE = true the wave becomes a sine wave, centered on half the supply. The Plotter in IDE 2 shows the last 50 lines, a little more than one and a half waves.

✓ What you should seeTwo triangles, one on top of the other: Sent_mV is the voltage requested, A3_mV the one read back. The multimeter is slow and struggles to follow the wave: that is normal.

7A value for power-up

With dac.setVoltage(2048, true) the code also goes into the EEPROM, and the chip reloads it at every power-up: the output starts from that value straight away, even before the sketch runs. Handy for a reference voltage that must always be there.

Warning
  • An EEPROM write takes up to 50 ms (datasheet) and the number of writes is not unlimited: do it once, in setup or when a button is pressed, never in the loop.

8With the Arduino UNO

  • VIN to 5V, GND to GND, SCL and SDA to the SCL and SDA pins next to AREF, VOUT to A3. The output goes from 0 to 5 V.
  • The sketch is the same: it compiles for the UNO and prints the A3 reading from 0 to 1023. The DAC and the UNO's ADC use the same 5 V as their reference, so the reading is about code ÷ 4 even if the USB port gives a little less than 5 V (our calculation).
  • No jumper wires: the STEMMA QT cable carries power and I²C, with male plugs for the UNO and female sockets for the FireBeetle. Red V+, black GND, blue SDA, yellow SCL; VOUT stays on the header.
Try it yourself
  • A slow ramp, from 0 to 4095 in ten seconds, to follow on the multimeter.
  • Read a potentiometer (guide no. 36) and copy its position to the DAC.
  • Measure the output with 0 and with 4095: how far is it from 0 V and from VDD?
✓ What you learned
  • a DAC gives a steady voltage, not pulses;
  • VOUT = VDD × code ÷ 4096: the reference is the supply;
  • with true the value stays in the EEPROM, but it should be written rarely.
Sources: Microchip, MCP4725 12-Bit Digital-to-Analog Converter with EEPROM Memory, datasheet DS20002039F (2023; same values as DS22039D) · Adafruit, MCP4725 Breakout Board (935): product page, guide “MCP4725 12-Bit DAC Tutorial”, schematic and Eagle files of the STEMMA QT version; Adafruit_MCP4725 2.0.2 library · DFRobot, FireBeetle 2 ESP32-E (DFR0654): wiki and dimensioned drawing · Arduino, language reference: analogRead() and analogWrite(); Arduino IDE 2, Serial Plotter · informaticait guides no. 8, 13, 14, 22, 36, 37 and 70

Useful products

Other guides

All our guides →
Loading...
Back to top