DAC SPI Mega2560

Hello everyone, I want to use a TI DAC8411 with the SPI library and output an sine wave. What I think is happening is due to an interrupt being fired at every 16 cycle. However the only problem with this is that it doesnt only happen every 16 cycles

“Level-triggered control input (active low). This is the frame sychronization signal for the input
data. When SYNC goes low, it enables the input shift register and data are transferred in on the
falling edges of the following clocks. The DAC is updated following the 24th (DAC8411) or 16th
(DAC8311) clock cycle, unless SYNC is taken high before this edge, in which case the rising
edge of SYNC acts as an interrupt and the write sequence is ignored by the DAC8x11. Refer to
the DAC8311 and DAC8411 SYNC Interrupt sections for more details.”

Documentation: http://www.ti.com/lit/ds/sbas439c/sbas439c.pdf

Screenshot of logic analyzer : Imgur: The magic of the Internet

Heres a sample of my code

/*
  Digital Pot Control

  This example controls an Analog Devices AD5206 digital potentiometer.
  The AD5206 has 6 potentiometer channels. Each channel's pins are labeled
  A - connect this to voltage
  W - this is the pot's wiper, which changes when you set it
  B - connect this to ground.

 The AD5206 is SPI-compatible,and to command it, you send two bytes,
 one with the channel number (0 - 5) and one with the resistance value for the
 channel (0 - 255).

 The circuit:
  * All A pins  of AD5206 connected to +5V
  * All B pins of AD5206 connected to ground
  * An LED and a 220-ohm resisor in series connected from each W pin to ground
  * CS - to digital pin 10  (SS pin)
  * SDI - to digital pin 11 (MOSI pin)
  * CLK - to digital pin 13 (SCK pin)

 created 10 Aug 2010
 by Tom Igoe

 Thanks to Heather Dewey-Hagborg for the original tutorial, 2005

*/


// inslude the SPI library:
#include <SPI.h>

float sinewave[256] ={
 127,130,133,136,139,143,146,149,152,155,158,161,164,167,170,173,176,178,181,184,187,190,192,195,198,200,203,205,208,210,212,215,217,219,221,223,225,227,229,231,233,234,236,238,239,240,
 242,243,244,245,247,248,249,249,250,251,252,252,253,253,253,254,254,254,254,254,254,254,253,253,253,252,252,251,250,249,249,248,247,245,244,243,242,240,239,238,236,234,233,231,229,227,225,223,
 221,219,217,215,212,210,208,205,203,200,198,195,192,190,187,184,181,178,176,173,170,167,164,161,158,155,152,149,146,143,139,136,133,130,127,124,121,118,115,111,108,105,102,99,96,93,90,87,84,81,78,
 76,73,70,67,64,62,59,56,54,51,49,46,44,42,39,37,35,33,31,29,27,25,23,21,20,18,16,15,14,12,11,10,9,7,6,5,5,4,3,2,2,1,1,1,0,0,0,0,0,0,0,1,1,1,2,2,3,4,5,5,6,7,9,10,11,12,14,15,16,18,20,21,23,25,27,29,31,
 33,35,37,39,42,44,46,49,51,54,56,59,62,64,67,70,73,76,78,81,84,87,90,93,96,99,102,105,108,111,115,118,121,124

};
// set pin 10 as the slave select for the digital pot:

#define DATAOUT 51   // MOSI 
#define DATAIN 50    // MISO 
#define SPICLOCK 52  // Clock 
#define SELPIN 53    // chip-select
void setup() {
  // set the slaveSelectPin as an output:
  pinMode(SELPIN, OUTPUT);
  pinMode(SPICLOCK, OUTPUT);
  pinMode(DATAOUT, OUTPUT);
  // initialize SPI:
  digitalWrite(SELPIN, HIGH); 
  
  SPI.setClockDivider( SPI_CLOCK_DIV16 ); // slow the SPI bus down
  SPI.setBitOrder(MSBFIRST);
  SPI.setDataMode(SPI_MODE0);    // SPI 0,0 as per MCP330x data sheet 
  SPI.begin();
  Serial.begin(115200);
}

