Linduino  1.3.0
Linear Technology Arduino-Compatible Demonstration Board
DC2692A.ino
Go to the documentation of this file.
1 /*!
2 Linear Technology DC2692A Demonstration Board.
3 LTC2662: 5-Channel 16-/12-Bit 300mA SoftSpan Current Source DACs
4 
5 @verbatim
6 NOTES
7  Setup:
8  Set the terminal baud rate to 115200 and select the newline terminator.
9 
10  An external +7V - 5V power supply is required to power the circuit.
11 
12  The program displays calculated currents which are based on the voltage
13  of the reference used and Radj resistor, be it internal or external. A
14  precision voltmeter is needed to verify the actual measured voltages
15  against the calculated current 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 five DACs to test : 0 to 4
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  current. If a current 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 shutdown 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 1.25v reference.
46 
47  7- Set SoftSpan: There are ten options.
48 
49  8- Toggle Selected Word: Switch between register A or B for DAC code.
50 
51  9- Set MUX: Sets the channel.
52 
53  10- Global Toggle Bit Settings - Enabling this feature sets the DAC to
54  toggle from register A(when TGL pin is LOW) and register b(when TGL pin
55  is HIGH). TGL pin is set HIGH with an internal pull up when the global toggle bit
56  is set, and TGL pin is set LOW with an internal pull down when the global toggle bit
57  is not set.
58 
59  11- Enable, disable, or store to EEPROM: To store to EEROM ensure all
60  registers are set to their desired settings. Next, go to th store
61  setting EEPROM menu and select it. Upon Linduinos power up, the
62  previously stored settings will be restored.
63 
64 USER INPUT DATA FORMAT:
65  decimal : 1024
66  hex : 0x400
67  octal : 02000 (leading 0 "zero")
68  binary : B10000000000
69  float : 1024.0
70 
71 @endverbatim
72 
73 http://www.linear.com/product/LTC2662
74 
75 http://www.linear.com/product/LTC2662#demoboards
76 
77 
78 Copyright 2018(c) Analog Devices, Inc.
79 
80 All rights reserved.
81 
82 Redistribution and use in source and binary forms, with or without
83 modification, are permitted provided that the following conditions are met:
84  - Redistributions of source code must retain the above copyright
85  notice, this list of conditions and the following disclaimer.
86  - Redistributions in binary form must reproduce the above copyright
87  notice, this list of conditions and the following disclaimer in
88  the documentation and/or other materials provided with the
89  distribution.
90  - Neither the name of Analog Devices, Inc. nor the names of its
91  contributors may be used to endorse or promote products derived
92  from this software without specific prior written permission.
93  - The use of this software may or may not infringe the patent rights
94  of one or more patent holders. This license does not release you
95  from the requirement that you obtain separate licenses from these
96  patent holders to use this software.
97  - Use of the software either in source or binary form, must be run
98  on or directly connected to an Analog Devices Inc. component.
99 
100 THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
101 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
102 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
103 IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
104 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
105 LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
106 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
107 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
108 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
109 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
110 */
111 
112 /*! @file
113  @ingroup LTC2662
114 */
115 
116 #include <Arduino.h>
117 #include <stdint.h>
118 #include "Linduino.h"
119 #include "LT_SPI.h"
120 #include "UserInterface.h"
121 #include "LT_I2C.h"
122 #include "QuikEval_EEPROM.h"
123 #include "LTC2662.h"
124 #include <SPI.h>
125 #include <Wire.h>
126 
127 // Macros
128 #define REF_EXTERNAL LTC2662_REF_DISABLE //!< External mode
129 #define REF_INTERNAL 0 //!< Internal mode
130 
131 // Function Declaration
132 
133 void restore_dac_from_eeprom(); // Restores DAC settings from EEPROM
134 void print_title(); // Print the title block
135 void print_prompt(int8_t selected_dac); // Prompt the user for an input command
136 int16_t prompt_current_or_code(uint8_t selected_dac); // Prompt the user for current or code
137 uint16_t get_current(uint8_t selected_dac); // Obtains current from user
138 uint16_t get_code(); // Obtains code from user
139 void display_fault(uint8_t fault); // Displays the fault
140 
141 void menu_1_select_dac(uint8_t *selected_dac); // Menu 1: prompts user for DAC selection
142 uint8_t menu_2_write_to_input_register(uint8_t selected_dac); // Menu 2: sends data to selected DAC register with no update
143 uint8_t menu_3_write_and_update_dac(uint8_t selected_dac); // Menu 3: sends data to selected DAC register with update
144 uint8_t menu_4_update_power_up_dac(uint8_t selected_dac); // Menu 4: updates and powers up selected DAC
145 uint8_t menu_5_power_down_dac(uint8_t selected_dac); // Menu 5: powers down selected DAC
146 uint8_t menu_6_set_reference_mode(); // Menu 6: prompts user to enable/disable internal reference
147 uint8_t menu_7_set_softspan_range(uint8_t selected_dac); // Menu 7: prompts user to sets the SoftSpan range
148 uint8_t menu_8_toggle_select_word(); // Menu 8: prompts user to enter the toggle select word
149 uint8_t menu_9_set_mux(); // Menu 9: sets MEX
150 uint8_t menu_10_global_toggle_settings(); // Menu 10: sets the global toggle bit
151 void menu_11_enable_disable_eeprom_restore(); // Menu 11: EEPOM restore settings
152 void menu_13_settling_test(); // Menu 13: Settling time test
153 void menu_14_demo_board_test(); // Menu 14: Demo Board functional test
154 
155 
156 // Global variable
157 static uint8_t demo_board_connected; //!< Set to 1 if the board is connected
158 
159 //! Used to manipulate EEPROM data.
161 {
162  struct data_struct_type //! EEPROM data structure
163  {
164  int16_t cal_key; //!< The key that keeps track of the calibration
165  uint8_t soft_span_range[5]; //!< SoftSpan range
166  uint16_t dac_code_a[16]; //!< DAC Register A
167  uint16_t dac_code_b[16]; //!< DAC Register B
168  uint16_t toggle_word; //!< Toggle control word
169  uint8_t global_toggle_bit; //!< Global toggle bit
170  uint8_t mux_state; //!< Multiplexer address AND enable bit
171  uint8_t reference_mode; //!< Int. reference may be disabled in external reference mode (not required)
172  } data_struct; //!< Name of structure
173 
174  char byte_array[sizeof(data_struct_type)]; //!< Array used to store the structure
175 };
176 
177 eeprom_data_union eeprom; // Create union
178 
179 // Constants
180 
181 //! Used to keep track to print current or print code
182 enum
183 {
184  PROMPT_CURRENT = 0, /**< 0 */
185  PROMPT_CODE = 1 /**< 1 */
186 };
187 
188 //! Initialize Linduino
189 void setup()
190 // Setup the program
191 {
192  char demo_name[] = "DC2692"; // Demo Board Name stored in QuikEval EEPROM
193 
194  quikeval_SPI_init(); // Configure the spi port for 4MHz SCK
195  quikeval_SPI_connect(); // Connect SPI to main data port
196  quikeval_I2C_init(); // Configure the EEPROM I2C port for 100kHz
197 
198  Serial.begin(115200); // Initialize the serial port to the PC
199  print_title();
202  {
204  print_prompt(0);
205  }
206 }
207 
208 //! Repeats Linduino loop
209 void loop()
210 {
211  int16_t user_command;
212  uint8_t fault_reg = 0;
213  static uint8_t selected_dac = 0; // The selected DAC to be updated (0=CH0, 1=CH1 ... 5=All). Initialized to CH0.
214 
215  if (Serial.available()) // Check for user input
216  {
217  user_command = read_int(); // Read the user command
218  Serial.println(user_command);
219  Serial.print(F("\n"));
220  Serial.flush();
221  switch (user_command)
222  {
223  case 1:
224  menu_1_select_dac(&selected_dac);
225  break;
226  case 2:
227  menu_2_write_to_input_register(selected_dac);
228  break;
229  case 3:
230  fault_reg |= menu_3_write_and_update_dac(selected_dac);
231  break;
232  case 4:
233  fault_reg |= menu_4_update_power_up_dac(selected_dac);
234  break;
235  case 5:
236  fault_reg |= menu_5_power_down_dac(selected_dac);
237  break;
238  case 6:
239  fault_reg |= menu_6_set_reference_mode();
240  break;
241  case 7:
242  fault_reg |= menu_7_set_softspan_range(selected_dac);
243  break;
244  case 8:
245  fault_reg |= menu_8_toggle_select_word();
246  break;
247  case 9:
248  fault_reg |= menu_9_set_mux();
249  break;
250  case 10:
251  fault_reg |= menu_10_global_toggle_settings();
252  break;
253  case 11:
255  break;
256  case 13:
258  break;
259  case 14:
261  break;
262  default:
263  Serial.println(F("Incorrect Option"));
264  break;
265  }
266  display_fault(fault_reg);
267  Serial.println(F("\n************************************************************"));
268  print_prompt(selected_dac);
269  }
270 
271 }
272 
273 // Function Definitions
274 
275 //! Select which DAC to operate on
276 void menu_1_select_dac(uint8_t *selected_dac)
277 {
278  // Select a DAC to operate on
279  Serial.print(F("Select DAC to operate on (0 to 4, 5 for ALL DACs)"));
280  *selected_dac = read_int();
281  if (*selected_dac == 5)
282  Serial.println(F("All"));
283  else
284  Serial.println(*selected_dac);
285 }
286 
287 //! Write data to input register, but do not update DAC output
288 //! @return fault code
289 uint8_t menu_2_write_to_input_register(uint8_t selected_dac)
290 {
291  uint16_t dac_code;
292  uint8_t fault_reg = 0;
293 
294  if (prompt_current_or_code(selected_dac) == PROMPT_CURRENT)
295  dac_code = get_current(selected_dac);
296  else
297  dac_code = get_code();
298 
299  if (selected_dac <= 4)
300  {
301  // Store dac_code to register variable a or b
302  if (eeprom.data_struct.toggle_word & (0x01 << selected_dac))
303  {
304  eeprom.data_struct.dac_code_b[selected_dac] = dac_code;
305  }
306  else
307  eeprom.data_struct.dac_code_a[selected_dac] = dac_code;
308  fault_reg |= LTC2662_write(LTC2662_CS, LTC2662_CMD_WRITE_N, selected_dac, dac_code);
309  }
310  else
311  {
312  // Store dac_code to register variable a or b
313  for (uint8_t i = 0; i <= 4 ; i++)
314  {
315  if (eeprom.data_struct.toggle_word & (0x01 << i))
316  {
317  eeprom.data_struct.dac_code_b[i] = dac_code;
318  }
319  else
320  eeprom.data_struct.dac_code_a[i] = dac_code;
321  }
322  fault_reg |= LTC2662_write(LTC2662_CS, LTC2662_CMD_WRITE_ALL, selected_dac, dac_code);
323  }
324  return fault_reg;
325 }
326 
327 //! Write data to DAC register (which updates output immediately)
328 //! @return fault code
329 uint8_t menu_3_write_and_update_dac(uint8_t selected_dac)
330 {
331  uint16_t dac_code;
332  uint8_t fault_reg = 0;
333 
334  if (prompt_current_or_code(selected_dac) == PROMPT_CURRENT)
335  dac_code = get_current(selected_dac);
336  else
337  dac_code = get_code();
338 
339  if (selected_dac <= 4)
340  {
341  // Store dac_code to register variable a or b
342  if (eeprom.data_struct.toggle_word & (0x01 << selected_dac))
343  {
344  eeprom.data_struct.dac_code_b[selected_dac] = dac_code;
345  }
346  else
347  eeprom.data_struct.dac_code_a[selected_dac] = dac_code;
348 
349  fault_reg |= LTC2662_write(LTC2662_CS,LTC2662_CMD_WRITE_N_UPDATE_N, selected_dac, dac_code); // Send dac_code
350  }
351  else // All DACs
352  {
353  // Store dac_code to register variable a or b
354  for (uint8_t i = 0; i <= 4 ; i++)
355  {
356  if (eeprom.data_struct.toggle_word & (0x01 << i))
357  {
358  eeprom.data_struct.dac_code_b[i] = dac_code;
359  }
360  else
361  eeprom.data_struct.dac_code_a[i] = dac_code;
362  }
363  fault_reg |= LTC2662_write(LTC2662_CS,LTC2662_CMD_WRITE_ALL_UPDATE_ALL, 0, dac_code); // Send dac_code
364  }
365  return fault_reg;
366 }
367 
368 //! Update DAC with data that is stored in input register, power up if sleeping
369 //! @return fault code
370 uint8_t menu_4_update_power_up_dac(uint8_t selected_dac)
371 {
372  uint8_t fault_reg = 0;
373  // Update DAC
374  if (selected_dac <= 4)
375  fault_reg |= LTC2662_write(LTC2662_CS,LTC2662_CMD_UPDATE_N, selected_dac, 0);
376  else
377  fault_reg |= LTC2662_write(LTC2662_CS,LTC2662_CMD_UPDATE_ALL, 0, 0);
378  return fault_reg;
379 }
380 
381 //! Power down DAC
382 //! @return fault code
383 uint8_t menu_5_power_down_dac(uint8_t selected_dac)
384 {
385  uint8_t fault_reg = 0;
386  // Power down DAC
387  if (selected_dac <= 4)
388  fault_reg |= LTC2662_write(LTC2662_CS, LTC2662_CMD_POWER_DOWN_N, selected_dac, 0);
389  else
391  return fault_reg;
392 }
393 
394 //! Set reference mode
395 //! @return fault code
397 {
398  uint8_t fault_reg = 0;
399  int16_t user_command;
400  Serial.println(F("0 - Power down the internal reference"));
401  Serial.println(F("1 - Power up the internal reference"));
402  user_command = read_int();
403  if (user_command > 1)
404  user_command = 1;
405  if (user_command < 0)
406  user_command = 0;
407 
408  if (user_command == 1)
409  {
412  Serial.println(F("Internal reference has been powered up"));
413  }
414  else
415  {
418  Serial.println(F("Internal reference has been powered down"));
419  }
420  return fault_reg;
421 }
422 
423 //! Set SoftSpan Range
424 //! @return fault code
425 uint8_t menu_7_set_softspan_range(uint8_t selected_dac)
426 {
427  int16_t user_command;
428  uint8_t fault_reg = 0;
429 
430  Serial.println(F("0- Hi-Z"));
431  Serial.println(F("1- 0mA to 3.125mA"));
432  Serial.println(F("2- 0mA to 6.25mA"));
433  Serial.println(F("3- 0mA to 12.5mA"));
434  Serial.println(F("4- 0mA to 25mA"));
435  Serial.println(F("5- 0mA to 50mA"));
436  Serial.println(F("6- 0mA to 100mA"));
437  Serial.println(F("7- 0mA to 200mA"));
438  Serial.println(F("8- Switch to V-"));
439  Serial.println(F("9- 0mA to 300mA"));
440  Serial.print(F("Select a SoftSpan Range: "));
441  user_command = read_int();
442 
443  if (user_command > 9)
444  user_command = 9;
445  if (user_command < 0)
446  user_command = 0;
447  Serial.println(user_command);
448 
449  // User command 9 maps to 0xF
450  if (user_command == 9)
451  user_command = 15;
452  if (selected_dac <= 4)
453  {
454  eeprom.data_struct.soft_span_range[selected_dac] = user_command;
455  fault_reg |= LTC2662_write(LTC2662_CS, LTC2662_CMD_SPAN, selected_dac, eeprom.data_struct.soft_span_range[selected_dac]);
456  }
457  else
458  {
459  for (uint8_t i = 0; i <= 4; i++)
460  eeprom.data_struct.soft_span_range[i] = user_command;
462  }
463  return fault_reg;
464 }
465 
466 //! Enter toggle select word, which also sets the register that will be written
467 //! if bit is 0, register A is written, if 1, register B is written.
468 //! @return fault code
470 {
471  uint8_t fault_reg = 0;
472  // Select a DAC to operate on
473  Serial.println(F("Toggle Select bit sets the register to be written for the corresponding DAC."));
474  Serial.println(F("0 for Register A or 1 for Register B."));
475  Serial.println(F("Note: DAC Update from Register B requires TGB = 1"));
476  Serial.println(F(" DAC Update from Register A requires TCB = 0"));
477  Serial.print(F("Enter Toggle Select Byte as hex (0xMM) or binary (B10101010): "));
478  eeprom.data_struct.toggle_word = 0x1F & read_int();
479 
481  Serial.println(eeprom.data_struct.toggle_word, BIN);
482  return fault_reg;
483 }
484 
485 //! Sets the channel for the MUX
486 //! @return fault code
487 uint8_t menu_9_set_mux()
488 {
489  int16_t user_command;
490  uint8_t fault_reg = 0;
491 
492  Serial.println(F("MUX Control:"));
493  Serial.println(F("0- Disable(Hi-Z)"));
494  Serial.println(F("1- OUT0 Current Mesurement"));
495  Serial.println(F("2- OUT1 Current Mesurement"));
496  Serial.println(F("3- OUT2 Current Mesurement"));
497  Serial.println(F("4- OUT3 Current Mesurement"));
498  Serial.println(F("5- OUT4 Current Mesurement"));
499  Serial.println(F("6- VCC"));
500  Serial.println(F("7- IOVCC"));
501  Serial.println(F("8- VREF"));
502  Serial.println(F("9- VREFLO"));
503  Serial.println(F("10- Die Temperatur"));
504  Serial.println(F("16- VDD0"));
505  Serial.println(F("17- VDD1"));
506  Serial.println(F("18- VDD2"));
507  Serial.println(F("19- VDD3"));
508  Serial.println(F("20- VDD4"));
509  Serial.println(F("21- V+"));
510  Serial.println(F("22- V-"));
511  Serial.println(F("23- GND"));
512  Serial.println(F("24- OUT0 Pin Voltage"));
513  Serial.println(F("25- OUT1 Pin Voltage"));
514  Serial.println(F("26- OUT2 Pin Voltage"));
515  Serial.println(F("27- OUT3 Pin Voltage"));
516  Serial.println(F("28- OUT4 Pin Voltage"));
517  Serial.print(F("Enter a command: "));
518  user_command = read_int();
519 
520 
521  if (user_command < 0)
522  user_command = 0;
523  user_command = user_command & 0x1F;
524  Serial.println(user_command);
527  return fault_reg;
528 }
529 //! Enable / Disable the global toggle bit
530 //! @return fault code
532 {
533  int16_t user_command;
534  uint8_t fault_reg = 0;
535  Serial.println(F("0- Disable Global Toggle"));
536  Serial.println(F("1- Enable Global Toggle"));
537  Serial.print(F("Enter a command: "));
538  user_command = read_int();
539 
540  if (user_command > 1)
541  user_command = 1;
542  if (user_command < 0)
543  user_command = 0;
544  Serial.println(user_command);
545 
548  return fault_reg;
549 }
550 
551 //! Enable / Disable restoration of DAC values from EEPROM Use with caution - behaviour is undefined if you
552 //! enable restoration and data has NOT been previously stored from a known state.
554 {
555  int16_t user_input;
556  Serial.println(F("\n0- Enable Restoration"));
557  Serial.println(F("1- Disable Restoration"));
558  Serial.println(F("2- Store DAC Settings"));
559  user_input = read_int();
560  switch (user_input)
561  {
562  case 0:
563  Serial.println(F("Enabling EEPROM restoration"));
566  break;
567  case 1:
568  Serial.println(F("Disabling EEPROM restoration"));
569  eeprom.data_struct.cal_key = 0;
571  break;
572  case 2:
575  Serial.println(F("Stored Settings to EEPROM"));
576  }
577 }
578 
579 
580 // Functional test for demo board, tests continuity, EEPROM contents,
581 // And correct resolution DAC installed.
583 {
584 
585  uint8_t i, errorcount = 0;
586 
587  Serial.println(F("Welcome to the LTC2662 Demo Board Test Program."));
588  Serial.print(F("Found board assembly type "));
589  Serial.println(demo_board.option);
590 
591  Serial.println(F("Checking EEPROM contents..."));
592 
594  ui_buffer[48] = 0;
595  Serial.println(ui_buffer);
596  switch (demo_board.option)
597  {
598  case 'A':
599  if (strcmp("LTC2662-16,Cls,D2662,01,01,DC,DC2692A-A,--------", ui_buffer))
600  {
601  Serial.println(F("FAILED EEPROM Contents"));
602  errorcount += 1;
603  }
604  break;
605  case 'B':
606  if (strcmp("LTC2662-12,Cls,D2662,01,01,DC,DC2692A-B,--------", ui_buffer))
607  {
608  Serial.println(F("FAILED EEPROM Contents"));
609  errorcount += 1;
610  }
611  break;
612  }
613  if (!errorcount)
614  Serial.println(F("EEPROM good!"));
615 
616  Serial.println(F("Ensure all jumpers are in the Upper position (INT ref, VDDx=V+"));
617  Serial.println(F("Writing ramp of currents to DAC outputs. Verify DAC0 = 10mA, DAC1 = 20mA,"));
618  Serial.println(F("DAC2 = 30mA ... DAC4 = 50MAV. Type 1, enter when done."));
619 
621 
622  for (i=0; i <= 4; ++i)
623  {
626  }
627 
628  read_int(); // Read the user command
629 
630  Serial.println(F("Setting MUX to VREF."));
631  Serial.println(F("Verify MUX output is between 1.24V and 1.26V"));
632 
635 
636  Serial.println(F("Type 1, enter when done."));
637  read_int();
638 
639  Serial.println(F("Remove the load from OUT0"));
640  Serial.println(F("The Fault LED should light up"));
641  Serial.println(F("Type 1, enter when done."));
642  read_int();
643 
644 }
645 
646 //! Prompt user to enter a current or digital code to send to DAC
647 //! @returns user input
648 int16_t prompt_current_or_code(uint8_t selected_dac )
649 {
650  int16_t user_input;
651 
652  Serial.print(F("Type 1 to enter current, 2 to enter code: "));
653  Serial.flush();
654  user_input = read_int();
655  Serial.println(user_input);
656 
657  if (user_input != 2)
658  {
659  if (selected_dac >= 5)
660  {
661  Serial.println(F("\nCaution! current SoftSpan could be different for different DACs"));
662  Serial.println(F("Ensure All DACs can be set to desired currents"));
663  Serial.println(F("DAC 0 is used for SoftSpan values for all DACs."));
664  Serial.print(F("Toggle Register Select Bits 0=A, 1 = B: 0b"));
665  Serial.println(eeprom.data_struct.toggle_word, BIN);
666  }
667  return(PROMPT_CURRENT);
668  }
669  else
670  {
671  if (selected_dac >= 5)
672  {
673  Serial.println(F("DAC 0 is used for SoftSpan values for all DACs."));
674  }
675  }
676  return(PROMPT_CODE);
677 }
678 
679 //! Get current from user input, calculate DAC code based on lsb, offset
680 //! @returns the DAC code
681 uint16_t get_current(uint8_t selected_dac)
682 {
683  float dac_current;
684 
685  Serial.print(F("Enter Desired DAC output current: "));
686  dac_current = read_float();
687  Serial.print(dac_current);
688  Serial.println(F(" mA"));
689  Serial.flush();
690 
691  if (selected_dac <= 4)
692  {
693  if (eeprom.data_struct.soft_span_range[selected_dac] == 15)
694  return(LTC2662_current_to_code(dac_current, LTC2662_MAX_OUTPUT[9]));
695  else
696  return(LTC2662_current_to_code(dac_current,
697  LTC2662_MAX_OUTPUT[eeprom.data_struct.soft_span_range[selected_dac]]));
698  }
699  else
700  {
701  if (eeprom.data_struct.soft_span_range[0] == 15)
702  return(LTC2662_current_to_code(dac_current, LTC2662_MAX_OUTPUT[9]));
703  else
704  return(LTC2662_current_to_code(dac_current,
706  }
707 }
708 
709 //! Get code to send to DAC directly, in decimal, hex, or binary
710 //! @return code from user
711 uint16_t get_code()
712 {
713  uint16_t returncode;
714  Serial.println(F("Enter Desired DAC Code"));
715  Serial.print(F("(Format 32768, 0x8000, 0100000, or B1000000000000000): "));
716  returncode = (uint16_t) read_int();
717  Serial.print(F("0x"));
718  Serial.println(returncode, HEX);
719  Serial.flush();
720  return(returncode);
721 }
722 
723 //! Prints the title block when program first starts.
725 {
726  Serial.println();
727  Serial.println(F("*****************************************************************"));
728  Serial.println(F("* DC2692 Demonstration Program *"));
729  Serial.println(F("* *"));
730  Serial.println(F("* This program demonstrates how to send data to the LTC2662 *"));
731  Serial.println(F("* five Channel 16/12-bit DAC found on the DC2692 demo board. *"));
732  Serial.println(F("* *"));
733  Serial.println(F("* Set the baud rate to 115200 and select the newline terminator.*"));
734  Serial.println(F("* *"));
735  Serial.println(F("*****************************************************************"));
736 }
737 
738 //! Prints main menu.
739 void print_prompt(int8_t selected_dac)
740 {
741  // Displays menu
742  Serial.println(F("\nCommand Summary:"));
743  Serial.println(F(" 1-Select DAC"));
744  Serial.println(F(" 2-Write to input register (no update)"));
745  Serial.println(F(" 3-Write and update DAC"));
746  Serial.println(F(" 4-Update / power up DAC"));
747  Serial.println(F(" 5-Power down DAC"));
748  Serial.println(F(" 6-Set reference mode"));
749  Serial.println(F(" 7-Set SoftSpan"));
750  Serial.println(F(" 8-Toggle selected register"));
751  Serial.println(F(" 9-Set Mux"));
752  Serial.println(F(" 10-Global toggle bit settings"));
753  Serial.println(F(" 11-Enable, disable, or store to EEPROM"));
754  Serial.println(F("\nPresent Values:"));
755  Serial.print(F(" Selected DAC: "));
756 
757  // Display current settings
758  if (selected_dac >= 4 )
759  {
760  Serial.println(F("All"));
761  Serial.print(F(" SoftSpan range: "));
762  if (eeprom.data_struct.soft_span_range[0] == 0)
763  Serial.println(F("Hi-Z"));
764  else if (eeprom.data_struct.soft_span_range[0] == 8)
765  Serial.println(F("Switch to V-"));
766  else
767  {
768  Serial.print(F("0 mA to "));
769  Serial.print(LTC2662_MAX_OUTPUT[eeprom.data_struct.soft_span_range[0]], 4);
770  Serial.println(F(" mA"));
771  }
772  }
773  else
774  {
775  Serial.println(selected_dac);
776  Serial.print(F(" SoftSpan range: "));
777  if (eeprom.data_struct.soft_span_range[selected_dac] == 0)
778  Serial.println(F("Hi-Z"));
779  else if (eeprom.data_struct.soft_span_range[selected_dac] == 8)
780  Serial.println(F("Switch to V-"));
781  else
782  {
783  Serial.print(F("0 mA to "));
784  if (eeprom.data_struct.soft_span_range[selected_dac] == 15)
785  Serial.print(LTC2662_MAX_OUTPUT[9], 4);
786  else
787  Serial.print(LTC2662_MAX_OUTPUT[eeprom.data_struct.soft_span_range[selected_dac]], 4);
788  Serial.println(F(" mA"));
789  }
790  }
791  Serial.print(F(" Toggle Register: "));
792  for (uint8_t i = 0; i <= 4; i++)
793  {
794  if ((eeprom.data_struct.toggle_word & (0x10 >> i)))
795  Serial.print(F("B"));
796  else
797  Serial.print(F("A"));
798  }
799  Serial.println();
800 
801  Serial.print(F(" Global Toggle Bit: "));
802  Serial.println(eeprom.data_struct.global_toggle_bit);
803 
804  Serial.print(F(" Reference: "));
806  Serial.println(F("Internal"));
807  else
808  Serial.println(F("External"));
809 
810  Serial.print(F("\nEnter a command: "));
811  Serial.flush();
812 }
813 
814 //! Read the alert settings from EEPROM
816 {
817  int16_t cal_key;
818  int8_t i;
819 
820  // Read the cal key from the EEPROM
822 
823  if (cal_key == EEPROM_CAL_KEY)
824  {
825  // Calibration has been stored, read thresholds
827 
828  // Write SoftSpan ranges
829  for (uint8_t i = 0; i <= 15; i++)
831 
832  // Write stored data to DAC A registers
833  for (uint8_t i = 0; i <= 15 ; i++)
835 
836  LTC2662_write(LTC2662_CS, LTC2662_CMD_TOGGLE_SEL, 0, 0xFFFF); // Set to B registers
837 
838  // Write stored data to DAC B registers
839  for (uint8_t i = 0; i <= 15 ; i++)
841 
843 
845 
847 
849 
850  LTC2662_write(LTC2662_CS,LTC2662_CMD_UPDATE_ALL, 0, 0); // Update ALL
851 
852  Serial.println(F("DAC settings loaded from EEPROM"));
853  }
854  else
855  Serial.println(F("EEPROM data not found"));
856 }
857 
858 //! Display fault conditions
859 void display_fault(uint8_t fault)
860 {
861  if (fault & 0x01)
862  Serial.println(F("******** Open-Circuit detected on OUT0 ********"));
863  if (fault & 0x02)
864  Serial.println(F("******** Open-Circuit detected on OUT1 ********"));
865  if (fault & 0x04)
866  Serial.println(F("******** Open-Circuit detected on OUT2 ********"));
867  if (fault & 0x08)
868  Serial.println(F("******** Open-Circuit detected on OUT3 ********"));
869  if (fault & 0x10)
870  Serial.println(F("******** Open-Circuit detected on OUT4 ********"));
871  if (fault & 0x20)
872  Serial.println(F("******** Over Temperature. Die > 160 C ********"));
873  if (fault & 0x40)
874  Serial.println(F("******** 10V Power Limit Exceeded on VDD to IOUT ********"));
875  if (fault & 0x80)
876  Serial.println(F("******** Invalid SPI Sequence Length ********"));
877 }
878 
879 
880 
881 ///////////////////////////////////////////////////////////////////////////
882 // The following functions are used internally for testing, and included //
883 // here for reference. //
884 ///////////////////////////////////////////////////////////////////////////
885 
886 // Settling time routine, used for datasheet pictures. Set scope to ARM trigger on SETTLE_TRIGGER
887 // Rising edge, trigger on CS pin for the actual edge that causes the update.
888 // You can test any other channel / starting / final values by setting up the DAC's
889 // register A to the initial (starting) voltage and register B to the final (settled) voltage.
890 // The channel's toggle bit must be set as well.
891 
892 #define INTEGRATOR_CONTROL 2 // Pin to control integrator on settling time circuit
893 // Set low for 100ms after full settling has occurred,
894 // high to run test.
895 #define SETTLE_TRIGGER 3 // High to low edge close to DAC active edge. Can also be
896 // used to drive DAC simulator.
897 
899 {
900  int16_t user_input, initial, final;
901  int8_t range;
902  int8_t settle_channel;// Which DAC to test for settling (only one at a time to prevent
903  // crosstalk artefacts.)
904  Serial.println(F("Select test to run:"));
905  Serial.println(F("0: presently programmed DAC values"));
906  Serial.println(F("1: 0-200mA rising, CH1"));
907  Serial.println(F("2: 200mA-0 falling, CH1"));
908  Serial.println(F("3: 145mA-155mA rising, CH1"));
909  Serial.println(F("4: 155mA-145mA falling, CH1"));
910  Serial.println(F("5: 0-3.125mA rising, CH3"));
911  Serial.println(F("6: 3.125-0 falling, CH3"));
912 
913  Serial.flush();
914  user_input = read_int();
915  switch (user_input)
916  {
917  case 1:
918  settle_channel = 1;
919  initial = 0x0000;
920  final = 0xFFFF;
921  range = LTC2662_SPAN_200MA;
922  break;
923  case 2:
924  settle_channel = 1;
925  initial = 0xFFFF;
926  final = 0x0000;
927  range = LTC2662_SPAN_200MA;
928  break;
929  case 3:
930  settle_channel = 1;
931  initial = 0xB99A;
932  final = 0xC666;
933  range = LTC2662_SPAN_200MA;
934  break;
935  case 4:
936  settle_channel = 1;
937  initial = 0xC666;
938  final = 0xB99A;
939  range = LTC2662_SPAN_200MA;
940  break;
941  case 5:
942  settle_channel = 3;
943  initial = 0x0000;
944  final = 0xFFFF;
945  range = LTC2662_SPAN_3_125MA;
946  break;
947  case 6:
948  settle_channel = 3;
949  initial = 0xFFFF;
950  final = 0x0000;
951  range = LTC2662_SPAN_3_125MA;
952  break;
953  default:
954  Serial.println("Using presently programmed DAC values");
955  }
956  if (user_input != 0) // Load DAC to be tested with range, initial, and final values.
957  {
958  LTC2662_write(LTC2662_CS, LTC2662_CMD_SPAN, settle_channel, range); // Set Span
959  LTC2662_write(LTC2662_CS, LTC2662_CMD_TOGGLE_SEL, 0, 0x0000); // Point to register A
960  LTC2662_write(LTC2662_CS, LTC2662_CMD_WRITE_N_UPDATE_N, settle_channel, initial); // Send dac_code
961  LTC2662_write(LTC2662_CS, LTC2662_CMD_TOGGLE_SEL, 0, 0x0001 << settle_channel); // Point to register B
962  LTC2662_write(LTC2662_CS, LTC2662_CMD_WRITE_N_UPDATE_N, settle_channel, final); // Send dac_code
963  }
964  Serial.println("Settling time test running, send any character to terminate.");
965  pinMode(INTEGRATOR_CONTROL, OUTPUT);
966  pinMode(SETTLE_TRIGGER, OUTPUT);
967  while (!Serial.available())
968  {
969  PORTD |= 1 << INTEGRATOR_CONTROL; // Disable integrator
970  PORTD |= 1 << SETTLE_TRIGGER;
971  LTC2662_write(LTC2662_CS, LTC2662_CMD_GLOBAL_TOGGLE, 0, 0); // Set global toggle bit LOW, INITIAL value
972  PORTD &= ~(1 << SETTLE_TRIGGER); // Reset settle trigger LOW
973  delay(10); // Wait to get to initial value
974  LTC2662_write(LTC2662_CS, LTC2662_CMD_GLOBAL_TOGGLE, 0, 1); // Set global toggle HIGH, FINAL value
975  delay(10); // Wait to get to final value, here is where you look at the settling
976  PORTD &= ~(1 << INTEGRATOR_CONTROL); // Enable integrator
977  delay(100);
978  }
979  Serial.read();
980  Serial.println("Exiting Settling time test.");
981 }
struct demo_board_type demo_board
Instantiate demo board structure.
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.
EEPROM data structure.
Definition: DC2692A.ino:162
char option
Demo Circuit option (A)
static void print_title()
Prints the title block when program first starts.
Definition: DC2692A.ino:724
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 INTEGRATOR_CONTROL
Definition: DC2692A.ino:892
unsigned char user_command
#define LTC2662_CMD_UPDATE_ALL
Update all DACs.
Definition: LTC2662.h:104
#define EEPROM_I2C_ADDRESS
static uint8_t menu_10_global_toggle_settings()
Enable / Disable the global toggle bit.
Definition: DC2692A.ino:531
#define REF_EXTERNAL
External mode.
Definition: DC2692A.ino:128
int8_t LTC2662_write(uint8_t cs, uint8_t dac_command, uint8_t dac_address, uint16_t dac_code)
Write the 16-bit dac_code to the LTC2662.
Definition: LTC2662.cpp:70
uint16_t toggle_word
Toggle control word.
Definition: DC2692A.ino:168
int16_t cal_key
The key that keeps track of the calibration.
Definition: DC2692A.ino:164
#define LTC2662_CMD_MUX
Select MUX channel (controlled by 5 LSbs in data word)
Definition: LTC2662.h:106
#define LTC2662_CMD_GLOBAL_TOGGLE
Software toggle control via global toggle bit.
Definition: LTC2662.h:108
static void menu_14_demo_board_test()
Definition: DC2692A.ino:582
#define LTC2662_CMD_SPAN
Write span to dac n.
Definition: LTC2662.h:101
Header File for Linduino Libraries and Demo Code.
static uint16_t get_code()
Get code to send to DAC directly, in decimal, hex, or binary.
Definition: DC2692A.ino:711
static uint16_t get_current(uint8_t selected_dac)
Get current from user input, calculate DAC code based on lsb, offset.
Definition: DC2692A.ino:681
static uint8_t 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: DC2692A.ino:370
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 loop()
Repeats Linduino loop.
Definition: DC2692A.ino:209
#define LTC2662_SPAN_100MA
Definition: LTC2662.h:122
#define LTC2662_CMD_CONFIG
Configure reference / toggle.
Definition: LTC2662.h:102
#define LTC2662_CMD_WRITE_ALL_UPDATE_ALL
Write to all input reg, update all DACs.
Definition: LTC2662.h:105
static uint8_t menu_8_toggle_select_word()
Enter toggle select word, which also sets the register that will be written if bit is 0...
Definition: DC2692A.ino:469
#define REF_INTERNAL
Internal mode.
Definition: DC2692A.ino:129
#define LTC2662_CMD_UPDATE_N
Update (power up) DAC register n.
Definition: LTC2662.h:95
uint8_t mux_state
Multiplexer address AND enable bit.
Definition: DC2692A.ino:170
#define LTC2662_SPAN_200MA
Definition: LTC2662.h:123
const float LTC2662_MAX_OUTPUT[10]
Definition: LTC2662.h:132
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 int16_t prompt_current_or_code(uint8_t selected_dac)
Prompt user to enter a current or digital code to send to DAC.
Definition: DC2692A.ino:648
static uint8_t demo_board_connected
Set to 1 if the board is connected.
Definition: DC2692A.ino:157
QuikEval EEPROM Library.
static uint8_t range
Definition: DC1096B.ino:111
#define LTC2662_CMD_SPAN_ALL
Set span for all DACs.
Definition: LTC2662.h:109
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: DC2692A.ino:553
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
#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 LTC2662_CMD_WRITE_N_UPDATE_N
Write to input register n, update (power-up)
Definition: LTC2662.h:97
static uint8_t menu_5_power_down_dac(uint8_t selected_dac)
Power down DAC.
Definition: DC2692A.ino:383
#define LTC2662_SPAN_3_125MA
Definition: LTC2662.h:117
uint8_t soft_span_range[5]
SoftSpan range.
Definition: DC2692A.ino:165
LT_SPI: Routines to communicate with ATmega328P&#39;s hardware SPI port.
LTC2662: 5-Channel 16-/12-Bit 300mA SoftSpan Current Source DACs.
uint16_t dac_code_a[16]
DAC Register A.
Definition: DC2692A.ino:166
static uint8_t menu_3_write_and_update_dac(uint8_t selected_dac)
Write data to DAC register (which updates output immediately)
Definition: DC2692A.ino:329
uint16_t LTC2662_current_to_code(float dac_current, float max_output)
Calculate a LTC2662 DAC code given the desired output current.
Definition: LTC2662.cpp:88
LT_I2C: Routines to communicate with ATmega328P&#39;s hardware I2C port.
#define LTC2662_CMD_TOGGLE_SEL
Select which DACs can be toggled (via toggle pin or global toggle bit)
Definition: LTC2662.h:107
static uint8_t menu_7_set_softspan_range(uint8_t selected_dac)
Set SoftSpan Range.
Definition: DC2692A.ino:425
char demo_name[]
Demo Board Name stored in QuikEval EEPROM.
Definition: DC1880A.ino:97
void quikeval_SPI_connect()
Connect SPI pins to QuikEval connector through the Linduino MUX. This will disconnect I2C...
Definition: LT_SPI.cpp:138
eeprom_data_union eeprom
Definition: DC2692A.ino:177
int32_t read_int()
float read_float()
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
#define LTC2662_CS
Define the SPI CS pin.
Definition: LTC2662.h:89
static void display_fault(uint8_t fault)
Display fault conditions.
Definition: DC2692A.ino:859
uint8_t global_toggle_bit
Global toggle bit.
Definition: DC2692A.ino:169
static void menu_13_settling_test()
Definition: DC2692A.ino:898
void quikeval_I2C_init(void)
Initializes Linduino I2C port.
Definition: LT_I2C.cpp:394
static uint8_t menu_6_set_reference_mode()
Set reference mode.
Definition: DC2692A.ino:396
static int i
Definition: DC2430A.ino:184
#define LTC2662_CMD_WRITE_N
Write to input register n.
Definition: LTC2662.h:94
static void restore_dac_from_eeprom()
Read the alert settings from EEPROM.
Definition: DC2692A.ino:815
struct eeprom_data_union::data_struct_type data_struct
Name of structure.
static uint8_t menu_9_set_mux()
Sets the channel for the MUX.
Definition: DC2692A.ino:487
#define LTC2662_CMD_WRITE_ALL
Write to all input registers.
Definition: LTC2662.h:103
static void setup()
Initialize Linduino.
Definition: DC2692A.ino:189
#define SETTLE_TRIGGER
Definition: DC2692A.ino:895
static uint8_t menu_2_write_to_input_register(uint8_t selected_dac)
Write data to input register, but do not update DAC output.
Definition: DC2692A.ino:289
#define LTC2662_CMD_POWER_DOWN_N
Power down n.
Definition: LTC2662.h:98
#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]
#define LTC2662_CMD_POWER_DOWN_ALL
Power down chip (all DAC&#39;s, MUX and reference)
Definition: LTC2662.h:99
static void print_prompt(int8_t selected_dac)
Prints main menu.
Definition: DC2692A.ino:739
static void menu_1_select_dac(uint8_t *selected_dac)
Select which DAC to operate on.
Definition: DC2692A.ino:276