Interfacing to MAX5724 DAC

Hi,

I have a MAX5724 8 channel 10 bit DAC's connected to a due, i believe i have it wired up correctly, however when i try to write a value to it doesn't seem to output anything. Either i misunderstood the datasheet in the wiring or im writing incorrectly to it. Since i have the LDAC connected to GND i think i can just use the CODEn command on page 21 of the datasheet.

A link to the datasheet:
http://datasheets.maximintegrated.com/en/ds/MAX5723-MAX5725.pdf

Here the code i use to write:

#include <SPI.h>

#define CS 52

void setup()
{

  Serial.begin(115200);
  SPI.begin(CS);
  SPI.setBitOrder(MSBFIRST);
  SPI.setDataMode(CS, 1);
  SPI.setClockDivider(CS, 3); // 28MHz
  pinMode(CS, OUTPUT);
}

void loop()
{
  digitalWrite(CS, HIGH);
  digitalWrite(CS, LOW);
  static int value = 1024;
  if (value >= 1024)
  {
    value = 1024;
  }
 
 byte msg1 = 0b10001000; 
 byte msg2 = (byte)(value>>2);
 byte msg3 = (byte)(value);
 msg3 = msg3 | 0b00000011;
// byte msg1=0b01010100; // 01111111
// byte msg2=0b00000001; // 11111111


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

}

wiring:
1 = 5V
2 - 9 = OUTPUT
10 = 5V
11 = 5V
12 = MOSI (middle pins)
13 = MISO (middle pins)
14 = SCK (middle pins)
15 = PIN 52
16 = OUTPUT
17 = 5V
18 = GND
19 = GND
20 = GND

connected to a due

On a Due the SPI pins are not on the same pins as the other Arduinos.
You can only get them on the ICSP header.
You can of course bit bang the signals on what ever pins you want but that will mean different software.

Ahh sorry, i realise i wasn't clear when i said middle pins, I meant to say ICSP header pins which are located in the middle of the arduino Due board.

I have a MAX5724 8 channel 10 bit DAC's connected to a due, i believe i have it wired up correctly

WARNING: Pin 11 needs to be 3.3V - the Due is a 3.3V board, it's I/O cannot tolerate anything beyond 3.9V.

Your SCLK Frequency is too high (28MHz) - see pg7.
Try 4MHz until you get it working. Then you could ramp it up to 8, 10.5 or 21MHz depending on the strobing method.

The default SPI mode for Arduino is mode 0, so you could use this:

SPI.setDataMode(CS, SPI_MODE0);
//or
SPI.setDataMode(CS, 0);

Ok changed the pin 11 to the 3.3V of the arduino and SPI.setClockDivider to 4MHz, also have SPI.setDataMode on SPI_MODE0

I however cannot get the output to do anything it just seems to stay on its default value, currently using CODE_ALL LOAD_ALL (on page 22), with LDAC connected to GND and sending 1024 in binary with no luck have posted code used below.

#include <SPI.h>
#define CS 52

void setup()
{
  Serial.begin(115200);
  Serial.println("INITIALIZE");
  SPI.begin(CS);
  SPI.setBitOrder(MSBFIRST);
  SPI.setDataMode(CS, SPI_MODE0);
  SPI.setClockDivider(CS, 21); // 4MHz
}
void loop()
{
  while (Serial.available() == 0);
  {
    delay(100);
    while (Serial.available() > 0)
    {
      (Serial.read());
    }
    byte msg1 = 0b11000010;
    byte msg2 = 0b10000000;
    byte msg3 = 0b00000000;
    SPI.transfer(CS, msg1, SPI_CONTINUE);
    SPI.transfer(CS, msg2, SPI_CONTINUE);
    SPI.transfer(CS, msg3, SPI_LAST);
    Serial.println("Sent");
  }
}

Is there a command i need to give it before i use CODE_ALL LOAD_ALL? or am i missing something else?

To read, I believe you'll need to use the SPI0_RDR register. See page 685 in the SAM3X/A datasheet.
You may also need to check the status register first REG_SPI0_SR.

pseudocode:

spistatus = REG_SPI0_SR;
rdrfull = spistatus & 0x1u;

if (rdrfull > 0) {
  spiread = REG_SPI0_RDR & 0xFFu;
}

Do i need to read before i write? I just want to write to the DAC's outputs don't really care what they send back.

