| Linduino 1.3.0 Linear Technology Arduino-Compatible Demonstration Board

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