| Linduino 1.3.0 Linear Technology Arduino-Compatible Demonstration Board

DC1397A.ino
Go to the documentation of this file.
1 /*!
2 Linear Technology DC1397A Demonstration Board.
3 LTC2656: Quad SPI 16-/12-Bit Rail-to-Rail DACs with 10ppm/C Max Reference.
4
5 @verbatim
6 NOTES
7 Setup:
8 Set the terminal baud rate to 115200 and select the newline terminator.
9 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 be
16 used: DC1397A-A, DC1397A-B
17
18
19 Explanation of Commands:
20 1- Select DAC: Select one of four 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 for
53 internal and external reference modes. Ideal calibration will be used
54 if the calibration parameter valid key is not set.
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/LTC2656
66
67 http://www.linear.com/product/LTC2656#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 LTC2656
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 "LTC2656.h"
116 #include <SPI.h>
117 #include <Wire.h>
118
119 #define EEPROM_CAL_KEY_INT 0x5678 //!< Calibration associated with internal reference
120 #define EEPROM_CAL_KEY_EXT 0x9ABC //!< Calibration associated with external reference
121
122 // DAC Reference State
123 // Could have been zero or 1, this allows you to use the
124 // variable "reference_mode" as the command argument to a write
125 #define REF_INTERNAL LTC2656_CMD_INTERNAL_REFERENCE //!< Stored reference state is Internal
126 #define REF_EXTERNAL LTC2656_CMD_EXTERNAL_REFERENCE //!< Stored reference state is External
127
128 // EEPROM memory locations
129 #define STORED_REF_STATE_BASE EEPROM_CAL_STATUS_ADDRESS //!< Base address of the stored reference state
130 #define INT_CAL_VALID_BASE STORED_REF_STATE_BASE + 2 //!< Base address of the "internal ref calibration valid" flag
131 #define INT_CAL_PARAMS_BASE INT_CAL_VALID_BASE + 2 //!< Base address of the internal ref calibration parameters
132 #define EXT_CAL_VALID_BASE INT_CAL_PARAMS_BASE + 32 //!< Base address of the "external ref calibration valid" flag
133 #define EXT_CAL_PARAMS_BASE EXT_CAL_VALID_BASE + 2 //!< Base address of the external ref calibration parameters
134 #define EXT_REF_V_BASE EXT_CAL_PARAMS_BASE + 32 //!< Base address of the stored external reference voltage
135
136 // Function Declaration
137 int8_t restore_calibration(); // Read the DAC calibration from EEPROM, Return 1 if successful, 0 if not
138 void store_calibration(); // Store the DAC calibration to the EEPROM
139 void print_title(); // Print the title block
140 void print_prompt(int16_t selected_dac); // Prompt the user for an input command
141 int16_t prompt_voltage_or_code();
142 uint16_t get_voltage(float LTC2656_lsb, int16_t LTC2656_offset);
143 uint16_t get_code();
144 void calibrate_dac(uint8_t index); // Calibrate the selected DAC using a voltmeter. The routine does a linear curve fit given two data points.
145
146 void menu_1_select_dac(int16_t *selected_dac);
147 void menu_2_write_to_input_register(int16_t selected_dac);
148 void menu_3_write_and_update_dac(int16_t selected_dac);
149 void menu_4_update_power_up_dac(int16_t selected_dac);
150 void menu_5_power_down_dac(int16_t selected_dac);
151 void menu_6_set_reference_mode(); // int, ext, if ext, prompt for voltage
152 void menu_7_calibrate_dacs();
153 void menu_8_enable_calibration();
154
155 // Global variables
156 static uint8_t demo_board_connected; //!< Set to 1 if the board is connected
157 static uint8_t shift_count = 0; //!< The data align shift count. For 16-bit=0, for 12-bits=4
158 static uint8_t reference_mode; //!< Tells whether to set internal or external reference
159
160 // Global calibration variables
161 static float reference_voltage; //!< Reference voltage, either internal or external
162 static int16_t LTC2656_offset[9]; //!< DAC offset - index 8 for "all DACs"
163 static float LTC2656_lsb[9]; //!< The LTC2656 lsb - index 8 for "all DACs"
164
165 // Constants
166
167 //! Lookup table for DAC address. Allows the "All DACs" address to be indexed right after DAC D in loops.
168 //! This technique is very useful for devices with non-monotonic channel addresses.
169 const uint8_t address_map[9] = {LTC2656_DAC_A, LTC2656_DAC_B, LTC2656_DAC_C, LTC2656_DAC_D, LTC2656_DAC_E,
170 LTC2656_DAC_F, LTC2656_DAC_G, LTC2656_DAC_H,LTC2656_DAC_ALL
171 }; //<! Map entered option 0..2 to DAC address
172
173 //! Used to choose between voltage and code
174 enum
175 {
176 PROMPT_VOLTAGE = 0, /**< 0 */
177 PROMPT_CODE = 1 /**< 1 */
178 };
179
180 //! Initialize Linduino
181 void setup()
182 // Setup the program
183 {
184 char demo_name[] = "DC1397"; // Demo Board Name stored in QuikEval EEPROM
185 quikeval_SPI_init(); // Configure the spi port for 4MHz SCK
186 quikeval_SPI_connect(); // Connect SPI to main data port
187 quikeval_I2C_init(); // Configure the EEPROM I2C port for 100kHz
188 Serial.begin(115200); // Initialize the serial port to the PC
189 print_title();
190 demo_board_connected = discover_demo_board(demo_name);
191 if (demo_board_connected)
192 {
193 restore_calibration();
194 print_prompt(0);
195 }
196 }
197
198 //! Repeats Linduino loop
199 void loop()
200 {
201 int16_t user_command;
202 static int16_t selected_dac = 0; // The selected DAC to be updated (0=A, 1=B ... 5=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 switch (user_command)
212 {
213 case 1:
214 menu_1_select_dac(&selected_dac);
215 break;
216 case 2:
217 menu_2_write_to_input_register(selected_dac);
218 break;
219 case 3:
220 menu_3_write_and_update_dac(selected_dac);
221 break;
222 case 4:
223 menu_4_update_power_up_dac(selected_dac);
224 break;
225 case 5:
226 menu_5_power_down_dac(selected_dac);
227 break;
228 case 6:
229 menu_6_set_reference_mode(); // int, ext, if ext, prompt for voltage
230 restore_calibration();
231 break;
232 case 7:
233 menu_7_calibrate_dacs();
234 restore_calibration();
235 break;
236 case 8:
237 menu_8_enable_calibration();
238 restore_calibration();
239 break;
240 default:
241 Serial.println("Incorrect Option");
242 break;
243 }
244 Serial.println("\n*****************************************************************");
245 print_prompt(selected_dac);
246 }
247 }
248 }
249
250 // Function Definitions
251
252 //! Select which DAC to operate on
253 void menu_1_select_dac(int16_t *selected_dac)
254 {
255 // Select a DAC to operate on
256 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)");
257 *selected_dac = read_int();
258 if (*selected_dac == 8)
259 Serial.println("All");
260 else
261 Serial.println(*selected_dac);
262 }
263
264 //! Write data to input register, but do not update DAC output
265 void menu_2_write_to_input_register(int16_t selected_dac)
266 {
267 uint16_t dac_code;
268
269 if (prompt_voltage_or_code() == PROMPT_VOLTAGE)
270 dac_code = get_voltage(LTC2656_lsb[selected_dac], LTC2656_offset[selected_dac]);
271 else
272 dac_code = get_code();
273
274 LTC2656_write(LTC2656_CS, LTC2656_CMD_WRITE, address_map[selected_dac], dac_code << shift_count);
275 }
276
277 //!Write data to DAC register (which updates output immediately)
278 void menu_3_write_and_update_dac(int16_t selected_dac)
279 {
280 uint16_t dac_code;
281
282 if (prompt_voltage_or_code() == PROMPT_VOLTAGE)
283 dac_code = get_voltage(LTC2656_lsb[selected_dac], LTC2656_offset[selected_dac]);
284 else
285 dac_code = get_code();
286
287 LTC2656_write(LTC2656_CS, LTC2656_CMD_WRITE_UPDATE, address_map[selected_dac], dac_code << shift_count);
288 }
289
290 //! Update DAC with data that is stored in input register, power up if sleeping
291 void menu_4_update_power_up_dac(int16_t selected_dac)
292 {
293 // Update DAC
294 LTC2656_write(LTC2656_CS, LTC2656_CMD_UPDATE, address_map[selected_dac], 0x0000);
295 }
296
297 //! Power down DAC
298 void menu_5_power_down_dac(int16_t selected_dac)
299 {
300 // Power down DAC
301 LTC2656_write(LTC2656_CS, LTC2656_CMD_POWER_DOWN, address_map[selected_dac], 0x0000);
302 }
303
304 //! Set reference mode and store to EEPROM
305 void menu_6_set_reference_mode(void) // int, ext, if ext, prompt for voltage
306 {
307 int16_t user_input;
308 Serial.println("Select reference mode - 0 for Internal, 1 for External");
309 user_input = read_int();
310 if (user_input == 1)
311 {
312 reference_mode = REF_EXTERNAL;
313 Serial.println("External reference mode; enter external reference voltage");
314 reference_voltage = read_float();
315 Serial.print(reference_voltage, 5);
316 Serial.println("V");
317 eeprom_write_float(EEPROM_I2C_ADDRESS, reference_voltage, EXT_REF_V_BASE);
318 }
319 else
320 {
321 reference_mode = REF_INTERNAL;
322 Serial.println("Internal reference mode selected");
323 }
324 Serial.println("Writing reference mode to EEPROM\n\n");
325 eeprom_write_byte(EEPROM_I2C_ADDRESS, reference_mode, STORED_REF_STATE_BASE);
326 }
327
328 //! Calibrate all DACs by measuring two known outputs
329 void menu_7_calibrate_dacs()
330 {
331 // Calibrate the DACs using a multimeter
332 uint8_t i;
333 for (i = 0; i < 8; i++)
334 {
335 calibrate_dac(i); // Run calibration routine
336 }
337 store_calibration();
338 }
339
340 //! Enable / Disable calibration. Use with caution - behavior is undefined if you enable calibration and an actual
341 //! calibration cycle has not been performed.
342 void menu_8_enable_calibration()
343 {
344 int16_t user_input;
345 Serial.println(F("\n\nSelect option - 0: Enable Internal, 1: Disable Internal, 2: Enable External, 3: Disable External"));
346 user_input = read_int();
347 switch (user_input)
348 {
349 case 0:
350 Serial.println(F("Enabling Internal Cal Params"));
351 eeprom_write_int16(EEPROM_I2C_ADDRESS, EEPROM_CAL_KEY, INT_CAL_VALID_BASE);
352 break;
353 case 1:
354 Serial.println(F("Disabling Internal Cal Params"));
355 eeprom_write_int16(EEPROM_I2C_ADDRESS, 0x0000, INT_CAL_VALID_BASE);
356 break;
357 case 2:
358 Serial.println(F("Enabling External Cal Params"));
359 eeprom_write_int16(EEPROM_I2C_ADDRESS, EEPROM_CAL_KEY, EXT_CAL_VALID_BASE);
360 break;
361 case 3:
362 Serial.println(F("Disabling External Cal Params"));
363 eeprom_write_int16(EEPROM_I2C_ADDRESS, 0x0000, EXT_CAL_VALID_BASE);
364 break;
365 }
366 }
367
368 //! Read stored calibration parameters from nonvolatile EEPROM on demo board
369 //! @return Return 1 if successful, 0 if not
370 int8_t restore_calibration()
371 // Read the DAC calibration from EEPROM
372 // Return 1 if successful, 0 if not
373 {
374 int16_t intvalid, extvalid;
375 uint8_t i, eeaddr;
376 float dac_count; // The number of codes, 4096 for 12 bits, 65536 for 16 bits
377
378 Serial.println(F("\n\nReading Calibration parameters from EEPROM..."));
379 float full_scale; // To avoid confusion - in internal ref mode, FS=Vref, in ext mode, FS=2*Vref
380 // Read the cal keys from the EEPROM.
381 eeprom_read_int16(EEPROM_I2C_ADDRESS, &intvalid, INT_CAL_VALID_BASE);
382 eeprom_read_int16(EEPROM_I2C_ADDRESS, &extvalid, EXT_CAL_VALID_BASE);
383 // Read the stored reference state
384 eeprom_read_byte(EEPROM_I2C_ADDRESS, (char *) &reference_mode, STORED_REF_STATE_BASE);
385 // Read external ref V unconditionally, overwrite with defaults if no cal found
386 eeprom_read_float(EEPROM_I2C_ADDRESS, &reference_voltage, EXT_REF_V_BASE);
387
388 if (reference_mode == REF_EXTERNAL)
389 {
390 Serial.println(F("Restored external ref. Voltage:"));
391 Serial.println(reference_voltage, 5);
392 }
393 else // EITHER reference is set to internal, OR not programmed in which case default to internal
394 {
395 reference_mode = REF_INTERNAL; // Redundant if already set
396 Serial.println("Internal reference mode set");
397 }
398
399 // Write the reference mode to the DAC right away
400 LTC2656_write(LTC2656_CS, reference_mode, 0x0F, 0x0000);
401
402 // Set up default values, shift count, DAC count
403 // Calibration parameters MAY be changed next, if match
404 // between reference mode and stored calibration
405 full_scale = reference_voltage * 2.0; // If external ref mode, this applies.
406
407 // The following two IF statements are used to allow the program to run with
408 // a QuikEval string that does not contain the demo board option.
409 // If the demo board option is found then these values are overwritten.
410 if (strcmp(demo_board.product_name, "LTC2656-L16") == 0)
411 {
412 // LTC2657CUF-L16, 16-bits, 2.5V full scale
413 shift_count = 0;
414 if (reference_mode == REF_INTERNAL) full_scale = 2.5;
415 dac_count = 65536;
416 }
417 if (strcmp(demo_board.product_name, "LTC2656-H16") == 0)
418 {
419 // LTC2657CUF-H16, 16-bits, 4.096V full scale
420 shift_count = 0;
421 if (reference_mode == REF_INTERNAL) full_scale = 4.096;
422 dac_count = 65536;
423 }
424
425 switch (demo_board.option)
426 {
427 case 'A':
428 // LTC2656CUF-L16, 16-bits, 2.5V full scale
429 shift_count = 0;
430 if (reference_mode == REF_INTERNAL) full_scale = 2.5;
431 dac_count = 65536;
432 break;
433 case 'B':
434 // LTC2656CUF-H16, 16-bits, 4.096V full scale
435 shift_count = 0;
436 if (reference_mode == REF_INTERNAL) full_scale = 4.096;
437 dac_count = 65536;
438 break;
439 case 'C':
440 // LTC2656CUF-L12, 12-bits, 2.5V full scale
441 shift_count = 4;
442 if (reference_mode == REF_INTERNAL) full_scale = 2.5;
443 dac_count = 4096;
444 break;
445 case 'D':
446 // LTC2656CUF-H12, 12-bits, 4.096V full scale
447 shift_count = 4;
448 if (reference_mode == REF_INTERNAL) full_scale = 4.096;
449 dac_count = 4096;
450 break;
451 }
452
453 for (i = 0; i <= 8; i++)
454 {
455 LTC2656_offset[i] = 0;
456 LTC2656_lsb[i] = full_scale / dac_count;
457 }
458
459 // Restore calibration IF reference mode matches stored calibration
460 eeaddr = 0; // Assume no calibration present or mismatch between cal and reference mode
461
462 if ((intvalid == EEPROM_CAL_KEY) && (reference_mode == REF_INTERNAL))
463 {
464 eeaddr = INT_CAL_PARAMS_BASE;
465 Serial.println(F("Found internal calibration, restoring...)"));
466 }
467 else if ((extvalid == EEPROM_CAL_KEY) && (reference_mode == REF_EXTERNAL))
468 {
469 eeaddr = EXT_CAL_PARAMS_BASE;
470 Serial.println(F("Found external calibration, restoring...)"));
471 }
472 else Serial.println(F("Calibration not found for this\nreference mode, using ideal calibration"));
473
474 if (eeaddr != 0) // If cal key was enabled and reference mode is correct, read offset and lsb
475 {
476 eeprom_read_int16(EEPROM_I2C_ADDRESS, &LTC2656_offset[0], eeaddr);
477 eeprom_read_int16(EEPROM_I2C_ADDRESS, &LTC2656_offset[1], eeaddr + 2);
478 eeprom_read_int16(EEPROM_I2C_ADDRESS, &LTC2656_offset[2], eeaddr + 4);
479 eeprom_read_int16(EEPROM_I2C_ADDRESS, &LTC2656_offset[3], eeaddr + 6);
480 eeprom_read_int16(EEPROM_I2C_ADDRESS, &LTC2656_offset[4], eeaddr + 8);
481 eeprom_read_int16(EEPROM_I2C_ADDRESS, &LTC2656_offset[5], eeaddr + 10);
482 eeprom_read_int16(EEPROM_I2C_ADDRESS, &LTC2656_offset[6], eeaddr + 12);
483 eeprom_read_int16(EEPROM_I2C_ADDRESS, &LTC2656_offset[7], eeaddr + 14);
484 eeprom_read_float(EEPROM_I2C_ADDRESS, &LTC2656_lsb[0], eeaddr + 16);
485 eeprom_read_float(EEPROM_I2C_ADDRESS, &LTC2656_lsb[1], eeaddr + 20);
486 eeprom_read_float(EEPROM_I2C_ADDRESS, &LTC2656_lsb[2], eeaddr + 24);
487 eeprom_read_float(EEPROM_I2C_ADDRESS, &LTC2656_lsb[3], eeaddr + 28);
488 eeprom_read_float(EEPROM_I2C_ADDRESS, &LTC2656_lsb[4], eeaddr + 32);
489 eeprom_read_float(EEPROM_I2C_ADDRESS, &LTC2656_lsb[5], eeaddr + 36);
490 eeprom_read_float(EEPROM_I2C_ADDRESS, &LTC2656_lsb[6], eeaddr + 40);
491 eeprom_read_float(EEPROM_I2C_ADDRESS, &LTC2656_lsb[7], eeaddr + 44);
492 LTC2656_offset[8] = LTC2656_offset[0]; // Copy cal value for DAC A to cal value for
493 LTC2656_lsb[8] = LTC2656_lsb[0]; // DAC ALL
494 Serial.println("Calibration Restored");
495 }
496 for (i=0; i<=8; ++i)
497 {
498 Serial.print("DAC ");
499 Serial.print((char) ('A' + i));
500 Serial.print(" offset: ");
501 Serial.print(LTC2656_offset[i]);
502 Serial.print(" , lsb: ");
503 Serial.print(LTC2656_lsb[i]*1000, 4);
504 Serial.println(" mV");
505 }
506 Serial.println("(DAC I applies to ALL DACs selections)");
507 if (eeaddr != 0) return (1);
508 return (0);
509 }
510
511 //! Store measured calibration parameters to nonvolatile EEPROM on demo board
512 void store_calibration()
513 // Store the DAC calibration to the EEPROM
514 {
515 uint8_t eeaddr;
516 if (reference_mode == REF_INTERNAL)
517 {
518 eeprom_write_int16(EEPROM_I2C_ADDRESS, EEPROM_CAL_KEY, INT_CAL_VALID_BASE);
519 eeaddr = INT_CAL_PARAMS_BASE;
520 }
521 else
522 {
523 eeprom_write_int16(EEPROM_I2C_ADDRESS, EEPROM_CAL_KEY, EXT_CAL_VALID_BASE);
524 eeaddr = EXT_CAL_PARAMS_BASE;
525 }
526
527 eeprom_write_int16(EEPROM_I2C_ADDRESS, LTC2656_offset[0], eeaddr); // Offset
528 eeprom_write_int16(EEPROM_I2C_ADDRESS, LTC2656_offset[1], eeaddr + 2);
529 eeprom_write_int16(EEPROM_I2C_ADDRESS, LTC2656_offset[2], eeaddr + 4);
530 eeprom_write_int16(EEPROM_I2C_ADDRESS, LTC2656_offset[3], eeaddr + 6);
531 eeprom_write_int16(EEPROM_I2C_ADDRESS, LTC2656_offset[4], eeaddr + 8);
532 eeprom_write_int16(EEPROM_I2C_ADDRESS, LTC2656_offset[5], eeaddr + 10);
533 eeprom_write_int16(EEPROM_I2C_ADDRESS, LTC2656_offset[6], eeaddr + 12);
534 eeprom_write_int16(EEPROM_I2C_ADDRESS, LTC2656_offset[7], eeaddr + 14);
535 eeprom_write_float(EEPROM_I2C_ADDRESS, LTC2656_lsb[0], eeaddr + 16); // lsb
536 eeprom_write_float(EEPROM_I2C_ADDRESS, LTC2656_lsb[1], eeaddr + 20);
537 eeprom_write_float(EEPROM_I2C_ADDRESS, LTC2656_lsb[2], eeaddr + 24);
538 eeprom_write_float(EEPROM_I2C_ADDRESS, LTC2656_lsb[3], eeaddr + 28);
539 eeprom_write_float(EEPROM_I2C_ADDRESS, LTC2656_lsb[4], eeaddr + 32); // lsb
540 eeprom_write_float(EEPROM_I2C_ADDRESS, LTC2656_lsb[5], eeaddr + 36);
541 eeprom_write_float(EEPROM_I2C_ADDRESS, LTC2656_lsb[6], eeaddr + 40);
542 eeprom_write_float(EEPROM_I2C_ADDRESS, LTC2656_lsb[7], eeaddr + 44);
543 Serial.println(F("Calibration Stored to EEPROM"));
544 }
545
546 //! Prompt user to enter a voltage or digital code to send to DAC
547 int16_t prompt_voltage_or_code()
548 {
549 int16_t user_input;
550 Serial.print(F("Type 1 to enter voltage, 2 to enter code:"));
551 Serial.flush();
552 user_input = read_int();
553 Serial.println(user_input);
554
555 if (user_input != 2)
556 return(PROMPT_VOLTAGE);
557 else
558 return(PROMPT_CODE);
559 }
560
561 //! Get voltage from user input, calculate DAC code based on lsb, offset
562 uint16_t get_voltage(float LTC2656_lsb, int16_t LTC2656_offset)
563 {
564 float dac_voltage;
565
566 Serial.print(F("Enter Desired DAC output voltage: "));
567 dac_voltage = read_float();
568 Serial.print(dac_voltage);
569 Serial.println(" V");
570 Serial.flush();
571 return(LTC2656_voltage_to_code(dac_voltage, LTC2656_lsb, LTC2656_offset));
572 }
573
574 //! Get code to send to DAC directly, in decimal, hex, or binary
575 uint16_t get_code()
576 {
577 uint16_t returncode;
578 Serial.println("Enter Desired DAC Code");
579 Serial.print("(Format 32768, 0x8000, 0100000, or B1000000000000000): ");
580 returncode = (uint16_t) read_int();
581 Serial.print("0x");
582 Serial.println(returncode, HEX);
583 Serial.flush();
584 return(returncode);
585 }
586
587 //! Prints the title block when program first starts.
588 void print_title()
589 {
590 Serial.println("");
591 Serial.println(F("*****************************************************************"));
592 Serial.println(F("* DC1397 Demonstration Program *"));
593 Serial.println(F("* *"));
594 Serial.println(F("* This program demonstrates how to send data to the LTC2656 *"));
595 Serial.println(F("* quad 16/12-bit DAC found on the DC1397 demo board. *"));
596 Serial.println(F("* *"));
597 Serial.println(F("* Set the baud rate to 115200 and select the newline terminator.*"));
598 Serial.println(F("* *"));
599 Serial.println(F("*****************************************************************"));
600 }
601
602 //! Prints main menu.
603 void print_prompt(int16_t selected_dac)
604 {
605 Serial.println(F("\nCommand Summary:"));
606 Serial.println(F(" 1-Select DAC"));
607 Serial.println(F(" 2-Write to input register (no update)"));
608 Serial.println(F(" 3-Write and update DAC"));
609 Serial.println(F(" 4-Update / power up DAC"));
610 Serial.println(F(" 5-Power down DAC"));
611 Serial.println(F(" 6-Set reference mode"));
612 Serial.println(F(" 7-Calibrate DAC"));
613 Serial.println(F(" 8-Enable / Disable calibration"));
614
615 Serial.println("\nPresent Values:");
616 Serial.print(" Selected DAC: ");
617 if (selected_dac != 8)
618 Serial.println((char) (selected_dac + 0x41));
619 else
620 Serial.println("All");
621
622 Serial.print(" DAC Reference: ");
623 if (reference_mode == REF_INTERNAL)
624 Serial.println("Internal");
625 else
626 {
627 Serial.print(F("External "));
628 Serial.print(reference_voltage, 5);
629 Serial.println(F("V reference, please verify"));
630 }
631 Serial.print(F("Enter a command:"));
632 Serial.flush();
633 }
634
635 //! Calibrate the selected DAC using a voltmeter. The routine
636 //! does a linear curve fit given two data points.
637 void calibrate_dac(uint8_t index)
638 {
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 LTC2656_write(LTC2656_CS, LTC2656_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 LTC2656_write(LTC2656_CS, LTC2656_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 LTC2656_calibrate(code1, code2, voltage1, voltage2, &LTC2656_lsb[index], &LTC2656_offset[index]);
663 }
demo_board
struct demo_board_type demo_board
Instantiate demo board structure.
Definition: QuikEval_EEPROM.cpp:71
EXT_CAL_VALID_BASE
#define EXT_CAL_VALID_BASE
Base address of the "external ref calibration valid" flag.
Definition: DC1397A.ino:132
demo_board_type::option
char option
Demo Circuit option (A)
Definition: QuikEval_EEPROM.h:72
LTC2656_lsb
static float LTC2656_lsb[9]
The LTC2656 lsb - index 8 for "all DACs".
Definition: DC1397A.ino:163
LTC2656_CMD_POWER_DOWN
#define LTC2656_CMD_POWER_DOWN
Power down n.
Definition: LTC2656.h:116
calibrate_dac
static void calibrate_dac(uint8_t index)
Calibrate the selected DAC using a voltmeter.
Definition: DC1397A.ino:637
INT_CAL_PARAMS_BASE
#define INT_CAL_PARAMS_BASE
Base address of the internal ref calibration parameters.
Definition: DC1397A.ino:131
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
print_title
static void print_title()
Prints the title block when program first starts.
Definition: DC1397A.ino:588
LTC2656_DAC_F
#define LTC2656_DAC_F
Definition: LTC2656.h:131
user_command
unsigned char user_command
Definition: Serial_EEPROM_Test.ino:75
menu_3_write_and_update_dac
static void menu_3_write_and_update_dac(int16_t selected_dac)
Write data to DAC register (which updates output immediately)
Definition: DC1397A.ino:278
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
menu_2_write_to_input_register
static void menu_2_write_to_input_register(int16_t selected_dac)
Write data to input register, but do not update DAC output.
Definition: DC1397A.ino:265
EXT_CAL_PARAMS_BASE
#define EXT_CAL_PARAMS_BASE
Base address of the external ref calibration parameters.
Definition: DC1397A.ino:133
LTC2656_DAC_E
#define LTC2656_DAC_E
Definition: LTC2656.h:130
menu_4_update_power_up_dac
static void 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: DC1397A.ino:291
menu_7_calibrate_dacs
static void menu_7_calibrate_dacs()
Calibrate all DACs by measuring two known outputs.
Definition: DC1397A.ino:329
LTC2656_DAC_A
#define LTC2656_DAC_A
Definition: LTC2656.h:126
Linduino.h
Header File for Linduino Libraries and Demo Code.
menu_5_power_down_dac
static void menu_5_power_down_dac(int16_t selected_dac)
Power down DAC.
Definition: DC1397A.ino:298
shift_count
static uint8_t shift_count
The data align shift count.
Definition: DC1397A.ino:157
REF_EXTERNAL
#define REF_EXTERNAL
Stored reference state is External.
Definition: DC1397A.ino:126
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
setup
static void setup()
Initialize Linduino.
Definition: DC1397A.ino:181
INT_CAL_VALID_BASE
#define INT_CAL_VALID_BASE
Base address of the "internal ref calibration valid" flag.
Definition: DC1397A.ino:130
address_map
const uint8_t address_map[9]
Lookup table for DAC address.
Definition: DC1397A.ino:169
LTC2656_CMD_WRITE
#define LTC2656_CMD_WRITE
Write to input register n.
Definition: LTC2656.h:112
LTC2656_DAC_B
#define LTC2656_DAC_B
Definition: LTC2656.h:127
STORED_REF_STATE_BASE
#define STORED_REF_STATE_BASE
Base address of the stored reference state.
Definition: DC1397A.ino:129
LTC2656_calibrate
void LTC2656_calibrate(uint16_t dac_code1, uint16_t dac_code2, float voltage1, float voltage2, float *LTC2656_lsb, int16_t *LTC2656_offset)
Calculate the LTC2656 offset and LSB voltage given two measured voltages and their corresponding code...
Definition: LTC2656.cpp:115
reference_mode
static uint8_t reference_mode
Tells whether to set internal or external reference.
Definition: DC1397A.ino:158
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: DC1397A.ino:547
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 void menu_8_enable_calibration()
Enable / Disable calibration.
Definition: DC1397A.ino:342
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
LTC2656_write
void LTC2656_write(uint8_t cs, uint8_t dac_command, uint8_t dac_address, uint16_t dac_code)
Write the 16-bit dac_code to the LTC2656.
Definition: LTC2656.cpp:79
LTC2656_offset
static int16_t LTC2656_offset[9]
DAC offset - index 8 for "all DACs".
Definition: DC1397A.ino:162
demo_board_connected
static uint8_t demo_board_connected
Set to 1 if the board is connected.
Definition: DC1397A.ino:156
REF_INTERNAL
#define REF_INTERNAL
Stored reference state is Internal.
Definition: DC1397A.ino:125
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
QuikEval_EEPROM.h
QuikEval EEPROM Library.
reference_voltage
static float reference_voltage
Reference voltage, either internal or external.
Definition: DC1397A.ino:161
LTC2656_DAC_D
#define LTC2656_DAC_D
Definition: LTC2656.h:129
store_calibration
static void store_calibration()
Store measured calibration parameters to nonvolatile EEPROM on demo board.
Definition: DC1397A.ino:512
menu_6_set_reference_mode
static void menu_6_set_reference_mode()
Set reference mode and store to EEPROM.
Definition: DC1397A.ino:305
menu_1_select_dac
static void menu_1_select_dac(int16_t *selected_dac)
Select which DAC to operate on.
Definition: DC1397A.ino:253
quikeval_SPI_init
void quikeval_SPI_init(void)
Configure the SPI port for 4Mhz SCK.
Definition: LT_SPI.cpp:151
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
LT_SPI.h
LT_SPI: Routines to communicate with ATmega328P&#39;s hardware SPI port.
loop
static void loop()
Repeats Linduino loop.
Definition: DC1397A.ino:199
LT_I2C.h
LT_I2C: Routines to communicate with ATmega328P&#39;s hardware I2C port.
EXT_REF_V_BASE
#define EXT_REF_V_BASE
Base address of the stored external reference voltage.
Definition: DC1397A.ino:134
demo_name
char demo_name[]
Demo Board Name stored in QuikEval EEPROM.
Definition: DC1880A.ino:97
quikeval_SPI_connect
void quikeval_SPI_connect()
Connect SPI pins to QuikEval connector through the Linduino MUX. This will disconnect I2C...
Definition: LT_SPI.cpp:138
UserInterface.h
read_int
int32_t read_int()
Definition: UserInterface.cpp:93
index
static int index
Definition: device_logger.ino:91
LTC2656_DAC_G
#define LTC2656_DAC_G
Definition: LTC2656.h:132
read_float
float read_float()
Definition: UserInterface.cpp:78
LTC2656_DAC_C
#define LTC2656_DAC_C
Definition: LTC2656.h:128
demo_board_type::product_name
char product_name[15]
LTC Product (LTC2654-L16)
Definition: QuikEval_EEPROM.h:70
quikeval_I2C_init
void quikeval_I2C_init(void)
Initializes Linduino I2C port.
Definition: LT_I2C.cpp:394
PROMPT_CODE
1
Definition: DC1397A.ino:177
get_code
static uint16_t get_code()
Get code to send to DAC directly, in decimal, hex, or binary.
Definition: DC1397A.ino:575
i
static int i
Definition: DC2430A.ino:184
LTC2656_CMD_WRITE_UPDATE
#define LTC2656_CMD_WRITE_UPDATE
Write to input register n, update (power up) all.
Definition: LTC2656.h:115
restore_calibration
static int8_t restore_calibration()
Read stored calibration parameters from nonvolatile EEPROM on demo board.
Definition: DC1397A.ino:370
LTC2656_voltage_to_code
uint16_t LTC2656_voltage_to_code(float dac_voltage, float LTC2656_lsb, int16_t LTC2656_offset)
Calculate a LTC2656 DAC code given the desired output voltage and DAC address (0-7) ...
Definition: LTC2656.cpp:94
LTC2656.h
LTC2656: Octal SPI 16-/12-Bit Rail-to-Rail DACs with 10ppm/C Max Reference.
LTC2656_CMD_UPDATE
#define LTC2656_CMD_UPDATE
Update (power up) DAC register n.
Definition: LTC2656.h:113
LTC2656_DAC_H
#define LTC2656_DAC_H
Definition: LTC2656.h:133
EEPROM_CAL_KEY
#define EEPROM_CAL_KEY
Definition: QuikEval_EEPROM.h:59
get_voltage
static uint16_t get_voltage(float LTC2656_lsb, int16_t LTC2656_offset)
Get voltage from user input, calculate DAC code based on lsb, offset.
Definition: DC1397A.ino:562
LTC2656_DAC_ALL
#define LTC2656_DAC_ALL
Definition: LTC2656.h:134
print_prompt
static void print_prompt(int16_t selected_dac)
Prints main menu.
Definition: DC1397A.ino:603
PROMPT_VOLTAGE
0
Definition: DC1397A.ino:176
LTC2656_CS
#define LTC2656_CS
Define the SPI CS pin.
Definition: LTC2656.h:106