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