MCP4922 problem

HI

I'm currently trying to get PWM to a proper analogue output using some MCP4922 and an arduino due, however, i have not been able to get signal out from the chip, i am using the wiring in
http://schianorobotics.altervista.org/Arduino_DUE___DAC_MCP4922.pdf
and using the sample code provide i have also tried other codes looking online and tried using the spi library, but nothing has worked i was just wondering if someone with a similar chip could follow the example quickly and tell me if they manage, or to help me out.

thanks a lot for your help!

manewc

Your link doesn't work for me.

link works fine for me

thanks

manewc

Yes, it does work. I was getting some foreign error message and didn't realize what it said. Strangely it worked just fine on my tablet.

Try removing SPI.setDataMode. I don't know why they're setting it to 2 when the datasheet clearly says it's mode 0 or 3.

I have the same DAC, but I haven't yet experimented with it. I'll let you know the results when I do.

i managed to make it work with the code provided, haven't worked out how to switch between the channels

thanks a lot for your help

manewc

#include <SPI.h> // Include the SPI Library

#define CS 10 // It can be 10,4, or 52 . Be careful if you use an Ethernet Shield
void setup() {
 // put your setup code here, to run once:
SPI.begin(CS);
SPI.setBitOrder(MSBFIRST);
pinMode(7,OUTPUT);
digitalWrite(7,HIGH);
Serial.begin(57600);

SPI.setDataMode(CS, 2);

SPI.setClockDivider(CS,21); // 4MHz
}
void loop() {

 digitalWrite(7,HIGH);

 int value=3333;

 if(value>=4095){
 value=4095;
 }

 byte msg2=(byte)value;
 byte msg1=(byte)(value>>8);
 msg1=msg1 | 0b01010000; 
// byte msg1=0b01010100; // 01111111
// byte msg2=0b00000001; // 11111111

 SPI.transfer(CS,msg1,SPI_CONTINUE);
 SPI.transfer(CS,msg2,SPI_LAST);
 delay(4000);
}

The MCP4922 datasheet says the output channel is selected by the most significant bit of the input message. Here's the datasheet, with the message structure described on page 24: http://ww1.microchip.com/downloads/en/DeviceDoc/22250A.pdf.

To switch to channel B, try changing this:

 msg1=msg1 | 0b01010000;

to this:

 msg1=msg1 | 0b11010000;

tmd3:
The MCP4922 datasheet says the output channel is selected by the most significant bit of the input message. Here's the datasheet, with the message structure described on page 24: http://ww1.microchip.com/downloads/en/DeviceDoc/22250A.pdf.

To switch to channel B, try changing this:

 msg1=msg1 | 0b01010000;

to this:

 msg1=msg1 | 0b11010000;

hi thanks a lot works like a charm!! also understand how it works a lot more

manewc

Manewc:
... works like a charm!

Delighted.

You may want to continue this discussion for another post or two, though, as the document you reference is more than a little ambiguous, and there may yet be issues with the design that you haven't bumped into yet. The ones I see have to do with the voltage that powers the MCP4922, and the reference voltages.

Here's the briefest description of what I'm thinking:

  • The posted code shows bit 13 of the message seent to teh MCP4922 as a '1', which selects a gain of 2X. If VREF is the same as VDD, it looks like the DAC will hit its power supply rail at half-scale, and won't be able to register higher voltages in response to bigger input codes. In essence, it'll operate as an 11-bit DAC. If you send code 3333, as shown in your sketch, and then send 4095, do you get the expected results?
  • If the MCP4922 is powered at 5V, as shown in the schematic, then the Due's output high voltage of 3.3V won't reach the level of VIH = 0.7*VDD = 3.5V. VIH is the lowest voltage that the manufacturer promises will be read as a logic high. The Due doesn't miss the mark by much, though, and the circuit may work properly nearly every time. But, if it does in fact glitch, it will be devilishly hard to troubleshoot.

