I am using this code which is a slightly tweaked version of GitHub - vexuk1971/AD537x-Arduino-Uno-R3-Control: Control an AD537x Eval Board with an Arduino - only Uno R3 supported yet
I am not able to understand the parameters that need to typed in serial monitor to view an output. BY default when I am measuring the voltage from channel 1, I get 0.004v, when I type in C I get -0.007V. when I type in DW, I see 6.68V... My connections are as per the suggestions mentioned in the code from the above link.. I use a 12v Vdd and a -12v Vss and a 5v Vcc from the Uno..
#include "SPI.h"
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Control of the AD5370 EVAL board using arduino uno R3/Mega
//
// AD5370 datasheet:
// https://www.analog.com/media/en/technical-documentation/data-sheets/AD5370.pdf
//
// EVAL-AD5370 board datasheet:
// https://www.analog.com/media/en/technical-documentation/evaluation-documentation/EVAL-AD5370_5372_5373EB.pdf
//
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
#define MY_DEBUG_VERSION
//===============================
// Pin assignments
//===============================
// SPI communication with EVAL-AD5370
// The Arduino Uno pins for the hardware SPI port are as follows:
// 10 - SS // slave select - unused here
// 11 - MOSI/SDI
// 12 - MISO/SDO // read data from device - unused here
// 13 - SCLK
//--------------
// Control pins
//--------------
constexpr uint8_t resetPin = 4; // RESET
constexpr uint8_t busyPin = 5; // BUSY, unused here
constexpr uint8_t clrPin = 6; // CLR
constexpr uint8_t ldacPin = 7; // LDAC, load DAC
constexpr uint8_t csPin = 8; // CS/SYNC
//===============================
// Defines
//===============================
#define SPI_FREQ 1000000UL
#define SPI_BIT_ORDER MSBFIRST
#define SPI_MODE SPI_MODE1
// TODO: check where XREGMIN value came from
#define XREGMIN 21844
#define XREGMAX 0xFFFF
// for default values of offset and gain, see AD5370 datasheet, page 15, table 7, registers M and C
#define DEFAULT_GAIN 0x3FFF
#define DEFAULT_OFFSET 0x2000
#define CHANMAX 40 // AD5370 - 40 Channels max.
// AD5370 Register modes, see datasheet, page 21, table 9
#define MXREG 0xc0 //b11000000
#define MOFFSET 128 //b10000000
#define MGAIN 64 //b01000000
//===============================
// Variables
//===============================
enum channelMode_t{MCHAN, MALL}; // MCHAN -> modify a specified channel; MALL -> modify all channels
enum registerMode_t{XREG, OFFSET, GAIN}; // XREG -> set current X register; OFFSET -> set OFFSET register; GAIN -> set GAIN register
bool clrPinIsLow;
uint16_t xreg[CHANMAX]; // X reg Buffer Array
uint16_t offset[CHANMAX]; // Offset Buffer Array
uint16_t gain[CHANMAX]; // Gain Buffer Array
//===============================
// Utils
//===============================
void resetBufferArrays()
{
for(int i=0;i<CHANMAX;i++)
{
xreg[i] = XREGMIN;
offset[i] = DEFAULT_OFFSET;
gain[i] = DEFAULT_GAIN;
}
}
//===================================================
// AD5370 control pins Reset/Clear/Load management
//===================================================
void initDacControlPins()
{
// initialize all control pins to the inactive state
pinMode(csPin, OUTPUT);
digitalWrite(csPin, HIGH); // CS pin, active LOW, this pin is managed by the SPI low level routines
pinMode(resetPin, OUTPUT);
digitalWrite(resetPin, HIGH); // RESET pin, active LOW
pinMode(clrPin, OUTPUT);
digitalWrite(clrPin, HIGH); // CLR pin, active LOW
pinMode(ldacPin, OUTPUT);
digitalWrite(ldacPin, HIGH); // LDAC pin, active LOW
}
//-----------------------------------------------------------------
// RESET pin
//
// For pin operations, see the datasheet, page 19, RESET FUNCTION
//
// Timing:
// Reset pulse LOW minimum time to reset the DAC is 30nS
// The time taken by the device to reset is 300 uS
//-----------------------------------------------------------------
void resetDac()
{
#ifdef MY_DEBUG_VERSION
Serial.println("Pulsing RESET");
#endif
digitalWrite(resetPin, LOW);
delayMicroseconds(10); // maybe not required, minimum duration is 30nS
digitalWrite(resetPin, HIGH);
delayMicroseconds(1000); // Reset Time after rising edge of Reset Pin, the minimum is 300 uS
}
//-------------------------------------------------------------------
// CLR pin
//
// From the AD5730 datasheet, page 19, CLEAR FUNCTION
//
// CLR is an active low input that should be high for normal
// operation. The CLR pin has in internal 500 kΩ pull-down
// resistor. When CLR is low, the input to each of the DAC output
// buffer stages, VOUT0 to VOUT39, is switched to the externally
// set potential on the relevant SIGGND pin. While CLR is low, all
// LDAC pulses are ignored. When CLR is taken high again, the
// DAC outputs remain cleared until LDAC is taken low. The contents
// of the input registers and DAC registers are not affected by taking
// CLR low. To prevent glitches from appearing on the outputs, CLR
// should be brought low by writing to the offset DAC whenever
// the output span is adjusted.
//--------------------------------------------------------------------
void setClearLow()
{
#ifdef MY_DEBUG_VERSION
Serial.println("CLR pin LOW");
#endif
clrPinIsLow = true;
digitalWrite(clrPin, LOW);
}
void setClearHigh()
{
#ifdef MY_DEBUG_VERSION
Serial.println("CLR pin HIGH");
#endif
clrPinIsLow = false;
digitalWrite(clrPin, HIGH);
}
void toggleClear()
{
if (clrPinIsLow)
setClearHigh();
else
setClearLow();
}
//------------------------------------------------------------
// LDAC pin
//
// See the AD5370 datasheet, page 19, BUSY AND LDAC FUNCTIONS
//------------------------------------------------------------
void loadDac()
{
#ifdef MY_DEBUG_VERSION
Serial.println("Pulsing LDAC");
#endif
digitalWrite(ldacPin, LOW);
delayMicroseconds(10); // TODO: check if that delay is required
digitalWrite(ldacPin, HIGH);
delayMicroseconds(10); // TODO: check if that delay is required
}
//=========================
// SPI low level I/O
//=========================
void spiWrite(uint8_t *writeList, size_t writeListLen)
{
// for the SPI basics, see
// https://docs.arduino.cc/learn/communication/spi/
// start the SPI transaction
SPI.beginTransaction(SPISettings(SPI_FREQ, SPI_BIT_ORDER, SPI_MODE));
// select the SPI device
digitalWrite(csPin, LOW);
// TODO: check if a delay is needed here
// start transferring (or requesting for) the bytes;
// response will overwrite writeList, not used here (MISO pin unconnected)
SPI.transfer(writeList, writeListLen);
// TODO: check if a delay is needed here
// Deselect the SPI device
digitalWrite(csPin, HIGH);
// End the transaction
SPI.endTransaction();
}
// write a special function command to the dac and call loadDac
// for special functions codes and operations, see datasheet, page 23
void writeFunction(uint8_t function, uint16_t value)
{
// Write special function
// function: 6 bit function code, the byte's upper 2 bits must be 0
// value: Value to write. 0-65535
#ifdef MY_DEBUG_VERSION
Serial.println("Write special function:");
Serial.print("Function 0x");
Serial.println(function, HEX);
Serial.print("Value 0x");
Serial.println(value, HEX);
#endif
uint8_t x = B00000000;
uint8_t a = function;
uint8_t writeList[3];
writeList[0] = x + a;
writeList[1] = uint8_t(value>> 8);
writeList[2] = value & 0xff;
spiWrite(writeList, sizeof(writeList));
loadDac();
}
// send a 24 bit value; does not call loadDac -> only set register(s) without modifying DAC outputs
void writeValueInt(registerMode_t reg, channelMode_t cmod, uint8_t channel, uint16_t value)
{
// Write XREG/OFFSET/GAIN value to specific output (cmod == MCHAN) or to all channels (cmod == MALL)
// if cmod == MALL, the channel parameter is ignored
#ifdef MY_DEBUG_VERSION
if(reg==XREG) Serial.println("XREG:");
else if(reg==OFFSET) Serial.println("OFFSET:");
else if(reg==GAIN) Serial.println("GAIN:");
if(cmod==MALL)
{
Serial.print("Write to all channels: ");
}
else
{
Serial.print("Write to channel #");
Serial.print(channel);
Serial.print(": ");
}
Serial.println(value, DEC);
#endif
uint8_t x=0; // mode bits
uint8_t a=0; // address bits; 0 -> all channels; 8+channel number -> specific channel
switch(reg)
{
case XREG: x=MXREG; break; //192 - Dac X1A or X1B Register select
case OFFSET: x=MOFFSET; break; //128 - Offset register select
case GAIN: x=MGAIN; break; //64 - Gain Register select
default: x=MXREG; // default is Dac X Register selected
}
if (channel >= CHANMAX)
{
Serial.println("Error: writeValueInt: channel number out of range");
return;
}
if (cmod == MCHAN)
{
a=channel+8; // Mode MCHAN -> a specific channel is selected - add group offset and channel number
}
uint8_t writeList[3];
writeList[0] = x + a; //summary Dac Register + Channel, a is 0 for mode MALL
writeList[1] = uint8_t(value >> 8); //value high byte
writeList[2] = value & 0xff; //value low byte
spiWrite(writeList, sizeof(writeList));
}
//==========================================
// XREG/GAIN/OFFSET register groups writing
//==========================================
// write the same value in all channels from root to target
// if root or target >= CHANMAX, write all channels
void initRegister(registerMode_t reg, uint8_t root, uint8_t target, uint16_t value )
{
uint16_t *pArray;
channelMode_t mode=MALL;
if((root < CHANMAX) && (target < CHANMAX))
{
mode=MCHAN;
if (root > target)
{
// swaps root and target, root should be always <= target
uint8_t temp = root;
root = target;
target = temp;
}
}
#ifdef MY_DEBUG_VERSION
if(reg==XREG) Serial.println("XREG:");
else if(reg==OFFSET) Serial.println("OFFSET:");
else if(reg==GAIN) Serial.println("GAIN:");
if(mode==MALL)
{
Serial.print("Init all channels to ");
}
else
{
Serial.print("Init channels from #");
Serial.print(root);
Serial.print(" to #");
Serial.print(target);
Serial.print(" to ");
}
Serial.println(value, DEC);
#endif
switch(reg)
{
case XREG: pArray=xreg; break;
case OFFSET: pArray=offset; break;
case GAIN: pArray=gain; break;
default: pArray=xreg;
}
if (mode == MALL)
{
writeValueInt(reg, MALL, 0, value); //simply write one time only a value to all channels/groups
for(uint8_t i=0; i<CHANMAX; i++)
pArray[i]=value; //update complete register Array
}
else if (mode == MCHAN)
{
for(uint8_t i=root; i<=target; i++)
{
pArray[i]=value; //update register Array from root to target channel
writeValueInt(reg, MCHAN, i, value); //write value from root to target channel in desired Register
}
}
// required, writeValueInt does not call loadDac()
loadDac();
}
// copy the values of a buffer array to all corresponding channels from root to target
// if root or target >= CHANMAX, write all channels
void writeFromArray(registerMode_t reg, uint8_t root, uint8_t target)
{
uint16_t *pArray;
uint16_t value=0;
channelMode_t mode=MALL;
if((root < CHANMAX) && (target < CHANMAX))
{
mode=MCHAN;
if (root > target)
{
uint8_t temp = root;
root = target;
target = temp;
}
}
#ifdef MY_DEBUG_VERSION
if(reg==XREG) Serial.println("XREG:");
else if(reg==OFFSET) Serial.println("OFFSET:");
else if(reg==GAIN) Serial.println("GAIN:");
if(mode==MALL)
{
Serial.println("Writing buffer array to all channels");
}
else
{
Serial.print("Writing buffer array values to channels from #");
Serial.print(root);
Serial.print(" to #");
Serial.println(target);
}
#endif
switch(reg)
{
case XREG: pArray=xreg; break;
case OFFSET: pArray=offset; break;
case GAIN: pArray=gain; break;
default: pArray=xreg;
}
if (mode==MALL)
{
for(uint8_t i=0; i<CHANMAX; i++)
{
value=pArray[i];
writeValueInt(reg, MCHAN, i, value);
}
}
else if (mode==MCHAN)
{
for(uint8_t i=root; i<=target; i++)
{
value=pArray[i];
writeValueInt(reg, MCHAN, i, value);
}
}
// required, writeValueInt does not call loadDac()
loadDac();
}
//================================
// User serial command processing
//================================
void serialEvent()
{
//
// Listens and executes the user commands entered on serial input
//
// Available commands are as follows:
//
// 1) Control pin management
// ----------------------
//
// "C" toggle CLR pin state
// "L" pulses LDAC
// "R" reset all registers
//
// 2) Set register type to be used for the multiple channels operations
// -----------------------------------------------------------------
//
// "X" set register type to XREG (DAC current X register)
// "O" set register type to OFFSET
// "G" set register type to GAIN
//
// 3) Multiple channels operations: updates all registers of assigned type for channel numbers from root to target
// ------------------------------------------------------------------------------------------------------------
//
// "F" set the root channel number for the "I" and "W" commands below; channel numbers start from 0
// "T" set the target channel number for the "I" and "W" commands below; channel numbers start from 0
//
// "I" writes an assigned value to the AD5730 channels from root to target included; if root or target channels numbers are >= CHANMAX writes all channels
// "W" writes values of the buffer arrays for the selected register type to the AD5730 corresponding channels from root to target included;
// if root or target channel numbers are >= CHANMAX writes all channels
//
// 4) Single channel operation, always uses the XREG register type
// ------------------------------------------------------------
//
// "@" sets channel number for single channel X register operation
// "$" sets and write the value to the X register of DAC channel set by the "@" command above.
//
// 5) Internal xreg buffer array management
// -------------------------------------
//
// "/" is used as delimiter between values to fill the xreg array: fills the current position of the xreg array with the preceding number and increments the current position
// "P" print all values in the xreg buffer array
//
// ----------------------
// COMMAND USAGE EXAMPLES
// ----------------------
//
// IMPORTANT NOTE: the Arduino IDE Serial Monitor baud rate must be set to 115200 baud to communicate with this program
//
// To test an example command string, copy (without the double quotes) and paste it in the input field of the Arduino IDE Serial Monitor, then press the Enter key
// Executing the "C", "L", "R", "I", "W", "$", "P" commands, the program will print some info on the Arduino IDE Serial Monitor
//
// a) Example command string for single channel operation:
//
// "31@65000$"
//
// where:
// "31@" set the channel #31
// "65000$" write the value 65000 to the DAC X register of the set channel (#31)
// Please notice that the channel number must always be set first
//
// b) Example command string for multiple channel operation:
//
// "X34F39T65000I"
//
// where:
// "X" will set the register type to XREG
// "34F" will set the root channel number to 34
// "39T" will set the target channel number to 39
// "65000I" will write the value 65000 to the DAC X registers of the channels numbers from root to target
//
static uint32_t serialdata=0;
static uint8_t i=0; // current update position for voltage array filling
static uint8_t channel=CHANMAX, root=CHANMAX, target=CHANMAX;
static registerMode_t reg=XREG;
while (Serial.available())
{
char inChar = Serial.read();
if(inChar > 47 && inChar < 58)
{
// digit input, update the current number in serialdata
serialdata*=10;
serialdata+=(inChar -48);
if (serialdata > 0xFFFF)
{
Serial.println("Command error: input number overflow");
serialdata = 0xFFFF;
}
continue;
}
switch(inChar)
{
case 'X': reg=XREG; serialdata=0; break; //Register type X register
case 'O': reg=OFFSET; serialdata=0; break; //Register type Offset
case 'G': reg=GAIN; serialdata=0; break; //Register type Gain
case 'F':
root = serialdata < CHANMAX ? serialdata : CHANMAX;
serialdata=0;
break; //root Channel Symbol use for Array and Initial operation
case 'T':
target = serialdata < CHANMAX ? serialdata : CHANMAX;
serialdata=0;
break; //target Channel Symbol use for Array and Initial operation
case 'I':
{
initRegister(reg, root, target, serialdata);
reg=XREG;
root=CHANMAX;
target=CHANMAX;
serialdata=0;
}
break;
case 'W':
{
writeFromArray(reg, root, target);
reg=XREG;
root=CHANMAX;
target=CHANMAX;
serialdata=0;
}
break;
case 'C': toggleClear(); serialdata=0; break;
case 'L': loadDac(); serialdata=0; break;
case 'R': resetDac(); serialdata=0; break;
case '@':
{ //Channel Symbol for specific Dac Channel
channel=serialdata;
//if(channel < CHANMAX) chipselect(0); //channel 0 to CHANMAX selected chip 0
//if(channel > CHANMAX) chipselect(1); //channel CHANMAX to CHAN2CHIP selected chip 1
serialdata=0;
}
break;
case '/':
{ //Value separator symbol increments channel and wrote value to buffer xreg array
xreg[i] = serialdata;
serialdata = 0;
i++;
if(i>=CHANMAX) i=0;
break;
}
case '$':
{ //Value symbol for specific Dac Channel
if(channel<CHANMAX)
{
writeValueInt(XREG, MCHAN, channel, serialdata);
loadDac();
xreg[channel] = serialdata;
}
else
{
Serial.println("$ command: channel number out of range");
}
channel = CHANMAX;
serialdata=0;
}
break;
case 'P':
{ //Print all data from voltage Array //later change to desired Register Array
Serial.println("Xreg buffer array:");
Serial.print("Current update position: ");
Serial.println(i);
for(uint8_t n=0; n<CHANMAX; n++)
{
Serial.print("Channel #");
Serial.print(n);
Serial.print(" Val ");
Serial.println(xreg[n], DEC);
}
serialdata=0;
}
break;
}
}
}
//----------------------------
// Arduino setup() and loop()
//----------------------------
void setup()
{
Serial.begin(115200);
// set all control pins as outputs and their output values to inactive
initDacControlPins();
resetBufferArrays();
SPI.begin();
resetDac();
loadDac();
}
void loop()
{
// the program uses the serialEvent function to parse user input and send the appropriate commands to the AD5370
// the serialEvent function call is not here because it is called automatically after exiting from the loop function
// see here:
// https://www.arduino.cc/reference/it/language/functions/communication/serial/serialevent/
}