void loop() {
  // go through the six channels of the digital pot:
  for (int channel = 0; channel < 256; channel++) {
    // change the resistance on this channel from min to max:
    writeSPI(sinewave[channel]);
    // wait a second at the top:
    delay(100);
  }

}

void writeSPI(float value) {
  // take the SS pin low to select the chip:
  digitalWrite(SELPIN, LOW);
  //  send in the address and value via SPI:
  int output = value;
  SPI.transfer(output);
  Serial.println(output);
  // take the SS pin high to de-select the chip:
  digitalWrite(SELPIN, HIGH);
}

Thanks

arcon19:
Hello everyone, I want to use a TI DAC8411 with the SPI library and output an sine wave. What I think is happening is due to an interrupt being fired at every 16 cycle. However the only problem with this is that it doesnt only happen every 16 cycles

“Level-triggered control input (active low). This is the frame sychronization signal for the input
data. When SYNC goes low, it enables the input shift register and data are transferred in on the
falling edges of the following clocks. The DAC is updated following the 24th (DAC8411) or 16th
(DAC8311) clock cycle, unless SYNC is taken high before this edge, in which case the rising
edge of SYNC acts as an interrupt and the write sequence is ignored by the DAC8x11. Refer to
the DAC8311 and DAC8411 SYNC Interrupt sections for more details.”

Documentation: http://www.ti.com/lit/ds/sbas439c/sbas439c.pdf

Screenshot of logic analyzer : Imgur: The magic of the Internet

Heres a sample of my code

/*

Digital Pot Control

This example controls an Analog Devices AD5206 digital potentiometer.
 The AD5206 has 6 potentiometer channels. Each channel’s pins are labeled
 A - connect this to voltage
 W - this is the pot’s wiper, which changes when you set it
 B - connect this to ground.

The AD5206 is SPI-compatible,and to command it, you send two bytes,
one with the channel number (0 - 5) and one with the resistance value for the
channel (0 - 255).

The circuit:
 * All A pins  of AD5206 connected to +5V
 * All B pins of AD5206 connected to ground
 * An LED and a 220-ohm resisor in series connected from each W pin to ground
 * CS - to digital pin 10  (SS pin)
 * SDI - to digital pin 11 (MOSI pin)
 * CLK - to digital pin 13 (SCK pin)

created 10 Aug 2010
by Tom Igoe

Thanks to Heather Dewey-Hagborg for the original tutorial, 2005

*/

// inslude the SPI library:
#include <SPI.h>

float sinewave[256] ={
127,130,133,136,139,143,146,149,152,155,158,161,164,167,170,173,176,178,181,184,187,190,192,195,198,200,203,205,208,210,212,215,217,219,221,223,225,227,229,231,233,234,236,238,239,240,
242,243,244,245,247,248,249,249,250,251,252,252,253,253,253,254,254,254,254,254,254,254,253,253,253,252,252,251,250,249,249,248,247,245,244,243,242,240,239,238,236,234,233,231,229,227,225,223,
221,219,217,215,212,210,208,205,203,200,198,195,192,190,187,184,181,178,176,173,170,167,164,161,158,155,152,149,146,143,139,136,133,130,127,124,121,118,115,111,108,105,102,99,96,93,90,87,84,81,78,
76,73,70,67,64,62,59,56,54,51,49,46,44,42,39,37,35,33,31,29,27,25,23,21,20,18,16,15,14,12,11,10,9,7,6,5,5,4,3,2,2,1,1,1,0,0,0,0,0,0,0,1,1,1,2,2,3,4,5,5,6,7,9,10,11,12,14,15,16,18,20,21,23,25,27,29,31,
33,35,37,39,42,44,46,49,51,54,56,59,62,64,67,70,73,76,78,81,84,87,90,93,96,99,102,105,108,111,115,118,121,124

};
// set pin 10 as the slave select for the digital pot:

