Linduino  1.3.0
Linear Technology Arduino-Compatible Demonstration Board
LTC5556.cpp
Go to the documentation of this file.
1 /*!
2 
3 Copyright 2018(c) Analog Devices, Inc.
4 
5 LTC5556: Dual Programmable Downconverting Mixer with IF DVGA
6 
7 @verbatim
8 
9 The LTC5556 dual programmable gain downconverting mixer
10 is ideal for diversity and MIMO receivers that require
11 precise gain setting. Each channel incorporates an active
12 mixer and a digital IF VGA with 15.5dB gain control range.
13 The IF gain of each channel is programmed in 0.5dB steps
14 through the SPI. A reduced power mode is also available
15 for each channel.
16 
17 @endverbatim
18 
19 http://www.analog.com/en/products/rf-microwave/mixers/single-double-triple-balanced-mixers/ltc5556.html
20 
21 All rights reserved.
22 
23 Redistribution and use in source and binary forms, with or without
24 modification, are permitted provided that the following conditions are met:
25  - Redistributions of source code must retain the above copyright
26  notice, this list of conditions and the following disclaimer.
27  - Redistributions in binary form must reproduce the above copyright
28  notice, this list of conditions and the following disclaimer in
29  the documentation and/or other materials provided with the
30  distribution.
31  - Neither the name of Analog Devices, Inc. nor the names of its
32  contributors may be used to endorse or promote products derived
33  from this software without specific prior written permission.
34  - The use of this software may or may not infringe the patent rights
35  of one or more patent holders. This license does not release you
36  from the requirement that you obtain separate licenses from these
37  patent holders to use this software.
38  - Use of the software either in source or binary form, must be run
39  on or directly connected to an Analog Devices Inc. component.
40 
41 THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
42 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
43 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
44 IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
45 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
46 LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
47 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
48 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
49 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
50 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
51 */
52 
53 /*! @ingroup RF_Timing
54  @{
55  @defgroup LTC5556 LTC5556: Dual Programmable Downconverting Mixer with IF DVGAs
56  @}
57 
58  @file
59  @ingroup LTC5556
60  Library for LTC5556: Dual Programmable Downconverting Mixer with IF DVGAs
61 */
62 
63 #include "LTC5556.h"
64 #include <SPI.h>
65 #include "LT_SPI.h"
66 #include "UserInterface.h"
67 #include "Linduino.h"
68 
69 /// Global Variables
70 // 8 control bits for mixer 1 (1/2 of the register)
71 uint8_t mixer_1_value;
72 
73 // 8 control bits for mixer 2 (1/2 of the register)
74 uint8_t mixer_2_value;
75 
76 // 16 bit register for writing to the part
77 uint16_t register_value;
78 
79 // 16 bit output from the part
80 uint16_t full_output;
81 
82 // 8 bit output from mixer 1
84 
85 // 8 bit output from mixer 2
87 
88 // Writes to the LTC5556 twice and reads back the last
89 // byte to make sure the LTC5556 was loaded properly
90 void LTC5556_write(uint8_t cs, uint16_t tx, uint16_t *rx) {
91  // Transfer 4 bytes
92  spi_transfer_word(cs, tx, rx);
93  spi_transfer_word(cs, tx, rx);
94 }
95 
96 // Take inputs and apply same settings to both mixer channels
98  // Bit for controlling the LTC5556's power mode
99  uint8_t power_bit;
100 
101  // Prompt for getting power mode
102  char *power_prompt = "Enter a command: ";
103 
104  // Bit for controlling the LTC5556's IF attenuation
105  uint8_t att_bits;
106 
107  // Prompt for getting att level
108  char *att_prompt = "\nDesired IF Attenuation (dB): ";
109 
110  // 16 bit input for the LTC5556
111  uint16_t whole_register;
112 
113  // Output variable to read back the register into
114  uint16_t output_value;
115 
116  // Get power mode bit
117  power_bit = LTC5556_get_power_mode(power_prompt);
118 
119  // Get IF attenuation level
120  att_bits = LTC5556_get_att(att_prompt);
121 
122  // Build mixer command byte
123  mixer_1_value = (power_bit | att_bits);
124 
125  // Load the full register with two sets of identical data
126  whole_register = (mixer_1_value << 8) | mixer_1_value;
127 
128  // Send the data to the LTC5556 and read back the previously loaded value
129  LTC5556_write(LTC5556_CS, whole_register, &full_output);
130 
131  // Return the register's value to the main program
132  return full_output;
133 }
134 
135 // Take inputs and apply different settings to each mixer channel
137  // Bit for controlling the LTC5556's power mode (Channel 1)
138  uint8_t power_1_bit;
139 
140  // Prompt for getting power mode (Channel 1)
141  char *power_1_prompt = "Enter a command for Channel 1: ";
142 
143  // Bit for controlling the LTC5556's power mode (Channel 2)
144  uint8_t power_2_bit;
145 
146  // Prompt for getting power mode (Channel 2)
147  char *power_2_prompt = "Enter a command for Channel 2: ";
148 
149  // Bit for controlling the LTC5556's IF attenuation (Channel 1)
150  uint8_t att_1_bits;
151 
152  // Prompt for getting att level (Channel 1)
153  char *att_1_prompt = "\nDesired Channel 1 IF Attenuation (dB): ";
154 
155  // Bit for controlling the LTC5556's IF attenuation (Channel 2)
156  uint8_t att_2_bits;
157 
158  // Prompt for getting att level (Channel 2)
159  char *att_2_prompt = "\nDesired Channel 2 IF Attenuation (dB): ";
160 
161  // 16 bit input for the LTC5556
162  uint16_t whole_register;
163 
164  // 16 bit output from the LTC5556 to be returned
165  uint8_t output_value;
166 
167  // Get channel 1 power mode bit
168  power_1_bit = LTC5556_get_power_mode(power_1_prompt);
169 
170  // Get channel 2 power mode bit
171  power_2_bit = LTC5556_get_power_mode(power_2_prompt);
172 
173  // Get IF1 attenuation level
174  att_1_bits = LTC5556_get_att(att_1_prompt);
175 
176  // Get IF2 attenuation level
177  att_2_bits = LTC5556_get_att(att_2_prompt);
178 
179  // Build mixer 1 command byte
180  mixer_1_value = (power_1_bit | att_1_bits);
181 
182  // Build mixer 2 command byte
183  mixer_2_value = (power_2_bit | att_2_bits);
184 
185  // Load the full register with the settings for each mixer
186  whole_register = (mixer_2_value << 8) | mixer_1_value;
187 
188  // Send the data to the LTC5556 and read back the previously loaded value
189  LTC5556_write(LTC5556_CS, whole_register, &full_output);
190 
191  // Return the least significant byte read back to the main program
192  return full_output;
193 }
194 
195 // Get power mode value from user
197  // Variable to break out of while loop
198  int keep_looping = 0;
199 
200  // The user command for power mode
201  int8_t power_command;
202 
203  // Bits for controlling the LTC5556's power mode
204  uint8_t power_bit = LTC5556_FULL_POWER;
205  while (1) {
206  keep_looping = 0;
207  Serial.println(F("\n\n1. Full Power Mode"));
208  Serial.println(F("2. Low Power Mode\n"));
209  Serial.print(prompt);
210 
211  // Take input from the user
212  power_command = read_int();
213 
214  // Prints the user command to com port
215  Serial.println(power_command);
216  switch (power_command) {
217  // Act on user input
218  case 1:
219  // Set the power bit to full power
220  power_bit = LTC5556_FULL_POWER;
221  break;
222  case 2:
223  // Set the power bit to reduced power
224  power_bit = LTC5556_REDUCED_POWER;
225  break;
226  default:
227  // User input was wrong, ask again
228  Serial.println(F("\n\nIncorrect Option\n"));
229  keep_looping = 1;
230  }
231  if (keep_looping == 0) {
232  // Return power bit value to the main program
233  // (shifted to correct position in the register)
234  return power_bit;
235  }
236  }
237 }
238 
239 // Get attenuation value from user
240 uint8_t LTC5556_get_att(char *prompt) {
241  // Variable to break out of while loop
242  int keep_looping = 0;
243 
244  // The user command for IF attenuation level
245  float att_command;
246 
247  // Bit for controlling the LTC5556's IF attenuation
248  uint8_t att_bits;
249  while (1) {
250  keep_looping = 0;
251  Serial.print(prompt);
252  att_command = read_float();
253 
254  // Prints the user command to com port
255  Serial.println(att_command, 1);
256 
257  // User input wasn't in 0.5dB increments, ask again
258  if (fmod(att_command, 0.5) != 0) {
259  Serial.println(F("\n\nIncorrect Option - Choose a number "
260  "between 0 and 15.5dB in 0.5dB increments\n"));
261  keep_looping = 1;
262  }
263  // User input was negative, ask again
264  else if (att_command < 0) {
265  Serial.println(F("\n\nIncorrect Option - Choose a number "
266  "between 0 and 15.5dB in 0.5dB increments\n"));
267  keep_looping = 1;
268  }
269  // User input was too high, ask again
270  else if (att_command > 31) {
271  Serial.println(F("\n\nIncorrect Option - Choose a number "
272  "between 0 and 15.5dB in 0.5dB increments\n"));
273  keep_looping = 1;
274  }
275  else {
276  // User input was within the accepted parameters
277 
278  // Double the input to convert it to a number between 0-31
279  att_command = att_command * 2.;
280 
281  // Set the bits to an integer of the commanded value
282  att_bits = static_cast<int>(att_command);
283  }
284 
285  if (keep_looping == 0) {
286  // Return att bits value to the main program
287  return att_bits;
288  }
289  }
290 }
291 
292 // Decode the register value read from the LTC5556
293 void LTC5556_decode_output(uint8_t output_register) {
294  // Power setting bit read back from the LTC5556
295  uint8_t power_bit_read;
296 
297  // Power setting value read back from the LTC5556
298  String power_setting_read;
299 
300  // Att bits read back from the LTC5556
301  uint8_t att_bits_read;
302 
303  // Attenuation setting value read back from the LTC5556
304  float att_setting_read;
305 
306  // Read bit 7 to get the isel bit back
307  power_bit_read = (output_register & 0x80) >> 7;
308  switch (power_bit_read) {
309  case 0:
310  power_setting_read = "Full Power";
311  break;
312  case 1:
313  power_setting_read = "Low Power";
314  break;
315  }
316 
317  // Print the power setting to the serial monitor
318  Serial.println("Power Setting: " + power_setting_read);
319 
320  // Read bits 0-4 to get attenuation bits back
321  att_bits_read = output_register & 0x1F;
322 
323  // Convert the 5 Attenuation bits (0-31) to an attenuation setting (0-15.5)
324  att_setting_read = (att_bits_read / 2.);
325 
326  // Print the Attenuation setting to the serial monitor
327  Serial.println("Attenuation Setting: " + String(att_setting_read, 1) + " dB");
328 }
329 
uint16_t LTC5556_diff_settings()
Function to apply unique settings for each LTC5556 channel.
Definition: LTC5556.cpp:136
uint8_t mixer_1_value
Global Variables.
Definition: LTC5556.cpp:71
Copyright 2018(c) Analog Devices, Inc.
uint8_t LTC5556_dupl_settings()
Function to duplicate settings for both LTC5556 channels.
Definition: LTC5556.cpp:97
uint16_t whole_register
Definition: LTC5566.cpp:75
Header File for Linduino Libraries and Demo Code.
void LTC5556_write(uint8_t cs, uint16_t tx, uint16_t *rx)
Writes to the LTC5556 twice and reads back the last byte to make sure the LTC5556 was loaded properly...
Definition: LTC5556.cpp:90
uint8_t mixer_2_output
Definition: LTC5556.cpp:86
void LTC5556_decode_output(uint8_t output_register)
Decode the register value read from the LTC5556.
Definition: LTC5556.cpp:293
uint8_t mixer_2_value
Definition: LTC5556.cpp:74
#define LTC5556_CS
Define the SPI CS pin.
Definition: LTC5556.h:72
void spi_transfer_word(uint8_t cs_pin, uint16_t tx, uint16_t *rx)
Reads and sends a word.
Definition: LT_SPI.cpp:98
#define LTC5556_FULL_POWER
Definition: LTC5556.h:77
LT_SPI: Routines to communicate with ATmega328P&#39;s hardware SPI port.
uint8_t mixer_1_output
Definition: LTC5556.cpp:83
int32_t read_int()
float read_float()
prompt
Used to keep track to print voltage or print code.
Definition: DC934A.ino:113
uint8_t LTC5556_get_att(char *prompt)
Get attenuation value from user.
Definition: LTC5556.cpp:240
#define LTC5556_REDUCED_POWER
Definition: LTC5556.h:78
uint16_t register_value
Definition: LTC5556.cpp:77
uint8_t LTC5556_get_power_mode(char *prompt)
Function to get data from user for power mode.
Definition: LTC5556.cpp:196
uint16_t full_output
Definition: LTC5556.cpp:80