You may have spotted these issues and designed around them; I can't tell from the posts. As a favor to the next guys who try to interpret that document, could you post a schematic of what you built, or at least a list of your connections?

Aye i was originally using the 3.3 and 3333V was near enough the max for testing purposes but i used a voltage divider circuit to split the voltage from the 5V to reduce the amount of connections going to the arduino, below handy website. With this circuit i reach the desired 5V. The equation is at the bottom of the website aswell.

http://hyperphysics.phy-astr.gsu.edu/hbase/electric/voldiv.html

The connections i have used on the arduino is:

+5V > 4922 pin 1 DUE pin CS > 4922 pin 3 (SS - slave select)
DUE SCK > 4922 pin 4 (SCK - clock) the one in the middle
DUE MOSI > 4922 pin 5 (MOSI - data out) the one in the middle
Ground > 4922 pin 8 (LDAC)
4922 pin 10 DAC A > OUTPUT
+5V > 4922 pin 11 (voltage ref DAC B) use a voltage divider circuit to get 2.5V with 2 resistors
Ground > 4922 pin 12
+5V> 4922 pin 13 (voltage ref DAC A) use a voltage divider circuit to get 2.5V with 2 resistors
4922 pin 14 DAC A > OUTPUT

OK, so it looks like this:

MCP4922   PIN        CONNECTED
PIN       FUNCTION   TO
-------   --------   ---
 1        VDD        5V             
 2        NC         ---             
 3        CS         DUE PIN 10 (CS)         
 4        SCK        DUE ICSP-3 (SCK)
 5        SDI        DUE ICSP-4 (MOSI)
 6        NC         ---              
 7        NC         ---             
 8        LDAC       GND
 9        SHDN       5V
10        VOUTB      -> DAC B OUT
11        VREFB      2.5V - RESISTIVE DIVIDER
12        VSS        GND
13        VREFA      2.5V - RESISTIVE DIVIDER
14        VOUTA      -> DAC A OUT

Changes I've made to your list:

  • Added the Due pin number for CS that corresponds to your code, pin 10.
  • Added the Due ICSP designations for those pins.
  • Added a connection between MCP4922 9, SHDN, the shutdown pin, and 5V. If that pin is left open and read by the MCP4922 as a low input, the DAC shuts down. If you don't use that pin, it should be tied high.

It's worth noting that you can use the same resistive divider to supply VREFA and VREFB. You may well have done it that way; I mention it for completeness.

Here's something else to note: The MCP4922's datasheet shows VIH, the minimum voltage that the circuit promises to read as high, as 0.7VDD. That's 3.5V. The Due's logic outputs can only be as high as 3.3V, and that's less than VIH. There's a possibility that the MCP4922 will not be able to see a high input from the Due, and will thus give unexpected results. It's not particularly likely, as 3.3V is pretty close to VIH, but it's not impossible for the MCP4922 to read lows where it should see highs under some conditions, and for some unlucky MCP5922's to never read a high in this circuit. If you start getting unexpected results, that's a possible reason. A remedy would be to apply some level-shifting between the Due and the MCP4922

With LDAC grounded, the input registers transfer immediately to the DAC output when they're received. It's easy, but the DAC is less functional in that mode. The purpose of LDAC is to allow synchronization of the A and B outputs, and other DAC's as well, if the device has others. You can load register A, load register B, then pulse LDAC, and both outputs will update simultaneously. You can also use LDAC for hardware-controlled timing, by loading the A and B registers, and letting a hardware timer output control the LDAC input. The outputs update precisely on the clock, and you can load the next values into the registers in response to the timer, by polling or interrupt.

Note that the function of the LDAC pin is controlled by bit 14 of the input message: if that's a 1, LDAC is active; if it's a 0, LDAC has no effect, and the DAC register transfers to the output immediately. Your code sets bit 14, so LDAC is active.

This is ancient, but such is the internet: no sin is forgotten.

Do NOT believe the nonsense quoted above. Bit 14 determines input impedance on VREFx. See sec. 4.1.2 in the MCP492X datasheet.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.