I am trying to change the output of the 8 channels. I assume with CODE_ALL LOAD_ALL (page 22 2nd in the table) it would change all 8 outputs to data being sent. Once i have the outputs changing i was going to change each channel individually. I am reading the output of each channel with an oscilloscope.

I however can't get the outputs to change at all, bit stumped at the moment. I thought with the code in my previous post above i would be able to change the outputs to 5V and the DAC would stay at 5V until i changed it to a different value, but they don't do anything and stay at default MZ.

#include <SPI.h>
#define CS 52

void setup()
{
  Serial.begin(115200);
  Serial.println("INITIALIZE");
  SPI.begin(CS);
  SPI.setBitOrder(MSBFIRST);
  SPI.setDataMode(CS, SPI_MODE0);
  SPI.setClockDivider(CS, 21); // 4MHz
}
void loop()
{
  byte msg1 = 0b11000010;
  byte msg2 = 0b10000000;
  byte msg3 = 0b00000000;
  SPI.transfer(CS, msg1, SPI_CONTINUE);
  SPI.transfer(CS, msg2, SPI_CONTINUE);
  SPI.transfer(CS, msg3, SPI_LAST);
}

I haven't used this IC, however it seems you have some connection problems.

New Wiring (3.3V):

1        REF          3.3V
2-9      OUT0-OUT7                     Analog Outputs (0-3.3V)
10       VDD          3.3V
11       VDDIO        3.3V
12       MISO         SPI              Master Input, Slave Output
13       MOSI         SPI              Master Output, Slave Input
14       SCK          SPI
15       CSB          Pin 52           Normally HIGH 3.3V   
16       IRQ          Arduino Input    Optional, 5K pullup to 3.3V, low = watchdog timeout
17       CLR          Arduino Output   Normally HIGH 3.3V    
18       LDAC         Arduino Output   Normally HIGH 3.3V 
19       GND
20       M/Z GND      DAC zero-scale

Refer to page 8, Figure 1. SPI Serial Interface Timing Diagram MAX5724

Try this (untested):

#include <SPI.h>
#define CS 52
const int nCLR = 6;
const int nLDAC = 7;

void setup()
{
  Serial.begin(115200);
  Serial.println("INITIALIZE");
  pinMode(nCLR, OUTPUT);
  pinMode(nLDAC, OUTPUT);
  digitalWrite(nCLR, HIGH);
  digitalWrite(nLDAC, HIGH);
  SPI.begin(CS);
  SPI.setBitOrder(MSBFIRST);
  SPI.setDataMode(CS, SPI_MODE0);
  SPI.setClockDivider(CS, 21); // 4MHz
}

void loop()
{
byte msg1 = 0b11000010;
byte msg2 = 0b10000000;
byte msg3 = 0b00000000;

// begin transfer...

// pulse CLR
digitalWrite(nCLR, LOW);
digitalWrite(nCLR, LOW);
digitalWrite(nCLR, HIGH);

SPI.transfer(CS, msg1, SPI_CONTINUE);  // CS goes LOW
SPI.transfer(CS, msg2, SPI_CONTINUE);

// pulse LDAC
digitalWrite(nLDAC, LOW);
digitalWrite(nLDAC, LOW);
digitalWrite(nLDAC, HIGH);

SPI.transfer(CS, msg3); // CS goes HIGH after transfer

Serial.println("Sent");
}

Why don't you try this one for $5:
It's a 12-bit DAC.

raschemmel:
Why don't you try this one for $5:
It's a 12-bit DAC.

NEW PRODUCT – MCP4725 Breakout Board – 12-Bit DAC w/I2C Interface « Adafruit Industries – Makers, hackers, artists, designers and engineers!

Why should he buy it?

OP is using an 8 channel spi dac. You post that he should use a single channel i2c based part and his problem is solved?

Aye i need 8 channels so that wouldn't help, the LDAC can be held low which makes DAC registers transparent and CLR can be held high (Page 18).

I have managed to move some outputs however, i have some very weird findings.

#include <SPI.h>
#define CS 52

void setup()
{
  Serial.begin(115200);
  Serial.println("INITIALIZE");
  pinMode(CS, OUTPUT);
  SPI.begin(CS);
  SPI.setBitOrder(MSBFIRST); 
  SPI.setDataMode(CS, SPI_MODE0); //this is correct
  SPI.setClockDivider(CS, 21); // low to start with
  digitalWrite(CS, HIGH);
}