#define DATAOUT 51   // MOSI
#define DATAIN 50    // MISO
#define SPICLOCK 52  // Clock
#define SELPIN 53    // chip-select
void setup() {
 // set the slaveSelectPin as an output:
 pinMode(SELPIN, OUTPUT);
 pinMode(SPICLOCK, OUTPUT);
 pinMode(DATAOUT, OUTPUT);
 // initialize SPI:
 digitalWrite(SELPIN, HIGH);
 
 SPI.setClockDivider( SPI_CLOCK_DIV16 ); // slow the SPI bus down
 SPI.setBitOrder(MSBFIRST);
 SPI.setDataMode(SPI_MODE0);    // SPI 0,0 as per MCP330x data sheet
 SPI.begin();
 Serial.begin(115200);
}

void loop() {
 // go through the six channels of the digital pot:
 for (int channel = 0; channel < 256; channel++) {
   // change the resistance on this channel from min to max:
   writeSPI(sinewave[channel]);
   // wait a second at the top:
   delay(100);
 }

}

void writeSPI(float value) {
 // take the SS pin low to select the chip:
 digitalWrite(SELPIN, LOW);
 //  send in the address and value via SPI:
 int output = value;
 SPI.transfer(output);
 Serial.println(output);
 // take the SS pin high to de-select the chip:
 digitalWrite(SELPIN, HIGH);
}




Thanks

Why did you define sinwave as a float array? you only use byte values (0…255)?

You define output as an int, but use SPI.transfer() which only sends a single byte. Because the Arduino uses an AVR ATMega chip multi byte values are stored LSB…MSB it happens to send the byte value you are using, but, you said the device expectes two bytes per transfer, a channel then value. I Don’t know why is it working at all.

I would change you sinwave, and change writeSpi():

void writeSPI(byte channel, byte value) {
  // take the SS pin low to select the chip:
  digitalWrite(SELPIN, LOW);
  //  send in the address and value via SPI:
  SPI.transfer(channel);
  SPI.transfer(value);
  digitalWrite(SELPIN,HIGH);
  Serial.println(output);
}

Also, SPI.begin() should be before any other calls to the SPI library.

Chuck

Hello Chuck,

Thanks for the response, I’m pretty new with SPI and DACs in general but I made the edits that you mentioned didn’t make sense. Here’s an updated version of my source that should hopefully be better although still doesn’t work. I’m still just trying to read a since wave from the Oscilloscope.

// inslude the SPI library:
#include <SPI.h>

byte sinewave[256] ={
 127,130,133,136,139,143,146,149,152,155,158,161,164,167,170,173,176,178,181,184,187,190,192,195,198,200,203,205,208,210,212,215,217,219,221,223,225,227,229,231,233,234,236,238,239,240,
 242,243,244,245,247,248,249,249,250,251,252,252,253,253,253,254,254,254,254,254,254,254,253,253,253,252,252,251,250,249,249,248,247,245,244,243,242,240,239,238,236,234,233,231,229,227,225,223,
 221,219,217,215,212,210,208,205,203,200,198,195,192,190,187,184,181,178,176,173,170,167,164,161,158,155,152,149,146,143,139,136,133,130,127,124,121,118,115,111,108,105,102,99,96,93,90,87,84,81,78,
 76,73,70,67,64,62,59,56,54,51,49,46,44,42,39,37,35,33,31,29,27,25,23,21,20,18,16,15,14,12,11,10,9,7,6,5,5,4,3,2,2,1,1,1,0,0,0,0,0,0,0,1,1,1,2,2,3,4,5,5,6,7,9,10,11,12,14,15,16,18,20,21,23,25,27,29,31,
 33,35,37,39,42,44,46,49,51,54,56,59,62,64,67,70,73,76,78,81,84,87,90,93,96,99,102,105,108,111,115,118,121,124

};

uint8_t divider = 24;
// set pin 10 as the slave select for the digital pot:

#define DATAOUT 51   // MOSI 
#define DATAIN 50    // MISO //not used
#define SPICLOCK 52  // Clock 
#define SELPIN 53    // chip-select
void setup() {

  // set the slaveSelectPin as an output:
  pinMode(SELPIN, OUTPUT);
  pinMode(SPICLOCK, OUTPUT);
  pinMode(DATAOUT, OUTPUT);
  // initialize SPI:
  digitalWrite(SELPIN, HIGH); 
   SPI.begin();
  SPI.setClockDivider( SPI_CLOCK_DIV16 ); // slow the SPI bus down
  SPI.setBitOrder(MSBFIRST);
  SPI.setDataMode(SPI_MODE1); 
  Serial.begin(115200);
}

void loop() {
  // go through the six channels of the digital pot:
  for (int channel = 0; channel < 256; channel++) {
    // change the resistance on this channel from min to max:
    writeSPI(channel ,sinewave[channel]);
    // wait a second at the top:
    delay(100);
  }

}

void writeSPI(byte channel ,byte value) {
  // take the SS pin low to select the chip:
  digitalWrite(SELPIN, LOW);
  //  send in the address and value via SPI:
  int output = value;
  SPI.transfer(channel);
  SPI.transfer(output);
  Serial.println(output);
  // take the SS pin high to de-select the chip:
  digitalWrite(SELPIN, HIGH);
}

I’m following the 9.1.1.3 DAC8x11 to 68HC11 Interface example as far as my pins and settings are concerned

"The 68HC11 should be configured so that its CPOL bit is a ‘0’ and its CPHA bit is a ‘1’. This configuration causes data appearing on the MOSI output to be valid on the falling edge of SCK. When data are being transmitted to the DAC, the SYNC line is taken low (PC7). Serial data from the 68HC11 are transmitted in 8-bit bytes with only eight falling clock edges occurring in the transmit cycle. Data are transmitted MSB first. In order to load data to the DAC8x11, PC7 is held low after the first eight bits are transferred, and a second serial write operation is performed to the DAC; PC7 is taken high at the end of this procedure.

but i still havn’t received any sort of output. Do you have any other suggestions?

arcon19:
Hello Chuck,

Thanks for the response, I’m pretty new with SPI and DACs in general but I made the edits that you mentioned didn’t make sense. Here’s an updated version of my source that should hopefully be better although still doesn’t work. I’m still just trying to read a since wave from the Oscilloscope.

// inslude the SPI library:

#include <SPI.h>

byte sinewave[256] ={
127,130,133,136,139,143,146,149,152,155,158,161,164,167,170,173,176,178,181,184,187,190,192,195,198,200,203,205,208,210,212,215,217,219,221,223,225,227,229,231,233,234,236,238,239,240,
242,243,244,245,247,248,249,249,250,251,252,252,253,253,253,254,254,254,254,254,254,254,253,253,253,252,252,251,250,249,249,248,247,245,244,243,242,240,239,238,236,234,233,231,229,227,225,223,
221,219,217,215,212,210,208,205,203,200,198,195,192,190,187,184,181,178,176,173,170,167,164,161,158,155,152,149,146,143,139,136,133,130,127,124,121,118,115,111,108,105,102,99,96,93,90,87,84,81,78,
76,73,70,67,64,62,59,56,54,51,49,46,44,42,39,37,35,33,31,29,27,25,23,21,20,18,16,15,14,12,11,10,9,7,6,5,5,4,3,2,2,1,1,1,0,0,0,0,0,0,0,1,1,1,2,2,3,4,5,5,6,7,9,10,11,12,14,15,16,18,20,21,23,25,27,29,31,
33,35,37,39,42,44,46,49,51,54,56,59,62,64,67,70,73,76,78,81,84,87,90,93,96,99,102,105,108,111,115,118,121,124

};

uint8_t divider = 24;
// set pin 10 as the slave select for the digital pot:

