| Linduino 1.3.0 Linear Technology Arduino-Compatible Demonstration Board

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