adar1000.c
1 /** 2 * MIT License 3 * 4 * Copyright (c) 2020 Jimmy Pentz 5 * 6 * Reach me at: github.com/jgpentz, jpentz1(at)gmail.com 7 * 8 * Permission is hereby granted, free of charge, to any person obtaining a copy 9 * of this software and associated documentation files (the "Software"), to deal 10 * in the Software without restriction, including without limitation the rights 11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sells 12 * copies of the Software, and to permit persons to whom the Software is 13 * furnished to do so, subject to the following conditions: 14 * 15 * The above copyright notice and this permission notice shall be included in all 16 * copies or substantial portions of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 * SOFTWARE. 25 */ 26 /* ADAR1000 4-Channel, X Band and Ku Band Beamformer */ 27 // ---------------------------------------------------------------------------- 28 // Includes 29 // ---------------------------------------------------------------------------- 30 #include "main.h" 31 #include "stm32f7xx_hal.h" 32 #include "stm32f7xx_hal_spi.h" 33 #include "stm32f7xx_hal_gpio.h" 34 #include "adar1000.h" 35 36 37 // ---------------------------------------------------------------------------- 38 // Preprocessor Definitions and Constants 39 // ---------------------------------------------------------------------------- 40 // VM_GAIN is 15 dB of gain in 128 steps. ~0.12 dB per step. 41 // A 15 dB attenuator can be applied on top of these values. 42 const uint8_t VM_GAIN[128] = { 43 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 44 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 45 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 46 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 47 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 48 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 49 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 50 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 51 }; 52 53 // VM_I and VM_Q are the settings for the vector modulator. 128 steps in 360 degrees. ~2.813 degrees per step. 54 const uint8_t VM_I[128] = { 55 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3E, 0x3E, 0x3D, 0x3D, 0x3C, 0x3C, 0x3B, 0x3A, 0x39, 0x38, 0x37, 56 0x36, 0x35, 0x34, 0x33, 0x32, 0x30, 0x2F, 0x2E, 0x2C, 0x2B, 0x2A, 0x28, 0x27, 0x25, 0x24, 0x22, 57 0x21, 0x01, 0x03, 0x04, 0x06, 0x07, 0x08, 0x0A, 0x0B, 0x0D, 0x0E, 0x0F, 0x11, 0x12, 0x13, 0x14, 58 0x16, 0x17, 0x18, 0x19, 0x19, 0x1A, 0x1B, 0x1C, 0x1C, 0x1D, 0x1E, 0x1E, 0x1E, 0x1F, 0x1F, 0x1F, 59 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1E, 0x1E, 0x1D, 0x1D, 0x1C, 0x1C, 0x1B, 0x1A, 0x19, 0x18, 0x17, 60 0x16, 0x15, 0x14, 0x13, 0x12, 0x10, 0x0F, 0x0E, 0x0C, 0x0B, 0x0A, 0x08, 0x07, 0x05, 0x04, 0x02, 61 0x01, 0x21, 0x23, 0x24, 0x26, 0x27, 0x28, 0x2A, 0x2B, 0x2D, 0x2E, 0x2F, 0x31, 0x32, 0x33, 0x34, 62 0x36, 0x37, 0x38, 0x39, 0x39, 0x3A, 0x3B, 0x3C, 0x3C, 0x3D, 0x3E, 0x3E, 0x3E, 0x3F, 0x3F, 0x3F, 63 }; 64 65 const uint8_t VM_Q[128] = { 66 0x20, 0x21, 0x23, 0x24, 0x26, 0x27, 0x28, 0x2A, 0x2B, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x33, 0x34, 67 0x35, 0x36, 0x37, 0x38, 0x38, 0x39, 0x3A, 0x3A, 0x3B, 0x3C, 0x3C, 0x3C, 0x3D, 0x3D, 0x3D, 0x3D, 68 0x3D, 0x3D, 0x3D, 0x3D, 0x3D, 0x3C, 0x3C, 0x3C, 0x3B, 0x3A, 0x3A, 0x39, 0x38, 0x38, 0x37, 0x36, 69 0x35, 0x34, 0x33, 0x31, 0x30, 0x2F, 0x2E, 0x2D, 0x2B, 0x2A, 0x28, 0x27, 0x26, 0x24, 0x23, 0x21, 70 0x20, 0x01, 0x03, 0x04, 0x06, 0x07, 0x08, 0x0A, 0x0B, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x13, 0x14, 71 0x15, 0x16, 0x17, 0x18, 0x18, 0x19, 0x1A, 0x1A, 0x1B, 0x1C, 0x1C, 0x1C, 0x1D, 0x1D, 0x1D, 0x1D, 72 0x1D, 0x1D, 0x1D, 0x1D, 0x1D, 0x1C, 0x1C, 0x1C, 0x1B, 0x1A, 0x1A, 0x19, 0x18, 0x18, 0x17, 0x16, 73 0x15, 0x14, 0x13, 0x11, 0x10, 0x0F, 0x0E, 0x0D, 0x0B, 0x0A, 0x08, 0x07, 0x06, 0x04, 0x03, 0x01, 74 }; 75 76 77 // ---------------------------------------------------------------------------- 78 // Function Definitions 79 // ---------------------------------------------------------------------------- 80 /** 81 * @brief Initialize the ADC on the ADAR by setting the ADC with a 2 MHz clk, 82 * and then enable it. 83 * 84 * @param p_adar[in] Adar pointer Which specifies the device and what function 85 * to use for SPI transfer. 86 * @param broadcast Send the message as a broadcast to all ADARs in the SPI chain 87 * if this set to BROADCAST_ON. 88 * 89 * @warning This is setup to only read temperature sensor data, not the power detectors. 90 */ 91 void Adar_AdcInit(const AdarDevice * p_adar, uint8_t broadcast) 92 { 93 uint8_t data; 94 95 data = ADAR1000_ADC_2MHZ_CLK | ADAR1000_ADC_EN; 96 97 Adar_Write(p_adar, REG_ADC_CONTROL, data, broadcast); 98 } 99 100 101 /** 102 * @brief Read a byte of data from the ADAR. 103 * 104 * @param p_adar[in] Adar pointer Which specifies the device and what function 105 * to use for SPI transfer. 106 * @param broadcast Send the message as a broadcast to all ADARs in the SPI chain 107 * if this set to BROADCAST_ON. 108 * 109 * @return Returns a byte of data that has been converted from the temperature sensor. 110 * 111 * @warning This is setup to only read temperature sensor data, not the power detectors. 112 */ 113 uint8_t Adar_AdcRead(const AdarDevice * p_adar, uint8_t broadcast) 114 { 115 uint8_t data; 116 117 // Start the ADC conversion 118 Adar_Write(p_adar, REG_ADC_CONTROL, ADAR1000_ADC_ST_CONV, broadcast); 119 120 // This is blocking for now... wait until data is converted, then read it 121 while (!(Adar_Read(p_adar, REG_ADC_CONTROL) & 0x01)) 122 { 123 } 124 125 data = Adar_Read(p_adar, REG_ADC_OUT); 126 127 return(data); 128 } 129 130 131 /** 132 * @brief Requests the device info from a specific ADAR and stores it in the 133 * provided AdarDeviceInfo struct. 134 * 135 * @param p_adar[in] Adar pointer Which specifies the device and what function 136 * to use for SPI transfer. 137 * @param info[out] Struct that contains the device info fields. 138 * 139 * @return Returns ADAR_ERROR_NOERROR if information was successfully received and stored in the struct. 140 */ 141 uint8_t Adar_GetDeviceInfo(const AdarDevice * p_adar, AdarDeviceInfo * info) 142 { 143 *((uint8_t *)info) = Adar_Read(p_adar, 0x002); 144 info->chip_type = Adar_Read(p_adar, 0x003); 145 info->product_id = ((uint16_t)Adar_Read(p_adar, 0x004)) << 8; 146 info->product_id |= ((uint16_t)Adar_Read(p_adar, 0x005)) & 0x00ff; 147 info->scratchpad = Adar_Read(p_adar, 0x00A); 148 info->spi_rev = Adar_Read(p_adar, 0x00B); 149 info->vendor_id = ((uint16_t)Adar_Read(p_adar, 0x00C)) << 8; 150 info->vendor_id |= ((uint16_t)Adar_Read(p_adar, 0x00D)) & 0x00ff; 151 info->rev_id = Adar_Read(p_adar, 0x045); 152 153 return(ADAR_ERROR_NOERROR); 154 } 155 156 157 /** 158 * @brief Read the data that is stored in a single ADAR register. 159 * 160 * @param p_adar[in] Adar pointer Which specifies the device and what function 161 * to use for SPI transfer. 162 * @param mem_addr Memory address of the register you wish to read from. 163 * 164 * @return Returns the byte of data that is stored in the desired register. 165 * 166 * @warning This function will clear ADDR_ASCN bits. 167 * @warning The ADAR does not allow for block reads. 168 */ 169 uint8_t Adar_Read(const AdarDevice * p_adar, uint32_t mem_addr) 170 { 171 uint8_t instruction[3]; 172 173 // Set SDO active 174 Adar_Write(p_adar, REG_INTERFACE_CONFIG_A, INTERFACE_CONFIG_A_SDO_ACTIVE, 0); 175 176 instruction[0] = 0x80 | ((p_adar->dev_addr & 0x03) << 5); 177 instruction[0] |= ((0xff00 & mem_addr) >> 8); 178 instruction[1] = (0xff & mem_addr); 179 instruction[2] = 0x00; 180 181 p_adar->Transfer(instruction, p_adar->p_rx_buffer, ADAR1000_RD_SIZE); 182 183 // Set SDO Inactive 184 Adar_Write(p_adar, REG_INTERFACE_CONFIG_A, 0, 0); 185 186 return(p_adar->p_rx_buffer[2]); 187 } 188 189 190 /** 191 * @brief Block memory write to an ADAR device. 192 * 193 * @pre ADDR_ASCN bits in register zero must be set! 194 * 195 * @param p_adar[in] Adar pointer Which specifies the device and what function 196 * to use for SPI transfer. 197 * @param mem_addr Memory address of the register you wish to read from. 198 * @param p_data Pointer to block of data to transfer (must have two unused bytes preceding the data for instruction). 199 * @param size Size of data in bytes, including the two additional leading bytes. 200 * 201 * @warning First two bytes of data will be corrupted if you do not provide two unused leading bytes! 202 */ 203 void Adar_ReadBlock(const AdarDevice * p_adar, uint16_t mem_addr, uint8_t * p_data, uint32_t size) 204 { 205 // Set SDO active 206 Adar_Write(p_adar, REG_INTERFACE_CONFIG_A, INTERFACE_CONFIG_A_SDO_ACTIVE | INTERFACE_CONFIG_A_ADDR_ASCN, 0); 207 208 // Prepare command 209 p_data[0] = 0x80 | ((p_adar->dev_addr & 0x03) << 5); 210 p_data[0] |= ((mem_addr) >> 8) & 0x1F; 211 p_data[1] = (0xFF & mem_addr); 212 213 // Start the transfer 214 p_adar->Transfer(p_data, p_data, size); 215 216 Adar_Write(p_adar, REG_INTERFACE_CONFIG_A, 0, 0); 217 // Return nothing since we assume this is non-blocking and won't wait around 218 } 219 220 221 /** 222 * @brief Sets the Rx/Tx bias currents for the LNA, VM, and VGA to be in either 223 * low power setting or nominal setting. 224 * 225 * @param p_adar[in] Adar pointer Which specifies the device and what function 226 * to use for SPI transfer. 227 * @param p_bias[in] An AdarBiasCurrents struct filled with bias settings 228 * as seen in the datasheet Table 6. SPI Settings for 229 * Different Power Modules 230 * @param broadcast Send the message as a broadcast to all ADARs in the SPI chain 231 * if this set to BROADCAST_ON. 232 * 233 * @return Returns ADAR_ERR_NOERROR if the bias currents were set 234 */ 235 uint8_t Adar_SetBiasCurrents(const AdarDevice * p_adar, AdarBiasCurrents * p_bias, uint8_t broadcast) 236 { 237 uint8_t bias = 0; 238 239 // RX LNA/VGA/VM bias 240 bias = (p_bias->rx_lna & 0x0f); 241 Adar_Write(p_adar, REG_BIAS_CURRENT_RX_LNA, bias, broadcast); // RX LNA bias 242 bias = (p_bias->rx_vga & 0x07 << 3) | (p_bias->rx_vm & 0x07); 243 Adar_Write(p_adar, REG_BIAS_CURRENT_RX, bias, broadcast); // RX VM/VGA bias 244 245 // TX VGA/VM/DRV bias 246 bias = (p_bias->tx_vga & 0x07 << 3) | (p_bias->tx_vm & 0x07); 247 Adar_Write(p_adar, REG_BIAS_CURRENT_TX, bias, broadcast); // TX VM/VGA bias 248 bias = (p_bias->tx_drv & 0x07); 249 Adar_Write(p_adar, REG_BIAS_CURRENT_TX_DRV, bias, broadcast); // TX DRV bias 250 251 return(ADAR_ERROR_NOERROR); 252 } 253 254 255 /** 256 * @brief Set the bias ON and bias OFF voltages for the four PA's and one LNA. 257 * 258 * @pre This will set all 5 bias ON values and all 5 bias OFF values at once. 259 * To enable these bias values, please see the data sheet and ensure that the BIAS_CTRL, 260 * LNA_BIAS_OUT_EN, TR_SOURCE, TX_EN, RX_EN, TR (input to chip), and PA_ON (input to chip) 261 * bits have all been properly set. 262 * 263 * @param p_adar[in] Adar pointer Which specifies the device and what function 264 * to use for SPI transfer. 265 * @param bias_on_voltage Array that contains the bias ON voltages. 266 * @param bias_off_voltage Array that contains the bias OFF voltages. 267 * 268 * @return Returns ADAR_ERR_NOERROR if the bias currents were set 269 */ 270 uint8_t Adar_SetBiasVoltages(const AdarDevice * p_adar, uint8_t bias_on_voltage[5], uint8_t bias_off_voltage[5]) 271 { 272 Adar_SetBit(p_adar, 0x30, 6, BROADCAST_OFF); 273 Adar_SetBit(p_adar, 0x31, 2, BROADCAST_OFF); 274 Adar_SetBit(p_adar, 0x38, 5, BROADCAST_OFF); 275 Adar_Write(p_adar, REG_PA_CH1_BIAS_ON,bias_on_voltage[0], BROADCAST_OFF); 276 Adar_Write(p_adar, REG_PA_CH2_BIAS_ON,bias_on_voltage[1], BROADCAST_OFF); 277 Adar_Write(p_adar, REG_PA_CH3_BIAS_ON,bias_on_voltage[2], BROADCAST_OFF); 278 Adar_Write(p_adar, REG_PA_CH4_BIAS_ON,bias_on_voltage[3], BROADCAST_OFF); 279 280 Adar_Write(p_adar, REG_PA_CH1_BIAS_OFF,bias_off_voltage[0], BROADCAST_OFF); 281 Adar_Write(p_adar, REG_PA_CH2_BIAS_OFF,bias_off_voltage[1], BROADCAST_OFF); 282 Adar_Write(p_adar, REG_PA_CH3_BIAS_OFF,bias_off_voltage[2], BROADCAST_OFF); 283 Adar_Write(p_adar, REG_PA_CH4_BIAS_OFF,bias_off_voltage[3], BROADCAST_OFF); 284 285 Adar_SetBit(p_adar, 0x30, 4, BROADCAST_OFF); 286 Adar_SetBit(p_adar, 0x30, 6, BROADCAST_OFF); 287 Adar_SetBit(p_adar, 0x31, 2, BROADCAST_OFF); 288 Adar_SetBit(p_adar, 0x38, 5, BROADCAST_OFF); 289 Adar_Write(p_adar, REG_LNA_BIAS_ON,bias_on_voltage[4], BROADCAST_OFF); 290 Adar_Write(p_adar, REG_LNA_BIAS_OFF,bias_off_voltage[4], BROADCAST_OFF); 291 292 Adar_ResetBit(p_adar, 0x30, 7, BROADCAST_OFF); 293 Adar_SetBit(p_adar, 0x31, 2, BROADCAST_OFF); 294 Adar_SetBit(p_adar, 0x31, 4, BROADCAST_OFF); 295 Adar_SetBit(p_adar, 0x31, 7, BROADCAST_OFF); 296 297 return(ADAR_ERROR_NOERROR); 298 } 299 300 301 /** 302 * @brief Setup the ADAR to use settings that are transferred over SPI. 303 * 304 * @param p_adar[in] Adar pointer Which specifies the device and what function 305 * to use for SPI transfer. 306 * @param broadcast Send the message as a broadcast to all ADARs in the SPI chain 307 * if this set to BROADCAST_ON. 308 * 309 * @return Returns ADAR_ERR_NOERROR if the bias currents were set 310 */ 311 uint8_t Adar_SetRamBypass(const AdarDevice * p_adar, uint8_t broadcast) 312 { 313 uint8_t data; 314 315 data = (MEM_CTRL_BIAS_RAM_BYPASS | MEM_CTRL_BEAM_RAM_BYPASS); 316 317 Adar_Write(p_adar, REG_MEM_CTL, data, broadcast); 318 319 return(ADAR_ERROR_NOERROR); 320 } 321 322 323 /** 324 * @brief Set the VGA gain value of a Receive channel in dB. 325 * 326 * @param p_adar[in] Adar pointer Which specifies the device and what function 327 * to use for SPI transfer. 328 * @param channel Channel in which to set the gain (1-4). 329 * @param vga_gain_db Gain to be applied to the channel, ranging from 0 - 30 dB. 330 * (Intended operation >16 dB). 331 * @param broadcast Send the message as a broadcast to all ADARs in the SPI chain 332 * if this set to BROADCAST_ON. 333 * 334 * @return Returns ADAR_ERROR_NOERROR if the gain was successfully set. 335 * ADAR_ERROR_FAILED if an invalid channel was selected. 336 * 337 * @warning 0 dB or 15 dB step attenuator may also be turned on, which is why intended operation is >16 dB. 338 */ 339 uint8_t Adar_SetRxVgaGain(const AdarDevice * p_adar, uint8_t channel, uint8_t vga_gain_db, uint8_t broadcast) 340 { 341 uint8_t vga_gain_bits = (uint8_t)(255*vga_gain_db/16); 342 uint32_t mem_addr = 0; 343 344 if((channel == 0) || (channel > 4)) 345 { 346 return(ADAR_ERROR_FAILED); 347 } 348 349 mem_addr = REG_CH1_RX_GAIN + (channel & 0x03); 350 351 // Set gain 352 Adar_Write(p_adar, mem_addr, vga_gain_bits, broadcast); 353 354 // Load the new setting 355 Adar_Write(p_adar, REG_LOAD_WORKING, 0x1, broadcast); 356 357 return(ADAR_ERROR_NOERROR); 358 } 359 360 361 /** 362 * @brief Set the phase of a given receive channel using the I/Q vector modulator. 363 * 364 * @pre According to the given @param phase, this sets the polarity (bit 5) and gain (bits 4-0) 365 * of the @param channel, and then loads them into the working register. 366 * A vector modulator I/Q look-up table has been provided at the beginning of this library. 367 * 368 * @param p_adar[in] Adar pointer Which specifies the device and what function 369 * to use for SPI transfer. 370 * @param channel Channel in which to set the gain (1-4). 371 * @param phase Byte that is used to set the polarity (bit 5) and gain (bits 4-0). 372 * @param broadcast Send the message as a broadcast to all ADARs in the SPI chain 373 * if this set to BROADCAST_ON. 374 * 375 * @return Returns ADAR_ERROR_NOERROR if the phase was successfully set. 376 * ADAR_ERROR_FAILED if an invalid channel was selected. 377 * 378 * @note To obtain your phase: 379 * phase = degrees * 128; 380 * phase /= 360; 381 */ 382 uint8_t Adar_SetRxPhase(const AdarDevice * p_adar, uint8_t channel, uint8_t phase, uint8_t broadcast) 383 { 384 uint8_t i_val = 0; 385 uint8_t q_val = 0; 386 uint32_t mem_addr_i, mem_addr_q; 387 388 if((channel == 0) || (channel > 4)) 389 { 390 return(ADAR_ERROR_FAILED); 391 } 392 393 //phase = phase % 128; 394 i_val = VM_I[phase]; 395 q_val = VM_Q[phase]; 396 397 mem_addr_i = REG_CH1_RX_PHS_I + (channel & 0x03) * 2; 398 mem_addr_q = REG_CH1_RX_PHS_Q + (channel & 0x03) * 2; 399 400 Adar_Write(p_adar, mem_addr_i, i_val, broadcast); 401 Adar_Write(p_adar, mem_addr_q, q_val, broadcast); 402 Adar_Write(p_adar, REG_LOAD_WORKING, 0x1, broadcast); 403 404 return(ADAR_ERROR_NOERROR); 405 } 406 407 408 /** 409 * @brief Set the VGA gain value of a Tx channel in dB. 410 * 411 * @param p_adar[in] Adar pointer Which specifies the device and what function 412 * to use for SPI transfer. 413 * @param broadcast Send the message as a broadcast to all ADARs in the SPI chain 414 * if this set to BROADCAST_ON. 415 * 416 * @return Returns ADAR_ERROR_NOERROR if the bias was successfully set. 417 * ADAR_ERROR_FAILED if an invalid channel was selected. 418 * 419 * @warning 0 dB or 15 dB step attenuator may also be turned on, which is why intended operation is >16 dB. 420 */ 421 uint8_t Adar_SetTxBias(const AdarDevice * p_adar, uint8_t broadcast) 422 { 423 uint8_t vga_bias_bits; 424 uint8_t drv_bias_bits; 425 uint32_t mem_vga_bias; 426 uint32_t mem_drv_bias; 427 428 mem_vga_bias = REG_BIAS_CURRENT_TX; 429 mem_drv_bias = REG_BIAS_CURRENT_TX_DRV; 430 431 // Set bias to nom 432 vga_bias_bits = 0x2D; 433 drv_bias_bits = 0x06; 434 435 // Set bias 436 Adar_Write(p_adar, mem_vga_bias, vga_bias_bits, broadcast); 437 // Set bias 438 Adar_Write(p_adar, mem_drv_bias, drv_bias_bits, broadcast); 439 440 // Load the new setting 441 Adar_Write(p_adar, REG_LOAD_WORKING, 0x2, broadcast); 442 443 return(ADAR_ERROR_NOERROR); 444 } 445 446 447 /** 448 * @brief Set the VGA gain value of a Tx channel. 449 * 450 * @param p_adar[in] Adar pointer Which specifies the device and what function 451 * to use for SPI transfer. 452 * @param channel Tx channel in which to set the gain, ranging from 1 - 4. 453 * @param gain Gain to be applied to the channel, ranging from 0 - 127, 454 * plus the MSb 15dB attenuator (Intended operation >16 dB). 455 * @param broadcast Send the message as a broadcast to all ADARs in the SPI chain 456 * if this set to BROADCAST_ON. 457 * 458 * @return Returns ADAR_ERROR_NOERROR if the gain was successfully set. 459 * ADAR_ERROR_FAILED if an invalid channel was selected. 460 * 461 * @warning 0 dB or 15 dB step attenuator may also be turned on, which is why intended operation is >16 dB. 462 */ 463 uint8_t Adar_SetTxVgaGain(const AdarDevice * p_adar, uint8_t channel, uint8_t gain, uint8_t broadcast) 464 { 465 uint32_t mem_addr; 466 467 if((channel == 0) || (channel > 4)) 468 { 469 return(ADAR_ERROR_FAILED); 470 } 471 472 mem_addr = REG_CH1_TX_GAIN + (channel & 0x03); 473 474 // Set gain 475 Adar_Write(p_adar, mem_addr, gain, broadcast); 476 477 // Load the new setting 478 Adar_Write(p_adar, REG_LOAD_WORKING, LD_WRK_REGS_LDTX_OVERRIDE, broadcast); 479 480 return(ADAR_ERROR_NOERROR); 481 } 482 483 484 /** 485 * @brief Set the phase of a given transmit channel using the I/Q vector modulator. 486 * 487 * @pre According to the given @param phase, this sets the polarity (bit 5) and gain (bits 4-0) 488 * of the @param channel, and then loads them into the working register. 489 * A vector modulator I/Q look-up table has been provided at the beginning of this library. 490 * 491 * @param p_adar[in] Adar pointer Which specifies the device and what function 492 * to use for SPI transfer. 493 * @param channel Channel in which to set the gain (1-4). 494 * @param phase Byte that is used to set the polarity (bit 5) and gain (bits 4-0). 495 * @param broadcast Send the message as a broadcast to all ADARs in the SPI chain 496 * if this set to BROADCAST_ON. 497 * 498 * @return Returns ADAR_ERROR_NOERROR if the phase was successfully set. 499 * ADAR_ERROR_FAILED if an invalid channel was selected. 500 * 501 * @note To obtain your phase: 502 * phase = degrees * 128; 503 * phase /= 360; 504 */ 505 uint8_t Adar_SetTxPhase(const AdarDevice * p_adar, uint8_t channel, uint8_t phase, uint8_t broadcast) 506 { 507 uint8_t i_val = 0; 508 uint8_t q_val = 0; 509 uint32_t mem_addr_i, mem_addr_q; 510 511 if((channel == 0) || (channel > 4)) 512 { 513 return(ADAR_ERROR_FAILED); 514 } 515 516 //phase = phase % 128; 517 i_val = VM_I[phase]; 518 q_val = VM_Q[phase]; 519 520 mem_addr_i = REG_CH1_TX_PHS_I + (channel & 0x03) * 2; 521 mem_addr_q = REG_CH1_TX_PHS_Q + (channel & 0x03) * 2; 522 523 Adar_Write(p_adar, mem_addr_i, i_val, broadcast); 524 Adar_Write(p_adar, mem_addr_q, q_val, broadcast); 525 Adar_Write(p_adar, REG_LOAD_WORKING, 0x1, broadcast); 526 527 return(ADAR_ERROR_NOERROR); 528 } 529 530 531 /** 532 * @brief Reset the whole ADAR device. 533 * 534 * @param p_adar[in] ADAR pointer Which specifies the device and what function 535 * to use for SPI transfer. 536 */ 537 void Adar_SoftReset(const AdarDevice * p_adar) 538 { 539 uint8_t instruction[3]; 540 541 instruction[0] = ((p_adar->dev_addr & 0x03) << 5); 542 instruction[1] = 0x00; 543 instruction[2] = 0x81; 544 545 p_adar->Transfer(instruction, NULL, sizeof(instruction)); 546 } 547 548 549 /** 550 * @brief Reset ALL ADAR devices in the SPI chain. 551 * 552 * @param p_adar[in] Adar pointer Which specifies the device and what function 553 * to use for SPI transfer. 554 */ 555 void Adar_SoftResetAll(const AdarDevice * p_adar) 556 { 557 uint8_t instruction[3]; 558 559 instruction[0] = 0x08; 560 instruction[1] = 0x00; 561 instruction[2] = 0x81; 562 563 p_adar->Transfer(instruction, NULL, sizeof(instruction)); 564 } 565 566 567 /** 568 * @brief Write a byte of @param data to the register located at @param mem_addr. 569 * 570 * @param p_adar[in] Adar pointer Which specifies the device and what function 571 * to use for SPI transfer. 572 * @param mem_addr Memory address of the register you wish to read from. 573 * @param data Byte of data to be stored in the register. 574 * @param broadcast Send the message as a broadcast to all ADARs in the SPI chain 575 if this set to BROADCAST_ON. 576 * 577 * @warning If writing the same data to multiple registers, use ADAR_WriteBlock. 578 */ 579 void Adar_Write(const AdarDevice * p_adar, uint32_t mem_addr, uint8_t data, uint8_t broadcast) 580 { 581 uint8_t instruction[3]; 582 583 if (broadcast) 584 { 585 instruction[0] = 0x08; 586 } 587 else 588 { 589 instruction[0] = ((p_adar->dev_addr & 0x03) << 5); 590 } 591 592 instruction[0] |= (0x1F00 & mem_addr) >> 8; 593 instruction[1] = (0xFF & mem_addr); 594 instruction[2] = data; 595 596 p_adar->Transfer(instruction, NULL, sizeof(instruction)); 597 } 598 599 600 /** 601 * @brief Block memory write to an ADAR device. 602 * 603 * @pre ADDR_ASCN BITS IN REGISTER ZERO MUST BE SET! 604 * 605 * @param p_adar[in] Adar pointer Which specifies the device and what function 606 * to use for SPI transfer. 607 * @param mem_addr Memory address of the register you wish to read from. 608 * @param p_data[in] Pointer to block of data to transfer (must have two unused bytes 609 preceding the data for instruction). 610 * @param size Size of data in bytes, including the two additional leading bytes. 611 * 612 * @warning First two bytes of data will be corrupted if you do not provide two unused leading bytes! 613 */ 614 void Adar_WriteBlock(const AdarDevice * p_adar, uint16_t mem_addr, uint8_t * p_data, uint32_t size) 615 { 616 // Prepare command 617 p_data[0] = ((p_adar->dev_addr & 0x03) << 5); 618 p_data[0] |= ((mem_addr) >> 8) & 0x1F; 619 p_data[1] = (0xFF & mem_addr); 620 621 // Start the transfer 622 p_adar->Transfer(p_data, NULL, size); 623 624 // Return nothing since we assume this is non-blocking and won't wait around 625 } 626 627 628 /** 629 * @brief Set contents of the INTERFACE_CONFIG_A register. 630 * 631 * @param p_adar[in] Adar pointer Which specifies the device and what function 632 * to use for SPI transfer. 633 * @param flags #INTERFACE_CONFIG_A_SOFTRESET, #INTERFACE_CONFIG_A_LSB_FIRST, 634 * #INTERFACE_CONFIG_A_ADDR_ASCN, #INTERFACE_CONFIG_A_SDO_ACTIVE 635 * @param broadcast Send the message as a broadcast to all ADARs in the SPI chain 636 * if this set to BROADCAST_ON. 637 */ 638 void Adar_WriteConfigA(const AdarDevice * p_adar, uint8_t flags, uint8_t broadcast) 639 { 640 Adar_Write(p_adar, 0x00, flags, broadcast); 641 } 642 643 644 /** 645 * @brief Write a byte of @param data to the register located at @param mem_addr and 646 * then read from the device and verify that the register was correctly set. 647 * 648 * @param p_adar[in] Adar pointer Which specifies the device and what function 649 * to use for SPI transfer. 650 * @param mem_addr Memory address of the register you wish to read from. 651 * @param data Byte of data to be stored in the register. 652 * 653 * @return Returns the number of attempts that it took to successfully write to a register, 654 * starting from zero. 655 * @warning This function currently only supports writes to a single regiter in a single ADAR. 656 */ 657 uint8_t Adar_WriteVerify(const AdarDevice * p_adar, uint32_t mem_addr, uint8_t data) 658 { 659 uint8_t rx_data; 660 661 for (uint8_t ii = 0; ii < 3; ii++) 662 { 663 Adar_Write(p_adar, mem_addr, data, 0); 664 665 // Can't read back from an ADAR with HW address 0 666 if (!((p_adar->dev_addr) % 4)) 667 { 668 return(ADAR_ERROR_INVALIDADDR); 669 } 670 rx_data = Adar_Read(p_adar, mem_addr); 671 if (rx_data == data) 672 { 673 return(ii); 674 } 675 } 676 677 return(ADAR_ERROR_FAILED); 678 } 679 680 void Adar_SetBit(const AdarDevice * p_adar, uint32_t mem_addr, uint8_t bit, uint8_t broadcast) 681 { 682 uint8_t temp = Adar_Read(p_adar, mem_addr); 683 uint8_t data = temp|(1<<bit); 684 Adar_Write(p_adar,mem_addr, data,broadcast); 685 } 686 687 void Adar_ResetBit(const AdarDevice * p_adar, uint32_t mem_addr, uint8_t bit, uint8_t broadcast) 688 { 689 uint8_t temp = Adar_Read(p_adar, mem_addr); 690 uint8_t data = temp&~(1<<bit); 691 Adar_Write(p_adar,mem_addr, data,broadcast); 692 } 693