I need some help in working my DAC output please

Hi,

I want to take 2 different outputs from my DAC (and it should be switching with/like the timer for both outputs) but my DAC only gives one output (in ISR - interrupt service routine only one of the if statement function or the else statement's (when if statement is commented) works, not both). I want the DAC to give value for both if and else statement in ISR. For the given code it is only giving 2.9375Volts (called in isr-if statement). Not giving 2.5V (called in isr-else statement)

My timer is giving correct output when I connect oscilloscope to Pin9 and gnd (0.9ms on and 1.6ms off).I am using TLV5616 DAC from TI. Any help will be extremely appreciated please.

Kind Regards.
Uzair Arif

This is my code:

// TLV5616 DAC communication using SPI
#include <SPI.h>

/* TI TLV5616CP (2.7 to 5.5V) LP 12-Bit Digital to Analog Converter
For sensor details see: http://www.ti.com/lit/ds/sbas415c/sbas415c.pdf

Circuit:
TLV attached to Uno pins as follows:
TLV Pin Uno Pin
1 (DIN) 11 (MOSI - Output)
2 (SCLK) 13 (SCK - Output)
3 (/CS) 8 (Chip selec8t - Output)
4 (FS) 10 (SS - Output)

Note: TLV5616 has no provision for MISO pin 12, output is in volts
Created: Nov. 7, 2011, by KC */

// Pin 8 = /CS, Pin 10 = SS
const int chipSelect = 8;
const int slaveSelect = 10;

// Variables for TLV5616 Testing
const unsigned int control = 0x4000;
const unsigned int msbMask = 0xFF00;
const unsigned int lsbMask = 0x00FF;
unsigned int command, data;
byte commandMsb, commandLsb;

//Variables for timers setting
uint16_t timerOneVal[] = {14400, 25600};
uint8_t timerTwoVal[] = {90, 160};
bool timerOneItr = 0;
bool timerTwoItr = 0;

void setup(void)
{
Serial.begin(9600);
/* To "condition" the hardware we begin with the call: SPI.begin()
which configures the SPI pins (SCK, MOSI, SS) as outputs. It sets
SCK and MOSI low and SS high. It then enables SPI mode with the
hardware in master mode which has a side effect of setting MISO as
an input.

If necessary I can change the mode (CPOL and CPHA) or bit order w/
the functions: SPI.setDataMode or SPI.setBitOrder.

The SPI.transfer call does the actual transfer of bytes. I must
set /CS and SS at the appropriate time. When finished, call
SPI.end() to turn SPI hardware off */

SPI.begin();
SPI.setClockDivider(SPI_CLOCK_DIV2); // Freq SPI_CLK = 8MHz
SPI.setDataMode(SPI_MODE1); // CPOL = 0, CPHA = 1
pinMode(chipSelect, OUTPUT);
pinMode(slaveSelect, OUTPUT);

pinMode(9, OUTPUT);
// pinMode(11, OUTPUT);

digitalWrite(9, LOW);
// digitalWrite(11, LOW);

setTimers();
// setTimers();

}

//
//float VoltageRead()
//{
//
// // read the voltage input on analog pin 0:
// int sensorValue = analogRead(A0);
//
// // Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 5V):
// float voltageofbattery = sensorValue * (5.0 / 1023.0);
//
// Serial.println(voltageofbattery);
//
// return voltageofbattery;
//}

void setTimers()
{
cli();

TCCR1A = 0;
TCCR1B = 0;
TCNT1 = 0;
OCR1A = 0xFFFF; // set compare match register first time to full value (change values later on in the Interrupt service routine - ISR)
TCCR1A = 0x40; // toggle OC1A on compare
TCCR1B = 0x09; // Set CS10 and WGM12 bits for no prescaling and turning on CTC mode
TIMSK1 = 0x02; // enable timer compare interrupt

sei();

}

void setDacOutput(unsigned int dacValue)
{
digitalWrite(chipSelect, LOW); // Enable TLV5616 /CS
digitalWrite(slaveSelect, LOW); // Enable TLV5616 FS

/* The TLV5616 control bits are D14 and D13, D15 and D12 is don't care. The data
to be written to the TLV5616 is in Bits D11 to D0. commandMsb is the (8-bit) MSB
and commandLsb is the (8-bit) LSB of the 16-bit TLV5616 control word */

command = control | dacValue;
commandMsb = (command & msbMask) >> 8;
commandLsb = command & lsbMask;
SPI.transfer(commandMsb);
SPI.transfer(commandLsb);
delayMicroseconds(1);
digitalWrite(slaveSelect, HIGH); // Disable TLV5616 FS
digitalWrite(chipSelect, HIGH); // Disable TLV5616 /CS
// SPI.end();
}

ISR(TIMER1_COMPA_vect)
{

OCR1A = timerOneVal[timerOneItr];

if(!timerOneItr){
setDacOutput(0x0966); // 2406/0x0966 for 2.9375V; 2045/0x0800 for 2.500V;
timerOneItr = !timerOneItr;
}
else{
setDacOutput(0x0800);
timerOneItr = !timerOneItr;
}

}

//for relaxation of 5 minutes after each charge-discharge cycle
//void turnOffTimer()
//{
// TIMSK1 = 0x00;
// setDacOutput(2045);
// delay(300000);
// TIMSK1 = 0x02;
//}

//ISR(TIMER2_COMPA_vect)
//{
// OCR2A = timerTwoVal[timerTwoItr];
//
// if(!timerTwoItr)
// setDacOutput(2406); // 2406 for 2.9375; 2045 for 2.500;
// else
// setDacOutput(2045);
//
// timerTwoItr = !timerTwoItr;
//}

//
//void chargingloop()
//{
// float voltageofbatterynow = VoltageRead();
//
// if (voltageofbatterynow <= 4.15)
// {
// setTimers();
// }
// else if (voltageofbatterynow >= 4.15)
// {
// setDacOutput(1045);
// }
//
//}
void loop(void)
{
// while(1){
//
// chargingloop();
// turnOffTimer();
// }

}

I think you problem is here in your ISR routine:

if(!timerOneItr){
setDacOutput(0x0966); // 2406/0x0966 for 2.9375V; 2045/0x0800 for 2.500V;
timerOneItr = !timerOneItr;
}
else{
setDacOutput(0x0800);
timerOneItr = !timerOneItr;
}

try "if(timerOneItr){" instead of "if(!timerOneItr){"

Hi Sherzaad,

Both the statements are working. I have tried Serial.printIn for both if and else. And as I have declared timerOneItr=0 on top, so !timerOneItr will run the if statement. The problem is my DAC is only giving one output (either for if or for else) not for both. I think SPI communication is only running once.

The problem is that SPI uses interrupts and you are calling that from within a ISR. You can't do that.

Hi Sherzaad,

Both the statements are working. I have tried Serial.printIn for both if and else. And as I have declared timerOneItr=0 on top, so !timerOneItr will run the if statement. The problem is my DAC is only giving one output (either for if or for else) not for both. I think SPI communication is only running once.

Thanks a lot blh64.

Can you please guide me how to solve the problem then? I want one output from DAC (2.9375V) for 0.9 ms (milliseconds) and other output (2.5V) for 1.6 ms. Can you kindly guide me how to achieve this without using interrupts?

Thanks a lot

The simplest approach is to set a flag in your ISR and then have your loop() code react to it. If all you are doing is timing, you don't really need a ISR and can do it all within loop(). See the "delay without milliseconds" example on how to time events

Hi,

I am using tlv5616. I want to it can output 0~5V, however, it just can output 0~3.86V.
And tlv5616's reference input voltage is 3.3V, and the supply voltage is 5V.

Can your tlv5616 output 0~5V? what is your reference input voltage and supply voltage?

Thanks a lot.