The MCP4922 is a dual analogue DAC - a buffered voltage output
device controlled from an SPI serial interface. It 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.
[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))
SPISettingssettingsA(16000000,MSBFIRST,SPI_MODE0);// At 16 = SPI Clock = 8MHz.
constPROGMEMuint16_tSineLookup_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
};
intRCLKPin=10;// pin 12 on the 74hc595 latch - nSS
intSRCLKPin=13;// pin 11 on the 74hc595 shift register clock - SCK
intSERPin=11;// MOSI
#define MARKER 4
//////////////////////////////////////////////////////////////////////////////
voidsetup(){
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
//
voidwriteMCP4922_AB(byteAB,uint16_tv){
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;
}
voidloop(){
for(inti=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.
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):
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))
constPROGMEMuint16_tSineLookup_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
};
intRCLKPin=10;// pin 12 on the 74hc595 latch - nSS
intSRCLKPin=13;// pin 11 on the 74hc595 shift register clock - SCK
intSERPin=11;// MOSI
#define MARKER 4
//////////////////////////////////////////////////////////////////////////////
voidsetup(){
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
//
voidwriteMCP4922_AB(byteAB,uint16_tv){
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);
}
voidloop(){
for(inti=0;i<DAC_ARRAY_INDICES;i++){
digitalWrite(MARKER,HIGH);
digitalWrite(MARKER,LOW);
writeMCP4922_AB(0,pgm_read_word(&(SineLookup_5bits[i])));
}
}
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.
[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.
Arduino joystick: A Tutorial showing you exactly how to read the outputs for precise joystick positioning. Test it with a new library making it Easy...
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.