[TUT][SOFT] AD5061 sample code

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

I had to control an AD5061 for my latest project, so I thought I'd share a bit of code I wrote to exercise it.

 

I very likely could have sped this up significantly using SPI, but for this application, it didn't need to go faster than bit-banging it. The DAC itself has a maximum clocking rate of 30 MHz - well above the maximum clock rate of the ATTiny being used.

 

The result of this is a rail-to-rail sine wave on the DAC. The frequency of the sine wave will give you an indication of how fast the DAC write can take place. The table is 1024 entries long, so the frequency (in Hz) / 1024 is how long each DAC operation takes. On an ATMega328P running at 20 MHz, I got 44 µs.

 

#include <avr/io.h>
#include <avr/pgmspace.h>

#define DAC_PORT PORTB
#define DAC_CS _BV(PORTB1)
#define DAC_DO _BV(PORTB3)
#define DAC_CLK _BV(PORTB5)

const unsigned int PROGMEM sine_table[] = {
32768,32969,33170,33371,33572,33774,33975,34176,
34377,34578,34779,34980,35180,35381,35582,35782,
35982,36183,36383,36583,36782,36982,37182,37381,
37580,37779,37978,38177,38375,38573,38771,38969,
39166,39364,39561,39757,39954,40150,40346,40542,
40737,40932,41127,41321,41515,41709,41903,42096,
42288,42481,42673,42864,43056,43247,43437,43627,
43817,44006,44195,44383,44571,44759,44946,45133,
45319,45504,45690,45874,46058,46242,46425,46608,
46790,46972,47153,47333,47513,47693,47872,48050,
48228,48405,48582,48758,48933,49108,49282,49455,
49628,49800,49972,50143,50313,50483,50652,50820,
50988,51155,51321,51487,51651,51815,51979,52142,
52303,52465,52625,52785,52944,53102,53259,53416,
53572,53727,53881,54035,54188,54339,54491,54641,
54790,54939,55087,55234,55380,55525,55669,55813,
55955,56097,56238,56378,56517,56655,56793,56929,
57065,57199,57333,57466,57597,57728,57858,57987,
58115,58242,58368,58493,58618,58741,58863,58984,
59104,59224,59342,59459,59575,59691,59805,59918,
60030,60141,60251,60360,60468,60575,60681,60786,
60890,60993,61095,61195,61295,61393,61491,61587,
61682,61776,61869,61961,62052,62142,62230,62318,
62404,62490,62574,62657,62739,62820,62899,62978,
63055,63131,63206,63280,63353,63425,63495,63565,
63633,63700,63766,63830,63894,63956,64017,64077,
64136,64193,64250,64305,64359,64412,64464,64514,
64563,64611,64658,64704,64748,64791,64834,64874,
64914,64952,64990,65025,65060,65094,65126,65157,
65187,65216,65243,65269,65294,65318,65340,65362,
65382,65401,65418,65435,65450,65464,65476,65488,
65498,65507,65515,65521,65526,65530,65533,65535,
65535,65534,65532,65528,65524,65518,65511,65503,
65493,65482,65470,65457,65442,65427,65410,65391,
65372,65351,65329,65306,65282,65256,65230,65201,
65172,65142,65110,65077,65043,65008,64971,64933,
64894,64854,64813,64770,64726,64681,64635,64587,
64539,64489,64438,64386,64332,64278,64222,64165,
64107,64047,63987,63925,63862,63798,63733,63666,
63599,63530,63460,63389,63317,63244,63169,63093,
63017,62939,62860,62779,62698,62616,62532,62447,
62361,62274,62186,62097,62007,61915,61823,61729,
61635,61539,61442,61344,61245,61145,61044,60942,
60838,60734,60629,60522,60415,60306,60196,60086,
59974,59862,59748,59633,59517,59401,59283,59164,
59044,58924,58802,58679,58556,58431,58305,58179,
58051,57923,57793,57663,57532,57399,57266,57132,
56997,56861,56724,56586,56448,56308,56168,56026,
55884,55741,55597,55452,55307,55160,55013,54865,
54716,54566,54415,54264,54111,53958,53804,53650,
53494,53338,53181,53023,52864,52705,52545,52384,
52223,52060,51897,51734,51569,51404,51238,51071,
50904,50736,50568,50398,50228,50058,49886,49714,
49542,49369,49195,49020,48845,48670,48493,48317,
48139,47961,47782,47603,47424,47243,47062,46881,
46699,46517,46334,46150,45966,45782,45597,45412,
45226,45039,44852,44665,44477,44289,44101,43912,
43722,43532,43342,43151,42960,42769,42577,42385,
42192,41999,41806,41612,41418,41224,41029,40835,
40639,40444,40248,40052,39856,39659,39462,39265,
39068,38870,38672,38474,38276,38077,37879,37680,
37481,37281,37082,36882,36683,36483,36283,36083,
35882,35682,35481,35281,35080,34879,34678,34477,
34276,34075,33874,33673,33472,33271,33069,32868,
32667,32466,32264,32063,31862,31661,31460,31259,
31058,30857,30656,30455,30254,30054,29853,29653,
29452,29252,29052,28852,28653,28453,28254,28054,
27855,27656,27458,27259,27061,26863,26665,26467,
26270,26073,25876,25679,25483,25287,25091,24896,
24700,24506,24311,24117,23923,23729,23536,23343,
23150,22958,22766,22575,22384,22193,22003,21813,
21623,21434,21246,21058,20870,20683,20496,20309,
20123,19938,19753,19569,19385,19201,19018,18836,
18654,18473,18292,18111,17932,17753,17574,17396,
17218,17042,16865,16690,16515,16340,16166,15993,
15821,15649,15477,15307,15137,14967,14799,14631,
14464,14297,14131,13966,13801,13638,13475,13312,
13151,12990,12830,12671,12512,12354,12197,12041,
11885,11731,11577,11424,11271,11120,10969,10819,
10670,10522,10375,10228,10083,9938,9794,9651,
9509,9367,9227,9087,8949,8811,8674,8538,
8403,8269,8136,8003,7872,7742,7612,7484,
7356,7230,7104,6979,6856,6733,6611,6491,
6371,6252,6134,6018,5902,5787,5673,5561,
5449,5339,5229,5120,5013,4906,4801,4697,
4593,4491,4390,4290,4191,4093,3996,3900,
3806,3712,3620,3528,3438,3349,3261,3174,
3088,3003,2919,2837,2756,2675,2596,2518,
2442,2366,2291,2218,2146,2075,2005,1936,
1869,1802,1737,1673,1610,1548,1488,1428,
1370,1313,1257,1203,1149,1097,1046,996,
948,900,854,809,765,722,681,641,
602,564,527,492,458,425,393,363,
334,305,279,253,229,206,184,163,
144,125,108,93,78,65,53,42,
32,24,17,11,7,3,1,0,
0,2,5,9,14,20,28,37,
47,59,71,85,100,117,134,153,
173,195,217,241,266,292,319,348,
378,409,441,475,510,545,583,621,
661,701,744,787,831,877,924,972,
1021,1071,1123,1176,1230,1285,1342,1399,
1458,1518,1579,1641,1705,1769,1835,1902,
1970,2040,2110,2182,2255,2329,2404,2480,
2557,2636,2715,2796,2878,2961,3045,3131,
3217,3305,3393,3483,3574,3666,3759,3853,
3948,4044,4142,4240,4340,4440,4542,4645,
4749,4854,4960,5067,5175,5284,5394,5505,
5617,5730,5844,5960,6076,6193,6311,6431,
6551,6672,6794,6917,7042,7167,7293,7420,
7548,7677,7807,7938,8069,8202,8336,8470,
8606,8742,8880,9018,9157,9297,9438,9580,
9722,9866,10010,10155,10301,10448,10596,10745,
10894,11044,11196,11347,11500,11654,11808,11963,
12119,12276,12433,12591,12750,12910,13070,13232,
13393,13556,13720,13884,14048,14214,14380,14547,
14715,14883,15052,15222,15392,15563,15735,15907,
16080,16253,16427,16602,16777,16953,17130,17307,
17485,17663,17842,18022,18202,18382,18563,18745,
18927,19110,19293,19477,19661,19845,20031,20216,
20402,20589,20776,20964,21152,21340,21529,21718,
21908,22098,22288,22479,22671,22862,23054,23247,
23439,23632,23826,24020,24214,24408,24603,24798,
24993,25189,25385,25581,25778,25974,26171,26369,
26566,26764,26962,27160,27358,27557,27756,27955,
28154,28353,28553,28753,28952,29152,29352,29553,
29753,29953,30154,30355,30555,30756,30957,31158,
31359,31560,31761,31963,32164,32365,32566,32768
};

