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
82 
83 // 8 bits read from the LTC5566's internal register
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
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
128 
129  // Shift the first command byte up to the most significant byte
131 
132  // Load the least significant byte with the mixer command byte
134 
135  // Send the data to the LTC5566 and read back the previously loaded value
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
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
206 
207  // Shift channel 2's command byte up to the most significant byte
209 
210  // Load the least significant byte with channel 1's command byte
212 
213  // Send the data to the LTC5566 and read back the previously loaded value
215 
216  // Return the register's value to the main program
217  return full_output;
218 }
219 
220 // Get power mode value from user
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
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 }
#define LTC5566_RF_TUNE_01
Definition: LTC5566.h:86
#define LTC5566_CS
Define the SPI CS pin.
Definition: LTC5566.h:72
uint8_t mixer_1_output
Definition: LTC5566.cpp:81
uint16_t whole_register
Definition: LTC5566.cpp:75
uint8_t LTC5566_dupl_settings()
Function to duplicate settings for both LTC5566 channels.
Definition: LTC5566.cpp:95
Header File for Linduino Libraries and Demo Code.
#define LTC5566_FULL_POWER
Definition: LTC5566.h:78
#define LTC5566_RF_TUNE_11
Definition: LTC5566.h:88
uint8_t mixer_1_value
Definition: LTC5566.cpp:69
#define LTC5566_REDUCED_POWER
Definition: LTC5566.h:79
#define LTC5566_RF_TUNE_10
Definition: LTC5566.h:87
uint8_t LTC5566_get_tune_mode(char *prompt)
Function to get data from user for RF input tune mode.
Definition: LTC5566.cpp:265
uint8_t LTC5566_get_power_mode(char *prompt)
Function to get data from user for power mode.
Definition: LTC5566.cpp:221
uint8_t LTC5566_get_att(char *prompt)
Function to get data from user for IF attenuation.
Definition: LTC5566.cpp:319
Copyright 2018(c) Analog Devices, Inc.
void spi_transfer_word(uint8_t cs_pin, uint16_t tx, uint16_t *rx)
Reads and sends a word.
Definition: LT_SPI.cpp:98
uint8_t mixer_2_output
Definition: LTC5566.cpp:84
#define LTC5566_RF_TUNE_00
Definition: LTC5566.h:85
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: Routines to communicate with ATmega328P&#39;s hardware SPI port.
uint16_t full_output
Definition: LTC5566.cpp:78
int32_t read_int()
float read_float()
prompt
Used to keep track to print voltage or print code.
Definition: DC934A.ino:113
uint16_t LTC5566_diff_settings()
Function to apply unique settings for each LTC5566 channel.
Definition: LTC5566.cpp:143
void LTC5566_decode_output(uint8_t output_register)
Decode the register value read from the LTC5555.
Definition: LTC5566.cpp:372
uint8_t mixer_2_value
Definition: LTC5566.cpp:72