MCP4922

The MCP4922 is a dual analogue DAC - a buffered voltage output device controlled from an SPI serial interface which outputs a proportion of the input voltage. Since it's a 12bit device its resolution is Vref/4096. So you can choose very fine steps dividing down from the reference (the supply voltage).


This device is similar to the other DAC chips: MCP4725, MCP4726, MCP4728.

There are three important differences:

  1. Uses SPI.
  2. NO EEPROM.
  3. NO Internal Reference.

So the consequences of this are:

  1. It is far faster than the other DACs mentioned.
  2. It can not remember a voltage through power down/up.
  3. Uses Vdd as the reference voltage.
TIP: The MCP4822 has an internal voltage reference (c.f. MCP4728).

This chip has the same synchronisation feature found in the MCP4728 (the LDACn control signal) which allows you to update the outputs simultaneously.

MCP4922 Block Diagram

mcp4922 block diagram
                            [Source: Datasheet]

MCP4922 Pinout

The chip comes in a standard 14 pin PDIP, SOIC and TSSOP.

mcp4922
                  pinout

                    [Source: Datasheet]

MCP4922 Datasheet

Download the MCP4922 datasheet here.

MCP4922 Specification

  Parameter
MCP4922
  Voltage Supply (Vs)
2V7 ~ 5V5
  Abs. Max VDD
-0V3 ~ 6V5
  Interface
SPI
  SPI rate
to 20MHz
  Resolution
12 bit
  Power Down I (h/w, s/w) (typ, max)
(0.3uA, 2uA) (3.3uA, 6uA)
  No load current (typ, max @5V) 350uA, 700uA
  Short circuit (Vout=GND) (typ, max)
15mA, 24mA
  Offset error (typ,max)
±0.02, 1.00 %FSR
  Offset error drift (-45~25, 25~85ºC, typ) ±0.16ppm, -0.44ppm
  INL (typ,max) LSB
±2, ±12
  DNL (min,typ,max) LSB
-0.75, ±0.2, ±0.75 [1]
  Gain error (typ, max) %FSR -0.1, 1
  Gain error drift
-3 ppm/ºC
  Phase margin
66º
  Capacitive load stability (5k load)
ns
  Slew rate
0.55V/us
  Output voltage settling time
4.5us
  Operating temperature
-40°C ~ 125°C
    [1] A number below 1 LSB means no codes are missed.

MCP4922 Uses

This chip is very similar in capability to the MCP4725 and because of this it will have similar uses - the most notable difference, other than having no EEPROM and giving you two outputs, is that it is capable of very high speed operation.

If you look at the results for the MCP4725 - it is a struggle to generate even a very low speed waveform with only 16 steps using and Ardunio Uno (218Hz), and the output would be even slower using more steps (unless using a faster microcontroller and using high speed I2C). The MCP4922 is capable of faster operation even with an Arduino Uno as the controller.

There are several uses for the chip:

  • Calibration (offset and set-point).
  • Precision selectable voltage reference.
  • High Speed Waveform generation.
  • Motor control feedback (fast SPI = faster than MCP4725).
  • Multiplier and Divider.

LDACn usage

For the MCL4922 you must connect LDACn to a control signal otherwise the output will not be updated.

For the MCP4728 there is either a software synchronous update UDACn or a hardware synchronous update LDACn.

Warning: You must connect LDACn to a microcontroller control signal.

If you don't care about controlled synchronisation then the easiest way to do this is to connect LDACn to chip select CSn. This will mean the output gets updated at the end of each write sequence to A or B registers.

Arduino Examples with the MCP4922

Software

Arduino IDE : Version 1.8.9+

Arduino Library

  • Library: None
For this chip there is only a 16 bit SPI write which is easy enough that a library is not required.

The only actions are:
  • Use a buffer.
  • Select channel A or B.
  • Send DAC value.

Warning: LDACn must be connected to a microcontroller control signal.

Hardware

