| Linduino 1.3.0 Linear Technology Arduino-Compatible Demonstration Board

LTC5566.cpp
Go to the documentation of this file.
1 /*!
2 Copyright 2018(c) Analog Devices, Inc.
3
4 LTC5566: Dual Programmable Gain Downconverting Mixer
5
6 @verbatim
7
8 The LTC5566 dual programmable gain downconverting mixer
9 is ideal for diversity and MIMO receivers that require precise
10 gain setting. Each channel incorporates an active mixer and a
11 digital IF VGA with 15.5dB gain control range. The IF gain of
12 each channel is programmed in 0.5dB steps through the SPI.
13
14 @endverbatim
15
16 http://www.linear.com/product/LTC5566
17
18 All rights reserved.
19
20 Redistribution and use in source and binary forms, with or without
21 modification, are permitted provided that the following conditions are met:
22 - Redistributions of source code must retain the above copyright
23 notice, this list of conditions and the following disclaimer.
24 - Redistributions in binary form must reproduce the above copyright
25 notice, this list of conditions and the following disclaimer in
26 the documentation and/or other materials provided with the
27 distribution.
28 - Neither the name of Analog Devices, Inc. nor the names of its
29 contributors may be used to endorse or promote products derived
30 from this software without specific prior written permission.
31 - The use of this software may or may not infringe the patent rights
32 of one or more patent holders. This license does not release you
33 from the requirement that you obtain separate licenses from these
34 patent holders to use this software.
35 - Use of the software either in source or binary form, must be run
36 on or directly connected to an Analog Devices Inc. component.
37
38 THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
39 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
40 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
41 IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
42 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
43 LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
44 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
45 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
46 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
47 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
48 */
49
50 //! @ingroup RF_Timing
51 //! @{
52 //! @defgroup LTC5566 LTC5566: Dual Programmable Gain Downconverting Mixer
53 //! @}
54
55 /*! @file
56 @ingroup LTC5566
57 Library for LTC5566: Dual Programmable Gain Downconverting Mixer
58 */
59
60 #include "LTC5566.h"
61 #include "LT_SPI.h"
62 #include "UserInterface.h"
63 #include "Linduino.h"
64 #include <SPI.h>
65
66 // Global Variables
67
68 // 8 control bits for mixer 1 (1/2 of the register)
69 uint8_t mixer_1_value;
70
71 // 8 control bits for mixer 2 (1/2 of the register)
72 uint8_t mixer_2_value;
73
74 // 16 bit register for writing to the part
75 uint16_t whole_register;
76
77 // 16 bit output from the part
78 uint16_t full_output;
79
80 // 8 bits read from the LTC5566's internal register
81 uint8_t mixer_1_output;
82
83 // 8 bits read from the LTC5566's internal register
84 uint8_t mixer_2_output;
85
86 // Writes to the LTC5566 twice and reads back the last
87 // two bytes to make sure the LTC5566 was loaded properly
88 void LTC5566_write(uint8_t cs, uint16_t tx, uint16_t *rx) {
89 // Transfer 4 bytes
90 spi_transfer_word(cs, tx, rx);
91 spi_transfer_word(cs, tx, rx);
92 }
93
94 // Take inputs and apply same settings to both mixer channels
95 uint8_t LTC5566_dupl_settings() {
96 // Bit for controlling the LTC5566's power mode
97 uint8_t power_bit;
98
99 // Prompt for getting power mode
100 char *power_prompt = "Enter a command: ";
101
102 // Bit for controlling the LTC5566's RF input tune mode
103 uint8_t tune_bits;
104
105 // Prompt for getting tune mode
106 char *tune_prompt = "\nDesired RF Input Tune setting: ";
107
108 // Bit for controlling the LTC5566's IF attenuation
109 uint8_t att_bits;
110
111 // Prompt for getting att level
112 char *att_prompt = "\nDesired IF Attenuation (dB): ";
113
114 // Get power mode bit
115 power_bit = LTC5566_get_power_mode(power_prompt);
116
117 // Get RF input tune mode
118 tune_bits = LTC5566_get_tune_mode(tune_prompt);
119
120 // Get IF attenuation level
121 att_bits = LTC5566_get_att(att_prompt);
122
123 // Build mixer command byte
124 mixer_1_value = ((power_bit | tune_bits) | att_bits);
125
126 // Load the register command with the first command byte
127 whole_register = mixer_1_value;
128
129 // Shift the first command byte up to the most significant byte
130 whole_register = whole_register << 8;
131
132 // Load the least significant byte with the mixer command byte
133 whole_register = whole_register | mixer_1_value;
134
135 // Send the data to the LTC5566 and read back the previously loaded value
136 LTC5566_write(LTC5566_CS, whole_register, &full_output);
137
138 // Return the register's value to the main program
139 return full_output;
140 }
141
142 // Take inputs and apply different settings to each Mixer Channel
143 uint16_t LTC5566_diff_settings() {
144 // Bit for controlling the LTC5566's power mode (Channel 1)
145 uint8_t power_1_bit;
146
147 // Prompt for getting power mode (Channel 1)
148 char *power_1_prompt = "Enter a command for Channel 1: ";
149
150 // Bit for controlling the LTC5566's power mode (Channel 2)
151 uint8_t power_2_bit;
152
153 // Prompt for getting power mode (Channel 2)
154 char *power_2_prompt = "Enter a command for Channel 2: ";
155
156 // Bit for controlling the LTC5566's RF input tune mode (Channel 1)
157 uint8_t tune_1_bits;
158
159 // Prompt for getting tune mode (Channel 1)
160 char *tune_1_prompt = "\nDesired Channel 1 RF Input Tune setting: ";
161
162 // Bit for controlling the LTC5566's RF input tune mode (Channel 2)
163 uint8_t tune_2_bits;
164
165 // Prompt for getting tune mode (Channel 2)
166 char *tune_2_prompt = "\nDesired Channel 2 RF Input Tune setting: ";
167
168 // Bit for controlling the LTC5566's IF attenuation (Channel 1)
169 uint8_t att_1_bits;
170
171 // Prompt for getting att level (Channel 1)
172 char *att_1_prompt = "\nDesired Channel 1 IF Attenuation (dB): ";
173
174 // Bit for controlling the LTC5566's IF attenuation (Channel 2)
175 uint8_t att_2_bits;
176
177 // Prompt for getting att level (Channel 2)
178 char *att_2_prompt = "\nDesired Channel 2 IF Attenuation (dB): ";
179
180 // Get channel 1 power mode bit
181 power_1_bit = LTC5566_get_power_mode(power_1_prompt);
182
183 // Get channel 2 power mode bit
184 power_2_bit = LTC5566_get_power_mode(power_2_prompt);
185
186 // Get RF1 input tune mode
187 tune_1_bits = LTC5566_get_tune_mode(tune_1_prompt);
188
189 // Get RF2 input tune mode
190 tune_2_bits = LTC5566_get_tune_mode(tune_2_prompt);
191
192 // Get IF1 attenuation level
193 att_1_bits = LTC5566_get_att(att_1_prompt);
194
195 // Get IF2 attenuation level
196 att_2_bits = LTC5566_get_att(att_2_prompt);
197
198 // Build mixer 1 command byte
199 mixer_1_value = ((power_1_bit | tune_1_bits) | att_1_bits);
200
201 // Build mixer 2 command byte
202 mixer_2_value = ((power_2_bit | tune_2_bits) | att_2_bits);
203
204 // Load the register command with channel 2's command byte
205 whole_register = mixer_2_value;
206
207 // Shift channel 2's command byte up to the most significant byte
208 whole_register = whole_register << 8;
209
210 // Load the least significant byte with channel 1's command byte
211 whole_register = whole_register | mixer_1_value;
212
213 // Send the data to the LTC5566 and read back the previously loaded value
214 LTC5566_write(LTC5566_CS, whole_register, &full_output);
215
216 // Return the register's value to the main program
217 return full_output;
218 }
219
220 // Get power mode value from user
221 uint8_t LTC5566_get_power_mode(char *prompt) {
222 // Variable to break out of while loop
223 int keep_looping = 0;
224
225 // The user command for power mode
226 int8_t power_command;
227
228 // Bits for controlling the LTC5566's power mode
229 uint8_t power_bit = LTC5566_FULL_POWER;
230 while (1) {
231 keep_looping = 0;
232 Serial.println(F("\n\n1. Full Power Mode"));
233 Serial.println(F("2. Low Power Mode\n"));
234 Serial.print(prompt);
235
236 // Take input from the user
237 power_command = read_int();
238
239 // Prints the user command to com port
240 Serial.println(power_command);
241 switch (power_command) {
242 // Act on user input
243 case 1:
244 // Set the power bit to full power
245 power_bit = LTC5566_FULL_POWER;
246 break;
247 case 2:
248 // Set the power bit to reduced power
249 power_bit = LTC5566_REDUCED_POWER;
250 break;
251 default:
252 // User input was wrong, ask again
253 Serial.println(F("\n\nIncorrect Option\n"));
254 keep_looping = 1;
255 }
256
257 if (keep_looping == 0) {
258 // Return power bit value to the main program
259 return power_bit;
260 }
261 }
262 }
263
264 // Get RF input tune mode value from user
265 uint8_t LTC5566_get_tune_mode(char *prompt) {
266 // Variable to break out of while loop
267 int keep_looping = 0;
268
269 // The user command for RF input tune mode
270 int8_t tune_command;
271
272 // Bits for controlling the LTC5566's RF input tune mode
273 uint8_t tune_bits = LTC5566_RF_TUNE_11;
274 while (1) {
275 keep_looping = 0;
276 Serial.println(F("\n1. RF Tune 00 (3.1GHz - 5.1GHz)"));
277 Serial.println(F("2. RF Tune 01 (1.8GHz - 4.4GHz)"));
278 Serial.println(F("3. RF Tune 10 (1.3GHz - 3.9GHz)"));
279 Serial.println(F("4. RF Tune 11 (Less than 1.3GHz)"));
280 Serial.print(prompt);
281
282 // Take input from the user
283 tune_command = read_int();
284
285 // Prints the user command to com port
286 Serial.println(tune_command);
287 switch (tune_command) {
288 // Act on user input
289 case 1:
290 // Set the RF input tune bits to 00
291 tune_bits = LTC5566_RF_TUNE_00;
292 break;
293 case 2:
294 // Set the RF input tune bits to 01
295 tune_bits = LTC5566_RF_TUNE_01;
296 break;
297 case 3:
298 // Set the RF input tune bits to 10
299 tune_bits = LTC5566_RF_TUNE_10;
300 break;
301 case 4:
302 // Set the RF input tune bits to 11
303 tune_bits = LTC5566_RF_TUNE_11;
304 break;
305 default:
306 // User input was wrong, ask again
307 Serial.println(F("\n\nIncorrect Option\n"));
308 keep_looping = 1;
309 }
310
311 if (keep_looping == 0) {
312 // Return tune bits value to the main program
313 return tune_bits;
314 }
315 }
316 }
317
318 // Get attenuation value from user
319 uint8_t LTC5566_get_att(char *prompt) {
320 // Variable to break out of while loop
321 int keep_looping = 0;
322
323 // The user command for IF attenuation level
324 float att_command;
325
326 // Bit for controlling the LTC5566's IF attenuation
327 uint8_t att_bits;
328 while (1) {
329 keep_looping = 0;
330 Serial.print(prompt);
331 att_command = read_float();
332
333 // Prints the user command to com port
334 Serial.println(att_command, 1);
335
336 // User input wasn't in 0.5dB increments, ask again
337 if (fmod(att_command, 0.5) != 0) {
338 Serial.println(F("\n\nIncorrect Option - Choose a number "
339 "between 0 and 15.5dB in 0.5dB increments\n"));
340 keep_looping = 1;
341 }
342 // User input was negative, ask again
343 else if (att_command < 0) {
344 Serial.println(F("\n\nIncorrect Option - Choose a number "
345 "between 0 and 15.5dB in 0.5dB increments\n"));
346 keep_looping = 1;
347 }
348 // User input was too high, ask again
349 else if (att_command > 31) {
350 Serial.println(F("\n\nIncorrect Option - Choose a number "
351 "between 0 and 15.5dB in 0.5dB increments\n"));
352 keep_looping = 1;
353 }
354 else {
355 // User input was within the accepted parameters
356
357 // Double the input to convert it to a number between 0-31
358 att_command = att_command * 2.;
359
360 // Set the bits to an integer of the commanded value
361 att_bits = static_cast<int>(att_command);
362 }
363
364 if (keep_looping == 0) {
365 // Return att bits value to the main program
366 return att_bits;
367 }
368 }
369 }
370
371 // Decode the register value read from the LTC5566
372 void LTC5566_decode_output(uint8_t output_register) {
373 // Power bit read back from the LTC5566
374 uint8_t power_bit_read;
375
376 // Power setting read back from the LTC5566
377 String power_setting_read;
378
379 // Tune bits read back from the LTC5566
380 uint8_t tune_bits_read;
381
382 // RF Tune setting read back from the LTC5566
383 String tune_setting_read;
384
385 // Att bits read back from the LTC5566
386 uint8_t att_bits_read;
387
388 // Attenuation setting read back from the LTC5566
389 float att_setting_read;
390
391 // Read bit 7 to get power bit back
392 power_bit_read = (output_register & 0x90) >> 7;
393 switch (power_bit_read) {
394 // The LTC5566 was in Full Power mode
395 case 0:
396 power_setting_read = "Full Power";
397 break;
398 // The LTC5566 was in Low Power mode
399 case 1:
400 power_setting_read = "Low Power";
401 break;
402 }
403
404 // Print the Power setting to the serial monitor
405 Serial.println("Power Setting: " + power_setting_read);
406
407 // Read bits 5 and 6 to get RF tune bits back
408 tune_bits_read = (output_register & 0x60) >> 5;
409 switch (tune_bits_read) {
410 case 0:
411 tune_setting_read = "RF Tune 00 (3.1GHz - 5.1GHz)";
412 break;
413 case 1:
414 tune_setting_read = "RF Tune 01 (1.8GHz - 4.4GHz)";
415 break;
416 case 2:
417 tune_setting_read = "RF Tune 10 (1.3GHz - 3.9GHz)";
418 break;
419 case 3:
420 tune_setting_read = "RF Tune 11 (Less than 1.3GHz)";
421 break;
422 }
423
424 // Print the RF Tune setting to the serial monitor
425 Serial.println("RF Input Setting: " + tune_setting_read);
426
427 // Read bits 0-4 to get attenuation bits back
428 att_bits_read = output_register & 0x1F;
429
430 // Convert the 5 Attenuation bits (0-31) to an attenuation setting (0-15.5)
431 att_setting_read = (att_bits_read / 2.);
432
433 // Print the Attenuation setting to the serial monitor
434 Serial.println("Attenuation Setting: " + String(att_setting_read, 1) + " dB");
435 }
LTC5566_RF_TUNE_01
#define LTC5566_RF_TUNE_01
Definition: LTC5566.h:86
LTC5566_CS
#define LTC5566_CS
Define the SPI CS pin.
Definition: LTC5566.h:72
mixer_1_output
uint8_t mixer_1_output
Definition: LTC5566.cpp:81
whole_register
uint16_t whole_register
Definition: LTC5566.cpp:75
LTC5566_dupl_settings
uint8_t LTC5566_dupl_settings()
Function to duplicate settings for both LTC5566 channels.
Definition: LTC5566.cpp:95
Linduino.h
Header File for Linduino Libraries and Demo Code.
LTC5566_FULL_POWER
#define LTC5566_FULL_POWER
Definition: LTC5566.h:78
LTC5566_RF_TUNE_11
#define LTC5566_RF_TUNE_11
Definition: LTC5566.h:88
mixer_1_value
uint8_t mixer_1_value
Definition: LTC5566.cpp:69
LTC5566_REDUCED_POWER
#define LTC5566_REDUCED_POWER
Definition: LTC5566.h:79
LTC5566_RF_TUNE_10
#define LTC5566_RF_TUNE_10
Definition: LTC5566.h:87
LTC5566_get_tune_mode
uint8_t LTC5566_get_tune_mode(char *prompt)
Function to get data from user for RF input tune mode.
Definition: LTC5566.cpp:265
LTC5566_get_power_mode
uint8_t LTC5566_get_power_mode(char *prompt)
Function to get data from user for power mode.
Definition: LTC5566.cpp:221
LTC5566_get_att
uint8_t LTC5566_get_att(char *prompt)
Function to get data from user for IF attenuation.
Definition: LTC5566.cpp:319
LTC5566.h
Copyright 2018(c) Analog Devices, Inc.
spi_transfer_word
void spi_transfer_word(uint8_t cs_pin, uint16_t tx, uint16_t *rx)
Reads and sends a word.
Definition: LT_SPI.cpp:98
mixer_2_output
uint8_t mixer_2_output
Definition: LTC5566.cpp:84
LTC5566_RF_TUNE_00
#define LTC5566_RF_TUNE_00
Definition: LTC5566.h:85
LTC5566_write
void LTC5566_write(uint8_t cs, uint16_t tx, uint16_t *rx)
Writes to the LTC5566 twice and reads back the last two bytes to make sure the LTC5566 was loaded pro...
Definition: LTC5566.cpp:88
LT_SPI.h
LT_SPI: Routines to communicate with ATmega328P&#39;s hardware SPI port.
full_output
uint16_t full_output
Definition: LTC5566.cpp:78
UserInterface.h
read_int
int32_t read_int()
Definition: UserInterface.cpp:93
read_float
float read_float()
Definition: UserInterface.cpp:78
prompt
prompt
Used to keep track to print voltage or print code.
Definition: DC934A.ino:113
LTC5566_diff_settings
uint16_t LTC5566_diff_settings()
Function to apply unique settings for each LTC5566 channel.
Definition: LTC5566.cpp:143
LTC5566_decode_output
void LTC5566_decode_output(uint8_t output_register)
Decode the register value read from the LTC5555.
Definition: LTC5566.cpp:372
mixer_2_value
uint8_t mixer_2_value
Definition: LTC5566.cpp:72