#define DATAOUT 51  // MOSI
#define DATAIN 50    // MISO //not used
#define SPICLOCK 52  // Clock
#define SELPIN 53    // chip-select
void setup() {

// set the slaveSelectPin as an output:
  pinMode(SELPIN, OUTPUT);
  pinMode(SPICLOCK, OUTPUT);
  pinMode(DATAOUT, OUTPUT);
  // initialize SPI:
  digitalWrite(SELPIN, HIGH);
  SPI.begin();
  SPI.setClockDivider( SPI_CLOCK_DIV16 ); // slow the SPI bus down
  SPI.setBitOrder(MSBFIRST);
  SPI.setDataMode(SPI_MODE1);
  Serial.begin(115200);
}

void loop() {
  // go through the six channels of the digital pot:
  for (int channel = 0; channel < 256; channel++) {
    // change the resistance on this channel from min to max:
    writeSPI(channel ,sinewave[channel]);
    // wait a second at the top:
    delay(100);
  }

}

void writeSPI(byte channel ,byte value) {
  // take the SS pin low to select the chip:
  digitalWrite(SELPIN, LOW);
  //  send in the address and value via SPI:
  int output = value;
  SPI.transfer(channel);
  SPI.transfer(output);
  Serial.println(output);
  // take the SS pin high to de-select the chip:
  digitalWrite(SELPIN, HIGH);
}





I'm following the 9.1.1.3 DAC8x11 to 68HC11 Interface example as far as my pins and settings are concerned

"The 68HC11 should be configured so that its CPOL bit is a '0' and its CPHA bit is a '1'. This configuration causes data appearing on the MOSI output to be valid on the falling edge of SCK. When data are being transmitted to the DAC, the SYNC line is taken low (PC7). Serial data from the 68HC11 are transmitted in 8-bit bytes with only eight falling clock edges occurring in the transmit cycle. Data are transmitted MSB first. In order to load data to the DAC8x11, PC7 is held low after the first eight bits are transferred, and a second serial write operation is performed to the DAC; PC7 is taken high at the end of this procedure."

but i still havn't received any sort of output. Do you have any other suggestions?

arcon19:
Hello Chuck,

Thanks for the response, I’m pretty new with SPI and DACs in general but I made the edits that you mentioned didn’t make sense. Here’s an updated version of my source that should hopefully be better although still doesn’t work. I’m still just trying to read a since wave from the Oscilloscope.

Ok,
Reading the Data sheet for your Chip, DAC8411, The chip responds to a 24bit command.

the first two bits are control, the next 16 are the DAC output value followed by a 6 bit filler. so your description of the DAC chip was not correct.

Here is what I think your writeSPI() should be

void writeSPI( byte value){ // I previously thought the DAC had multiple outputs (channels), it only has one
// and the mode control bits are inserted into the bit stream.  I was wrong on how to send the data stream.

// configure SPI hardware for the maximum clock rate, bit order, clock phase and polarity

  SPI.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE2)); // set correct SPI modes

  // take the SS pin low to select the chip:

  digitalWrite(SELPIN, LOW);


  //  send device Mode bits and the first 6bits of the DAC value via SPI:

  byte output = value >>2; // the high bits b7, b6 need to be 0 for normal mode
 
  // send the control bits plus the high 6 bits of the output value
 
  SPI.transfer(output);

  output = value << 6; //  get the rest of the input value, the lower 2 bits of value, pad with zero's

  SPI.transfer(output);
  
  output = 0;
  // Send a filler byte, the device expects 24 bits of data
  SPI.transfer(output);

  // take the SS pin high to de-select the chip:
  digitalWrite(SELPIN, HIGH);
  SPI.endTransaction(); // release SPI bus for other devices
  
}

and the SPI Mode should be 2,
and the Chip can accept up to 50mhz clock, but the max of the UNO is 4,000,000

SPI.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE2));

void setup(){

digitalWrite(SELPIN,HIGH);
pinMode(SELPIN,OUTPUT);
SPI.begin();

// other setup code for serial

}

if these changes don’t work, try changing the SPIMODE value in the range of 0 to 3.

Chuck.