Components

  • Arduino Uno R3/Arduino Nano.
  • MCP4922.
  • Solderless breadboard.
  • Connection wires.

Connections

For testing use an Arduino Uno and connect it as follows:

Arduino MCP4922
  5V
VDD
  GND
GND
  11 (MOSI)
SDI
  12 (MISO)
n/c
  13 (SCK) SCK
  10 (CS)
CSn
  10 (CS) or another uC pin
LDACn
  VCC
SHDNn

Since data can not be read from the MCP4922 don't connect MISO.

Example Programs

The first example investigates performance speed using the buit in SPI hardware module while the second investigates using the Arduino shiftOut() function.

Example Program 1

This sketches below are setup using 32 intervals in a complete sine wave (16 steps from top to bottom). So that the  output goes through 360/32 degrees and obtaining a DAC result for each angle.

it generates a sine wave with 16 steps top to bottom. This is to allow comparison with the MCP4725 results.

Note: Interrupts are off so the waveform does not "wobble". The first example uses the "fast" internal SPI module, while the second uses the bit-banged shiftOut function.

// MCP4922 Demo code sinewave at 16 res top to bot.
// For comparison to MCP4725 operation (DAC_RESOLUTION=-5).
#include <SPI.h>

#define DAC_RESOLUTION    5
#define DAC_ARRAY_INDICES (pow(2,DAC_RESOLUTION))

SPISettings settingsA(16000000, MSBFIRST, SPI_MODE0);  // At 16 = SPI Clock = 8MHz.

const PROGMEM uint16_t SineLookup_5bits[32]
{
2048, 2447, 2831, 3185, 3495, 3750, 3939, 4056,
4095, 4056, 3939, 3750, 3495, 3185, 2831, 2447,
2048, 1648, 1264,  910,  600,  345,  156,   39,
   0,   39,  156,  345,  600,  910, 1264, 1648
};

int RCLKPin  = 10;   // pin 12 on the 74hc595 latch - nSS
int SRCLKPin = 13;  // pin 11 on the 74hc595 shift register clock - SCK
int SERPin   = 11;    //  MOSI
#define MARKER 4
//////////////////////////////////////////////////////////////////////////////
void setup() {
  Serial.begin(115200);        // Start serial port (debug).

  pinMode(RCLKPin,  OUTPUT);   // Set SPI control PINs to output.
  pinMode(SRCLKPin, OUTPUT);
  pinMode(SERPin,   OUTPUT);
  pinMode(MARKER,   OUTPUT);

  SPI.begin();

  Serial.println("MCP4922 SPI Dual DAC SPI hardware mode");
  noInterrupts();
}

//////////////////////////////////////////////////////////////////////////////
// 0 - A, 1 - B
//
void writeMCP4922_AB(byte AB, uint16_t v) {

    v |=0xf000;             // B15(A/B)=1 B, B14(BUF)=1 on, B13(GAn) 1=x1  B12(SHDNn) 1=off
    if (!AB)  v &= ~0x8000; // When zero clear B15 for A.

    SPI.beginTransaction(settingsA);
    digitalWrite(RCLKPin, LOW);
    SPI.transfer( (0xff00 & v)>>8 );
    SPI.transfer(      0x00ff & v );
    digitalWrite(RCLKPin, HIGH);
    SPI.endTransaction;
}

void loop() {
   for (int i = 0; i < DAC_ARRAY_INDICES; i++) {
      digitalWrite(MARKER, HIGH);
      digitalWrite(MARKER, LOW);
      writeMCP4922_AB( 0, pgm_read_word(&(SineLookup_5bits[i])) );
   }
}

            [ Sketch: mcp4922-spi-module.ino ]

The oscilloscope was setup with 1V per division and shows a output frequency of 1.475kHz.

mcp4922 spi module

Timebase: 100us/div, Yellow 1V/div.

