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).
[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.
How to get accurate DHT22 digital humidity sensor readings with an Arduino. Did you know it also measures temperature as Well? Find out why, in this page...
A PIR sensor lets your Arduino sense movement without contact. This tutorial covers PIR sensor basics, connecting one to an Arduino board and coding a motion detector.
Arduino Hall Effect Sensor: Add magnetic sensing superpowers to your Arduino projects with an easy-to-use hall effect sensor. With full code and layout...
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.