static void writeDacValue(unsigned int value) {
  PORTB |= DAC_CLK;
  PORTB &= ~DAC_CS;
  PORTB &= ~DAC_DO;
  // we're going to write a bunch of zeros. The first six are just
  // padding, and the last two are power-off bits that we want to be
  // always zero.
  for(int i = 0; i < 8; i++) {
    PORTB &= ~DAC_CLK;
    PORTB |= DAC_CLK;
  }
  for(int i = 15; i >= 0; i--) {
    if ((value >> i) & 0x1)
      PORTB |= DAC_DO;
    else
      PORTB &= ~DAC_DO;
    PORTB &= ~DAC_CLK;
    PORTB |= DAC_CLK;
  }
  PORTB |= DAC_CS;
}

void main() {
  PORTB |= DAC_CS;
  DDRB = _BV(DDB1) | _BV(DDB3) | _BV(DDB5);

  while(1) {
    for(int i = 0; i < sizeof(sine_table) / sizeof(unsigned int); i++) {
      unsigned int val = pgm_read_word(&(sine_table[i]));
      writeDacValue(val);
    }
  }
}

Last Edited: Wed. Aug 9, 2017 - 03:55 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Since writing that, I came up with an efficiency improvement.

 

If you replace writeDacValue with:

 

static void writeDacValue(const unsigned int value) {
  // First, insure CLK is high
  PORTB |= DAC_CLK;
  // Now assert CS to start
  PORTB &= ~DAC_CS;
  unsigned long v = value;
  // This would be the point at which we would OR in any
  // control bits we might want to set. It turns out, we
  // don't want to.
  for(unsigned long mask = 1L << 23 ; mask != 0; mask <<= 1) {
    // Copy the appropriate bit to the DO pin
    if (v & mask)
      PORTB |= DAC_DO;
    else
      PORTB &= ~DAC_DO;
    // Toggle the clock pin
    PORTB &= ~DAC_CLK;
    PORTB |= DAC_CLK;
  }
  // And finally, de-assert CS
  PORTB |= DAC_CS;
}

 

In the original code, (value >> i) winds up itself being a loop in assembly language, so you wind up with the first bits being sent much faster than the last ones.

 

This code also works for the AD5680 DAC, except that the parameter is an unsigned long instead of an unsigned int (since the AD5680 is an 18 bit DAC), and to make 'v' from 'value', you need to left-shift it two positions (and there are, in fact, no control bits to play with). It's still a 24 bit word.

Last Edited: Tue. Dec 27, 2016 - 05:56 AM