Wiring

Wiring the MCP4728 to communicate with your microcontroller is straightforward thanks to the I2C interface. For these examples, we can use the Metro or Arduino to update the DAC. The instructions below show a Metro, but the same applies to an Arduino

  • Arduino 5V to MCP4728 VCC (red wire) if you are running a 5V board Arduino (Uno, etc.). If your board is 3V, connect to that instead.
  • Arduino GND to MCP4728 GND (black wire)
  • Arduino SCL to MCP4728 SCL (yellow wire)
  • Arduino SDA to MCP4728 SDA (blue wire)
  • Multimeter Positive Lead to MCP4728 VA, VB, VC, and VD in sequence
  • Multimeter Negative Lead to GND

Library Installation

Once wired up, to start using the MCP4728, you'll need to install the Adafruit_MCP4728 library. The library is available through the Arduino library manager so we recommend taking that approach.

From the Arduino IDE, open up the Library Manager:

Click the Manage Libraries ... menu item, search for Adafruit MCP4728, and select the Adafruit MCP4728 library and click Install:

Basic Reading Example

Open up File -> Examples -> Adafruit MCP4728 -> basic_demo and upload to your Arduino wired up to the sensor.

One you've uploaded the sketch to your board, measure the voltages on each of the four channel outputs and verify that they're within the ranges given for the logic level of your microcontroller.

The values will differ slightly for you but they should be close to the following for a 5V logic level device such as a Metro 328 or Arduino Uno:

  • 5V on VA
  • 2.5V on VB
  • 1.25V on VC
  • 0V on VD

For a 3.3V logic level device such as a Metro M4 or Feather M0 the voltages should be close to:

  • 3.3V on VA
  • 1.65V on VB
  • 0.825V on VC
  • 0V on VD

Basic Example Code

// Basic demo for configuring the MCP4728 4-Channel 12-bit I2C DAC
#include <Adafruit_MCP4728.h>
#include <Wire.h>

Adafruit_MCP4728 mcp;

void setup(void) {
  Serial.begin(115200);
  while (!Serial)
    delay(10); // will pause Zero, Leonardo, etc until serial console opens

  Serial.println("Adafruit MCP4728 test!");

  // Try to initialize!
  if (!mcp.begin()) {
    Serial.println("Failed to find MCP4728 chip");
    while (1) {
      delay(10);
    }
  }

  mcp.setChannelValue(MCP4728_CHANNEL_A, 4095);
  mcp.setChannelValue(MCP4728_CHANNEL_B, 2048);
  mcp.setChannelValue(MCP4728_CHANNEL_C, 1024);
  mcp.setChannelValue(MCP4728_CHANNEL_D, 0);
}

void loop() { delay(1000); }

Vrefs and You

Reference Voltages (Vref for short) are an important topic to understand when working with DACs. The Vref determines the top of the voltage range that the DAC will output. This is because the DAC starts with the Vref as the output voltage and if the DAC settings specify a lower voltage, the internal circuitry will reduce the Vref voltage down to the specified amount.

If your Vref is 5V, you will be able to have the DAC output voltages from 0V up to 5V. Similarly if you are using a 3.3V source as your Vref, you will be able to scale the DAC's output voltages from 0V to 3.3V. If you need your DAC to output a voltage, your Vref will need to be the same or a higher voltage.

The MCP4728 can choose one of two sources for its Vref. The first is the VCC pin which can take a supply voltage between 2.7V and 5.5V. This will match the output range of the DAC to the logic level of your microcontroller.

The second option is to use the 2.048V Vref in the MCP4728 itself. Normally this would mean the highest voltage you can output is 2.048V however when using the internal Vref, you can optionally apply a 2X gain to the Vref, doubling it and allowing your output voltages to range from 0V to 4.096V

Vref Example

The second included demo has an example of how to set the Vref and Gain for a channel. Open up File -> Examples -> Adafruit MCP4728 -> vref_demo and upload to your board wired up to the sensor.

With the exception of Channel A, the examples below show how using the same value for the channels but  different Vref values will change the output voltage for the channel.

Use your multimeter on the channel's voltage pin to verify the values.

Channel A

Download: file
// Vref = MCP_VREF_VDD, value = 0, 0V
  mcp.setChannelValue(MCP4728_CHANNEL_A, 0);