So this method is a lot faster than the MCP4725. However it is still limited by the Speed of the Arduino Uno. Even though 16Mhz SPI clock is requested it can only go at 8MHz. Also remember this is a low resolution waveform. Adding more steps will slow it down.

The following waveform shows the SPI clock at 8MHz (Even though 16MHz was requested the Arduno uno can only supply 8MHz - reasonable since the main clock of the Arduino is 16Mhz):

Arduino SPI clock using SPI module

Timebase: 200ns/div, Yellow 2V/div.

Example Program 2

What is the capability of the MCP49222 when using shiftout?

The shiftout function is a bit banged serial output generator that can be configured in different ways. For instance you can select MSB or LSB first operation. The problem with being muti-functional is that time is used in processing these extras.

The following code generates a sine wave with 16 steps top to bottom. This is to allow comparison with the MCP4725 results.

// MCP4922 Demo code sinewave at 16 res top to bot.
// For comparison to MCP4725 operation (DAC_RESOLUTION=-5).

#define DAC_RESOLUTION    5
#define DAC_ARRAY_INDICES (pow(2,DAC_RESOLUTION))

const PROGMEM uint16_t SineLookup_5bits[32]
{
2048, 2447, 2831, 3185, 3495, 3750, 3939, 4056,
4095, 4056, 3939, 3750, 3495, 3185, 2831, 2447,
2048, 1648, 1264,  910,  600,  345,  156,   39,
   0,   39,  156,  345,  600,  910, 1264, 1648
};

int RCLKPin  = 10;   // pin 12 on the 74hc595 latch - nSS
int SRCLKPin = 13;  // pin 11 on the 74hc595 shift register clock - SCK
int SERPin   = 11;    //  MOSI
#define MARKER 4
//////////////////////////////////////////////////////////////////////////////
void setup() {
  Serial.begin(115200);        // Start serial port (debug).

  pinMode(RCLKPin,  OUTPUT);   // Set SPI control PINs to output.
  pinMode(SRCLKPin, OUTPUT);
  pinMode(SERPin,   OUTPUT);
  pinMode(MARKER,   OUTPUT);

  Serial.println("MCP4922 SPI Dual DAC");
}

//////////////////////////////////////////////////////////////////////////////
// 0 - A, 1 - B
//
void writeMCP4922_AB(byte AB, uint16_t v) {

    v |=0xf000;             // B15(A/B)=1 B, B14(BUF)=1 on, B13(GAn) 1=x1  B12(SHDNn) 1=off
    if (!AB)  v &= ~0x8000; // When zero clear B15 for A.
    digitalWrite(RCLKPin, LOW);
    shiftOut(SERPin, SRCLKPin, MSBFIRST, (0xff00 & v)>>8);
    shiftOut(SERPin, SRCLKPin, MSBFIRST,  0x00ff & v);
    digitalWrite(RCLKPin, HIGH);
}

void loop() {
   for (int i = 0; i < DAC_ARRAY_INDICES; i++) {
      digitalWrite(MARKER, HIGH);
      digitalWrite(MARKER, LOW);
      writeMCP4922_AB( 0, pgm_read_word(&(SineLookup_5bits[i])) );
   }
}


            [ Sketch: mcp4922-shiftout.ino ]

Note: The sine table is from https://github.com/adafruit/Adafruit_MCP4725/blob/master/examples/sinewave/sinewave.ino where you can find more tables (up to 9 bits).

This sketch is setup using 32 intervals in a complete sine wave (16 steps from top to bottom). So that is going through 360/32 degrees and obtaining a DAC result for each angle. The oscilloscope was setup with 1V per division and shows a output frequency of 130Hz. So this bit banged method is slower than the MCP4725 and it is 10 times slower than using the SPI hardware.

mcp4922 shiftout sine waveform

Timebase: 1ms/div, Yellow 1V/div.

MCP4725 Specification vs MCP4922

  Parameter
MCP4725
MCP4922
  Voltage Supply (Vs)
