Linduino  1.3.0
Linear Technology Arduino-Compatible Demonstration Board
EVAL-AD5696R.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 (sean.smith@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  100000, // i2c max speed (hz)
70  0x0F, // i2c slave address
71 };
72 
74 {
76  0,
77  1,
78  0,
79  0,
80 };
81 
82 ad5686_init_param init_params =
83 {
84  i2c_params, // I2C parameters
85  spi_params, // SPI parameters (not used)
86  4, //3, // GPIO reset pin
87  5, //2, // GPIO LDAC pin
88  ID_AD5696R, // Device type (16bit)
89  // Possible types
90  // ID_AD5694R, ID_AD5695R, ID_AD5696R
91 
92 };
93 
94 ad5686_dev *device;
95 
97 {
98  GENERIC_GPIO, // type
99  0, // ID
100  2, // Number
101 };
102 
103 int32_t connected = FAILURE;
104 
105 void setup()
106 {
107  char demo_name[] = "AD5696R";
108 
109  Serial.begin(115200);
110 
111  // Give the serial port a chance to initialize
112  // Without this we get some garbage on the console
113  delay(100);
114 
115  connected = ad5686_init(&device, init_params);
116 
117  Serial.print("Initialized, ");
118  Serial.println(connected);
119 
120  if (connected == SUCCESS)
121  {
122  // de-assert reset
123  gpio_direction_input(device->gpio_reset); // DC2741 has pullup to VIO
124  // Set GAIN high
125  gpio_set_value(&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("AD5696R 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-569xRSDZ Demonstration Program *"));
222  Serial.println(F("* *"));
223  Serial.println(F("* This program demonstrates communication with the AD5696R *"));
224  Serial.println(F("* 16-Bit Quad Rail-to-Rail DAC with I2C 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 register"));
238  Serial.println(F(" 4 -Write and update DAC"));
239  Serial.println(F(" 5 -Set DAC power-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.print(F(" Applying power mode to DAC "));
410  Serial.println(selected_dac);
411  ad5686_power_mode(device, selected_dac, selected_mode);
412 
413  Serial.println(F(" Done!"));
414 
415  return SUCCESS;
416 }
417 
418 // Select reference voltage
420 {
421  // Prompt for internal or external
422  Serial.println(F(" 1-Internal (2.5v)"));
423  Serial.println(F(" 2-External"));
424  Serial.print(F(" Select a reference voltage source: "));
425 
426  uint8_t vref_source = read_int(); // 1-Internal, 2-External
427  Serial.println(vref_source);
428 
429  float fvref = 0; // Custom vref
430 
431  switch (vref_source)
432  {
433  case 1:
434  *vref = 2.5;
435  break;
436 
437  case 2:
438  // If external, prompt for exact vref
439  Serial.println(F(" Enter selected external reference voltage: "));
440  fvref = read_float();
441  Serial.print(fvref);
442  Serial.println(F("V"));
443  *vref = fvref;
444  break;
445 
446  default:
447  Serial.println(F(" Incorrect entry"));
448  break;
449  }
450 
451  return SUCCESS;
452 }
453 
454 // Reads back all DAC registers
456 {
457  uint32_t reg1 = ad5686_read_back_register(device, AD5686_CH_0);
458  uint32_t reg2 = ad5686_read_back_register(device, AD5686_CH_1);
459  uint32_t reg3 = ad5686_read_back_register(device, AD5686_CH_2);
460  uint32_t reg4 = ad5686_read_back_register(device, AD5686_CH_3);
461 
462  Serial.println(F("\n All DAC-input register values:"));
463  Serial.print(F(" DAC A - "));
464  Serial.println(reg1, HEX);
465  Serial.print(F(" DAC B - "));
466  Serial.println(reg2, HEX);
467  Serial.print(F(" DAC C - "));
468  Serial.println(reg3, HEX);
469  Serial.print(F(" DAC D - "));
470  Serial.println(reg4, HEX);
471 
472  return SUCCESS;
473 }
474 
475 /*
476 uint8_t menu_old_read_back_dac_input_registers()
477 {
478  uint8_t *read_data;
479  //#define AD5686_CH_ALL 0xF
480  //uint32_t read_data = ad5696_read_back_register(device, AD5686_CH_ALL);
481  uint32_t reg1 = ad5686_read_back_register(device, AD5686_CH_A);
482  uint32_t reg2 = ad5686_read_back_register(device, AD5686_CH_1);
483  uint32_t reg3 = ad5686_read_back_register(device, AD5686_CH_C);
484  uint32_t reg4 = ad5686_read_back_register(device, AD5686_CH_D);
485  //https://www.tutorialspoint.com/cprogramming/c_return_arrays_from_function.htm
486  Serial.println(F("\n All DAC-input register values:"));
487  /*
488  for(int i = 0 ; i<8;i++) {
489  Serial.println(*(read_data + %d), HEX);
490 
491  }
492 
493  Serial.print(F(" DAC A - "));
494  Serial.println(reg1, HEX);
495  Serial.print(F(" DAC B - "));
496  Serial.println(reg2, HEX);
497  Serial.print(F(" DAC C - "));
498  Serial.println(reg3, HEX);
499  Serial.print(F(" DAC D - "));
500  Serial.println(reg4, HEX);
501 
502  return SUCCESS;
503 }
504 */
505 
507 {
508  Serial.println(F(" Enter LDAC mask (for binary, prefix with a B)"));
509  Serial.println(F(" Masked channels will not be updated when LDAC is asserted"));
510  Serial.println(F(" Example: B0101 masks A & C"));
511  Serial.print(F(" Mask: "));
512 
513  uint8_t mask = read_int();
514  if (mask > 15) mask = 15; // Clamp at 1111
515  Serial.println(mask, BIN);
516 
517  ad5686_ldac_mask(device, mask, 0x01);
518 
519  Serial.println(F(" Updated LDAC mask"));
520 
521  return SUCCESS;
522 }
523 
525 {
527  delay(0.1); // Wait just in case our clock speed is too fast (not likely)
528  gpio_direction_input(device->gpio_ldac); // DC2741 has pullup to VIO
529  Serial.println(F(" Asserted LDAC"));
530 
531  return SUCCESS;
532 }
533 
535 {
536  Serial.println(F(" GAIN options: "));
537  Serial.println(F(" 1-Low gain (1x)"));
538  Serial.println(F(" 2-High gain (2x)"));
539  Serial.print(F(" Make selection: "));
540 
541  uint8_t selected_gain = read_int();
542  if (selected_gain > 2) selected_gain = 2;
543  if (selected_gain < 1) selected_gain = 1;
544  Serial.println(selected_gain);
545 
546  switch (selected_gain)
547  {
548  case 1:
549  //AD5686_GAIN_LOW;
550  // Explicitly set direction, drive low.
551  gpio_direction_output(&gpio_gain, GPIO_LOW);
552  //gpio_set_value(&gpio_gain, GPIO_LOW); // This would be more typical
553  Serial.println(F(" Setting gain low"));
554  break;
555 
556  case 2:
557  gpio_direction_input(&gpio_gain); // DC2741 has pullup to VIO
558  Serial.println(F(" Setting gain high"));
559  break;
560 
561  default:
562  break;
563  }
564 
565  return SUCCESS;
566 }
567 
569 {
570  Serial.println(F(" Performing software reset"));
571 
572  ad5686_software_reset(device);
573 
574  return SUCCESS;
575 }
576 
578 {
579  Serial.println(F(" Performing hardware reset"));
580 
581  // Pull reset low then high
582  gpio_direction_output(device->gpio_reset, GPIO_LOW);
583  delay(0.1); // Wait just in case our clock speed is faster than 30ns (unlikely)
584  gpio_direction_input(device->gpio_reset); // DC2741 has pullup to VIO
585 
586  return SUCCESS;
587 }
588 
589 // Convert voltage float to code the DAC understands
590 uint16_t voltage_to_code(float voltage, float vRef)
591 {
592  uint8_t gain_state;
593  gpio_get_value(&gpio_gain, &gain_state);
594 
595  Serial.print("GAIN STATE: ");
596  Serial.println(gain_state);
597 
598  if (gain_state == GPIO_HIGH) // Replace 1 with gain state
599  {
600  vRef *= 2;
601  }
602 
603  uint32_t max_code = ((uint32_t)1 << 16)-1; //
604  return (unsigned short)(voltage * (float)max_code / vRef); // 5 is vRef*2 because of GAIN
605 }
606 
607 // Gets a voltage from the user and converts it to the code the DAC understands
608 uint16_t get_voltage_code(float vRef)
609 {
610  return voltage_to_code(get_voltage_float(), vRef);
611 }
612 
613 // Prompts user to enter a voltage
614 // @return - float of the voltage
615 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)
616 {
617  float dac_voltage;
618 
619  Serial.print(F(" Enter Desired DAC output voltage: ")); //! Prompt user to enter a voltage
620  dac_voltage = read_float(); //! Read a float from the serial terminal
621  Serial.print(dac_voltage);
622  Serial.println(F(" V"));
623  Serial.flush();
624  return dac_voltage;
625 }
static uint8_t menu_10_set_gain()
gpio_desc gpio_gain
int32_t gpio_direction_input(gpio_desc *desc)
Enable the input direction of the specified GPIO.
unsigned char user_command
static uint8_t menu_7_read_back_dac_input_registers()
static uint8_t menu_6_select_ref_voltage(float *vref)
static void print_title()
Prints the title block.
Header File for Linduino Libraries and Demo Code.
#define FAILURE
Definition: LT_PMBus.h:63
int32_t gpio_direction_output(gpio_desc *desc, uint8_t value)
Enable the output direction of the specified GPIO.
static int32_t connected
const String dac_selection[4]
static uint8_t menu_11_assert_soft_reset()
static void print_prompt(uint8_t selected_dac, float ref_voltage)
static uint8_t menu_2_write_to_input_register(uint8_t selected_dac, float vref)
Menu 2: Write to input register only.
static void loop()
static uint8_t menu_9_assert_ldac()
static float get_voltage_float()
#define GPIO_HIGH
spi_init_param spi_params
i2c_init_param i2c_params
static uint8_t menu_8_set_ldac_mask()
static uint8_t menu_3_update_dac(uint8_t selected_dac)
Header file of Generic Platform Drivers.
QuikEval EEPROM Library.
static uint8_t menu_12_assert_hard_reset()
ad5686_init_param init_params
char demo_name[]
Demo Board Name stored in QuikEval EEPROM.
Definition: DC1880A.ino:97
int32_t read_int()
ad5686_dev * device
static uint8_t menu_5_set_DAC_power_mode(uint8_t selected_dac)
float read_float()
int32_t gpio_set_value(gpio_desc *desc, uint8_t value)
Set the value of the specified GPIO.
#define SUCCESS
Definition: LT_PMBus.h:62
static uint16_t get_voltage_code(float vRef)
static float voltage
Definition: DC2289AA.ino:71
#define GPIO_LOW
static uint8_t menu_1_select_dac(uint8_t *selected_dac)
static uint8_t menu_4_write_and_update_dac(uint8_t selected_dac, float vref)
static void setup()
static uint16_t voltage_to_code(float voltage, float vRef)
int32_t gpio_get_value(gpio_desc *desc, uint8_t *value)
Get the value of the specified GPIO.