The value for Channel A is being set to 0, so the Vref doesn't matter, the voltage on the VA pin will be 0V either way.

Channel B

Download: file
// value is vref/2, with 2.048V internal Vref and 1X gain
  // = 2.048/2 = 1.024V
  mcp.setChannelValue(MCP4728_CHANNEL_B, 2048, MCP4728_VREF_INTERNAL,
                      MCP4728_GAIN_1X);

For Channel B we're using the Internal 2.048 Vref with the 1X gain, so the Vref is 2.048V. The value is set to 2048 or Vref/2, so the resulting voltage on the VB pin is half of 2.048V, 1.024V

Channel C

Download: file
// value is vref/2, with 2.048V internal vref and *2X gain*
  // = 4.096/2 = 2.048V
  mcp.setChannelValue(MCP4728_CHANNEL_C, 2048, MCP4728_VREF_INTERNAL,
                      MCP4728_GAIN_2X);

Channel C uses the 2.048V internal Vref with a 2X gain, bringing the Vref up to 4.096V. The value is again set to Vref/ 2, so the resulting voltage on the VC pin is 2.048V

Channel D

Download: file
// value is vref/2, Vref is MCP4728_VREF_VDD(default), the power supply voltage (usually 3.3V or 5V)
  // For Vdd/Vref = 5V, voltage = 2.5V
  // For 3.3V, voltage = 1.65V
  // Values will vary depending on the actual Vref/Vdd
  mcp.setChannelValue(MCP4728_CHANNEL_D, 2048);

Finally, channel D is using the power supply voltage as Vref, so with the 5V logic level of an Arduino Uno or similar Vref will be 5V. Just like the previous examples, the value for Channel D is set to Vref/2 but because the Vref in this case is 5V, the resulting voltage on pin VD is 2.5V. 

Note that if you are using a 3.3V logic level board, Vref will be 3.3V so to voltage on VD will be 1.65V

Vref Example

// Demo for configuring the Vref of the MCP4728 4-Channel 12-bit I2C DAC
#include <Adafruit_MCP4728.h>
#include <Wire.h>

Adafruit_MCP4728 mcp;

void setup(void) {
  Serial.begin(115200);
  while (!Serial)
    delay(10); // will pause Zero, Leonardo, etc until serial console opens

  Serial.println("Adafruit MCP4728 test!");

  // Try to initialize!
  if (!mcp.begin()) {
    Serial.println("Failed to find MCP4728 chip");
    while (1) {
      delay(10);
    }
  }
  Serial.println("MCP4728 Found!");
  /*
   * @param channel The channel to update
   * @param new_value The new value to assign
   * @param new_vref Optional vref setting - Defaults to `MCP4728_VREF_VDD`
   * @param new_gain Optional gain setting - Defaults to `MCP4728_GAIN_1X`
   * @param new_pd_mode Optional power down mode setting - Defaults to
   * `MCP4728_PD_MOOE_NORMAL`
   * @param udac Optional UDAC setting - Defaults to `false`, latching (nearly).
   * Set to `true` to latch when the UDAC pin is pulled low
   *
   */

  // Vref = MCP_VREF_VDD, value = 0, 0V
  mcp.setChannelValue(MCP4728_CHANNEL_A, 0);

  // value is vref/2, with 2.048V internal Vref and 1X gain
  // = 2.048/2 = 1.024V
  mcp.setChannelValue(MCP4728_CHANNEL_B, 2048, MCP4728_VREF_INTERNAL,
                      MCP4728_GAIN_1X);

  // value is vref/2, with 2.048V internal vref and *2X gain*
  // = 4.096/2 = 2.048V
  mcp.setChannelValue(MCP4728_CHANNEL_C, 2048, MCP4728_VREF_INTERNAL,
                      MCP4728_GAIN_2X);

  // value is vref/2, Vref is MCP4728_VREF_VDD(default), the power supply
  // voltage (usually 3.3V or 5V) For Vdd/Vref = 5V, voltage = 2.5V For 3.3V,
  // voltage = 1.65V Values will vary depending on the actual Vref/Vdd
  mcp.setChannelValue(MCP4728_CHANNEL_D, 2048);

  mcp.saveToEEPROM();
}

void loop() { delay(1000); }
This guide was first published on Jan 07, 2020. It was last updated on Jan 07, 2020. This page (Arduino) was last updated on Jan 27, 2020.