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.
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
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  {
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  {
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
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
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 }
const uint8_t DAC_B
Definition: DC2197.ino:74
static void loop()
Repeats Linduino loop.
Definition: DC2197.ino:136
unsigned char user_command
static float fullScale
Definition: DC2197.ino:94
Header File for Linduino Libraries and Demo Code.
static void setup()
Initialize Linduino.
Definition: DC2197.ino:106
static int16_t prompt_voltage_or_code()
Prompt user to enter a voltage or digital code to send to DAC.
Definition: DC2197.ino:343
static void print_prompt()
const uint8_t DAC_A
Definition: DC2197.ino:73
static float percentDutyCycle[4]
Full Scale Voltage.
Definition: DC2197.ino:95
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
const uint8_t DAC_C
Definition: DC2197.ino:75
static void menu_1_select_dac(int16_t *selected_dac)
static void pwm_16_bit(uint8_t pin, uint16_t duty)
Sets duty cycle for 16-bit PWM.
Definition: DC2197.ino:234
static void menu_2_set_duty(int8_t selected_dac)
Sets the duty cycle for the DAC.
Definition: DC2197.ino:254
int32_t read_int()
float read_float()
static void print_title()
Prints the title block when program first starts.
Definition: DC2197.ino:170
static uint16_t get_code()
Get code to send to DAC directly, in decimal, hex, or binary.
Definition: DC2197.ino:374
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
static int i
Definition: DC2430A.ino:184
static void init_16_bit_PWM()
Initializes Pin 9 and 10 for 16-bit PWM.
Definition: DC2197.ino:202
const uint8_t DAC_D
Definition: DC2197.ino:76
static void test()
Definition: DC2197.ino:387
static void python_program()
Used to interact with the corresponding python program.
Definition: DC2197.ino:290