void loop()
{
  while (Serial.available() == 0);
  {
    delay(100);
    while (Serial.available() > 0)
    {
      (Serial.read());
    }
    digitalWrite(CS, LOW);
    byte msg1 = 0b11000010;
    byte msg2 = 0b10000000;
    byte msg3 = 0b00000000;
    Serial.println(msg1, BIN);
    Serial.println(msg2, BIN);
    Serial.println(msg3, BIN);
    SPI.transfer(CS, msg1, SPI_CONTINUE);
    SPI.transfer(CS, msg2, SPI_CONTINUE);
    SPI.transfer(CS, msg3, SPI_LAST);
    delay(100);
    digitalWrite(CS, HIGH);
    Serial.println("Sent");
  }
}

The code above seems to work however it does not send correctly. The code below i expect would according to the data sheet code_all and load_all and all channels would change to 512 about half voltage.

byte msg1 = 0b11000010;
byte msg2 = 0b10000000;
byte msg3 = 0b00000000;

But what seems to happen is the register ignores the first binary number in each msg and adds a 1 to the end of each msg so my output is doing code_n on channel 101 (channel 5) and setting it 0, code below is what is actually output (number in brackets at the end is what is oddly added and number in brackets at the start is what is ignored)

byte msg1 = 0b(1)1000010(1);
byte msg2 = 0b(1)0000000(1);
byte msg3 = 0b(0)0000000(1);

Any theories? hope this made sense.

Check reply #7 .. do you have everything connected so its using 3.3V voltage levels?

