| Linduino 1.3.0 Linear Technology Arduino-Compatible Demonstration Board

DC1703A.ino
Go to the documentation of this file.
1 /*!
2 Linear Technology DC1703A Demonstration Board.
3 LTC2655: Quad I2C 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 The program displays calculated voltages which are based on the voltage
10 of the reference used, be it internal or external. A precision voltmeter
11 is needed to verify the actual measured voltages against the calculated
12 voltage displayed. If an external reference is used, a precision voltage
13 source is required to apply the external reference voltage. A precision
14 voltmeter is also required to measure the external reference voltage.
15 No external power supply is required. Any assembly option may be used:
16 DC1703A-A, DC1703A-B, DC1703A-C, DC1703A-D.
17
18
19 Explanation of Commands:
20 1- Select DAC: Select one of four DACs to test: A, B, C, D.
21
22 2- Write to DAC input register: Value is stored in the DAC for updating
23 later, allowing multiple channels to be updated at once, either
24 through a software "Update All" command or by asserting the LDAC# pin.
25 User will be prompted to enter either a code in hex or decimal, or a
26 voltage. If a voltage is entered, a code will be calculated based on
27 the active scaling and reference parameters - ideal values if no
28 calibration was ever stored.
29
30 3- Write and Update: Similar to item 1, but DAC is updated immediately.
31
32 4- Update DAC: Copies the value from the input register into the DAC
33 Register. Note that a "write and update" command writes the code to
34 BOTH the input register and DAC register, so subsequent "update" commands
35 will simply re-copy the same data (no change in output).
36
37 5- Power Down DAC: Disable DAC output. Power supply current is reduced. DAC
38 code present in DAC registers at time of shutdown are preserved.
39
40 6- Set reference mode, either internal or external: Selecting external mode
41 prompts for the external refernce voltage, which is used directly if no
42 individual DAC calibration is stored. The selection and entered volgage
43 are stored to EEPROM so it is persisent across reset / power cycles.
44
45 7- Calibrate DAC: Use a precision voltmeter to obtain and enter VOUT readings
46 taken with different DAC codes. Set reference mode FIRST, as values are stored
47 separately for internal and external reference mode. Entries are used to
48 calculate the closest code to send to the DAC to achieve an entered voltage.
49
50 8- Enable / Disable calibration: Switch between stored calibration values and
51 defaults. Calibration parameters are stored separately for internal and
52 external reference modes. Ideal calibration will be used if the calibration
53 parameter valid key is not set.
54
55
56 USER INPUT DATA FORMAT:
57 decimal : 1024
58 hex : 0x400
59 octal : 02000 (leading 0 "zero")
60 binary : B10000000000
61 float : 1024.0
62
63 @endverbatim
64
65 http://www.linear.com/product/LTC2655
66
67 http://www.linear.com/product/LTC2655#demoboards
68
69
70 Copyright 2018(c) Analog Devices, Inc.
71
72 All rights reserved.
73
74 Redistribution and use in source and binary forms, with or without
75 modification, are permitted provided that the following conditions are met:
76 - Redistributions of source code must retain the above copyright
77 notice, this list of conditions and the following disclaimer.
78 - Redistributions in binary form must reproduce the above copyright
79 notice, this list of conditions and the following disclaimer in
80 the documentation and/or other materials provided with the
81 distribution.
82 - Neither the name of Analog Devices, Inc. nor the names of its
83 contributors may be used to endorse or promote products derived
84 from this software without specific prior written permission.
85 - The use of this software may or may not infringe the patent rights
86 of one or more patent holders. This license does not release you
87 from the requirement that you obtain separate licenses from these
88 patent holders to use this software.
89 - Use of the software either in source or binary form, must be run
90 on or directly connected to an Analog Devices Inc. component.
91
92 THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
93 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
94 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
95 IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
96 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
97 LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
98 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
99 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
100 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
101 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
102 */
103
104 /*! @file
105 @ingroup LTC2655
106 */
107
108 #include <Arduino.h>
109 #include <stdint.h>
110 #include "Linduino.h"
111 #include "LT_SPI.h"
112 #include "UserInterface.h"
113 #include "LT_I2C.h"
114 #include "QuikEval_EEPROM.h"
115 #include "LTC2655.h"
116 #include <Wire.h>
117 #include <SPI.h>
118
119 //! Calibration associated with internal reference.
120 //! This value is stored in EEPROM_CAL address of QuikEval EEPROM to indicate that a calibration occurred using the internal reference.
121 #define EEPROM_CAL_KEY_INT 0x5678
122 //! Calibration associated with external reference.
123 //! This value is stored in EEPROM_CAL address of QuikEval EEPROM to indicate that a calibration occurred using the external reference.
124 #define EEPROM_CAL_KEY_EXT 0x9ABC //!< Calibration associated with external reference. (Stored in EEPROM_CAL address of QuikEval EEPROM).
125
126 // DAC Reference State
127 // Could have been 0 or 1. This allows you to use the
128 // variable "reference_mode" as the command argument to a write
129 #define REF_INTERNAL LTC2655_CMD_INTERNAL_REFERENCE //!< Stored reference state is Internal
130 #define REF_EXTERNAL LTC2655_CMD_EXTERNAL_REFERENCE //!< Stored reference state is External
131
132 // EEPROM memory locations
133 #define STORED_REF_STATE_BASE EEPROM_CAL_STATUS_ADDRESS //!< Base address of the stored reference state
134 #define INT_CAL_VALID_BASE STORED_REF_STATE_BASE + 2 //!< Base address of the "internal ref calibration valid" flag
135 #define INT_CAL_PARAMS_BASE INT_CAL_VALID_BASE + 2 //!< Base address of the internal ref calibration parameters
136 #define EXT_CAL_VALID_BASE INT_CAL_PARAMS_BASE + 32 //!< Base address of the "external ref calibration valid" flag
137 #define EXT_CAL_PARAMS_BASE EXT_CAL_VALID_BASE + 2 //!< Base address of the external ref calibration parameters
138 #define EXT_REF_V_BASE EXT_CAL_PARAMS_BASE + 32 //!< Base address of the stored external reference voltage
139
140 // Function Declaration
141 int8_t restore_calibration(); // Read the DAC calibration from EEPROM, Return 1 if successful, 0 if not
142 void store_calibration(); // Store the DAC calibration to the EEPROM
143 void print_title(); // Print the title block
144 void print_prompt(int16_t selected_dac); // Prompt the user for an input command
145 int16_t prompt_voltage_or_code();
146 uint16_t get_voltage(float LTC2655_lsb, int16_t LTC2655_offset);
147 uint16_t get_code();
148 int8_t calibrate_dac(uint8_t index); // Calibrate the selected DAC using a voltmeter. The routine does a linear curve fit given two data points.
149
150 int8_t menu_1_select_dac(int16_t *selected_dac);
151 int8_t menu_2_write_to_input_register(int16_t selected_dac);
152 int8_t menu_3_write_and_update_dac(int16_t selected_dac);
153 int8_t menu_4_update_power_up_dac(int16_t selected_dac);
154 int8_t menu_5_power_down_dac(int16_t selected_dac);
155 int8_t menu_6_set_reference_mode(); // int, ext, if ext, prompt for voltage
156 int8_t menu_7_calibrate_dacs();
157 int8_t menu_8_enable_calibration();
158
159 // Global variables
160 static uint8_t demo_board_connected; //!< Set to 1 if the board is connected
161 static uint8_t shift_count = 0; //!< The data align shift count. For 16-bit=0, for 12-bits=4
162 static uint8_t reference_mode; //!< Tells whether to set internal or external reference
163
164 // Global calibration variables
165 static float reference_voltage; //!< Reference voltage, either internal or external
166 static int16_t LTC2655_offset[5]; //!< DAC offset - index 4 for "all DACs." If part is calibrated, then index 0 is stored to "all DACs."
167 static float LTC2655_lsb[5]; //!< The LTC2655 lsb - index 4 for "all DACs." If part is calibrated, then index 0 is stored to "all DACs."
168
169 // Constants
170
171 //! Lookup table for DAC address. Allows the "All DACs" address to be indexed right after DAC D in loops.
172 //! This technique is very useful for devices with non-monotonic channel addresses.
173 const uint8_t address_map[5] = {LTC2655_DAC_A, LTC2655_DAC_B, LTC2655_DAC_C, LTC2655_DAC_D, LTC2655_DAC_ALL}; //!< Map entered option 0..2 to DAC address
174
175 //! Used to keep track to print voltage or print code
176 enum
177 {
178 PROMPT_VOLTAGE = 0, /**< 0 */
179 PROMPT_CODE = 1 /**< 1 */
180 };
181
182 //! Initialize Linduino
183 void setup()
184 // Setup the program
185 {
186 char demo_name[] = "DC1703"; // Demo Board Name stored in QuikEval EEPROM
187 quikeval_I2C_init(); // Configure the EEPROM I2C port for 100khz
188 quikeval_I2C_connect(); // Connect I2C to main data port
189 Serial.begin(115200); // Initialize the serial port to the PC
190 print_title();
191 demo_board_connected = discover_demo_board(demo_name);
192 if (demo_board_connected)
193 {
194 restore_calibration();
195 print_prompt(0);
196 }
197 }
198
199 //! Repeats Linduino loop
200 void loop()
201 {
202 int8_t ack=0;
203 int16_t user_command;
204 static int16_t selected_dac = 0; // The selected DAC to be updated (0=A, 1=B ... 5=All). Initialized to "A".
205 // The main control loop
206 if (demo_board_connected) // Do nothing if the demo board is not connected
207 {
208 if (Serial.available()) // Check for user input
209 {
210 user_command = read_int(); // Read the user command
211 Serial.println(user_command);
212 Serial.flush();
213 ack = 0;
214 switch (user_command)
215 {
216 case 1:
217 ack |= menu_1_select_dac(&selected_dac);
218 break;
219 case 2:
220 ack |= menu_2_write_to_input_register(selected_dac);
221 break;
222 case 3:
223 ack |= menu_3_write_and_update_dac(selected_dac);
224 break;
225 case 4:
226 ack |= menu_4_update_power_up_dac(selected_dac);
227 break;
228 case 5:
229 ack |= menu_5_power_down_dac(selected_dac);
230 break;
231 case 6:
232 ack |= menu_6_set_reference_mode(); // int, ext, if ext, prompt for voltage
233 ack |= restore_calibration();
234 break;
235 case 7:
236 ack |= menu_7_calibrate_dacs();
237 restore_calibration();
238 break;
239 case 8:
240 menu_8_enable_calibration();
241 restore_calibration();
242 break;
243 default:
244 Serial.println("Incorrect Option");
245 break;
246 }
247 if (ack) Serial.println("I2C NACK received, check address\n");
248 Serial.println("\n*****************************************************************");
249 print_prompt(selected_dac);
250 }
251 }
252 }
253
254 // Function Definitions
255
256 //! Select which DAC to operate on
257 //! @return 0
258 int8_t menu_1_select_dac(int16_t *selected_dac)
259 {
260 // Select a DAC to operate on
261 Serial.print("Select DAC to operate on (0=A, 1=B, 2=C, 3=D, 4=All)");
262 *selected_dac = read_int();
263 if (*selected_dac == 4)
264 Serial.println("All");
265 else
266 Serial.println(*selected_dac);
267 return(0);
268 }
269
270 //! Write data to input register, but do not update DAC output
271 //! @return ACK bit (0=acknowledge, 1=no acknowledge)
272 int8_t menu_2_write_to_input_register(int16_t selected_dac)
273 {
274 int8_t ack=0;
275 uint16_t dac_code;
276
277 if (prompt_voltage_or_code() == PROMPT_VOLTAGE)
278 dac_code = get_voltage(LTC2655_lsb[selected_dac], LTC2655_offset[selected_dac]);
279 else
280 dac_code = get_code();
281
282 ack |= LTC2655_write(LTC2655_I2C_ADDRESS, LTC2655_CMD_WRITE, address_map[selected_dac], dac_code << shift_count);
283 return (ack);
284 }
285
286 //!Write data to DAC register (which updates output immediately)
287 //! @return ACK bit (0=acknowledge, 1=no acknowledge)
288 int8_t menu_3_write_and_update_dac(int16_t selected_dac)
289 {
290 int8_t ack=0;
291 uint16_t dac_code;
292
293 if (prompt_voltage_or_code() == PROMPT_VOLTAGE)
294 dac_code = get_voltage(LTC2655_lsb[selected_dac], LTC2655_offset[selected_dac]);
295 else
296 dac_code = get_code();
297
298 ack |= LTC2655_write(LTC2655_I2C_ADDRESS, LTC2655_CMD_WRITE_UPDATE, address_map[selected_dac], dac_code << shift_count);
299 return (ack);
300 }
301
302 //! Update DAC with data that is stored in input register, power up if sleeping
303 //! @return ACK bit (0=acknowledge, 1=no acknowledge)
304 int8_t menu_4_update_power_up_dac(int16_t selected_dac)
305 {
306 // Update DAC
307 int8_t ack=0;
308 ack |= LTC2655_write(LTC2655_I2C_ADDRESS, LTC2655_CMD_UPDATE, address_map[selected_dac], 0x0000);
309 return (ack);
310 }
311
312 //! Power down DAC
313 //! @return ACK bit (0=acknowledge, 1=no acknowledge)
314 int8_t menu_5_power_down_dac(int16_t selected_dac)
315 {
316 // Power down DAC
317 int8_t ack=0;
318 ack |= LTC2655_write(LTC2655_I2C_ADDRESS, LTC2655_CMD_POWER_DOWN, address_map[selected_dac], 0x0000);
319 return (ack);
320 }
321
322 //! Set reference mode and store to EEPROM
323 //! @return 0
324 int8_t menu_6_set_reference_mode(void) // int, ext, if ext, prompt for voltage
325 {
326 int16_t user_input;
327 Serial.println("Select reference mode - 0 for Internal, 1 for External");
328 user_input = read_int();
329 if (user_input == 1)
330 {
331 reference_mode = REF_EXTERNAL;
332 Serial.println("External reference mode; enter external reference voltage");
333 reference_voltage = read_float();
334 Serial.print(reference_voltage, 5);
335 Serial.println("V");
336 eeprom_write_float(EEPROM_I2C_ADDRESS, reference_voltage, EXT_REF_V_BASE);
337 }
338 else
339 {
340 reference_mode = REF_INTERNAL;
341 Serial.println("Internal reference mode selected");
342 }
343 Serial.println("Writing reference mode to EEPROM\n\n");
344 eeprom_write_byte(EEPROM_I2C_ADDRESS, reference_mode, STORED_REF_STATE_BASE);
345 return(0);
346 }
347
348 //! Calibrate all DACs by measuring two known outputs
349 //! @return 0
350 int8_t menu_7_calibrate_dacs()
351 {
352 // Calibrate the DACs using a multi-meter
353 uint8_t i;
354 for (i = 0; i < 4; i++)
355 {
356 calibrate_dac(i); // Run calibration routine
357 }
358 store_calibration();
359 return (0);
360 }
361
362 //! Enable / Disable calibration. Use with caution - behavior is undefined if you enable calibration and an actual
363 //! calibration cycle has not been performed.
364 //! @return 0
365 int8_t menu_8_enable_calibration()
366 {
367 int16_t user_input;
368 Serial.println(F("\n\nSelect option - 0: Enable Internal, 1: Disable Internal, 2: Enable External, 3: Disable External"));
369 user_input = read_int();
370 switch (user_input)
371 {
372 case 0:
373 Serial.println(F("Enabling Internal Cal Params"));
374 eeprom_write_int16(EEPROM_I2C_ADDRESS, EEPROM_CAL_KEY, INT_CAL_VALID_BASE);
375 break;
376 case 1:
377 Serial.println(F("Disabling Internal Cal Params"));
378 eeprom_write_int16(EEPROM_I2C_ADDRESS, 0x0000, INT_CAL_VALID_BASE);
379 break;
380 case 2:
381 Serial.println(F("Enabling External Cal Params"));
382 eeprom_write_int16(EEPROM_I2C_ADDRESS, EEPROM_CAL_KEY, EXT_CAL_VALID_BASE);
383 break;
384 case 3:
385 Serial.println(F("Disabling External Cal Params"));
386 eeprom_write_int16(EEPROM_I2C_ADDRESS, 0x0000, EXT_CAL_VALID_BASE);
387 break;
388 }
389 return(0);
390 }
391
392 //! Read stored calibration parameters from nonvolatile EEPROM on demo board
393 //! @return Return 1 if successful, 0 if not
394 int8_t restore_calibration()
395 // Read the DAC calibration from EEPROM
396 // Return 1 if successful, 0 if not
397 {
398 int8_t ack=0;
399 int16_t intvalid, extvalid;
400 uint8_t i, eeaddr;
401 float dac_count; // The number of codes, 4096 for 12 bits, 65536 for 16 bits
402
403 Serial.println(F("\n\nReading Calibration parameters from EEPROM..."));
404 float full_scale; // To avoid confusion - in internal ref mode, FS=Vref, in ext mode, FS=2*Vref
405 // Read the cal keys from the EEPROM.
406 eeprom_read_int16(EEPROM_I2C_ADDRESS, &intvalid, INT_CAL_VALID_BASE);
407 eeprom_read_int16(EEPROM_I2C_ADDRESS, &extvalid, EXT_CAL_VALID_BASE);
408 // Read the stored reference state
409 eeprom_read_byte(EEPROM_I2C_ADDRESS, (char *) &reference_mode, STORED_REF_STATE_BASE);
410 // Read external ref V unconditionally, overwrite with defaults if no cal found
411 eeprom_read_float(EEPROM_I2C_ADDRESS, &reference_voltage, EXT_REF_V_BASE);
412
413 if (reference_mode == REF_EXTERNAL)
414 {
415 Serial.println(F("Restored external ref. Voltage:"));
416 Serial.println(reference_voltage, 5);
417 }
418 else // EITHER reference is set to internal, OR not programmed in which case default to internal
419 {
420 reference_mode = REF_INTERNAL; // Redundant if already set
421 Serial.println("Internal reference mode set");
422 }
423
424 // Write the reference mode to the DAC right away
425 ack |= LTC2655_write(LTC2655_I2C_ADDRESS, reference_mode, 0x0F, 0x0000);
426
427 // Set up default values, shift count, DAC count
428 // Calibration parameters MAY be changed next, if match
429 // between reference mode and stored calibration
430 full_scale = reference_voltage * 2.0; // If external ref mode, this applies.
431 switch (demo_board.option)
432 {
433 case 'A':
434 // LTC2655CUF-L16, 16-bits, 2.5V full scale
435 shift_count = 0;
436 if (reference_mode == REF_INTERNAL) full_scale = 2.5;
437 dac_count = 65536;
438 break;
439 case 'B':
440 // LTC2655CUF-H16, 16-bits, 4.096V full scale
441 shift_count = 0;
442 if (reference_mode == REF_INTERNAL) full_scale = 4.096;
443 dac_count = 65536;
444 break;
445 case 'C':
446 // LTC2655CUF-L12, 12-bits, 2.5V full scale
447 shift_count = 4;
448 if (reference_mode == REF_INTERNAL) full_scale = 2.5;
449 dac_count = 4096;
450 break;
451 case 'D':
452 // LTC2655CUF-H12, 12-bits, 4.096V full scale
453 shift_count = 4;
454 if (reference_mode == REF_INTERNAL) full_scale = 4.096;
455 dac_count = 4096;
456 break;
457 }
458
459 for (i = 0; i <= 4; i++)
460 {
461 LTC2655_offset[i] = 0;
462 LTC2655_lsb[i] = full_scale / dac_count;
463 }
464
465 // Restore calibration IF reference mode matches stored calibraiton
466 eeaddr = 0; // Assume no calibration present or mismatch between cal and reference mode
467
468 if ((intvalid == EEPROM_CAL_KEY) && (reference_mode == REF_INTERNAL))
469 {
470 eeaddr = INT_CAL_PARAMS_BASE;
471 Serial.println(F("Found internal calibration, restoring...)"));
472 }
473 else if ((extvalid == EEPROM_CAL_KEY) && (reference_mode == REF_EXTERNAL))
474 {
475 eeaddr = EXT_CAL_PARAMS_BASE;
476 Serial.println(F("Found external calibration, restoring...)"));
477 }
478 else Serial.println(F("Calibration not found for this\nreference mode, using ideal calibration"));
479
480 if (eeaddr != 0) // If cal key was enabled and reference mode is correct, read offset and lsb
481 {
482 eeprom_read_int16(EEPROM_I2C_ADDRESS, &LTC2655_offset[0], eeaddr);
483 eeprom_read_int16(EEPROM_I2C_ADDRESS, &LTC2655_offset[1], eeaddr + 2);
484 eeprom_read_int16(EEPROM_I2C_ADDRESS, &LTC2655_offset[2], eeaddr + 4);
485 eeprom_read_int16(EEPROM_I2C_ADDRESS, &LTC2655_offset[3], eeaddr + 6);
486 eeprom_read_float(EEPROM_I2C_ADDRESS, &LTC2655_lsb[0], eeaddr + 8);
487 eeprom_read_float(EEPROM_I2C_ADDRESS, &LTC2655_lsb[1], eeaddr + 12);
488 eeprom_read_float(EEPROM_I2C_ADDRESS, &LTC2655_lsb[2], eeaddr + 16);
489 eeprom_read_float(EEPROM_I2C_ADDRESS, &LTC2655_lsb[3], eeaddr + 20);
490 LTC2655_offset[4] = LTC2655_offset[0]; // Copy cal value for DAC A to cal value for
491 LTC2655_lsb[4] = LTC2655_lsb[0]; // DAC ALL
492 Serial.println("Calibration Restored");
493 }
494 for (i=0; i<=4; ++i)
495 {
496 Serial.print("DAC ");
497 Serial.print((char) ('A' + i));
498 Serial.print(" offset: ");
499 Serial.print(LTC2655_offset[i]);
500 Serial.print(" , lsb: ");
501 Serial.print(LTC2655_lsb[i]*1000, 4);
502 Serial.println(" mv");
503 }
504 Serial.println("(DAC E applies to ALL DACs selections)");
505 if (eeaddr != 0) return (1);
506 return (ack);
507 }
508
509 //! Store measured calibration parameters to nonvolatile EEPROM on demo board
510 void store_calibration()
511 // Store the DAC calibration to the EEPROM
512 {
513 uint8_t eeaddr;
514 if (reference_mode == REF_INTERNAL)
515 {
516 eeprom_write_int16(EEPROM_I2C_ADDRESS, EEPROM_CAL_KEY, INT_CAL_VALID_BASE);
517 eeaddr = INT_CAL_PARAMS_BASE;
518 }
519 else
520 {
521 eeprom_write_int16(EEPROM_I2C_ADDRESS, EEPROM_CAL_KEY, EXT_CAL_VALID_BASE);
522 eeaddr = EXT_CAL_PARAMS_BASE;
523 }
524
525 eeprom_write_int16(EEPROM_I2C_ADDRESS, LTC2655_offset[0], eeaddr); // Offset
526 eeprom_write_int16(EEPROM_I2C_ADDRESS, LTC2655_offset[1], eeaddr + 2);
527 eeprom_write_int16(EEPROM_I2C_ADDRESS, LTC2655_offset[2], eeaddr + 4);
528 eeprom_write_int16(EEPROM_I2C_ADDRESS, LTC2655_offset[3], eeaddr + 6);
529 eeprom_write_float(EEPROM_I2C_ADDRESS, LTC2655_lsb[0], eeaddr + 8); // lsb
530 eeprom_write_float(EEPROM_I2C_ADDRESS, LTC2655_lsb[1], eeaddr + 12);
531 eeprom_write_float(EEPROM_I2C_ADDRESS, LTC2655_lsb[2], eeaddr + 16);
532 eeprom_write_float(EEPROM_I2C_ADDRESS, LTC2655_lsb[3], eeaddr + 20);
533 Serial.println(F("Calibration Stored to EEPROM"));
534 }
535
536 //! Prompt user to enter a voltage or digital code to send to DAC
537 //! @return prompt type
538 int16_t prompt_voltage_or_code()
539 {
540 int16_t user_input;
541 Serial.print(F("Type 1 to enter voltage, 2 to enter code:"));
542 Serial.flush();
543 user_input = read_int();
544 Serial.println(user_input);
545
546 if (user_input != 2)
547 return(PROMPT_VOLTAGE);
548 else
549 return(PROMPT_CODE);
550 }
551
552 //! Get voltage from user input, calculate DAC code based on lsb, offset
553 //! @return voltage
554 uint16_t get_voltage(float LTC2655_lsb, int16_t LTC2655_offset)
555 {
556 float dac_voltage;
557
558 Serial.print(F("Enter Desired DAC output voltage: "));
559 dac_voltage = read_float();
560 Serial.print(dac_voltage);
561 Serial.println(" V");
562 Serial.flush();
563 return(LTC2655_voltage_to_code(dac_voltage, LTC2655_lsb, LTC2655_offset));
564 }
565
566 //! Get code to send to DAC directly, in decimal, hex, or binary
567 //! @return DAC code
568 uint16_t get_code()
569 {
570 uint16_t returncode;
571 Serial.println("Enter Desired DAC Code");
572 Serial.print("(Format 32768, 0x8000, 0100000, or B1000000000000000): ");
573 returncode = (uint16_t) read_int();
574 Serial.print("0x");
575 Serial.println(returncode, HEX);
576 Serial.flush();
577 return(returncode);
578 }
579
580 //! Prints the title block when program first starts.
581 void print_title()
582 {
583 Serial.println("");
584 Serial.println(F("*****************************************************************"));
585 Serial.println(F("* DC1703 Demonstration Program *"));
586 Serial.println(F("* *"));
587 Serial.println(F("* This program demonstrates how to send data to the LTC2655 *"));
588 Serial.println(F("* quad 16/12-bit DAC found on the DC1703 demo board. *"));
589 Serial.println(F("* *"));
590 Serial.println(F("* Set the baud rate to 115200 and select the newline terminator.*"));
591 Serial.println(F("* *"));
592 Serial.println(F("*****************************************************************"));
593 }
594
595 //! Prints main menu.
596 void print_prompt(int16_t selected_dac)
597 {
598 Serial.println(F("\nCommand Summary:"));
599 Serial.println(F(" 1-Select DAC"));
600 Serial.println(F(" 2-Write to input register (no update)"));
601 Serial.println(F(" 3-Write and update DAC"));
602 Serial.println(F(" 4-Update / power up DAC"));
603 Serial.println(F(" 5-Power down DAC"));
604 Serial.println(F(" 6-Set reference mode"));
605 Serial.println(F(" 7-Calibrate DAC"));
606 Serial.println(F(" 8-Enable / Disable calibration"));
607
608 Serial.println("\nPresent Values:");
609 Serial.print(" Selected DAC: ");
610 if (selected_dac != 4)
611 Serial.println((char) (selected_dac + 0x41));
612 else
613 Serial.println("All");
614 //Serial.print(" DAC Code: 0x");
615 // Serial.println(code[selected_dac], HEX);
616 // Serial.print(" Calculated DAC Output Voltage = ");
617 // Serial.print(voltage, 4);
618 // Serial.println(" V");
619 Serial.print(" DAC Reference: ");
620 if (reference_mode == REF_INTERNAL)
621 Serial.println("Internal");
622 else
623 {
624 Serial.print(F("External "));
625 Serial.print(reference_voltage, 5);
626 Serial.println(F("V reference, please verify"));
627 Serial.print(F("Enter a command:"));
628
629 }
630 Serial.flush();
631 }
632
633 //! Calibrate the selected DAC using a voltmeter. The routine
634 //! does a linear curve fit given two data points.
635 //! @return ACK bit (0=acknowledge, 1=no acknowledge)
636 int8_t calibrate_dac(uint8_t index)
637 {
638 int8_t ack=0;
639 uint16_t code1 = 0x0200; //! Calibration code 1
640 uint16_t code2 = 0xFFFF; //! Calibration code 2
641 float voltage1; //! Calibration voltage 1
642 float voltage2; //! Calibration voltage 2
643 Serial.println("");
644 Serial.print("Calibrating DAC ");
645 Serial.println((char) (0x41 + index));
646 // Left align 12-bit code1 to 16 bits & write to DAC
647 ack |= LTC2655_write(LTC2655_I2C_ADDRESS, LTC2655_CMD_WRITE_UPDATE, index, code1 << shift_count);
648 Serial.print("DAC code set to 0x");
649 Serial.println(code1, HEX);
650 Serial.print("Enter measured DAC voltage:");
651 voltage1 = read_float();
652 Serial.print(voltage1, 6);
653 Serial.println(" V");
654 // Left align 12-bit code2 to 16 bits & write to DAC
655 ack |= LTC2655_write(LTC2655_I2C_ADDRESS, LTC2655_CMD_WRITE_UPDATE, index, code2 << shift_count);
656 Serial.print("DAC code set to 0x");
657 Serial.println(code2, HEX);
658 Serial.print("Enter measured DAC voltage:");
659 voltage2 = read_float();
660 Serial.print(voltage2, 6);
661 Serial.println(" V");
662 LTC2655_calibrate(code1, code2, voltage1, voltage2, &LTC2655_lsb[index], &LTC2655_offset[index]);
663 return(ack);
664 }
demo_board
struct demo_board_type demo_board
Instantiate demo board structure.
Definition: QuikEval_EEPROM.cpp:71
demo_board_type::option
char option
Demo Circuit option (A)
Definition: QuikEval_EEPROM.h:72
PROMPT_VOLTAGE
0
Definition: DC1703A.ino:178
LTC2655.h
LTC2655: Quad I2C 16-/12-Bit Rail-to-Rail DACs with 10ppm/C Max Reference.
LTC2655_DAC_D
#define LTC2655_DAC_D
Definition: LTC2655.h:164
menu_7_calibrate_dacs
static int8_t menu_7_calibrate_dacs()
Calibrate all DACs by measuring two known outputs.
Definition: DC1703A.ino:350
eeprom_read_int16
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.
Definition: QuikEval_EEPROM.cpp:395
user_command
unsigned char user_command
Definition: Serial_EEPROM_Test.ino:75
demo_board_connected
static uint8_t demo_board_connected
Set to 1 if the board is connected.
Definition: DC1703A.ino:160
shift_count
static uint8_t shift_count
The data align shift count.
Definition: DC1703A.ino:161
EEPROM_I2C_ADDRESS
#define EEPROM_I2C_ADDRESS
Definition: QuikEval_EEPROM.h:60
eeprom_write_byte
uint8_t eeprom_write_byte(uint8_t i2c_address, char data, uint16_t address)
Write the data byte to the EEPROM with i2c_address starting at EEPROM address.
Definition: QuikEval_EEPROM.cpp:214
LTC2655_lsb
static float LTC2655_lsb[5]
The LTC2655 lsb - index 4 for "all DACs." If part is calibrated, then index 0 is stored to "all DACs...
Definition: DC1703A.ino:167
LTC2655_calibrate
void LTC2655_calibrate(uint16_t dac_code1, uint16_t dac_code2, float voltage1, float voltage2, float *LTC2655_lsb, int16_t *LTC2655_offset)
Calculate the LTC2655 offset and LSB voltages given two measured voltages and their corresponding cod...
Definition: LTC2655.cpp:112
restore_calibration
static int8_t restore_calibration()
Read stored calibration parameters from nonvolatile EEPROM on demo board.
Definition: DC1703A.ino:394
INT_CAL_VALID_BASE
#define INT_CAL_VALID_BASE
Base address of the "internal ref calibration valid" flag.
Definition: DC1703A.ino:134
Linduino.h
Header File for Linduino Libraries and Demo Code.
menu_4_update_power_up_dac
static int8_t menu_4_update_power_up_dac(int16_t selected_dac)
Update DAC with data that is stored in input register, power up if sleeping.
Definition: DC1703A.ino:304
STORED_REF_STATE_BASE
#define STORED_REF_STATE_BASE
Base address of the stored reference state.
Definition: DC1703A.ino:133
eeprom_read_float
uint8_t eeprom_read_float(uint8_t i2c_address, float *read_data, uint16_t address)
Read the four byte float data from the EEPROM starting at address.
Definition: QuikEval_EEPROM.cpp:435
LTC2655_offset
static int16_t LTC2655_offset[5]
DAC offset - index 4 for "all DACs." If part is calibrated, then index 0 is stored to "all DACs...
Definition: DC1703A.ino:166
setup
static void setup()
Initialize Linduino.
Definition: DC1703A.ino:183
reference_voltage
static float reference_voltage
Reference voltage, either internal or external.
Definition: DC1703A.ino:165
EXT_CAL_PARAMS_BASE
#define EXT_CAL_PARAMS_BASE
Base address of the external ref calibration parameters.
Definition: DC1703A.ino:137
reference_mode
static uint8_t reference_mode
Tells whether to set internal or external reference.
Definition: DC1703A.ino:162
LTC2655_voltage_to_code
uint16_t LTC2655_voltage_to_code(float dac_voltage, float LTC2655_lsb, int16_t LTC2655_offset)
Calculate a LTC2655 DAC code given the desired output voltage.
Definition: LTC2655.cpp:91
INT_CAL_PARAMS_BASE
#define INT_CAL_PARAMS_BASE
Base address of the internal ref calibration parameters.
Definition: DC1703A.ino:135
REF_EXTERNAL
#define REF_EXTERNAL
Stored reference state is External.
Definition: DC1703A.ino:130
LTC2655_DAC_C
#define LTC2655_DAC_C
Definition: LTC2655.h:163
menu_6_set_reference_mode
static int8_t menu_6_set_reference_mode()
Set reference mode and store to EEPROM.
Definition: DC1703A.ino:324
LTC2655_DAC_B
#define LTC2655_DAC_B
Definition: LTC2655.h:162
LTC2655_CMD_POWER_DOWN
#define LTC2655_CMD_POWER_DOWN
Definition: LTC2655.h:151
eeprom_write_float
uint8_t eeprom_write_float(uint8_t i2c_address, float write_data, uint16_t address)
Write the 4 byte float data to the EEPROM starting at address.
Definition: QuikEval_EEPROM.cpp:412
menu_8_enable_calibration
static int8_t menu_8_enable_calibration()
Enable / Disable calibration.
Definition: DC1703A.ino:365
calibrate_dac
static int8_t calibrate_dac(uint8_t index)
Calibrate the selected DAC using a voltmeter.
Definition: DC1703A.ino:636
eeprom_write_int16
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.
Definition: QuikEval_EEPROM.cpp:377
print_title
static void print_title()
Prints the title block when program first starts.
Definition: DC1703A.ino:581
address_map
const uint8_t address_map[5]
Lookup table for DAC address.
Definition: DC1703A.ino:173
eeprom_read_byte
uint8_t eeprom_read_byte(uint8_t i2c_address, char *data, uint16_t address)
Read a data byte at address from the EEPROM with i2c_address.
Definition: QuikEval_EEPROM.cpp:282
get_code
static uint16_t get_code()
Get code to send to DAC directly, in decimal, hex, or binary.
Definition: DC1703A.ino:568
QuikEval_EEPROM.h
QuikEval EEPROM Library.
LTC2655_write
int8_t LTC2655_write(uint8_t i2c_address, uint8_t dac_command, uint8_t dac_address, uint16_t dac_code)
Write a 16-bit dac_code to the LTC2655.
Definition: LTC2655.cpp:82
print_prompt
static void print_prompt(int16_t selected_dac)
Prints main menu.
Definition: DC1703A.ino:596
prompt_voltage_or_code
static int16_t prompt_voltage_or_code()
Prompt user to enter a voltage or digital code to send to DAC.
Definition: DC1703A.ino:538
LTC2655_CMD_UPDATE
#define LTC2655_CMD_UPDATE
Definition: LTC2655.h:149
menu_1_select_dac
static int8_t menu_1_select_dac(int16_t *selected_dac)
Select which DAC to operate on.
Definition: DC1703A.ino:258
discover_demo_board
int8_t discover_demo_board(char *demo_name)
Read the ID string from the EEPROM and determine if the correct board is connected.
Definition: QuikEval_EEPROM.cpp:141
LTC2655_DAC_A
#define LTC2655_DAC_A
Definition: LTC2655.h:161
EXT_CAL_VALID_BASE
#define EXT_CAL_VALID_BASE
Base address of the "external ref calibration valid" flag.
Definition: DC1703A.ino:136
LTC2655_CMD_WRITE
#define LTC2655_CMD_WRITE
Definition: LTC2655.h:148
LT_SPI.h
LT_SPI: Routines to communicate with ATmega328P&#39;s hardware SPI port.
get_voltage
static uint16_t get_voltage(float LTC2655_lsb, int16_t LTC2655_offset)
Get voltage from user input, calculate DAC code based on lsb, offset.
Definition: DC1703A.ino:554
LT_I2C.h
LT_I2C: Routines to communicate with ATmega328P&#39;s hardware I2C port.
demo_name
char demo_name[]
Demo Board Name stored in QuikEval EEPROM.
Definition: DC1880A.ino:97
UserInterface.h
read_int
int32_t read_int()
Definition: UserInterface.cpp:93
index
static int index
Definition: device_logger.ino:91
read_float
float read_float()
Definition: UserInterface.cpp:78
LTC2655_CMD_WRITE_UPDATE
#define LTC2655_CMD_WRITE_UPDATE
Definition: LTC2655.h:150
store_calibration
static void store_calibration()
Store measured calibration parameters to nonvolatile EEPROM on demo board.
Definition: DC1703A.ino:510
quikeval_I2C_init
void quikeval_I2C_init(void)
Initializes Linduino I2C port.
Definition: LT_I2C.cpp:394
loop
static void loop()
Repeats Linduino loop.
Definition: DC1703A.ino:200
quikeval_I2C_connect
void quikeval_I2C_connect(void)
Switch MUX to connect I2C pins to QuikEval connector.
Definition: LT_I2C.cpp:401
i
static int i
Definition: DC2430A.ino:184
LTC2655_I2C_ADDRESS
#define LTC2655_I2C_ADDRESS
Definition: LTC2655.h:114
menu_3_write_and_update_dac
static int8_t menu_3_write_and_update_dac(int16_t selected_dac)
Write data to DAC register (which updates output immediately)
Definition: DC1703A.ino:288
REF_INTERNAL
#define REF_INTERNAL
Stored reference state is Internal.
Definition: DC1703A.ino:129
EEPROM_CAL_KEY
#define EEPROM_CAL_KEY
Definition: QuikEval_EEPROM.h:59
menu_2_write_to_input_register
static int8_t menu_2_write_to_input_register(int16_t selected_dac)
Write data to input register, but do not update DAC output.
Definition: DC1703A.ino:272
PROMPT_CODE
1
Definition: DC1703A.ino:179
EXT_REF_V_BASE
#define EXT_REF_V_BASE
Base address of the stored external reference voltage.
Definition: DC1703A.ino:138
menu_5_power_down_dac
static int8_t menu_5_power_down_dac(int16_t selected_dac)
Power down DAC.
Definition: DC1703A.ino:314
LTC2655_DAC_ALL
#define LTC2655_DAC_ALL
Definition: LTC2655.h:165