| Linduino 1.3.0 Linear Technology Arduino-Compatible Demonstration Board

Synth.ino
Go to the documentation of this file.
1 /*
2 LTC Synthesizer Demo
3
4 Copyright 2018(c) Analog Devices, Inc.
5
6 All rights reserved.
7
8 Redistribution and use in source and binary forms, with or without
9 modification, are permitted provided that the following conditions are met:
10 - Redistributions of source code must retain the above copyright
11 notice, this list of conditions and the following disclaimer.
12 - Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in
14 the documentation and/or other materials provided with the
15 distribution.
16 - Neither the name of Analog Devices, Inc. nor the names of its
17 contributors may be used to endorse or promote products derived
18 from this software without specific prior written permission.
19 - The use of this software may or may not infringe the patent rights
20 of one or more patent holders. This license does not release you
21 from the requirement that you obtain separate licenses from these
22 patent holders to use this software.
23 - Use of the software either in source or binary form, must be run
24 on or directly connected to an Analog Devices Inc. component.
25
26 THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
27 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
28 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
29 IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
30 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
32 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
33 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
34 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 */
37
38 #include <Arduino.h>
39 #include <stdint.h>
40 #include "Linduino.h"
41 #include "LT_SPI.h"
42 #include "UserInterface.h"
43 #include "LT_I2C.h"
44 #include "QuikEval_EEPROM.h"
45 #include "LTC6946.h"
46 #include "math.h"
47 #include <LiquidCrystal.h>
48 #include <EEPROM.h>
49 #include <SPI.h>
50 #include <Wire.h>
51
52 const int16_t RS = 8;
53 const int16_t E = 9;
54 const int16_t D4 = 4;
55 const int16_t D5 = 5;
56 const int16_t D6 = 6;
57 const int16_t D7 = 7;
58 const int16_t BUTTON_PIN = 0;
59 const int8_t UP = 1;
60 const int8_t DOWN = 2;
61 const int8_t LEFT = 3;
62 const int8_t RIGHT = 4;
63 const int8_t SELECT = 5;
64
65 uint8_t REG[12]; //!< Register values to be written to read from
66 int8_t demo_board_connected; //!< Demo Board Name stored in QuikEval EEPROM
67 char demo_name[] = "DC1705"; //!< Demo Board Name stored in QuikEval EEPROM
68
69 int16_t pos = 5;
70 int8_t MHz[6] = {0, 0, 0, 0, 0, 1};
71
72 // initialize the library with the numbers of the interface pins
73 LiquidCrystal lcd(RS, E, D4, D5, D6, D7);
74
75 void setup()
76 {
77 quikeval_SPI_init(); //! Configure the spi port for 4MHz SCK
78 quikeval_SPI_connect(); //! Connect SPI to main data port
79 quikeval_I2C_init(); //! Configure the EEPROM I2C port for 100kHz
80
81 demo_board_connected = discover_demo_board(demo_name); //! Checks if correct demo board is connected.
82
83 lcd.begin(16, 2);
84
85 lcd.print("LTC Synthesizer");
86 lcd.setCursor(0, 1);
87 lcd.print("V 1.0");
88 delay(1000);
89 lcd.clear();
90
91 if (!demo_board_connected)
92 {
93 lcd.print("No Demo Board");
94 lcd.setCursor(0, 1);
95 lcd.print(" Detected");
96 while (1); //! Does nothing if the demo board is not connected
97 }
98
99 lcd.print("Found The");
100 lcd.setCursor(0, 1);
101 lcd.print(demo_board.product_name);
102 delay(1000);
103 lcd.clear();
104
105 restore_settings();
106 lcd.clear();
107 }
108
109 void loop()
110 {
111 int8_t in;
112
113 in = read_switches();
114
115 //Display Frequency
116 lcd.setCursor(0, 0);
117 lcd.print("Freq:");
118 lcd.print(MHz[5]);
119 lcd.print(MHz[4]);
120 lcd.print(MHz[3]);
121 lcd.print(MHz[2]);
122 lcd.print(".");
123 lcd.print(MHz[1]);
124 lcd.print(MHz[0]);
125 lcd.print("MHz");
126
127 //Controls position
128 if (in == RIGHT)
129 pos -= 1;
130 if (in == LEFT)
131 pos += 1;
132 if (pos > 5)
133 pos = 0;
134 if (pos < 0)
135 pos = 5;
136
137 //Sets cursor to correct location
138 lcd.cursor();
139 if (pos == 0)
140 lcd.setCursor(11, 0);
141 if (pos == 1)
142 lcd.setCursor(10, 0);
143 if (pos == 2)
144 lcd.setCursor(8, 0);
145 if (pos == 3)
146 lcd.setCursor(7, 0);
147 if (pos == 4)
148 lcd.setCursor(6, 0);
149 if (pos == 5)
150 lcd.setCursor(5, 0);
151
152 // Frequency Out Array Control
153 if (in == UP)
154 {
155 MHz[pos] += 1;
156 lcd.noCursor();
157 lcd.clear();
158 }
159 if (in == DOWN)
160 {
161 MHz[pos] -= 1;
162 lcd.noCursor();
163 lcd.clear();
164 }
165 if (MHz[pos] < 0)
166 MHz[pos] = 9;
167 if (MHz[pos] > 9)
168 MHz[pos] = 0;
169
170 //Designes the loop when select is pressed
171 if (in == SELECT)
172 {
173 loop_design();
174 lcd.clear();
175 }
176 delay(250);
177 }
178
179 //Reads the Switches
180 //Returns the selected button
181 int8_t read_switches()
182 {
183 int16_t input = 0;
184
185 input = analogRead(BUTTON_PIN);
186 if ((input <= 170) && (input >= 120))
187 return UP;
188 if ((input <= 350) && (input >= 300))
189 return DOWN;
190 if ((input <= 550) && (input >= 450))
191 return LEFT;
192 if ((input <= 800) && (input >= 700))
193 return SELECT;
194 if (input <= 100)
195 return RIGHT;
196 return 0;
197 }
198
199 void loop_design()
200 {
201 uint8_t O_DIV;
202 uint8_t filt;
203 uint8_t LKWIN;
204 uint8_t B_DIV;
205 uint8_t BST;
206 float R_DIV;
207 float f_PFD;
208 float N_DIV;
209 float f_VCO;
210 uint8_t O_DIV_possible = 0;
211 uint8_t ref_out = 0; //!< Used to keep track of reference out status
212
213 //Change these Variables to design the loop
214 //to different configurations
215 uint8_t rfo = 3;
216 uint8_t i_cp = 11;
217 uint8_t lkcnt = 0;
218 float f_ref = 100; //MHz
219 float f_STEP = .5; //MHz
220 float f_rf= 0; //Desired frequency
221 float dBm = 21;
222
223 //Convert the Array to a float
224 f_rf += MHz[0]*.01;
225 f_rf += MHz[1]*.1;
226 f_rf += MHz[2];
227 f_rf += MHz[3]*10;
228 f_rf += MHz[4]*100;
229 f_rf += MHz[5]*1000;
230
231
232 //Selcts the O divder for different parts
233 if (strcmp(demo_board.product_name, "LTC6946-1") == 0)
234 O_DIV_possible = O_divide_1(f_rf, &O_DIV);
235 else if (strcmp(demo_board.product_name, "LTC6946-2") == 0)
236 O_DIV_possible = O_divide_2(f_rf, &O_DIV);
237 else if (strcmp(demo_board.product_name, "LTC6946-3") == 0)
238 O_DIV_possible = O_divide_3(f_rf, &O_DIV);
239
240 //If a solution is not found, then it does not design the loop
241 if (!O_DIV_possible)
242 {
243 lcd.setCursor(0, 1);
244 lcd.print("No Loop Solution");
245 delay(1000);
246 return;
247 }
248
249 //Calculates the R Divider
250 R_DIV = R_divide(f_ref, &f_STEP, O_DIV);
251
252 //Calculates the PFD
253 f_PFD = f_pfd(f_ref, R_DIV);
254
255 //Calculates the N divider
256 N_DIV = N_divide(f_rf, O_DIV, f_PFD);
257
258 //Calculates the VCO
259 f_VCO = f_vco(f_ref, N_DIV, R_DIV);
260
261 //Calculates the B divider
262 B_DIV = B_div(f_PFD);
263
264 //Selects the filter
265 filt = filter(f_ref);
266
267 //Calculates the LKWIN
268 LKWIN = lkwin(f_PFD);
269
270 //Calculates the BST
271 BST = bst(dBm);
272
273 //Sets the RFO
274 if (rfo == 0)
275 rfo = LTC6946_RFO_0;
276 else if (rfo == 1)
277 rfo = LTC6946_RFO_1;
278 else if (rfo == 2)
279 rfo = LTC6946_RFO_2;
280 else
281 rfo = LTC6946_RFO_3;
282
283 //Sets the I_CP
284 switch (i_cp)
285 {
286 case 0:
287 i_cp = LTC6946_CP_0;
288 break;
289 case 1:
290 i_cp = LTC6946_CP_1;
291 break;
292 case 2:
293 i_cp = LTC6946_CP_2;
294 break;
295 case 3:
296 i_cp = LTC6946_CP_3;
297 break;
298 case 4:
299 i_cp = LTC6946_CP_4;
300 break;
301 case 5:
302 i_cp = LTC6946_CP_5;
303 break;
304 case 6:
305 i_cp = LTC6946_CP_6;
306 break;
307 case 7:
308 i_cp = LTC6946_CP_7;
309 break;
310 case 8:
311 i_cp = LTC6946_CP_8;
312 break;
313 case 9:
314 i_cp = LTC6946_CP_9;
315 break;
316 case 10:
317 i_cp = LTC6946_CP_10;
318 break;
319 default:
320 i_cp = LTC6946_CP_11;
321 break;
322 }
323
324 //Sets the lock count
325 if (lkcnt == 3)
326 lkcnt = LTC6946_LKCNT_3;
327 else if (lkcnt == 2)
328 lkcnt = LTC6946_LKCNT_2;
329 else if (lkcnt == 1)
330 lkcnt = LTC6946_LKCNT_1;
331 else
332 lkcnt = LTC6946_LKCNT_0;
333
334 //Places loop design into correct registers
335 union
336 {
337 uint8_t R[2];
338 uint16_t code;
339 };
340 code = R_DIV;
341 if (ref_out == 0)
342 REG[2] = LTC6946_PDREFO | LTC6946_MTCAL;
343 else
344 REG[2] = LTC6946_MTCAL;
345 REG[3] = B_DIV |R[1];
346 REG[4] = R[0];
347
348 union
349 {
350 uint8_t N[2];
351 uint16_t Code;
352 };
353 Code = N_DIV;
354 REG[5] = N[1];
355 REG[6] = N[0];
356 REG[7] = LTC6946_ALCCAL | LTC6946_ALCULOK | LTC6946_LKEN | LTC6946_CAL; // Required settings to allow proper loop locking
357 REG[8] = BST | filt | O_DIV | rfo;
358 REG[9] = i_cp | LKWIN | lkcnt;
359 REG[10] = LTC6946_CPCHI | LTC6946_CPCLO; // Sets charge pump
360
361 //Set registers
362 write_all();
363
364 lcd.clear();
365 lcd.print("Loop Set");
366 delay(1000);
367
368 store_settings();
369 }
370 void store_settings()
371 // Store the PLL Settings to the EEPROM
372 {
373 eeprom_write_int16(EEPROM_I2C_ADDRESS, EEPROM_CAL_KEY, EEPROM_CAL_STATUS_ADDRESS); // Cal key
374 for (uint8_t i = 2; i <= 10 ; i++)
375 eeprom_write_byte(EEPROM_I2C_ADDRESS,(char) REG[i], EEPROM_CAL_STATUS_ADDRESS + i);
376 lcd.clear();
377 lcd.print("Settings Stored");
378 delay(1000);
379 }
380 //! Read stored PLL settings from nonvolatile EEPROM on demo board
381 void restore_settings()
382 // Read the PLL settings from EEPROM
383 {
384 int16_t cal_key;
385 // read the cal key from the EEPROM
386 eeprom_read_int16(EEPROM_I2C_ADDRESS, &cal_key, EEPROM_CAL_STATUS_ADDRESS);
387 if (cal_key == EEPROM_CAL_KEY)
388 {
389 // PLL Settings has been stored, read PLL Settings
390 for (uint8_t i = 2; i <= 10 ; i++)
391 eeprom_read_byte(EEPROM_I2C_ADDRESS,(char *) &REG[i], EEPROM_CAL_STATUS_ADDRESS + i);
392
393 //Update registers
394 write_all();
395
396 lcd.clear();
397 lcd.print("Settings");
398 lcd.setCursor(0,1);
399 lcd.print("Restored");
400 delay(1000);
401 }
402 else
403 {
404 lcd.clear();
405 lcd.print("No Settings");
406 lcd.setCursor(0,1);
407 lcd.print(" Found");
408 delay(1000);
409 }
410 }
411
412 //! Write all registers for the LTC6946 and displays them.
413 void write_all()
414 {
415 // Write All Registers
416 LTC6946_write(LTC6946_CS, LTC6946_REG_H01, REG[1]);
417 LTC6946_write(LTC6946_CS, LTC6946_REG_H02, REG[2]);
418 LTC6946_write(LTC6946_CS, LTC6946_REG_H03, REG[3]);
419 LTC6946_write(LTC6946_CS, LTC6946_REG_H04, REG[4]);
420 LTC6946_write(LTC6946_CS, LTC6946_REG_H05, REG[5]);
421 LTC6946_write(LTC6946_CS, LTC6946_REG_H06, REG[6]);
422 LTC6946_write(LTC6946_CS, LTC6946_REG_H07, REG[7]);
423 LTC6946_write(LTC6946_CS, LTC6946_REG_H08, REG[8]);
424 LTC6946_write(LTC6946_CS, LTC6946_REG_H09, REG[9]);
425 LTC6946_write(LTC6946_CS, LTC6946_REG_H0A, REG[10]);
426 }
demo_board
struct demo_board_type demo_board
Instantiate demo board structure.
Definition: QuikEval_EEPROM.cpp:71
pos
static int16_t pos
Definition: Synth.ino:69
lcd
LiquidCrystal lcd(RS, E, D4, D5, D6, D7)
E
const int16_t E
Definition: Synth.ino:53
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
loop_design
static void loop_design()
Definition: Synth.ino:199
D4
const int16_t D4
Definition: Synth.ino:54
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
Linduino.h
Header File for Linduino Libraries and Demo Code.
LTC6946_ALCULOK
#define LTC6946_ALCULOK
for spi_map array, defines location for field specific information used to create the spi map ...
Definition: LTC6946.h:86
LTC6946_CS
#define LTC6946_CS
Define the SPI CS pin.
Definition: LTC6946.h:76
demo_name
char demo_name[]
Demo Board Name stored in QuikEval EEPROM.
Definition: Synth.ino:67
read_switches
static int8_t read_switches()
Definition: Synth.ino:181
RIGHT
const int8_t RIGHT
Definition: Synth.ino:62
restore_settings
static void restore_settings()
Read stored PLL settings from nonvolatile EEPROM on demo board.
Definition: Synth.ino:381
LTC6946_MTCAL
#define LTC6946_MTCAL
for spi_map array, defines location for field specific information used to create the spi map ...
Definition: LTC6946.h:104
LTC6946_LKEN
#define LTC6946_LKEN
for spi_map array, defines location for field specific information used to create the spi map ...
Definition: LTC6946.h:101
ref_out
static uint8_t ref_out
Used to keep track of reference out status.
Definition: DC1649A.ino:122
D7
const int16_t D7
Definition: Synth.ino:57
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
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.
SELECT
const int8_t SELECT
Definition: Synth.ino:63
input
#define input(pin)
Return the state of pin "pin".
Definition: Linduino.h:79
quikeval_SPI_init
void quikeval_SPI_init(void)
Configure the SPI port for 4Mhz SCK.
Definition: LT_SPI.cpp:151
LTC6946_PDREFO
#define LTC6946_PDREFO
for spi_map array, defines location for field specific information used to create the spi map ...
Definition: LTC6946.h:112
EEPROM_CAL_STATUS_ADDRESS
#define EEPROM_CAL_STATUS_ADDRESS
Definition: QuikEval_EEPROM.h:58
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
setup
static void setup()
Definition: Synth.ino:75
demo_board_connected
static int8_t demo_board_connected
Demo Board Name stored in QuikEval EEPROM.
Definition: Synth.ino:66
LTC6946_write
void LTC6946_write(uint8_t cs, uint8_t address, uint8_t Data)
LTC6946 Write Single Address writes 8 bit Data field to LTC6946.
Definition: LTC6946.cpp:165
LTC6946_CAL
#define LTC6946_CAL
for spi_map array, defines location for field specific information used to create the spi map ...
Definition: LTC6946.h:89
LEFT
const int8_t LEFT
Definition: Synth.ino:61
D5
const int16_t D5
Definition: Synth.ino:55
LT_SPI.h
LT_SPI: Routines to communicate with ATmega328P&#39;s hardware SPI port.
LTC6946.h
LTC6946: Ultralow Noise and Spurious 0.37GHz to 6.39GHz Integer-N Synthesizer with Integrated VCO...
REG
static uint8_t REG[12]
Register values to be written to read from.
Definition: Synth.ino:65
LT_I2C.h
LT_I2C: Routines to communicate with ATmega328P&#39;s hardware I2C port.
LTC6946_ALCCAL
#define LTC6946_ALCCAL
for spi_map array, defines location for field specific information used to create the spi map ...
Definition: LTC6946.h:81
DOWN
const int8_t DOWN
Definition: Synth.ino:60
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
demo_board_type::product_name
char product_name[15]
LTC Product (LTC2654-L16)
Definition: QuikEval_EEPROM.h:70
store_settings
static void store_settings()
Definition: Synth.ino:370
write_all
static void write_all()
Write all registers for the LTC6946 and displays them.
Definition: Synth.ino:413
quikeval_I2C_init
void quikeval_I2C_init(void)
Initializes Linduino I2C port.
Definition: LT_I2C.cpp:394
i
static int i
Definition: DC2430A.ino:184
LTC6946_CPCHI
#define LTC6946_CPCHI
for spi_map array, defines location for field specific information used to create the spi map ...
Definition: LTC6946.h:91
BUTTON_PIN
const int16_t BUTTON_PIN
Definition: Synth.ino:58
UP
const int8_t UP
Definition: Synth.ino:59
RS
const int16_t RS
Definition: Synth.ino:52
D6
const int16_t D6
Definition: Synth.ino:56
EEPROM_CAL_KEY
#define EEPROM_CAL_KEY
Definition: QuikEval_EEPROM.h:59
LTC6946_CPCLO
#define LTC6946_CPCLO
for spi_map array, defines location for field specific information used to create the spi map ...
Definition: LTC6946.h:92
loop
static void loop()
Definition: Synth.ino:109
MHz
static int8_t MHz[6]
Definition: Synth.ino:70