I don't see where you're using CLR and LDAC in your code (it's use is shown in the timing diagram).

Also, the CS output is already being setup and controlled by the SPI library so you shouldn't manually digitalWrite to it.

Also, the CS output is already being setup and controlled by the SPI library so you shouldn't manually digitalWrite to it.

You sure of that? Because it would mean that you could not put more than one device on the SPI bus.

You sure of that? Because it would mean that you could not put more than one device on the SPI bus.

Yes. For the Due, the library takes full control of the CS line. There's no need to configure it or write to it separately, or this would create conflicts.

But what seems to happen is the register ignores the first binary number in each msg and adds a 1 to the end of each msg so my output is doing code_n on channel 101 (channel 5) and setting it 0, code below is what is actually output (number in brackets at the end is what is oddly added and number in brackets at the start is what is ignored)

This looks like you're getting close .. check that the starting levels for the CLK and other SPI signals make sense.

May just need to change the mode to SPI_MODE1. (this has same polarity but inverted phase as mode SPI_MODE0).

EDIT: I recommend using IDE version 1.5.8 as it has some improvements made with regards to SPI.

For the Due, the library takes full control of the CS line.

Thanks, I see:-
But you tell it what line that is, that is the vital bit that was missing from your first statement.

I got it working with this code thanks a lot for your help (tidied up the code a bit and made it generic)! Had to change the SPI MODE, i don't really understand why it works at SPI_MODE3 and why if i change the clock to about 20MHz, when the datsheet (page1) says it should work up to 50MHz.

Can i change the VDD (analog supply voltage) to 5V and the Vref to 5v, while leaving VDDIO (Digital Supply Voltage) to 3.3v, so i can out 5V and not damage my arduino due?

quick question i can only have 3 of these per arduino due right? On CS line 4,10,52?

#include <SPI.h>
#define CS_DAC1 52

void dacSetup (int CS)
{
  SPI.begin(CS);
  SPI.setBitOrder(MSBFIRST);
  SPI.setDataMode(CS, SPI_MODE3); //this is correct none of the others work
  SPI.setClockDivider(CS, 21); // low to start with
}

void dacWrite (int CS, int value, int channel)
{
  if (value > 1023)
  {
    value = 1023;
  }
  byte msg1 = (byte)channel;
  msg1 = msg1 | B10000000;// CODEn + DAC selection (Page 21 MAX5724 datasheet) 
  byte msg3 = (byte)value;
  byte msg2 = (byte)(value >> 2);
  msg3 = msg3 & B00000011;

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

void setup()
{
  dacSetup(CS_DAC1);
}

void loop()
{
  static int channel = 2;
  static int value = 0;
 
  dacWrite(CS_DAC1, value, 0);
  dacWrite(CS_DAC1, value, 1);
  dacWrite(CS_DAC1, value, 2);
  dacWrite(CS_DAC1, value, 3);
  dacWrite(CS_DAC1, value, 4);
  dacWrite(CS_DAC1, value, 5);
  dacWrite(CS_DAC1, value, 6);
  dacWrite(CS_DAC1, value, 7);
  value += 100;
  if (value > 1100)
  {
    value = 0;
  }
  delay(3);
}

Had to change the SPI MODE, i don't really understand why it works at SPI_MODE3...

I think the DAC would work in other modes, but the method for reading the data might be different (see pg 19).

... and why if i change the clock to about 20MHz, when the datsheet (page1) says it should work up to 50MHz.

Readback speeds are 12.5/25/50MHz depending on the details mentioned on pg19. I wouldn't trust much more than 4MHz while testing on a breadboard. For higher speed operation, the shorter the leads, the better - a PCB solution is best. Note that on the Due, 21MHz would be about the top speed, however I think I've read somewhere about a memory interface with test results @ 42MHz when using SPI with DMA.

Can i change the VDD (analog supply voltage) to 5V and the Vref to 5v, while leaving VDDIO (Digital Supply Voltage) to 3.3v, so i can out 5V and not damage my arduino due?

This looks possible (see pg32) as long as OUT0-7 are not directly connected to the Due.

quick question i can only have 3 of these per arduino due right? On CS line 4,10,52?

You should be able to extend this to more than three by using an appropriate analog switch IC (or similar).

Hey,

I know, it has been some time since the last post in this topic, but I had to use the MAX5725(wich is just the 12-bit version of the 5724) an figured out how to do that. Maybe some one out there is still looking for some working code!

I just had 8bit Iformation to shift out thouth the DACs so the functions i wrote just handle bytes.
So here we go:

SPISettings SettingsMAX( 16000000, MSBFIRST, SPI_MODE1);

//write a a byte value to any DAC from 0 to 7, 8 will write to all DACs
void writeMAX5725 (byte value, byte dac_channel)
{
    if (value > 255)
    {
        value = 255;
    }
    
    byte msg[3];
    msg[0] = B10110000 |dac_channel;// CODEn&LOADn + DAC selection (Page 21 MAX5725 datasheet)
    msg[1] = value;
    msg[2] = 0;
    digitalWrite(SS_MAX5725,HIGH);
    asm("nop\n"); // delay of one operation ( I think this is 62.5ns; 20ns needed)
    digitalWrite(SS_MAX5725, LOW);
     
    SPI.beginTransaction(SettingsMAX);
    SPI.transfer(msg[0]);
    SPI.transfer(msg[1]);
    SPI.transfer(msg[2]);
    SPI.endTransaction();
    
}
void setupMAX5725()
{
    //get all pins ready
    digitalWrite(SS_MAX5725, LOW);
    digitalWrite(13, LOW); // CLK pin
    digitalWrite(11, LOW); // MOSI pin
  
  
    byte msg[3] = {0};
    msg[0] = B00100101 ;// set the internal REF to 2,5V Change last 2 bit to "11" for 4.1V or "10" for 2V
    msg[1] = B00000000; 
    msg[2] = B00000000;
    digitalWrite(SS_MAX5725,HIGH);
    asm("nop\n"); // dealy of one operation ( i think this is 62.5ns; 20ns needed) 
    digitalWrite(SS_MAX5725, LOW);
     
    SPI.beginTransaction(SettingsMAX);
    SPI.transfer(msg[0]);
    SPI.transfer(msg[1]);
    SPI.transfer(msg[2]);
    SPI.endTransaction();
    delay(2); // just to be safe
}

PIN SETUP for an Arduino UNO/NANO:

MAX5725:
1: / ( check here for right REF voltage)
2-9: DAC OUT 0-7
10: 5V ( or any other possible Vcc)
11: 5V (for me, can be different 3.3V is typical too)
12: / ( i dont need to read back anything)
13: connect to pin 11 ( MOSI)
14: connect to pin 13 (CLK)
15: connect to the SalveSelect pin (choose one)
16: / ( i dont need timeout interupst)
17: connect to VCCIO or any pin witch is HIGH (LOW causes to clear all DAC OUTs.Iif this is unconected nothing will happen!!!)
18: connect to VCC
19: connect to GND
20: connect to GND

Additionaly I used a smal Cap of 100nF between GND and 5V. That helps to supply all the devices with enough current for fast rising an falling times!

I hope that helps!
have fun!

Manewc:
12 = MOSI (middle pins)
13 = MISO (middle pins)

Wrong way round, MOSI is Slave In, ie Din pin 13

Also given the DAC works at 3.3V, I'd have initially used 3.3V supply for it rather than
risk over-voltage death for the expensive Due while testing stuff. Its really not happy with
5V on any pin.