| Linduino 1.3.0 Linear Technology Arduino-Compatible Demonstration Board

DC2197.ino
Go to the documentation of this file.
1 /*!
2 Linear Technology DC2197 Demonstration Board.
3 LTC2645 Quad 12-/10-/8-Bit PWM to VOUT DACs with 10ppm/C Reference
4
5 @verbatim
6
7 NOTES
8 Setup:
9 Set the terminal baud rate to 115200 and select the newline terminator.
10 Equipment required is a precision voltage source (null box) and a precision voltmeter (to monitor voltage source).
11 No external power supply is required.
12 Ensure JP1 is installed in the default position from the factory.
13
14 USER INPUT DATA FORMAT:
15 decimal : 1024
16 hex : 0x400
17 octal : 02000 (leading 0 "zero")
18 binary : B10000000000
19 float : 1024.0
20
21 @endverbatim
22
23 http://www.linear.com/product/LTC2645
24
25 http://www.linear.com/product/LTC2645
26
27
28 Copyright 2018(c) Analog Devices, Inc.
29
30 All rights reserved.
31
32 Redistribution and use in source and binary forms, with or without
33 modification, are permitted provided that the following conditions are met:
34 - Redistributions of source code must retain the above copyright
35 notice, this list of conditions and the following disclaimer.
36 - Redistributions in binary form must reproduce the above copyright
37 notice, this list of conditions and the following disclaimer in
38 the documentation and/or other materials provided with the
39 distribution.
40 - Neither the name of Analog Devices, Inc. nor the names of its
41 contributors may be used to endorse or promote products derived
42 from this software without specific prior written permission.
43 - The use of this software may or may not infringe the patent rights
44 of one or more patent holders. This license does not release you
45 from the requirement that you obtain separate licenses from these
46 patent holders to use this software.
47 - Use of the software either in source or binary form, must be run
48 on or directly connected to an Analog Devices Inc. component.
49
50 THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
51 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
52 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
53 IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
54 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
55 LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
56 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
57 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
58 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
59 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
60 */
61
62 /*! @file
63 @ingroup LTC2645
64 */
65
66 #include <Arduino.h>
67 #include <stdint.h>
68 #include "Linduino.h"
69 #include "UserInterface.h"
70 #include "math.h"
71
72 // Pin Map
73 const uint8_t DAC_A = 9; // 16-bit PWM Pin
74 const uint8_t DAC_B = 10; // 16-bit PWM Pin
75 const uint8_t DAC_C = 5; // 8-bit PWM Pin
76 const uint8_t DAC_D = 6; // 8-bit PWM Pin
77
78
79 // Function Decoration
80 void print_title(); // Print the title block
81 void print_prompt(); // Prompt the user for an input command
82 void init_16_bit_PWM(); // Initializes Pin 9 and 10 for 16-bit PWM
83 void pwm_16_bit(uint8_t pin, uint16_t duty); // Sets the 16-bit PWM
84 void menu_1_select_dac(int16_t *selected_dac); // Selects DAC
85 void menu_2_set_duty(int8_t selected_dac); // Sets the Duty Cycle
86 uint16_t LTC2645_voltage_to_pwm_code(float dac_voltage, float fullScaleVoltage, int8_t pwmBitResolution); // Converts voltage to PWM code(DAC Code)
87 void python_program(); // Used for the corresponding Python program
88 int16_t prompt_voltage_or_code(); // Prompts for voltage or code
89 uint16_t get_voltage(float fullScaleVoltage, int8_t pwmBitResolution); // Obtains voltage from user
90 uint16_t get_code(); // Obtains code from user
91 void test();
92
93 // Global Variable
94 float fullScale = 2.5; //! Full Scale Voltage
95 float percentDutyCycle[4] = {0.0,0.0,0.0,0.0};
96
97 //! Used to keep track to print voltage or print code
98 enum
99 {
100 PROMPT_VOLTAGE = 0, /**< 0 */
101 PROMPT_CODE = 1 /**< 1 */
102 };
103
104
105 //! Initialize Linduino
106 void setup()
107 {
108
109 init_16_bit_PWM(); // Initialize the 16-bit PWM
110 Serial.begin(115200); // Initialize the serial port to the PC
111
112 // Goes into Python Mode if 'z' is sent by the Python program
113 char python_char = 'x';
114 for (int i = 0; i <= 50; i++)
115 {
116 if (Serial.available() > 0)
117 python_char = Serial.read();
118 if ((python_char == 'Z') || (python_char == 'z') )
119 python_program();
120 delay(30);
121 }
122
123 // Initialize toggle pin
124 pinMode(4,OUTPUT);
125
126 // Read the indicator pin for Reference Voltage
127 pinMode(2, INPUT);
128 if (digitalRead(2))
129 fullScale = 4.096;
130
131 print_title();
132 print_prompt(0);
133 }
134
135 //! Repeats Linduino loop
136 void loop()
137 {
138 int16_t user_command;
139 static int8_t selected_dac = 0; // The selected DAC to be updated (0=A, 1=B ... 3=D). Initialized to "A".
140
141 if (Serial.available()) // Check for user input
142 {
143 user_command = read_int(); // Read the user command
144 Serial.println(user_command);
145 Serial.flush();
146 switch (user_command)
147 {
148 case 1:
149 menu_1_select_dac(&selected_dac);
150 break;
151 case 2:
152 menu_2_set_duty(selected_dac);
153 break;
154 case 3:
155 test();
156 break;
157 default:
158 Serial.println("Incorrect Option");
159 break;
160 }
161 Serial.println("\n*****************************************");
162 print_prompt(selected_dac);
163 }
164 }
165
166
167 // Function Definition
168
169 //! Prints the title block when program first starts.
170 void print_title()
171 {
172 Serial.println();
173 Serial.println(F("*****************************************************************"));
174 Serial.println(F("* DCxxxxx Demonstration Program *"));
175 Serial.println(F("* *"));
176 Serial.println(F("* This program demonstrates how to implement a PWM signal *"));
177 Serial.println(F("* to set the LTC2645 DACs. "));
178 Serial.println(F("* *"));
179 Serial.println(F("* Set the baud rate to 115200 and select the newline terminator.*"));
180 Serial.println(F("* *"));
181 Serial.println(F("*****************************************************************"));
182 }
183
184
185 //! Prints main menu.
186 void print_prompt(int16_t selected_dac)
187 {
188 Serial.println(F("\nCommand Summary:"));
189 Serial.println(F(" 1-Select DAC"));
190 Serial.println(F(" 2-Set Duty Cycle"));
191
192 Serial.print(F(" Selected DAC: "));
193 Serial.println((char) (selected_dac + 0x41));
194 Serial.print(F(" Current Duty Cycle: "));
195 Serial.print(percentDutyCycle[selected_dac], 2);
196 Serial.println(F("%"));
197 Serial.print(F("Enter a command:"));
198 Serial.flush();
199 }
200
201 //! Initializes Pin 9 and 10 for 16-bit PWM
202 void init_16_bit_PWM()
203 {
204 pinMode(DAC_A, OUTPUT); // Set Pin 9 as output
205 pinMode(DAC_B, OUTPUT); // Set Pin 10 as output
206
207
208 // Enable timer1 for PWM, Phase Correct mode for pin 9 and 10.
209 // Use IRC1 as top, no prescalar (~122Hz),
210 // Negative Edge Triggered
211 TCCR1A = _BV(COM1A1) | _BV(COM1B1) | _BV(WGM11);
212 TCCR1B = _BV(WGM13) | _BV(CS10);
213 TCCR1C = 0x0;
214 ICR1 = 0xFFFF; // Set Timer for 16-bit
215
216 // The following code should be uncommented if Fast PWM Mode
217 // is desired
218 /*
219 // Enable timer1 for Fast PWM mode for pin 9 and 10.
220 // Use IRC1 as top, no prescalar (~244Hz),
221 // Negative Edge Triggered
222 TCCR1A = _BV(COM1A1) | _BV(COM1B1) | _BV(WGM11);
223 TCCR1B = _BV(WGM13)| _BV(WGM12) | _BV(CS10);
224 TCCR1C = 0x0;
225 ICR1 = 0xFFFF; // Set Timer for 16-bit
226 */
227
228 // Set to 0% duty cycle
229 OCR1A = 0x0;
230 OCR1B = 0x0;
231 }
232
233 //! Sets duty cycle for 16-bit PWM.
234 void pwm_16_bit(uint8_t pin, uint16_t duty)
235 {
236 if (pin == 9)
237 OCR1A = duty; // Pin 9
238 else
239 OCR1B = duty; // Pin 10
240 }
241
242 //! Select which DAC to operate on
243 void menu_1_select_dac(int8_t *selected_dac)
244 {
245 // Select a DAC to operate on
246 Serial.print(F("Select DAC to operate on (0=A, 1=B, 2=C, 3=D)"));
247 *selected_dac = read_int();
248 if (*selected_dac >= 4)
249 *selected_dac = 3;
250 Serial.println(*selected_dac);
251 }
252
253 //! Sets the duty cycle for the DAC
254 void menu_2_set_duty(int8_t selected_dac)
255 {
256 int32_t pwm_code;
257
258 if ((selected_dac == 0) || (selected_dac == 1))
259 {
260 if (prompt_voltage_or_code() == PROMPT_VOLTAGE)
261 pwm_code = get_voltage(fullScale, (int8_t)16); // Converts voltage to 16 bit code
262 else
263 pwm_code = get_code();
264 percentDutyCycle[selected_dac] = (pwm_code + 1)/ 65536.0*100;
265 if (selected_dac == 0)
266 pwm_16_bit(DAC_A, (uint16_t)pwm_code);
267 else
268 pwm_16_bit(DAC_B, (uint16_t)pwm_code);
269
270 }
271 else
272 {
273 if (prompt_voltage_or_code() == PROMPT_VOLTAGE)
274 pwm_code = get_voltage(fullScale, (int8_t)8);
275 else
276 pwm_code = get_code();
277 percentDutyCycle[selected_dac] = (pwm_code + 1) / 256.0*100;
278 if (selected_dac == 2)
279 analogWrite(DAC_C, pwm_code);
280 else
281 analogWrite(DAC_D, pwm_code);
282
283 }
284
285 }
286
287 //! Used to interact with the corresponding python program.
288 //! Accepts Serial strings to control the DAC output
289 //! i.e.: Set DAC A (16 bit pwm) to 50% duty cycle -> 32767A
290 void python_program()
291 {
292 uint16_t duty;
293 char dac;
294 Serial.println("Python Mode");
295 while (1)
296 {
297 if (Serial.available() > 0)
298 {
299 duty = Serial.parseInt(); // Parse string to an integer
300 dac = Serial.read(); // Read one byte
301
302 switch (dac)
303 {
304 case 'a':
305 case 'A':
306 pwm_16_bit(DAC_A, (uint16_t)duty);
307 break;
308 case 'b':
309 case 'B':
310 pwm_16_bit(DAC_B, (uint16_t)duty);
311 break;
312 case 'c':
313 case 'C':
314 analogWrite(DAC_C, duty);
315 break;
316 case 'd':
317 case 'D':
318 analogWrite(DAC_D, duty);
319 break;
320 }
321 }
322 }
323 }
324
325 //! Calculate a LTC2645 duty code given the desired output voltage
326 //! @return PWM Code
327 uint16_t LTC2645_voltage_to_pwm_code(float dac_voltage, float fullScaleVoltage, int8_t pwmBitResolution)
328 {
329 float float_code, max_code;
330 max_code = pow(2, pwmBitResolution) - 1; // Calculate max code
331 max_code = (max_code > (floor(max_code) + 0.5)) ? ceil(max_code) : floor(max_code); // Round max code
332 float_code = (dac_voltage / fullScaleVoltage) * max_code; // Calculate the DAC code
333 float_code = (float_code > (floor(float_code) + 0.5)) ? ceil(float_code) : floor(float_code); // Round
334 if (float_code < 0) // If DAC code < 0, Then DAC code = 0
335 float_code = 0;
336 if (float_code > max_code) // If DAC code > max code, then DAC code = max code
337 float_code = max_code;
338 return ((uint16_t)float_code); // Cast DAC code as uint16_t
339 }
340
341 //! Prompt user to enter a voltage or digital code to send to DAC
342 //! @return prompt type
343 int16_t prompt_voltage_or_code()
344 {
345 int16_t user_input;
346 Serial.print(F("Type 1 to enter voltage, 2 to enter code:"));
347 Serial.flush();
348 user_input = read_int();
349 Serial.println(user_input);
350
351 if (user_input != 2)
352 return(PROMPT_VOLTAGE);
353 else
354 return(PROMPT_CODE);
355 }
356
357 //! Get voltage from user input, calculate DAC code based
358 //! on full scale voltage and PWM bit resolution
359 //! @return voltage
360 uint16_t get_voltage(float fullScaleVoltage, int8_t pwmBitResolution)
361 {
362 float dac_voltage;
363
364 Serial.print(F("Enter Desired DAC output voltage: "));
365 dac_voltage = read_float();
366 Serial.print(dac_voltage);
367 Serial.println(" V");
368 Serial.flush();
369 return(LTC2645_voltage_to_pwm_code(dac_voltage, fullScaleVoltage, pwmBitResolution));
370 }
371
372 //! Get code to send to DAC directly, in decimal, hex, or binary
373 //! @return DAC code
374 uint16_t get_code()
375 {
376 uint16_t returncode;
377 Serial.println(F("\nEnter Desired Duty Code"));
378 Serial.println(F("Range: DAC A/B- 0-65535(16-bit PWM)\n DAC C/D- 0-255(8-bit PWM)"));
379 Serial.print(F("(Format 32768, 0x8000, 0100000, or B1000000000000000): "));
380 returncode = (uint16_t) read_int();
381 Serial.print(F("0x"));
382 Serial.println(returncode, HEX);
383 Serial.flush();
384 return(returncode);
385 }
386
387 void test()
388 {
389 // while(1)
390 // {
391 // PORTD = PORTD | 0xFF;
392 // pwm_16_bit(DAC_B, 32751);
393 // delay(10);
394 // PORTD = (PORTD | 0xFF) & 0xEF;
395 // pwm_16_bit(DAC_B, 32815);
396 // delay(10);
397 Serial.println(F("Writing 0.5V ladder to DACs..."));
398 Serial.println(F("Verify VOUTA between 0.490 and 0.510"));
399 Serial.println(F("Verify VOUTB between 0.990 and 1.010"));
400 Serial.println(F("Verify VOUTC between 1.490 and 1.510"));
401 Serial.println(F("Verify VOUTD between 1.990 and 2.010"));
402 pwm_16_bit(DAC_A, 13107);
403 pwm_16_bit(DAC_B, 26214);
404 analogWrite(DAC_C, 153);
405 analogWrite(DAC_D, 204);
406 // }
407 }
DAC_B
const uint8_t DAC_B
Definition: DC2197.ino:74
loop
static void loop()
Repeats Linduino loop.
Definition: DC2197.ino:136
user_command
unsigned char user_command
Definition: Serial_EEPROM_Test.ino:75
fullScale
static float fullScale
Definition: DC2197.ino:94
Linduino.h
Header File for Linduino Libraries and Demo Code.
setup
static void setup()
Initialize Linduino.
Definition: DC2197.ino:106
PROMPT_VOLTAGE
0
Definition: DC2197.ino:100
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: DC2197.ino:343
print_prompt
static void print_prompt()
DAC_A
const uint8_t DAC_A
Definition: DC2197.ino:73
percentDutyCycle
static float percentDutyCycle[4]
Full Scale Voltage.
Definition: DC2197.ino:95
PROMPT_CODE
1
Definition: DC2197.ino:101
get_voltage
static uint16_t get_voltage(float fullScaleVoltage, int8_t pwmBitResolution)
Get voltage from user input, calculate DAC code based on full scale voltage and PWM bit resolution...
Definition: DC2197.ino:360
DAC_C
const uint8_t DAC_C
Definition: DC2197.ino:75
menu_1_select_dac
static void menu_1_select_dac(int16_t *selected_dac)
pwm_16_bit
static void pwm_16_bit(uint8_t pin, uint16_t duty)
Sets duty cycle for 16-bit PWM.
Definition: DC2197.ino:234
menu_2_set_duty
static void menu_2_set_duty(int8_t selected_dac)
Sets the duty cycle for the DAC.
Definition: DC2197.ino:254
UserInterface.h
read_int
int32_t read_int()
Definition: UserInterface.cpp:93
read_float
float read_float()
Definition: UserInterface.cpp:78
print_title
static void print_title()
Prints the title block when program first starts.
Definition: DC2197.ino:170
get_code
static uint16_t get_code()
Get code to send to DAC directly, in decimal, hex, or binary.
Definition: DC2197.ino:374
LTC2645_voltage_to_pwm_code
static uint16_t LTC2645_voltage_to_pwm_code(float dac_voltage, float fullScaleVoltage, int8_t pwmBitResolution)
Calculate a LTC2645 duty code given the desired output voltage.
Definition: DC2197.ino:327
i
static int i
Definition: DC2430A.ino:184
init_16_bit_PWM
static void init_16_bit_PWM()
Initializes Pin 9 and 10 for 16-bit PWM.
Definition: DC2197.ino:202
DAC_D
const uint8_t DAC_D
Definition: DC2197.ino:76
test
static void test()
Definition: DC2197.ino:387
python_program
static void python_program()
Used to interact with the corresponding python program.
Definition: DC2197.ino:290