| 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
83 uint8_t mixer_1_output;
84
85 // 8 bit output from mixer 2
86 uint8_t mixer_2_output;
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
97 uint8_t LTC5556_dupl_settings() {
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
136 uint16_t LTC5556_diff_settings() {
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
196 uint8_t LTC5556_get_power_mode(char *prompt) {
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
LTC5556_diff_settings
uint16_t LTC5556_diff_settings()
Function to apply unique settings for each LTC5556 channel.
Definition: LTC5556.cpp:136
mixer_1_value
uint8_t mixer_1_value
Global Variables.
Definition: LTC5556.cpp:71
LTC5556.h
Copyright 2018(c) Analog Devices, Inc.
LTC5556_dupl_settings
uint8_t LTC5556_dupl_settings()
Function to duplicate settings for both LTC5556 channels.
Definition: LTC5556.cpp:97
whole_register
uint16_t whole_register
Definition: LTC5566.cpp:75
Linduino.h
Header File for Linduino Libraries and Demo Code.
LTC5556_write
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
mixer_2_output
uint8_t mixer_2_output
Definition: LTC5556.cpp:86
LTC5556_decode_output
void LTC5556_decode_output(uint8_t output_register)
Decode the register value read from the LTC5556.
Definition: LTC5556.cpp:293
mixer_2_value
uint8_t mixer_2_value
Definition: LTC5556.cpp:74
LTC5556_CS
#define LTC5556_CS
Define the SPI CS pin.
Definition: LTC5556.h:72
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
LTC5556_FULL_POWER
#define LTC5556_FULL_POWER
Definition: LTC5556.h:77
LT_SPI.h
LT_SPI: Routines to communicate with ATmega328P&#39;s hardware SPI port.
UserInterface.h
mixer_1_output
uint8_t mixer_1_output
Definition: LTC5556.cpp:83
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
LTC5556_get_att
uint8_t LTC5556_get_att(char *prompt)
Get attenuation value from user.
Definition: LTC5556.cpp:240
LTC5556_REDUCED_POWER
#define LTC5556_REDUCED_POWER
Definition: LTC5556.h:78
register_value
uint16_t register_value
Definition: LTC5556.cpp:77
LTC5556_get_power_mode
uint8_t LTC5556_get_power_mode(char *prompt)
Function to get data from user for power mode.
Definition: LTC5556.cpp:196
full_output
uint16_t full_output
Definition: LTC5556.cpp:80