Linduino  1.3.0
Linear Technology Arduino-Compatible Demonstration Board
DC2196A.ino
Go to the documentation of this file.
1 /*!
2 Linear Technology DC2025A Demonstration Board.
3 LTC2666: 8 Channel SPI 16-/12-Bit Rail-to-Rail DACs with 10ppm/C Max Reference.
4 
5 @verbatim
6 NOTES
7  Setup:
8  Set the terminal baud rate to 115200 and select the newline terminator.
9 
10  An external +/- 15V power supply is required to power the circuit.
11 
12  The program displays calculated voltages which are based on the voltage
13  of the reference used, be it internal or external. A precision voltmeter
14  is needed to verify the actual measured voltages against the calculated
15  voltage displayed.
16 
17  If an external reference is used, a precision voltage
18  source is required to apply the external reference voltage. A
19  precision voltmeter is also required to measure the external reference
20  voltage.
21 
22  Explanation of Commands:
23  1- Select DAC: Select one of eight DACs to test : 0 to 7
24 
25  2- Write to DAC input register: Value is stored in the DAC for updating
26  later, allowing multiple channels to be updated at once, either
27  through a software "Update All" command or by asserting the LDAC# pin.
28  User will be prompted to enter either a code in hex or decimal, or a
29  voltage. If a voltage is entered, a code will be calculated based on
30  the active scaling and reference parameters - ideal values if no
31  calibration was ever stored.
32 
33  3- Write and Update: Similar to item 1, but DAC is updated immediately.
34 
35  4- Update DAC: Copies the value from the input register into the DAC
36  Register. Note that a "write and update" command writes the code to
37  BOTH the input register and DAC register, so subsequent "update"
38  commands will simply re-copy the same data (no change in output.)
39 
40  5- Power Down DAC: Disable DAC output. Power supply current is reduced.
41  DAC code present in DAC registers at time of shut down are preserved.
42 
43  6- Set reference mode, either internal or external: Selecting external
44  mode powers down the internal reference voltage. It is the users
45  responsibility to apply a 2.5v reference.
46 
47  7- Set SoftSpan: There are four options. In external mode, it is the users
48  responsibility to compensate for the desired voltage.
49 
50  8- Toggle Selected Word: Switch between register A or B for DAC code.
51 
52  9- Set MUX: Enables / disables the MUX and sets the channel.
53 
54  10- Global Toggle Bit Settings - Enabling this feature sets the DAC to
55  toggle from register A(when TGL pin is LOW) and register b(when TGL pin
56  is HIGH). TGL pin is set HIGH with an internal pull up when the global toggle bit
57  is set, and TGL pin is set LOW with an internal pull down when the global toggle bit
58  is not set.
59 
60  11- Enable, disable, or store to EEPROM: To store to EEROM ensure all
61  registers are set to their desired settings. Next, go to the store
62  setting EEPROM menu and select it. Upon Linduino power up, the
63  previously stored settings will be restored.
64 
65  12- Voltage Ramp: Sets a voltage ramp to all the channels. CH0 = 0V, CH1 = 0.1V,
66  CH2 = 0.2V, CH3 = 0.4V, ect.
67 
68 USER INPUT DATA FORMAT:
69  decimal : 1024
70  hex : 0x400
71  octal : 02000 (leading 0 "zero")
72  binary : B10000000000
73  float : 1024.0
74 
75 @endverbatim
76 
77 http://www.linear.com/product/LTC2666
78 
79 http://www.linear.com/product/LTC2666#demoboards
80 
81 
82 Copyright 2018(c) Analog Devices, Inc.
83 
84 All rights reserved.
85 
86 Redistribution and use in source and binary forms, with or without
87 modification, are permitted provided that the following conditions are met:
88  - Redistributions of source code must retain the above copyright
89  notice, this list of conditions and the following disclaimer.
90  - Redistributions in binary form must reproduce the above copyright
91  notice, this list of conditions and the following disclaimer in
92  the documentation and/or other materials provided with the
93  distribution.
94  - Neither the name of Analog Devices, Inc. nor the names of its
95  contributors may be used to endorse or promote products derived
96  from this software without specific prior written permission.
97  - The use of this software may or may not infringe the patent rights
98  of one or more patent holders. This license does not release you
99  from the requirement that you obtain separate licenses from these
100  patent holders to use this software.
101  - Use of the software either in source or binary form, must be run
102  on or directly connected to an Analog Devices Inc. component.
103 
104 THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
105 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
106 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
107 IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
108 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
109 LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
110 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
111 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
112 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
113 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
114 */
115 
116 /*! @file
117  @ingroup LTC2666
118 */
119 
120 
121 #include <Arduino.h>
122 #include <stdint.h>
123 #include "Linduino.h"
124 #include "LT_SPI.h"
125 #include "UserInterface.h"
126 #include "LT_I2C.h"
127 #include "QuikEval_EEPROM.h"
128 #include "LTC2666.h"
129 #include <SPI.h>
130 #include <Wire.h>
131 
132 // Macros
133 #define REF_EXTERNAL LTC2666_REF_DISABLE //!< External mode
134 #define REF_INTERNAL 0 //!< Internal mode
135 
136 // Function Declaration
137 
138 void restore_dac_from_eeprom(); // Restores DAC settings from EEPROM
139 void print_title(); // Print the title block
140 void print_prompt(int8_t selected_dac); // Prompt the user for an input command
141 int16_t prompt_voltage_or_code(uint8_t selected_dac); // Prompt the user for voltage or code
142 uint16_t get_voltage(uint8_t selected_dac); // Obtains voltage from user
143 uint16_t get_code(); // Obtains code from user
144 
145 void menu_1_select_dac(uint8_t *selected_dac); // Menu 1: prompts user for DAC selection
146 void menu_2_write_to_input_register(uint8_t selected_dac); // Menu 2: sends data to selected DAC register with no update
147 void menu_3_write_and_update_dac(uint8_t selected_dac); // Menu 3: sends data to selected DAC register with update
148 void menu_4_update_power_up_dac(uint8_t selected_dac); // Menu 4: updates and powers up selected DAC
149 void menu_5_power_down_dac(uint8_t selected_dac); // Menu 5: powers down selected DAC
150 void menu_6_set_reference_mode(); // Menu 6: prompts user to enable/disable internal reference
151 void menu_7_set_softspan_range(uint8_t selected_dac); // Menu 7: prompts user to sets the SoftSpan range
152 void menu_8_toggle_select_word(); // Menu 8: prompts user to enter the toggle select word
153 void menu_9_set_mux(); // Menu 9: sets MEX
154 void menu_10_global_toggle_settings(); // Menu 10: sets the global toggle bit
155 void menu_11_enable_disable_eeprom_restore(); // Menu 11: EEPOM restore settings
156 void menu_12_voltage_ramp(); // Menu 12: sets a voltage ramp for the LTC2666
157 void menu_13_settling_test(); // Menu 13: Settling time test
158 void menu_14_demo_board_test(); // Menu 14: Demo Board functional test
159 void menu_15_loopback_test();
160 
161 // Global variable
162 static uint8_t demo_board_connected; //!< Set to 1 if the board is connected
163 
164 //! Used to manipulate EEPROM data.
165 union eeprom_data_union
166 {
167  struct data_struct_type //! EEPROM data structure
168  {
169  int16_t cal_key; //!< The key that keeps track of the calibration
170  uint8_t soft_span_range[8]; //!< SoftSpan range
171  uint16_t dac_code_a[8]; //!< DAC Register A
172  uint16_t dac_code_b[8]; //!< DAC Register B
173  uint16_t toggle_word; //!< Toggle control word
174  uint8_t global_toggle_bit; //!< Global toggle bit
175  uint8_t mux_state; //!< Multiplexer address AND enable bit
176  uint8_t reference_mode; //!< Int. reference may be disabled in external reference mode (not required)
177  } data_struct; //!< Name of structure
178 
179  char byte_array[sizeof(data_struct_type)]; //!< Array used to store the structure
180 };
181 
182 eeprom_data_union eeprom; // Create union
183 
184 // Constants
185 
186 //! Used to keep track to print voltage or print code
187 enum
188 {
189  PROMPT_VOLTAGE = 0, /**< 0 */
190  PROMPT_CODE = 1 /**< 1 */
191 };
192 
193 //! Initialize Linduino
194 void setup()
195 // Setup the program
196 {
197  char demo_name[] = "DC2196"; // Demo Board Name stored in QuikEval EEPROM
198 
199  quikeval_SPI_init(); // Configure the spi port for 4MHz SCK
200  quikeval_SPI_connect(); // Connect SPI to main data port
201  quikeval_I2C_init(); // Configure the EEPROM I2C port for 100kHz
202 
203  Serial.begin(115200); // Initialize the serial port to the PC
204  print_title();
207  {
209  print_prompt(0);
210  }
211 }
212 
213 //! Repeats Linduino loop
214 void loop()
215 {
216  int16_t user_command;
217  static uint8_t selected_dac = 0; // The selected DAC to be updated (0=CH0, 1=CH1 ... 8=All). Initialized to CH0.
218 
219  if (Serial.available()) // Check for user input
220  {
221  user_command = read_int(); // Read the user command
222  Serial.println(user_command);
223  Serial.print(F("\n"));
224  Serial.flush();
225  switch (user_command)
226  {
227  case 1:
228  menu_1_select_dac(&selected_dac);
229  break;
230  case 2:
231  menu_2_write_to_input_register(selected_dac);
232  break;
233  case 3:
234  menu_3_write_and_update_dac(selected_dac);
235  break;
236  case 4:
237  menu_4_update_power_up_dac(selected_dac);
238  break;
239  case 5:
240  menu_5_power_down_dac(selected_dac);
241  break;
242  case 6:
244  break;
245  case 7:
246  menu_7_set_softspan_range(selected_dac);
247  break;
248  case 8:
250  break;
251  case 9:
252  menu_9_set_mux();
253  break;
254  case 10:
256  break;
257  case 11:
259  break;
260  case 12:
262  break;
263  case 13:
265  break;
266  case 14:
268  break;
269  case 15:
271  break;
272  default:
273  Serial.println(F("Incorrect Option"));
274  break;
275  }
276  Serial.println(F("\n************************************************************"));
277  print_prompt(selected_dac);
278  }
279 
280 }
281 
282 // Function Definitions
283 
284 //! Select which DAC to operate on
285 void menu_1_select_dac(uint8_t *selected_dac)
286 {
287  // Select a DAC to operate on
288  Serial.print(F("Select DAC to operate on (0 to 7, 8 for ALL DACs): "));
289  *selected_dac = read_int();
290  if (*selected_dac == 8)
291  Serial.println(F("All"));
292  else
293  Serial.println(*selected_dac);
294 }
295 
296 //! Write data to input register, but do not update DAC output
297 void menu_2_write_to_input_register(uint8_t selected_dac)
298 {
299  uint16_t dac_code;
300 
301  if (prompt_voltage_or_code(selected_dac) == PROMPT_VOLTAGE)
302  dac_code = get_voltage(selected_dac);
303  else
304  dac_code = get_code();
305 
306  if (selected_dac <= 7)
307  {
308  // Store dac_code to register variable a or b
309  if (eeprom.data_struct.toggle_word & (0x01 << selected_dac))
310  {
311  eeprom.data_struct.dac_code_b[selected_dac] = dac_code;
312  }
313  else
314  eeprom.data_struct.dac_code_a[selected_dac] = dac_code;
315  LTC2666_write(LTC2666_CS, LTC2666_CMD_WRITE_N, selected_dac, dac_code);
316  }
317  else
318  {
319  // Store dac_code to register variable a or b
320  for (uint8_t i = 0; i <= 7 ; i++)
321  {
322  if (eeprom.data_struct.toggle_word & (0x01 << i))
323  {
324  eeprom.data_struct.dac_code_b[i] = dac_code;
325  }
326  else
327  eeprom.data_struct.dac_code_a[i] = dac_code;
328  }
329  LTC2666_write(LTC2666_CS, LTC2666_CMD_WRITE_ALL, selected_dac, dac_code);
330  }
331 }
332 
333 //! Write data to DAC register (which updates output immediately)
334 void menu_3_write_and_update_dac(uint8_t selected_dac)
335 {
336  uint16_t dac_code;
337 
338  if (prompt_voltage_or_code(selected_dac) == PROMPT_VOLTAGE)
339  dac_code = get_voltage(selected_dac);
340  else
341  dac_code = get_code();
342 
343  if (selected_dac <= 7)
344  {
345  // Store dac_code to register variable a or b
346  if (eeprom.data_struct.toggle_word & (0x01 << selected_dac))
347  {
348  eeprom.data_struct.dac_code_b[selected_dac] = dac_code;
349  }
350  else
351  eeprom.data_struct.dac_code_a[selected_dac] = dac_code;
352 
353  LTC2666_write(LTC2666_CS,LTC2666_CMD_WRITE_N_UPDATE_N, selected_dac, dac_code); // Send dac_code
354  }
355  else // All DACs
356  {
357  // Store dac_code to register variable a or b
358  for (uint8_t i = 0; i <= 7 ; i++)
359  {
360  if (eeprom.data_struct.toggle_word & (0x01 << i))
361  {
362  eeprom.data_struct.dac_code_b[i] = dac_code;
363  }
364  else
365  eeprom.data_struct.dac_code_a[i] = dac_code;
366  }
367  LTC2666_write(LTC2666_CS,LTC2666_CMD_WRITE_ALL_UPDATE_ALL, 0, dac_code); // Send dac_code
368  }
369 }
370 
371 //! Update DAC with data that is stored in input register, power up if sleeping
372 void menu_4_update_power_up_dac(uint8_t selected_dac)
373 {
374  // Update DAC
375  if (selected_dac <= 7)
377  else
379 }
380 
381 //! Power down DAC
382 void menu_5_power_down_dac(uint8_t selected_dac)
383 {
384  // Power down DAC
385  if (selected_dac <= 7)
387  else
389 }
390 
391 //! Set reference mode
393 {
394  int16_t user_command;
395  Serial.println(F("0 - Power down the internal reference"));
396  Serial.println(F("1 - Power up the internal reference"));
397  user_command = read_int();
398  if (user_command > 1)
399  user_command = 1;
400  if (user_command < 0)
401  user_command = 0;
402 
403  if (user_command == 1)
404  {
407  Serial.println(F("Internal reference has been powered up"));
408  }
409  else
410  {
413  Serial.println(F("Internal reference has been powered down"));
414  }
415 }
416 
417 //! Set SoftSpan Range
418 void menu_7_set_softspan_range(uint8_t selected_dac)
419 {
420  int16_t user_command;
421 
422  Serial.println(F("0- 0V to 5V"));
423  Serial.println(F("1- 0V to 10V"));
424  Serial.println(F("2- -5V to 5V"));
425  Serial.println(F("3- -10V to 10V"));
426  Serial.println(F("4- -2.5V to 2.5V"));
427  Serial.print(F("Select a SoftSpan Range: "));
428  user_command = read_int();
429 
430  if (user_command > 4)
431  user_command = 4;
432  if (user_command < 0)
433  user_command = 0;
434  Serial.println(user_command);
435 
436  if (selected_dac <= 7)
437  {
438  eeprom.data_struct.soft_span_range[selected_dac] = user_command;
439  LTC2666_write(LTC2666_CS, LTC2666_CMD_SPAN, selected_dac, eeprom.data_struct.soft_span_range[selected_dac]);
440  }
441  else
442  {
443  for (uint8_t i = 0; 0 <= 7; i++)
444  eeprom.data_struct.soft_span_range[i] = user_command;
445 
447  }
448 }
449 
450 //! Enter toggle select word, which also sets the register that will be written
451 //! if bit is 0, register A is written, if 1, register B is written.
453 {
454  // Select a DAC to operate on
455  Serial.println(F("Toggle Select bit sets the register to be written for the corresponding DAC."));
456  Serial.println(F("0 for Register A or 1 for Register B."));
457  Serial.println(F("Note: DAC Update from Register B requires TGB = 1"));
458  Serial.println(F(" DAC Update from Register A requires TCB = 0"));
459  Serial.print(F("Enter Toggle Select Byte as hex (0xMM) or binary (B10101010): "));
460 
461 
462  eeprom.data_struct.toggle_word = read_int();
463  // Toggle bits are stored as 16 bit word with don't care MSB
464 
466  Serial.println(eeprom.data_struct.toggle_word, BIN);
467 }
468 
469 //! Enable / Disable and sets the channel for the MUX
471 {
472  int16_t user_command;
473  Serial.println(F("0- Disable Mux"));
474  Serial.println(F("1- Enable Mux"));
475  Serial.print(F("Enter a command: "));
476  user_command = read_int();
477 
478  if (user_command == 1)
479  {
480  Serial.print(F("Select MUX channel(0-CH0, 1-CH1,...,7-CH7, 8-REFLO, 9-REF, 10-TEMP Monitor, 11-V+, 12-V- : "));
481  user_command = read_int();
482 
483  if (user_command > 12)
484  user_command = 12;
485  if (user_command < 0)
486  user_command = 0;
487 
488  Serial.println(user_command);
491  }
492  else
493  {
496  Serial.println(F("The MUX has been disabled"));
497  }
498 }
499 //! Enable / Disable the global toggle bit
501 {
502  int16_t user_command;
503  Serial.println(F("0- Disable Global Toggle"));
504  Serial.println(F("1- Enable Global Toggle"));
505  Serial.print(F("Enter a command: "));
506  user_command = read_int();
507 
508  if (user_command > 1)
509  user_command = 1;
510  if (user_command < 0)
511  user_command = 0;
512  Serial.println(user_command);
513 
516 }
517 
518 //! Enable / Disable restoration of DAC values from EEPROM Use with caution - behaviour is undefined if you
519 //! enable restoration and data has NOT been previously stored from a known state.
521 {
522  int16_t user_input;
523  Serial.println(F("\n0- Enable Restoration"));
524  Serial.println(F("1- Disable Restoration"));
525  Serial.println(F("2- Store DAC Settings"));
526  user_input = read_int();
527  switch (user_input)
528  {
529  case 0:
530  Serial.println(F("Enabling EEPROM restoration"));
533  break;
534  case 1:
535  Serial.println(F("Disabling EEPROM restoration"));
536  eeprom.data_struct.cal_key = 0;
538  break;
539  case 2:
542  Serial.println(F("Stored Settings to EEPROM"));
543  }
544 }
545 
546 //! Sets a voltage ramp to all the channels
548 {
549  uint8_t i;
550  for (i=0; i <= 7; ++i)
551  {
553  }
554  Serial.println("A voltage ramp was set to the LTC2666");
555 }
556 
557 ///////////////////////////////////////////////////////////////////////////
558 // The following functions are used internally for testing, and included //
559 // here for reference. //
560 ///////////////////////////////////////////////////////////////////////////
561 
562 // Settling time routine, used for datasheet pictures. Set scope to ARM trigger on SETTLE_TRIGGER
563 // Rising edge, trigger on CS pin for the actual edge that causes the update.
564 // You can test any other channel / starting / final values by setting up the DAC's
565 // register A to the initial (starting) voltage and register B to the final (settled) voltage.
566 // The channel's toggle bit must be set as well.
567 
568 #define INTEGRATOR_CONTROL 2 // Pin to control integrator on settling time circuit
569 // Set low for 100ms after full settling has occurred,
570 // high to run test.
571 #define SETTLE_TRIGGER 3 // High to low edge close to DAC active edge. Can also be
572 // used to drive DAC simulator.
573 #define SETTLE_CHANNEL 0 // Which DAC to test for settling (only one at a time to prevent
574 // crosstalk artefacts.)
575 
577 {
578  int16_t user_input, initial, final;
579  int8_t range;
580  Serial.println(F("Select test to run:"));
581  Serial.println(F("0: presently programmed DAC values"));
582  Serial.println(F("1: 0-5 rising"));
583  Serial.println(F("2: 0-5 falling"));
584  Serial.println(F("3: 0-10 rising"));
585  Serial.println(F("4: 0-10 falling"));
586  Serial.println(F("5: bipolar 10 rising"));
587  Serial.println(F("6: bipolar 10 falling"));
588  Serial.println(F("7: 0-5 1/4 to 3/4 scale, rising"));
589  Serial.println(F("8: 0-5 3/4 to 1/4 scale, falling"));
590  Serial.println(F("9: bipolar 5 rising"));
591  Serial.println(F("10: bipolar 5 falling"));
592  Serial.println(F("11: bipolar 2.5 rising"));
593  Serial.println(F("12: bipolar 2.5 falling"));
594 
595  Serial.flush();
596  user_input = read_int();
597  switch (user_input)
598  {
599  case 1:
600  initial = 0x0000;
601  final = 0xFFFF;
602  range = LTC2666_SPAN_0_TO_5V;
603  break;
604  case 2:
605  initial = 0xFFFF;
606  final = 0x0000;
607  range = LTC2666_SPAN_0_TO_5V;
608  break;
609  case 3:
610  initial = 0x0000;
611  final = 0xFFFF;
612  range = LTC2666_SPAN_0_TO_10V;
613  break;
614  case 4:
615  initial = 0xFFFF;
616  final = 0x0000;
617  range = LTC2666_SPAN_0_TO_10V;
618  break;
619  case 5:
620  initial = 0x0000;
621  final = 0xFFFF;
623  break;
624  case 6:
625  initial = 0xFFFF;
626  final = 0x0000;
628  break;
629  case 7:
630  initial = 0x4000;
631  final = 0xC000;
632  range = LTC2666_SPAN_0_TO_5V;
633  break;
634  case 8:
635  initial = 0xC000;
636  final = 0x4000;
637  range = LTC2666_SPAN_0_TO_5V;
638  break;
639  case 9:
640  initial = 0x0000;
641  final = 0xFFFF;
643  break;
644  case 10:
645  initial = 0xFFFF;
646  final = 0x0000;
648  break;
649  case 11:
650  initial = 0x0000;
651  final = 0xFFFF;
653  break;
654  case 12:
655  initial = 0xFFFF;
656  final = 0x0000;
658  break;
659  default:
660  Serial.println("Using presently programmed DAC values");
661  }
662 
663  if (user_input != 0) // Load DAC to be tested with range, initial, and final values.
664  {
666  LTC2666_write(LTC2666_CS, LTC2666_CMD_TOGGLE_SEL, 0, 0x00); // Point to register A
668  LTC2666_write(LTC2666_CS, LTC2666_CMD_TOGGLE_SEL, 0, 0x01 << SETTLE_CHANNEL); // Point to register B
670  }
671 
672  Serial.println("Settling time test running, Press Enter to terminate.");
673  pinMode(INTEGRATOR_CONTROL, OUTPUT);
674  pinMode(SETTLE_TRIGGER, OUTPUT);
675  while (!Serial.available())
676  {
677  PORTD |= 1 << INTEGRATOR_CONTROL; // Disable integrator
678  PORTD |= 1 << SETTLE_TRIGGER;
679  LTC2666_write(LTC2666_CS, LTC2666_CMD_GLOBAL_TOGGLE, 0, 0); // Set global toggle bit LOW, INITIAL value
680  PORTD &= ~(1 << SETTLE_TRIGGER); // Reset settle trigger LOW
681  delay(10); // Wait to get to initial value
682  LTC2666_write(LTC2666_CS, LTC2666_CMD_GLOBAL_TOGGLE, 0, 1); // Set global toggle HIGH, FINAL value
683  delay(10); // Wait to get to final value, here is where you look at the settling
684  PORTD &= ~(1 << INTEGRATOR_CONTROL); // Enable integrator
685  delay(100);
686  }
687  Serial.read();
688  Serial.println("Exiting Settling time test.");
689 }
690 
691 // Functional test for demo board, tests continuity, EEPROM contents,
692 // And correct resolution DAC installed.
694 {
695  uint8_t i, errorcount = 0;
696 
697  Serial.println(F("Welcome to the LTC2666 Demo Board Test Program."));
698  Serial.print(F("Found board assembly type "));
699  Serial.println(demo_board.option);
700 
701  Serial.println(F("Checking EEPROM contents..."));
702 
704  ui_buffer[48] = 0;
705  Serial.println(ui_buffer);
706  switch (demo_board.option)
707  {
708  case 'A':
709  if (strcmp("LTC2666-16,Cls,D2668,01,01,DC,DC2196A-A,--------", ui_buffer))
710  {
711  Serial.println(F("FAILED EEPROM Contents"));
712  errorcount += 1;
713  }
714  break;
715  case 'B':
716  if (strcmp("LTC2666-12,Cls,D2668,01,01,DC,DC2196A-B,--------", ui_buffer))
717  {
718  Serial.println(F("FAILED EEPROM Contents"));
719  errorcount += 1;
720  }
721  break;
722  }
723 
724  // LTC2666-16,Cls,D2668,01,01,DC,DC2025A-A,--------
725  if (!errorcount)
726  Serial.println(F("EEPROM good!"));
727 
728  Serial.println(F("Ensure all jumpers are in the LEFT position (INT ref, MSP0,1,2 = 1."));
729  Serial.println(F("Writing ramp of voltages to DAC outputs. Verify DAC0 = 0.10V, DAC1 = 0.20V,"));
730  Serial.println(F("DAC2 = 0.3V ... DAC7 = 0.8V. Type 1, enter when done."));
731 
733 
734  for (i=0; i <= 15; ++i)
735  {
738  }
739 
740  read_int(); // Read the user command
741 
742  Serial.println(F("Setting SoftSpan range to +/-10V, DAC7 to -10V, and MUX to DAC7."));
743  Serial.println(F("Verify MUX output is between -9.95V and -10.05V"));
744 
748 
749  Serial.println(F("Type 1, enter when done."));
750  read_int();
751 
754  Serial.println(F("Verifying correct resolution LTC2666 installed"));
755  Serial.println(F("output set to 0V, press REL(delta) button on meter"));
756  Serial.println(F("Type 1, enter when done."));
757  read_int();
759 
760  switch (demo_board.option)
761  {
762  case 'A':
763  Serial.println(F("16 bit device - verify output voltage is GREATER than 1mV"));
764  break;
765  case 'B':
766  Serial.println(F("12 bit device - verify output voltage is LESS than 1mV"));
767  break;
768  }
769 
770  Serial.println(F("Type 1, enter when done."));
771  read_int();
772 }
773 
774 // Loopback test to verify data integrity.
776 {
777  uint16_t i;
778  int8_t ack = 0;
779  Serial.print(F("Testing readback by writing 0-10,000, NOP commands\n"));
780  LTC2666_write(LTC2666_CS, LTC2666_CMD_NO_OPERATION, 0, 0); // If this is the first time the read function is called, need to initialize
781  for (i=0; i<=10000; ++i)
782  {
784  }
785  if (ack)
786  {
787  Serial.print(F("Oops, got an error somewhere!"));
788  }
789  else
790  {
791  Serial.print(F("No errors!!"));
792  }
793 }
794 
795 
796 //! Prompt user to enter a voltage or digital code to send to DAC
797 //! @returns user input
798 int16_t prompt_voltage_or_code(uint8_t selected_dac )
799 {
800  int16_t user_input;
801 
802  Serial.print(F("Type 1 to enter voltage, 2 to enter code: "));
803  Serial.flush();
804  user_input = read_int();
805  Serial.println(user_input);
806 
807  if (user_input != 2)
808  {
809  if (selected_dac >= 8)
810  {
811  Serial.println(F("\nCaution! Voltage SoftSpan could be different for different DACs"));
812  Serial.println(F("Ensure All DACs can be set to desired voltages"));
813  Serial.println(F("DAC 0 is used for SoftSpan values for all DACs."));
814  Serial.print(F("Toggle Register Select Bits 0=A, 1 = B: 0b"));
815  Serial.println(eeprom.data_struct.toggle_word, BIN);
816  }
817  return(PROMPT_VOLTAGE);
818  }
819  else
820  {
821  if (selected_dac >= 8)
822  {
823  Serial.println(F("DAC 0 is used for SoftSpan values for all DACs."));
824  }
825  }
826  return(PROMPT_CODE);
827 }
828 
829 //! Get voltage from user input, calculate DAC code based on lsb, offset
830 //! @returns the DAC code
831 uint16_t get_voltage(uint8_t selected_dac)
832 {
833  float dac_voltage;
834 
835  Serial.print(F("Enter Desired DAC output voltage: "));
836  dac_voltage = read_float();
837  Serial.print(dac_voltage);
838  Serial.println(F(" V"));
839  Serial.flush();
840 
841  if (selected_dac <= 7)
842  return(LTC2666_voltage_to_code(dac_voltage,
843  LTC2666_MIN_OUTPUT[eeprom.data_struct.soft_span_range[selected_dac]],
844  LTC2666_MAX_OUTPUT[eeprom.data_struct.soft_span_range[selected_dac]]));
845  else
846  return(LTC2666_voltage_to_code(dac_voltage,
849 }
850 
851 //! Get code to send to DAC directly, in decimal, hex, or binary
852 //! @return code from user
853 uint16_t get_code()
854 {
855  uint16_t returncode;
856  Serial.println(F("Enter Desired DAC Code"));
857  Serial.print(F("(Format 32768, 0x8000, 0100000, or B1000000000000000): "));
858  returncode = (uint16_t) read_int();
859  Serial.print(F("0x"));
860  Serial.println(returncode, HEX);
861  Serial.flush();
862  return(returncode);
863 }
864 
865 //! Prints the title block when program first starts.
867 {
868  Serial.println();
869  Serial.println(F("*****************************************************************"));
870  Serial.println(F("* DC2196 Demonstration Program *"));
871  Serial.println(F("* *"));
872  Serial.println(F("* This program demonstrates how to send data to the LTC2666 *"));
873  Serial.println(F("* Eight Channel 16/12-bit DAC found on the DC2196 demo board. *"));
874  Serial.println(F("* *"));
875  Serial.println(F("* Set the baud rate to 115200 and select the newline terminator.*"));
876  Serial.println(F("* *"));
877  Serial.println(F("*****************************************************************"));
878 }
879 
880 //! Prints main menu.
881 void print_prompt(int8_t selected_dac)
882 {
883  // Displays menu
884  Serial.println(F("\nCommand Summary:"));
885  Serial.println(F(" 1-Select DAC"));
886  Serial.println(F(" 2-Write to input register (no update)"));
887  Serial.println(F(" 3-Write and update DAC"));
888  Serial.println(F(" 4-Update / power up DAC"));
889  Serial.println(F(" 5-Power down DAC"));
890  Serial.println(F(" 6-Set reference mode"));
891  Serial.println(F(" 7-Set SoftSpan"));
892  Serial.println(F(" 8-Toggle selected register"));
893  Serial.println(F(" 9-Set Mux"));
894  Serial.println(F(" 10-Global toggle bit settings"));
895  Serial.println(F(" 11-Enable, disable, or store to EEPROM"));
896  Serial.println(F(" 12-Voltage Ramp"));
897  Serial.println(F("\nPresent Values:"));
898  Serial.print(F(" Selected DAC: "));
899 
900  // Display current settings
901  if (selected_dac >= 7 )
902  {
903  Serial.println(F("All"));
904  Serial.print(F(" SoftSpan range: "));
905  Serial.print(LTC2666_MIN_OUTPUT[eeprom.data_struct.soft_span_range[0]], 4);
906  Serial.print(F(" V to "));
907  Serial.print(LTC2666_MAX_OUTPUT[eeprom.data_struct.soft_span_range[0]], 4);
908  Serial.println(F(" V"));
909  }
910  else
911  {
912  Serial.println(selected_dac);
913  Serial.print(F(" SoftSpan range: "));
914  Serial.print(LTC2666_MIN_OUTPUT[eeprom.data_struct.soft_span_range[selected_dac]], 4);
915  Serial.print(F(" V to "));
916  Serial.print(LTC2666_MAX_OUTPUT[eeprom.data_struct.soft_span_range[selected_dac]], 4);
917  Serial.println(F(" V"));
918  }
919  Serial.print(F(" Toggle Register: "));
920  // printed in the order T7 T6 T5 T4 T3 T2 T1 T0
921  for (uint8_t i = 8; i <= 15; i++)
922  {
923  if ((eeprom.data_struct.toggle_word & (0x8000 >> i))) //toggle_word is 16 bits with don't care MSB
924  Serial.print(F("B"));
925  else
926  Serial.print(F("A"));
927  }
928  Serial.println();
929 
930  Serial.print(F(" Global Toggle Bit: "));
931  Serial.println(eeprom.data_struct.global_toggle_bit);
932 
933  Serial.print(F(" Reference: "));
935  Serial.println(F("Internal"));
936  else
937  Serial.println(F("External"));
938 
939  Serial.print(F("\nEnter a command: "));
940  Serial.flush();
941 }
942 
943 //! Read the alert settings from EEPROM
945 {
946  int16_t cal_key;
947  int8_t i;
948 
949  // Read the cal key from the EEPROM
951 
952  if (cal_key == EEPROM_CAL_KEY)
953  {
954  // Calibration has been stored, read thresholds
956 
957  // Write SoftSpan ranges
958  for (uint8_t i = 0; i <= 7; i++)
960 
961  // Write stored data to DAC A registers
962  for (uint8_t i = 0; i <= 7 ; i++)
964 
965  LTC2666_write(LTC2666_CS, LTC2666_CMD_TOGGLE_SEL, 0, 0xFFFF); // Set to B registers
966 
967  // Write stored data to DAC B registers
968  for (uint8_t i = 0; i <= 7 ; i++)
970 
972 
974 
976 
978 
979  LTC2666_write(LTC2666_CS,LTC2666_CMD_UPDATE_ALL, 0, 0); // Update ALL
980 
981  Serial.println(F("DAC settings loaded from EEPROM"));
982  }
983  else
984  Serial.println(F("EEPROM data not found"));
985 }
struct demo_board_type demo_board
Instantiate demo board structure.
static void menu_14_demo_board_test()
Definition: DC2196A.ino:693
uint8_t eeprom_read_byte_array(uint8_t i2c_address, char *data, uint16_t address, uint8_t num_bytes)
Read a data byte at address from the EEPROM with i2c_address.
char option
Demo Circuit option (A)
#define LTC2666_CMD_MUX
Select MUX channel (controlled by 5 LSbs in data word)
Definition: LTC2666.h:107
#define LTC2666_CMD_NO_OPERATION
No operation.
Definition: LTC2666.h:111
#define LTC2666_CMD_GLOBAL_TOGGLE
Software toggle control via global toggle bit.
Definition: LTC2666.h:109
uint8_t eeprom_read_int16(uint8_t i2c_address, int16_t *read_data, uint16_t address)
Read the two byte integer data from the EEPROM starting at address.
#define REF_INTERNAL
Internal mode.
Definition: DC2196A.ino:134
#define LTC2666_SPAN_PLUS_MINUS_10V
Definition: LTC2666.h:122
unsigned char user_command
static void menu_10_global_toggle_settings()
Enable / Disable the global toggle bit.
Definition: DC2196A.ino:500
#define EEPROM_I2C_ADDRESS
#define LTC2666_CMD_UPDATE_N
Update (power up) DAC register n.
Definition: LTC2666.h:96
#define REF_EXTERNAL
External mode.
Definition: DC2196A.ino:133
uint16_t toggle_word
Toggle control word.
Definition: DC2692A.ino:168
static void restore_dac_from_eeprom()
Read the alert settings from EEPROM.
Definition: DC2196A.ino:944
#define LTC2666_SPAN_PLUS_MINUS_2V5
Definition: LTC2666.h:123
int16_t cal_key
The key that keeps track of the calibration.
Definition: DC2692A.ino:164
static void print_prompt(int8_t selected_dac)
Prints main menu.
Definition: DC2196A.ino:881
Header File for Linduino Libraries and Demo Code.
#define LTC2666_CMD_WRITE_ALL
Write to all input registers.
Definition: LTC2666.h:104
static void menu_12_voltage_ramp()
Sets a voltage ramp to all the channels.
Definition: DC2196A.ino:547
uint8_t eeprom_write_byte_array(uint8_t i2c_address, char data[], uint16_t address, uint8_t num_bytes)
Write the data byte array to the EEPROM with i2c_address starting at EEPROM address.
static void menu_1_select_dac(uint8_t *selected_dac)
Select which DAC to operate on.
Definition: DC2196A.ino:285
LTC2666: 8-Channel SPI 16-/12-Bit +/-10V Vout SoftSpan DACs with 10ppm/C Max Reference.
const float LTC2666_MAX_OUTPUT[5]
Definition: LTC2666.h:130
static void setup()
Initialize Linduino.
Definition: DC2196A.ino:194
uint8_t mux_state
Multiplexer address AND enable bit.
Definition: DC2692A.ino:170
#define SETTLE_CHANNEL
Definition: DC2196A.ino:573
#define SETTLE_TRIGGER
Definition: DC2196A.ino:571
#define LTC2666_SPAN_0_TO_5V
Definition: LTC2666.h:119
#define LTC2666_SPAN_0_TO_10V
Definition: LTC2666.h:120
#define LTC2666_MUX_ENABLE
Definition: LTC2666.h:144
static void menu_8_toggle_select_word()
Enter toggle select word, which also sets the register that will be written if bit is 0...
Definition: DC2196A.ino:452
static void menu_7_set_softspan_range(uint8_t selected_dac)
Set SoftSpan Range.
Definition: DC2196A.ino:418
const float LTC2666_MIN_OUTPUT[5]
Definition: LTC2666.h:129
int8_t LTC2666_write(uint8_t cs, uint8_t dac_command, uint8_t dac_address, uint16_t dac_code)
Write the 16-bit dac_code to the LTC2666.
Definition: LTC2666.cpp:70
#define LTC2666_CMD_SPAN_ALL
Set span for all DACs.
Definition: LTC2666.h:110
#define LTC2666_CMD_POWER_DOWN_N
Power down n.
Definition: LTC2666.h:99
uint8_t eeprom_write_int16(uint8_t i2c_address, int16_t write_data, uint16_t address)
Write the 2 byte integer data to the EEPROM starting at address.
static uint16_t get_code()
Get code to send to DAC directly, in decimal, hex, or binary.
Definition: DC2196A.ino:853
#define LTC2666_CMD_SPAN
Write span to dac n.
Definition: LTC2666.h:102
#define LTC2666_CMD_WRITE_ALL_UPDATE_ALL
Write to all input reg, update all DACs.
Definition: LTC2666.h:106
static void loop()
Repeats Linduino loop.
Definition: DC2196A.ino:214
QuikEval EEPROM Library.
static uint8_t range
Definition: DC1096B.ino:111
static void menu_4_update_power_up_dac(uint8_t selected_dac)
Update DAC with data that is stored in input register, power up if sleeping.
Definition: DC2196A.ino:372
static void menu_3_write_and_update_dac(uint8_t selected_dac)
Write data to DAC register (which updates output immediately)
Definition: DC2196A.ino:334
static void menu_5_power_down_dac(uint8_t selected_dac)
Power down DAC.
Definition: DC2196A.ino:382
void quikeval_SPI_init(void)
Configure the SPI port for 4Mhz SCK.
Definition: LT_SPI.cpp:151
Used to manipulate EEPROM data.
Definition: DC2692A.ino:160
static void menu_6_set_reference_mode()
Set reference mode.
Definition: DC2196A.ino:392
#define EEPROM_CAL_STATUS_ADDRESS
int8_t discover_demo_board(char *demo_name)
Read the ID string from the EEPROM and determine if the correct board is connected.
#define INTEGRATOR_CONTROL
Definition: DC2196A.ino:568
uint8_t soft_span_range[5]
SoftSpan range.
Definition: DC2692A.ino:165
LT_SPI: Routines to communicate with ATmega328P&#39;s hardware SPI port.
#define LTC2666_CMD_TOGGLE_SEL
Select which DACs can be toggled (via toggle pin or global toggle bit)
Definition: LTC2666.h:108
static void menu_2_write_to_input_register(uint8_t selected_dac)
Write data to input register, but do not update DAC output.
Definition: DC2196A.ino:297
#define LTC2666_CMD_POWER_DOWN_ALL
Power down chip (all DAC&#39;s, MUX and reference)
Definition: LTC2666.h:100
static void menu_13_settling_test()
Definition: DC2196A.ino:576
uint16_t dac_code_a[16]
DAC Register A.
Definition: DC2692A.ino:166
#define LTC2666_CS
Define the SPI CS pin.
Definition: LTC2666.h:90
LT_I2C: Routines to communicate with ATmega328P&#39;s hardware I2C port.
static void menu_15_loopback_test()
Definition: DC2196A.ino:775
static void menu_9_set_mux()
Enable / Disable and sets the channel for the MUX.
Definition: DC2196A.ino:470
char demo_name[]
Demo Board Name stored in QuikEval EEPROM.
Definition: DC1880A.ino:97
#define LTC2666_SPAN_PLUS_MINUS_5V
Definition: LTC2666.h:121
void quikeval_SPI_connect()
Connect SPI pins to QuikEval connector through the Linduino MUX. This will disconnect I2C...
Definition: LT_SPI.cpp:138
int32_t read_int()
static int16_t prompt_voltage_or_code(uint8_t selected_dac)
Prompt user to enter a voltage or digital code to send to DAC.
Definition: DC2196A.ino:798
float read_float()
static uint8_t demo_board_connected
Set to 1 if the board is connected.
Definition: DC2196A.ino:162
char byte_array[sizeof(data_struct_type)]
Array used to store the structure.
Definition: DC2692A.ino:174
uint16_t dac_code_b[16]
DAC Register B.
Definition: DC2692A.ino:167
static void menu_11_enable_disable_eeprom_restore()
Enable / Disable restoration of DAC values from EEPROM Use with caution - behaviour is undefined if y...
Definition: DC2196A.ino:520
uint8_t global_toggle_bit
Global toggle bit.
Definition: DC2692A.ino:169
void quikeval_I2C_init(void)
Initializes Linduino I2C port.
Definition: LT_I2C.cpp:394
static void print_title()
Prints the title block when program first starts.
Definition: DC2196A.ino:866
static int i
Definition: DC2430A.ino:184
#define LTC2666_CMD_CONFIG
Configure reference / toggle.
Definition: LTC2666.h:103
#define LTC2666_CMD_WRITE_N
Write to input register n.
Definition: LTC2666.h:95
#define LTC2666_CMD_UPDATE_ALL
Update all DACs.
Definition: LTC2666.h:105
#define LTC2666_CMD_WRITE_N_UPDATE_N
Write to input register n, update (power-up)
Definition: LTC2666.h:98
uint16_t LTC2666_voltage_to_code(float dac_voltage, float min_output, float max_output)
Calculate a LTC2666 DAC code given the desired output voltage and DAC address (0-3) ...
Definition: LTC2666.cpp:103
struct eeprom_data_union::data_struct_type data_struct
Name of structure.
static uint16_t get_voltage(uint8_t selected_dac)
Get voltage from user input, calculate DAC code based on lsb, offset.
Definition: DC2196A.ino:831
eeprom_data_union eeprom
Definition: DC2196A.ino:182
#define EEPROM_CAL_KEY
uint8_t read_quikeval_id_string(char *buffer)
Read the id string from the EEPROM, then parse the product name, demo board name, and demo board opti...
char ui_buffer[UI_BUFFER_SIZE]