2V7 ~ 5V5 Same
  Abs. Max VDD
-0V3 ~ 6V5
Same
  Interface
I2C
SPI
  I2C rate
100kHz, 400kHz, 3.4MHz 20MHz
  Resolution
12 bit Same
  Power Down I (VDD=5V5 typ, max)
0.06uA, 2uA
0.3uA,2uA
  No load current (typ, max) 210uA, 400uA
350uA,700uA
  Short circuit (Vout=GND) (mn,tp, mx)
7mA, 15mA, 24mA
Same no min
  Offset error (typ,max) %FSR ±0.02, 0.75  ±0.02, 1.00
  Offset error drift (-45~25, 25~85ºC,typ) ppm
±1, ±2 ±0.16, -0.44
  INL (typ,max) LSB
±2, ±14.5 [3] ±2, ±12
  DNL (min,typ,max) LSB [2] -0.75,±0.2,±0.75 
Same
  Gain error (min, typ, max) %FSR -2, -0.1, 2
x,-0.1,1
  Gain error drift
-3 ppm/ºC
Same
  Phase margin
66º Same
  Capacitive load stability (5k load)
1000pF ns
  Slew rate
0.55V/us
Same
  Output voltage settling time
6us
4.56us
  I2C Addresses (h/w selected = 8off)
0x60, 0x61 [1] n/a
  Operating temperature
-40°C ~ 125°C
Same
    [2] A number below 1 LSB means no codes are missed.

Theoretical Maximum Speed

Approximately how fast could this chip go in generating a 32 bit sinewave?

The sinewave goes through a cycle of 32 bits from max to min, and then to max again, so from top to bottom there are 16 steps.

Ignoring slew rate, and settling time, and processor time. From the waveforms you can see that 16 bits must be output. If the clock is 20Mhz (MAX SPI speed) then this would take 16*(1/20e6) = 800ns.

To generate 32 segments will take 32*800e-9=25.6us

That generates a frequency of 1/25.6e-6 = 39kHz.

Warning: This is a low resolution sinewave. More steps = slower.

This is the maximum theoretical sine wave - remember this is a low resolution sine wave and would slow down if more segments were needed.

The above calculations are for one register update only. For both channel updates the rate would reduce to 19.5kHz

Warning: Calculations assume the processor is dedicated to this task!

Note: Maximum theoretical single channel update : 39kHz. LOW RES

Conclusions

The MCP4922 is a useful device for generating a specific controlled voltage e.g. for a set point or an offset calibration. You could use it for a digitally programmable voltage or current output circuit.

The device is faster than the I2C equivalents but for waveform generation its difficult to get a high audio frequency (with high step size).

Speed

The MCP4922 is a capable device and does operate faster than all the I2C versions. You can make the chip operate fast but with an Arduino Uno it is fairly slow. The examples show a very low resolution waveform output at 1.4kHz and more steps will take longer reducing the output frequency.

If you are looking for high speed operation you would need a faster processor such as a DSP processor. However even then the maximum frequency output is 39kHz and that is still only for a 16 step waveform.

An easy alternative for wave form output is the AD9833 (this however is not a DAC and generates single sinewaves only). Another alternative is a parallel DAC e.g. DAC08. More details are here.

Memory

Unlike the I2C versions this chip does not have EEPROM so can not keep the same output after power down.

Voltage reference

This chip does not have an internal voltage reference - you can get the MCP4822 that does have a reference.

Outputs

The MCP4922 has two outputs. If speed is not a concern and you need lots of outputs the MCP4728 has four on an I2C bus.

Breadboarding

This chip is easy to use on a solderless breadboard, since it also comes in a standard PDIP package, and gives you control of two analogue outputs.


Comments

Have your say about what you just read! Leave me a comment in the box below.

Don’t see the comments box? Log in to your Facebook account, give Facebook consent, then return to this page and refresh it.




Privacy Policy | Contact | About Me

Site Map | Terms of Use