[TUT] AVR 0/1-series DAC one-shot waveform generation

Go To Last Post
3 posts / 0 new
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

In this "commented example" i've tested some limits of DAC. First i'll list some experimental results (all gained in room temperature with VDD=5V):
1. With DAC is quite simple measure voltage reference "start-up time". Datasheet (40001913A) claims that is typicaly 25us. Note there is not maximum value - how long i should wait if i want to be sure ? :D I've set up DACs output at maximum value and change references. Reference voltage ramping up with rate 0.27V/us and ramping down 0.48V/us. If you are changing or disabling reference in aplication (for example autoranging or low-power design) you can calculate stabilisation time for specific situation.
2. Static accuarcy of ADC looks good. I've tested unloaded and 10k to GND loaded output with 2.5V reference in 20 points (more densely around both range ends) and deviation stays in 2.5mV (0.1% or 0.25LSB) range. Even in funny "forbidden" zones (0 to 0.2V) and (VDD-0.2 to VDD).  That of course don't cover errors in voltage reference.  
3. Datasheet says that output should not be loaded by smaller resistance then 5kOhm. I can confirm that, with maximum output voltage of DAC (4.34V) loading by 2kOhms to GND cause drop about 0.5LSB.
4. Question is temperature stability of internal voltage references. I've setup DAC to 255, select variety of references and heat chip up about 20°C over room temperature. Voltage rises about 0.7%. May be i've done something wrong, but its in confilct with datasheet. In typical characteristics reference should not change more then 0.4% in whole temperature range (-40 to +120°C). Especially in range 20 to 40°C (pretty close to my conditions) it should change less then 0.1% ... hm :/
5. Slew rate of DAC output (into 10kOhm load) is little more then 2V/us as evidenced by oscillogram below.

Slew rate of DAC output

Slew rate of DAC output

And now to the example itself.
Program should every 0.1s generate one-shot arbitrary waveform (gaussian pulse) with maximum possible sample rate (of course somebody can do that even faster). Output of DAC is PA6. Pin PA4 serves for time measurment and for calculating real sample rate. Voltage reference for DAC is 4.34V, and waveform is stored in table.h file (in attachment). Using of DAC is very easy. You should select reference, enable ADC and write into DAC0.DATA... thats all. Because there is not DAC triggering mechanism it can be difficulty ensure proper timing. Pitty that there is not option to use for example events to trigger DA conversion.

/* tutorial TinyAVR 1-Series
* DAC 2
* One-shot waveform generation with sample rate about 2Msps
* Waveform saved in table.h in array "table", DAC output at PA6
* At PA4 measuring time needed to "put out" whole waveform
* compiled with optimisation -O3

/* Fuses selected 20MHz oscillator */
#define F_CPU 20000000UL
#include <util/delay.h>
#include <avr/io.h>
#include "table.h" // there is stored waveform (2048 8bit points)

extern const uint8_t table[]; // array with waveform samples
void clock_20MHz(void);
void init_dac(void);
void init_tca(void);
uint16_t idx; // index going thru waveform array

int main(void){
 clock_20MHz(); // full speed of 20MHz
 init_dac(); // config DAC (reference 4.34V)
 PORTA.DIRSET = PIN4_bm; // output for time measuring

 while (1){
  idx=sizeof(table)-1; // going thru table backwards
  PORTA.OUTSET = PIN4_bm; // start generating
  while(idx){ // until reach end of array
   DAC0.DATA = table[idx]; // load new sample into DAC
   idx--; // decrementing index
  PORTA.OUTCLR = PIN4_bm; // generating done
  _delay_ms(100); // wait 0.1ms and start again

void init_dac(void){
 VREF.CTRLA = VREF_DAC0REFSEL_4V34_gc; // start voltage reference for DAC (4.34V)
 _delay_us(25); // startup time for voltage reference
 DAC0.CTRLA = DAC_ENABLE_bm | DAC_OUTEN_bm; // enable DAC and enable its output (PA6)

//Setup 20MHz clock 20MHz from internal RC oscillator
void clock_20MHz(void){
 // may disable interruption around this code
 _PROTECTED_WRITE(CLKCTRL.MCLKCTRLB, 0); // disable prescaler (route 20MHz directly to core)


Result of this code can be observed at oscillogram below. Note PA4 signal. Pulse is ~1012ms wide (don't believe last two digits - it's only scope) and we can guess that conversion speed was about 2Msps. Not bad for cheap micro. Of course its only 8bit and some waveforms (which includings large steps) can be limited by slew rate. For generation waveforms with slower rates and "precise" timing consider using timer with high priority interrupt.

example output - gaussian pulse

waveform file (table.h) in attachment with matlab/octave script (generator_pulz.txt) to generate that data.


Last Edited: Sun. Feb 17, 2019 - 08:34 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Nice work yes


Now I feel I should contribute some AVR 0/1 tutorials too... I did some experiments, but they are scattered as random posts.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well done!