Go Down

Topic: Due DAC Update Rate / Resolution (Read 1 time) previous topic - next topic

CogentDev

I'm new to the Due and am having trouble getting good analog voltage resolution from DAC0 and DAC1.   I've been searching through this forum and other websites for a clue.  Many have asked about similar problems or issues, but I have not been able to find this specific issue addressed.

When I upload the attached code and connect a voltmeter to DAC0, the voltage does vary, but does so  in very large increments.   The voltmeter initially indicates 1.26 volts on the pin and remains at this voltage until the serial output indicates over 2 volts.  Once the serial output is over 2 volts the voltmeter jumps from 1.26 to 2 volts.  The voltmeter remains at 2 volts while the serial output increases from 2 volts to 2.6 volts and decreases back below 2 volts.  Once the serial output decreases below 2 volts, the voltmeter drops back down to 1.26 again.  Similarly on the lower half of the sine wave, the voltmeter indicates 0.53 volts while the serial output is below 1.26 volts.  Essentially, I'm only getting 3 steps worth of resolution even though I've specified analogWriteResolution(12). 

I've tried this on both DAC0 and DAC1 on two Due boards with the same results. Based on the analog out voltage limitations of the board, I've also tried limiting the range in the mapping function from 0.5 to 2.5 volts (which did not have an significant effect on the resolution). I have no doubt I'm overlooking something very simple / fundamental, so I appreciate your time and any effort to assist.   

I've attached the code (Dac_test.ino) and the serial output (as an Excel file).



CogentDev

I've re-attached the serial output as a (csv) txt file.

ard_newbie


How about posting your code (between code tags !!)

CogentDev

Per request, code inserted below:

Code: [Select]


float amp;
float phase;
float freq;
float offset;
float aovolt;

unsigned long timestamp;

void setup() {
  // put your setup code here, to run once:

  freq = 0.01;
  offset = 1.6;
  aovolt = offset;
  analogWriteResolution(12);
  Serial.begin(9600);
}

void loop() {
  // put your main code here, to run repeatedly:

  timestamp = millis();
 
  aovolt = offset + sin(freq * timestamp / 1000.);
  analogWrite(DAC0, map(aovolt, 0.55, 2.5, 0, 4095));
 
  Serial.print(timestamp);
  Serial.print(", ");
  Serial.println(aovolt, 6);
 
  delay(6000);
}


ard_newbie


Try the snippet below. You should observe an DAC output on DAC0 and DAC1 between (1/6) * 3.3 V and (5/6) * 3.3 V by selecting Menu > Tools > Serial Tracer.

To filter noise and preserve your DACs, I suggest that you connect a jumper from DAC0 to a 2K resistor, then the other side of the resistor to A0 and to a capacitor of a few nf, and the other side of the capacitor to GND.

You can do the same experiment with DAC1.

Code: [Select]

const uint32_t sinsize = 256;
uint32_t sinus[sinsize];

void setup()
{
  Serial.begin(250000);
  analogReadResolution(12);
 
  for (uint32_t i = 0; i < sinsize; i++)   // Fill Sinus buffer
  {
    uint32_t chsel = (0 << 12) | (1 << 28);               // MSB [31:16]on DAC channel 1, LSB [15:0] on DAC channel 0
    sinus[i]  = 2047 * sin(i * 2 * PI / sinsize) + 2047; //  0 < sinus [i] < 4096
    sinus[i] |= sinus[i] << 16 | chsel;
  }

  dacc_setup();
}


void loop() {

  dac_write ();
  Serial.println(analogRead(A0));  // Output of DAC0
  //Serial.println(analogRead(A1)); // Output of DAC1

}

void dacc_setup () {

  PIOB->PIO_PDR |= PIO_PDR_P15 | PIO_PDR_P16;  // Disable GPIO on corresponding pins DAC0 and DAC1


  PMC->PMC_PCER1 |= PMC_PCER1_PID38 ;     // DACC power ON
  DACC->DACC_CR = DACC_CR_SWRST ;         // reset DACC

  DACC->DACC_MR = DACC_MR_REFRESH (1)
                  | DACC_MR_STARTUP_0
                  | DACC_MR_MAXS
                  | DACC_MR_TAG_EN
                  | DACC_MR_WORD_WORD;


  DACC->DACC_CHER = DACC_CHER_CH0 | DACC_CHER_CH1;      // enable DAC channel 0 and DAC channel 1

}

void dac_write () {

  static uint32_t Index = 0;

  while (!(DACC->DACC_ISR && DACC_ISR_TXRDY));  // Wait until DACC is ready for a new conversion
  DACC->DACC_CDR = (uint32_t) sinus[Index];  // Request a new conversion

  Index++;

  if (Index == sinsize) Index = 0;

}





CogentDev

Thank you for the snippet and the suggestion.  I spent some time yesterday looking over the code.  No doubt this will take me some time to decipher & digest.  I do appreciate the guidance.

Go Up