Linduino  1.3.0
Linear Technology Arduino-Compatible Demonstration Board
EVAL-AD5686R.ino
Go to the documentation of this file.
1 /***************************************************************************//**
2  * @file EVAL-AD5686R.ino
3  * @brief Exerciser program for ad5686 no-OS driver
4  * @author Gbrisebois (gregory.brisebois@analog.com)
5 ********************************************************************************
6  * Copyright 2017(c) Analog Devices, Inc.
7  *
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions are met:
12  * - Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  * - Redistributions in binary form must reproduce the above copyright
15  * notice, this list of conditions and the following disclaimer in
16  * the documentation and/or other materials provided with the
17  * distribution.
18  * - Neither the name of Analog Devices, Inc. nor the names of its
19  * contributors may be used to endorse or promote products derived
20  * from this software without specific prior written permission.
21  * - The use of this software may or may not infringe the patent rights
22  * of one or more patent holders. This license does not release you
23  * from the requirement that you obtain separate licenses from these
24  * patent holders to use this software.
25  * - Use of the software either in source or binary form, must be run
26  * on or directly connected to an Analog Devices Inc. component.
27  *
28  * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
29  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
30  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
31  * IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
32  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
33  * LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
34  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
35  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
36  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
37  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 *******************************************************************************/
39 
40 #include <Arduino.h>
41 #include <stdint.h>
42 #include "Linduino.h"
43 #include "UserInterface.h"
44 #include "QuikEval_EEPROM.h"
45 #include <platform_drivers.h>
46 extern "C" {
47 #include <ad5686.h>
48 };
49 
50 
51 /******************************************************************************/
52 /************************** Variables Declarations ****************************/
53 /******************************************************************************/
54 
55 // Converts our DAC code into letters of which DAC is selected
56 const String dac_selection[4] =
57 {
58  "A",
59  "B",
60  "C",
61  "D"
62 };
63 
64 
66 {
67  GENERIC_I2C, // i2c type
68  0, // i2c id
69  0, // i2c max speed (hz)
70  0, // i2c slave address
71 };
72 
74 {
77  50000000,
78  1, // SPI mode
80 };
81 
82 ad5686_init_param init_params =
83 {
84  i2c_params, // I2C parameters (not used)
85  spi_params, // SPI parameters
86  4, // GPIO reset pin
87  5, // GPIO LDAC pin
88  ID_AD5686R, // Device type
89 };
90 
91 ad5686_dev *device;
92 
94 {
95  GENERIC_GPIO, // type
96  0, // ID
97  2, // Number
98 };
99 
100 int32_t connected = -1;
101 
102 void setup()
103 {
104  char demo_name[] = "AD5686R";
105 
106  Serial.begin(115200);
107 
108  // Give the serial port a chance to initialize
109  // Without this we get some garbage on the console
110  delay(100);
111 
112  connected = ad5686_init(&device, init_params);
113 
114  Serial.print("Initialized, ");
115  Serial.println(connected);
116 
117  if (connected == SUCCESS)
118  {
119  // De-assert reset
120  // DC2741 adapter has pullups to VIO as a crude output level-shifter
121  // on reset, gain, LDAC signals.
122  gpio_direction_input(device->gpio_reset); // DC2741 has pullup to VIO
123  // gpio_set_value(device->gpio_reset, GPIO_HIGH); // This would be more typical
124  // Set GAIN low
125  gpio_direction_output(&gpio_gain, GPIO_LOW);
126  // Set LDAC high so we can write to registers without updating
127  gpio_direction_input(device->gpio_ldac); // DC2741 has pullup to VIO
128 
129  print_title();
130  }
131  else
132  {
133  Serial.println(F("AD5686R not found! :("));
134  }
135 }
136 
137 void loop()
138 {
139  if (connected != SUCCESS) return;
140 
141  // DAC(s) to perform actions on
142  // Binarily represents which are selected with bits arranged like so: DCBA
143  // Examples:
144  // 0110 = B & C
145  // 1010 = B & D
146  // 1101 = A, C & D
147  // 1111 = All
148  static uint8_t selected_dac = 0;
149  static float ref_voltage = 2.5;
150 
151 
152  // Switch menu based on user's input
153  print_prompt(selected_dac, ref_voltage);
154  int user_command = read_int();
155  Serial.println(user_command);
156  Serial.flush();
157  switch (user_command)
158  {
159  case 1:
160  menu_1_select_dac(&selected_dac);
161  break;
162 
163  case 2:
164  menu_2_write_to_input_register(selected_dac, ref_voltage);
165  break;
166 
167  case 3:
168  menu_3_update_dac(selected_dac);
169  break;
170 
171  case 4:
172  menu_4_write_and_update_dac(selected_dac, ref_voltage);
173  break;
174 
175  case 5:
176  menu_5_set_DAC_power_mode(selected_dac);
177  break;
178 
179  case 6:
180  menu_6_select_ref_voltage(&ref_voltage);
181  break;
182 
183  case 7:
185  break;
186 
187  case 8:
189  break;
190 
191  case 9:
193  break;
194 
195  case 10:
197  break;
198 
199  case 11:
201  break;
202 
203  case 12:
205  break;
206 
207  default:
208  Serial.println("Incorrect Option");
209  break;
210  }
211 }
212 
213 
214 
215 
216 
217 //! Prints the title block
219 {
220  Serial.println(F("*****************************************************************"));
221  Serial.println(F("* EVAL-5686RSDZ Demonstration Program *"));
222  Serial.println(F("* *"));
223  Serial.println(F("* This program demonstrates communication with the AD5686R *"));
224  Serial.println(F("* 16-Bit Quad Rail-to-Rail DAC with SPI Interface. *"));
225  Serial.println(F("* *"));
226  Serial.println(F("* Set the baud rate to 115200 select the newline terminator. *"));
227  Serial.println(F("*****************************************************************"));
228 }
229 
230 // Prints the "main menu" prompt to the console
231 void print_prompt(uint8_t selected_dac, float ref_voltage) //!< this parameter is passed so that it can be printed at the bottom of the menu.
232 {
233  Serial.println(F("\nCommand Summary:"));
234 
235  Serial.println(F(" 1 -Select DAC"));
236  Serial.println(F(" 2 -Write to input register (no update)"));
237  Serial.println(F(" 3 -Update DAC from input"));
238  Serial.println(F(" 4 -Write and update DAC"));
239  Serial.println(F(" 5 -Power down mode"));
240  Serial.println(F(" 6 -Select reference voltage"));
241  Serial.println(F(" 7 -Read back all registers"));
242  Serial.println(F(" 8 -Set LDAC# mask"));
243  Serial.println(F(" 9 -Assert LDAC#"));
244  Serial.println(F(" 10-Set gain"));
245  Serial.println(F(" 11-Assert Software Reset"));
246  Serial.println(F(" 12-Assert Hardware Reset"));
247  Serial.println();
248 
249  Serial.print(F(" Selected DAC: "));
250  Serial.print(selected_dac, DEC);
251  Serial.print(F(" "));
252  Serial.println(dac_selection[selected_dac]);
253 
254  Serial.print(F(" Reference Voltage: "));
255  Serial.print(ref_voltage);
256  Serial.println(F("V"));
257 
258  Serial.println();
259  Serial.print(F("Enter a command: "));
260 }
261 
262 // Menu for user to select a DAC
263 // @param selected_dac - Reference of DAC identifier
264 uint8_t menu_1_select_dac(uint8_t *selected_dac)
265 {
266  // Serial.println(F(" DAC selections are represented in binary with"));
267  // Serial.println(F(" bits corresponding to: DCBA"));
268  // Serial.println(F(" (See datasheet for details and explanation)"));
269  // Serial.println(F(" For example:"));
270  // Serial.println(F(" B0001 - DAC A"));
271  // Serial.println(F(" B0010 - DAC B"));
272  // Serial.println(F(" B0100 - DAC C"));
273  // Serial.println(F(" B1000 - DAC D"));
274  // Serial.println(F(" B0101 - DAC A&C"));
275  // Serial.println(F(" B1111 - ALL"));
276  Serial.print(F(" Enter DAC to select (0 - 3, corresponding to DAC A - D)"));
277 
278  *selected_dac = (uint8_t)read_int();
279 
280  if (*selected_dac > 3)
281  *selected_dac = 3; // If user enters and invalid option, default to 3.
282  if (*selected_dac < 0)
283  *selected_dac = 0;
284 
285  Serial.println(*selected_dac, BIN);
286  Serial.print(F(" You selected DAC(s): "));
287  Serial.println(dac_selection[*selected_dac]);
288 
289  return SUCCESS; // Always returns success, consider adding a fail code later.
290 }
291 
292 //! Menu 2: Write to input register only. Does not update the output voltage.
293 //! @return Returns the state of the acknowledge bit after the I2C address write. 0=acknowledge, 1=no acknowledge.
294 uint8_t menu_2_write_to_input_register(uint8_t selected_dac, float vref) //!< DAC to be updated. 0=A, 1=B, 2=All
295 {
296  unsigned short vdata = get_voltage_code(vref);
297 
298  ad5686_write_register(device, selected_dac, vdata);
299 
300  return SUCCESS;// Always returns success, consider adding a fail code later.
301 }
302 
303 // Updates DAC outputs from its input registers
304 uint8_t menu_3_update_dac(uint8_t selected_dac)
305 {
306  //AD568X_WriteFunction(AD568X_CMD_UPDATE_DAC_N, selected_dac, 0);
307  ad5686_update_register(device, selected_dac);
308  Serial.println(F(" Updated DAC(s)"));
309 
310  return SUCCESS;
311 }
312 
313 // Menu for user to change a DAC's output voltage
314 // @param selected_dac - Reference of DAC identifier to update,
315 // corresponding to 0=A, 1=B, 2=C, 3=D, 4=A&B, 5=ALL
316 uint8_t menu_4_write_and_update_dac(uint8_t selected_dac, float vref) //!< DAC to be updated. 0=A, 1=B, 2=All
317 {
318  unsigned short vdata = get_voltage_code(vref);
319 
320  Serial.print("Entered code: ");
321  Serial.println(vdata, HEX);
322 
323  ad5686_write_update_register(device, selected_dac, vdata);
324 
325  return SUCCESS;
326 }
327 
328 
329 uint8_t menu_5_set_DAC_power_mode(uint8_t selected_dac)
330 {
331  // Cancel if no DAC selected
332  if (selected_dac == 0)
333  {
334  Serial.println(F(" No DAC selected, no changes made"));
335  return FAILURE;
336  }
337 
338  // Prompt for power mode
339  Serial.println(F("\n Power Modes:"));
340  Serial.println(F(" 1-Normal Operation"));
341  Serial.println(F(" 2-1kOhm to GND Power-Down"));
342  Serial.println(F(" 3-100kOhm to GND Power-Down"));
343  Serial.println(F(" 4-Three-State Power-Down"));
344  Serial.println();
345  Serial.print(F(" Select a power mode: "));
346 
347  // Get input
348  uint8_t mode_input = read_int();
349  uint8_t selected_mode = 0;
350 
351  // Validate input
352  if (mode_input > 4) mode_input = 4;
353  if (mode_input < 1) mode_input = 1;
354 
355  // Show validated input on console
356  Serial.println(mode_input);
357 
358  // Select proper power mode
359  switch (mode_input)
360  {
361  case 1:
362  selected_mode = AD5686_PWRM_NORMAL;
363  break;
364 
365  case 2:
366  selected_mode = AD5686_PWRM_1K;
367  break;
368 
369  case 3:
370  selected_mode = AD5686_PWRM_100K;
371  break;
372 
373  case 4:
374  selected_mode = AD5686_PWRM_THREESTATE;
375  break;
376 
377  default:
378  break;
379  }
380 
381  // Check bit-wise which DACs are selected
382  uint8_t dac1 = (selected_dac >> 0) & 1;
383  uint8_t dac2 = (selected_dac >> 1) & 1;
384  uint8_t dac3 = (selected_dac >> 2) & 1;
385  uint8_t dac4 = (selected_dac >> 3) & 1;
386 
387  // Apply power to selected DACS
388  if (dac1)
389  {
390  Serial.println(F(" Applying power mode to DAC A..."));
391  ad5686_power_mode(device, AD5686_CH_0, selected_mode);
392  }
393  if (dac2)
394  {
395  Serial.println(F(" Applying power mode to DAC B..."));
396  ad5686_power_mode(device, AD5686_CH_1, selected_mode);
397  }
398  if (dac3)
399  {
400  Serial.println(F(" Applying power mode to DAC C..."));
401  ad5686_power_mode(device, AD5686_CH_2, selected_mode);
402  }
403  if (dac4)
404  {
405  Serial.println(F(" Applying power mode to DAC D..."));
406  ad5686_power_mode(device, AD5686_CH_3, selected_mode);
407  }
408 
409  Serial.println(F(" Done!"));
410 
411  return SUCCESS;
412 }
413 
414 // Select reference voltage
416 {
417  // Prompt for internal or external
418  Serial.println(F(" 1-Internal (2.5v)"));
419  Serial.println(F(" 2-External"));
420  Serial.print(F(" Select a reference voltage source: "));
421 
422  uint8_t vref_source = read_int(); // 1-Internal, 2-External
423  Serial.println(vref_source);
424 
425  float fvref = 0; // Custom vref
426 
427  switch (vref_source)
428  {
429  case 1:
430  *vref = 2.5;
431  break;
432 
433  case 2:
434  // If external, prompt for exact vref
435  Serial.println(F(" Enter selected external reference voltage: "));
436  fvref = read_float();
437  Serial.print(fvref);
438  Serial.println(F("V"));
439  *vref = fvref;
440  break;
441 
442  default:
443  Serial.println(F(" Incorrect entry"));
444  break;
445  }
446 
447  return SUCCESS;
448 }
449 
450 // Reads back all DAC registers
452 {
453  uint32_t reg1 = ad5686_read_back_register(device, AD5686_CH_0);
454  uint32_t reg2 = ad5686_read_back_register(device, AD5686_CH_1);
455  uint32_t reg3 = ad5686_read_back_register(device, AD5686_CH_2);
456  uint32_t reg4 = ad5686_read_back_register(device, AD5686_CH_3);
457 
458  Serial.println(F("\n All DAC register values:"));
459  Serial.print(F(" DAC A - "));
460  Serial.println(reg1, HEX);
461  Serial.print(F(" DAC B - "));
462  Serial.println(reg2, HEX);
463  Serial.print(F(" DAC C - "));
464  Serial.println(reg3, HEX);
465  Serial.print(F(" DAC D - "));
466  Serial.println(reg4, HEX);
467 
468  return SUCCESS;
469 }
470 
472 {
473  Serial.println(F(" Enter LDAC mask (for binary, prefix with a B)"));
474  Serial.println(F(" Masked channels will not be updated when LDAC is asserted"));
475  Serial.println(F(" Example: B0101 masks A & C"));
476  Serial.print(F(" Mask: "));
477 
478  uint8_t mask = read_int();
479  if (mask > 15) mask = 15; // Clamp at 1111
480  Serial.println(mask, BIN);
481 
482  ad5686_ldac_mask(device, mask, 0x01);
483 
484  Serial.println(F(" Updated LDAC mask"));
485 
486  return SUCCESS;
487 }
488 
490 {
492  delay(0.1); // Wait just in case our clock speed is too fast (not likely)
493  gpio_direction_input(device->gpio_ldac); // DC2741 has pullup to VIO
494  Serial.println(F(" Asserted LDAC"));
495 
496  return SUCCESS;
497 }
498 
500 {
501  Serial.println(F(" GAIN options: "));
502  Serial.println(F(" 1-Low gain (1x)"));
503  Serial.println(F(" 2-High gain (2x)"));
504  Serial.print(F(" Make selection: "));
505 
506  uint8_t selected_gain = read_int();
507  if (selected_gain > 2) selected_gain = 2;
508  if (selected_gain < 1) selected_gain = 1;
509  Serial.println(selected_gain);
510 
511  switch (selected_gain)
512  {
513  case 1:
514  //AD5686_GAIN_LOW;
515  // Explicitly set direction, drive low.
516  gpio_direction_output(&gpio_gain, GPIO_LOW);
517  //gpio_set_value(&gpio_gain, GPIO_LOW); // This would be more typical
518  Serial.println(F(" Setting gain low"));
519  break;
520 
521  case 2:
522  gpio_direction_input(&gpio_gain); // DC2741 has pullup to VIO
523  Serial.println(F(" Setting gain high"));
524  break;
525 
526  default:
527  break;
528  }
529 
530  return SUCCESS;
531 }
532 
534 {
535  Serial.println(F(" Performing software reset"));
536 
537  ad5686_software_reset(device);
538 
539  return SUCCESS;
540 }
541 
543 {
544  Serial.println(F(" Performing hardware reset"));
545 
546  // Pull reset low then high
547  gpio_direction_output(device->gpio_reset, GPIO_LOW);
548  delay(0.1); // Wait just in case our clock speed is faster than 30ns (unlikely)
549  gpio_direction_input(device->gpio_reset); // DC2741 has pullup to VIO
550 
551  return SUCCESS;
552 }
553 
554 // Convert voltage float to code the DAC understands
555 uint16_t voltage_to_code(float voltage, float vRef)
556 {
557  uint8_t gain_state;
558  gpio_get_value(&gpio_gain, &gain_state);
559 
560  Serial.print("GAIN STATE: ");
561  Serial.println(gain_state);
562 
563  if (gain_state == GPIO_HIGH) // Replace 1 with gain state
564  {
565  vRef *= 2;
566  }
567 
568  uint32_t max_code = ((uint32_t)1 << 16)-1; //
569  return (unsigned short)(voltage * (float)max_code / vRef); // 5 is vRef*2 because of GAIN
570 }
571 
572 // Gets a voltage from the user and converts it to the code the DAC understands
573 uint16_t get_voltage_code(float vRef)
574 {
575  return voltage_to_code(get_voltage_float(), vRef);
576 }
577 
578 // Prompts user to enter a voltage
579 // @return - float of the voltage
580 float get_voltage_float() //@TODO the arguments don't do anything, should remove. !< lsb weight of the LTC2607 (possibly calibrated) !< offset of LTC2607 (possibly calibrated)
581 {
582  float dac_voltage;
583 
584  Serial.print(F(" Enter Desired DAC output voltage: ")); //! Prompt user to enter a voltage
585  dac_voltage = read_float(); //! Read a float from the serial terminal
586  Serial.print(dac_voltage);
587  Serial.println(F(" V"));
588  Serial.flush();
589  return dac_voltage;
590 }
ad5686_dev * device
static uint8_t menu_1_select_dac(uint8_t *selected_dac)
const String dac_selection[4]
static void print_prompt(uint8_t selected_dac, float ref_voltage)
int32_t gpio_direction_input(gpio_desc *desc)
Enable the input direction of the specified GPIO.
unsigned char user_command
gpio_desc gpio_gain
Header File for Linduino Libraries and Demo Code.
#define FAILURE
Definition: LT_PMBus.h:63
static void loop()
int32_t gpio_direction_output(gpio_desc *desc, uint8_t value)
Enable the output direction of the specified GPIO.
static int32_t connected
static uint8_t menu_9_assert_ldac()
static uint8_t menu_11_assert_soft_reset()
static uint8_t menu_2_write_to_input_register(uint8_t selected_dac, float vref)
Menu 2: Write to input register only.
static float get_voltage_float()
static uint8_t menu_3_update_dac(uint8_t selected_dac)
#define GPIO_HIGH
i2c_init_param i2c_params
Header file of Generic Platform Drivers.
spi_init_param spi_params
QuikEval EEPROM Library.
static uint8_t menu_12_assert_hard_reset()
static uint8_t menu_8_set_ldac_mask()
static uint16_t get_voltage_code(float vRef)
char demo_name[]
Demo Board Name stored in QuikEval EEPROM.
Definition: DC1880A.ino:97
int32_t read_int()
static uint8_t menu_10_set_gain()
float read_float()
static uint16_t voltage_to_code(float voltage, float vRef)
static uint8_t menu_5_set_DAC_power_mode(uint8_t selected_dac)
#define SUCCESS
Definition: LT_PMBus.h:62
ad5686_init_param init_params
static float voltage
Definition: DC2289AA.ino:71
static uint8_t menu_6_select_ref_voltage(float *vref)
static uint8_t menu_4_write_and_update_dac(uint8_t selected_dac, float vref)
#define GPIO_LOW
#define QUIKEVAL_CS
QuikEval CS pin (SPI chip select on QuikEval connector pin 6) connects to Arduino SS pin...
Definition: Linduino.h:57
static void print_title()
Prints the title block.
static void setup()
static uint8_t menu_7_read_back_registers()
int32_t gpio_get_value(gpio_desc *desc, uint8_t *value)
Get the value of the specified GPIO.