Skip to content

Commit d982420

Browse files
committed
drivers: rf-transceiver: navassa: Added README documentation for ADRV9001/2 driver
Added the readme file for the ADRV9001 device driver. Also modified the sphinx drivers_doc.rst file to add the corresponding source for this new readme. Signed-off-by: Joyce Velasco <joyce.velasco@analog.com>
1 parent be307b5 commit d982420

File tree

3 files changed

+295
-0
lines changed

3 files changed

+295
-0
lines changed

doc/sphinx/source/drivers/navassa.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.. include:: ../../../../drivers/rf-transceiver/navassa/README.rst

doc/sphinx/source/drivers_doc.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ RF TRANSCEIVER
100100
:maxdepth: 1
101101

102102
drivers/madura
103+
drivers/navassa
103104

104105
TEMPERATURE
105106
==============
Lines changed: 293 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,293 @@
1+
ADRV9001 no-OS Driver
2+
====================
3+
4+
Supported Devices
5+
-----------------
6+
7+
- :adi:`ADRV9002`
8+
9+
Overview
10+
--------
11+
12+
The ADRV9002 is a dual-mode RF transceiver supporting both narrow-band
13+
and wideband operations from 30 MHz to 6000 MHz, suitable for VHF, UHF,
14+
ISM, and cellular bands with bandwidths up to 40 MHz. It features dual
15+
transmitters and receivers, customizable synthesizers, and digital
16+
filters for improved performance. The transceiver supports TDD and FDD
17+
applications, offering high linearity and dynamic range, and includes
18+
capabilities such as low power monitoring, dynamic profile switching,
19+
rapid frequency hopping, and synchronization across multiple chips. In
20+
addition, several auxiliary functions, such as auxiliary
21+
analog-to-digital converters (ADCs), auxiliary digital-to-analog
22+
converters (DACs), and general-purpose inputs/outputs (GPIOs), are
23+
integrated to provide additional monitoring and control capability.
24+
25+
Applications
26+
------------
27+
28+
- Mission Critical Communications
29+
- Very High Frequency (VHF), Ultra High Frequency (UHF),
30+
and Cellular to 6 GHz
31+
- Time Division Duplex (TDD) and Frequency Division Duplex (FDD)
32+
Applications
33+
34+
Operation Modes
35+
---------------
36+
37+
+-------------------------+-------------------------+-----------------+-------------------------+
38+
| Mode Name | Description | Configuration | Typical Use |
39+
| | | Bits | Case |
40+
+-------------------------+-------------------------+-----------------+-------------------------+
41+
| ADI_ADRV9001_LDO_POWER_ | Sets all LDO power | 0x00 | Used during low-power |
42+
| SAVING_MODE_1 | saving modes for the | | operations to save |
43+
| | device. | | power. |
44+
+-------------------------+-------------------------+-----------------+-------------------------+
45+
| ADI_ADRV9001_SPI_MODE | Allows operations | SPI | Used when direct |
46+
| | through the SPI | | control via SPI is |
47+
| | interface. | | required. |
48+
+-------------------------+-------------------------+-----------------+-------------------------+
49+
| ADI_ADRV9001_CHANNEL_ | State in which the | Channel Mask | Initial state for |
50+
| PRIMED | channel is ready but | | channels in TDD mode. |
51+
| | not transmitting/ | | |
52+
| | receiving. | | |
53+
+-------------------------+-------------------------+-----------------+-------------------------+
54+
| ADI_ADRV9001_CHANNEL_ | State allowing full RF | N/A | Used in FDD mode for |
55+
| RF_ENABLED | functionality. | | active transmission/ |
56+
| | | | reception. |
57+
+-------------------------+-------------------------+-----------------+-------------------------+
58+
| ADI_ADRV9001_INT_LO1 | Uses internal LO1 for | LO1 | Standard operation with |
59+
| | operations. | Configuration | internal local |
60+
| | | | oscillator. |
61+
+-------------------------+-------------------------+-----------------+-------------------------+
62+
63+
Device Configuration
64+
--------------------
65+
66+
Initialization and Configuration
67+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
68+
69+
The ADRV9002 initialization and configuration functions handle initial
70+
setup, ensuring optimal operation of the RF transceiver. Key functions
71+
like ``adrv9002_setup`` integrate device channels, configure GPIOs,
72+
manage power, and perform initial calibrations. These operations align
73+
the device parameters with application-specific requirements,
74+
facilitating effective device boot-up and functionality. Key operations
75+
include implementing error-handling routines throughout the
76+
initialization process to report and manage issues encountered, allowing
77+
for a robust configuration adaptable to numerous RF applications.
78+
79+
Transceiver Path Management
80+
~~~~~~~~~~~~~~~~~~~~~~~~~~~
81+
82+
Transceiver path management functions in the ADRV9002 handle the
83+
configuration of RX and TX paths, adjusting gain, transmit power, and
84+
data interfaces to meet specific operation needs. For instance,
85+
``adrv9002_tx_path_config`` and ``adrv9001_rx_path_config`` set channel
86+
states and apply gain control settings through API calls. These
87+
functions ensure that the signal paths remain robust under various
88+
operational modes, such as TDD and FDD. They dynamically manage the
89+
transceiver’s performance metrics to maintain signal integrity aligned
90+
with predetermined operational conditions.
91+
92+
Frequency Hopping and Calibration
93+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
94+
95+
These functions support dynamic frequency switching and system
96+
calibration tasks, vital for efficient multi-frequency operations. The
97+
frequency hopping is managed through modes and configurations set during
98+
initialization with precise timing requirements, allowing the ADRV9002
99+
to dynamically adapt its operating frequency to limit interference, as
100+
seen in frequency hopping functions that control PLL retunes and hop
101+
tables efficiently. Calibration routines like
102+
``adi_adrv9001_cals_InitCals_Run`` maintain performance by aligning
103+
internal parameters with environmental conditions and hardware states,
104+
offset by the frequency hopping capabilities.
105+
106+
Test Pattern and Performance Tuning
107+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
108+
109+
Performance tuning functions for the ADRV9002 focus on validating and
110+
enhancing signal integrity through digital interface tuning and test
111+
pattern configurations. Functions like
112+
``adrv9002_axi_tx_test_pattern_set`` and
113+
``adrv9002_axi_rx_test_pattern_pn_sel`` set specific test patterns and
114+
perform interface tuning to optimize transmission and reception paths.
115+
These tasks involve iterative adjustments of clock and data delays,
116+
logging test results, and storing configurations, creating a refined
117+
tuning approach that ensures device operation at desired performance
118+
thresholds. Functions like ``adrv9002_check_tx_test_pattern`` further
119+
assess signal correctness, providing a comprehensive tuning suite.
120+
121+
Driver Initialization Example
122+
-----------------------------
123+
124+
.. code-block:: C
125+
126+
#include <stdio.h>
127+
#include "no_os_spi.h"
128+
#include "no_os_gpio.h"
129+
#include "no_os_error.h"
130+
#include "adrv9002.h"
131+
132+
struct no_os_spi_init_param spi_init = {
133+
.device_id = XPAR_PS7_SPI_0_DEVICE_ID,
134+
.max_speed_hz = 20000000,
135+
.mode = NO_OS_SPI_MODE_0,
136+
.chip_select = 0,
137+
.platform_ops = &xil_spi_ops,
138+
};
139+
140+
struct no_os_gpio_init_param gpio_reset_init = {
141+
.number = 46 + GPIO_OFFSET,
142+
.platform_ops = &xil_gpio_ops,
143+
};
144+
145+
struct no_os_gpio_desc *gpio_reset;
146+
struct no_os_spi_desc *spi_desc;
147+
148+
struct adrv9002_hal_cfg *phal = (struct adrv9002_hal_cfg *)devHalCfg;
149+
150+
/* Initialize GPIO for reset */
151+
ret = no_os_gpio_get(&gpio_reset, &gpio_reset_init);
152+
if (ret) {
153+
printf("GPIO initialization failed\n");
154+
return ret;
155+
}
156+
157+
ret = no_os_gpio_direction_output(gpio_reset, NO_OS_GPIO_LOW);
158+
if (ret) {
159+
printf("GPIO direction set failed\n");
160+
return ret;
161+
}
162+
163+
/* Initialize SPI */
164+
ret = no_os_spi_init(&spi_desc, &spi_init);
165+
if (ret) {
166+
printf("SPI initialization failed\n");
167+
return ret;
168+
}
169+
170+
/* Reset the device */
171+
ret = no_os_gpio_set_value(gpio_reset, NO_OS_GPIO_HIGH);
172+
if (ret) {
173+
printf("GPIO set value failed\n");
174+
return ret;
175+
}
176+
177+
printf("Driver initialization complete\n");
178+
179+
/* Cleanup */
180+
no_os_gpio_remove(gpio_reset);
181+
no_os_spi_remove(spi_desc);
182+
183+
return 0;
184+
}
185+
186+
IIO Initialization Example
187+
--------------------------
188+
189+
.. code-block:: C
190+
191+
#define IIO_DEV_COUNT 2 // Define the number of IIO devices
192+
193+
/* Define ADC and DAC buffers */
194+
static uint8_t adc_buffers[IIO_DEV_COUNT][1024];
195+
static uint8_t dac_buffers[IIO_DEV_COUNT][1024];
196+
197+
/* Define ADC and DAC initialization parameters */
198+
static struct iio_axi_adc_init_param adc_pars[IIO_DEV_COUNT] = {
199+
// ...initialize ADC parameters for each device...
200+
};
201+
202+
static struct iio_axi_dac_init_param dac_pars[IIO_DEV_COUNT] = {
203+
// ...initialize DAC parameters for each device...
204+
};
205+
206+
static int32_t iio_run(struct iio_axi_adc_init_param *adc_pars,
207+
struct iio_axi_dac_init_param *dac_pars)
208+
{
209+
struct iio_axi_adc_desc *adcs[IIO_DEV_COUNT] = {0};
210+
struct iio_axi_dac_desc *dacs[IIO_DEV_COUNT] = {0};
211+
struct iio_data_buffer iio_dac_buffers[IIO_DEV_COUNT];
212+
struct iio_data_buffer iio_adc_buffers[IIO_DEV_COUNT];
213+
struct iio_device *iio_descs[IIO_DEV_COUNT * 2];
214+
struct iio_app_device app_devices[IIO_DEV_COUNT * 2] = {0};
215+
struct xil_uart_init_param platform_uart_init_par = {
216+
.type = UART_PS,
217+
.irq_id = UART_IRQ_ID
218+
};
219+
220+
struct no_os_uart_init_param iio_uart_ip = {
221+
.device_id = UART_DEVICE_ID,
222+
.irq_id = UART_IRQ_ID,
223+
.baud_rate = UART_BAUDRATE,
224+
.size = NO_OS_UART_CS_8,
225+
.parity = NO_OS_UART_PAR_NO,
226+
.stop = NO_OS_UART_STOP_1_BIT,
227+
.extra = &platform_uart_init_par,
228+
.platform_ops = &xil_uart_ops
229+
};
230+
231+
struct iio_app_desc *app;
232+
struct iio_app_init_param app_init_param = {0};
233+
int32_t i, ret;
234+
int32_t a; // Linear iterator for iio_descs and app_devices flat arrays
235+
236+
for (i = 0; i < IIO_DEV_COUNT; i++) {
237+
/* ADC setup */
238+
iio_adc_buffers[i].buff = adc_buffers[i];
239+
iio_adc_buffers[i].size = sizeof(adc_buffers[i]);
240+
ret = iio_axi_adc_init(&adcs[i], &adc_pars[i]);
241+
if (ret < 0) {
242+
printf("ADC initialization failed for device %d\n", i);
243+
goto cleanup;
244+
}
245+
a = 2 * i;
246+
iio_axi_adc_get_dev_descriptor(adcs[i], &iio_descs[a]);
247+
app_devices[a].name = adc_pars[i].rx_adc->name;
248+
app_devices[a].dev = adcs[i];
249+
app_devices[a].dev_descriptor = iio_descs[a];
250+
app_devices[a].read_buff = &iio_adc_buffers[i];
251+
252+
/* DAC setup */
253+
iio_dac_buffers[i].buff = dac_buffers[i];
254+
iio_dac_buffers[i].size = sizeof(dac_buffers[i]);
255+
ret = iio_axi_dac_init(&dacs[i], &dac_pars[i]);
256+
if (ret < 0) {
257+
printf("DAC initialization failed for device %d\n", i);
258+
goto cleanup;
259+
}
260+
a = 2 * i + 1;
261+
iio_axi_dac_get_dev_descriptor(dacs[i], &iio_descs[a]);
262+
app_devices[a].name = dac_pars[i].tx_dac->name;
263+
app_devices[a].dev = dacs[i];
264+
app_devices[a].dev_descriptor = iio_descs[a];
265+
app_devices[a].write_buff = &iio_dac_buffers[i];
266+
}
267+
268+
app_init_param.devices = app_devices;
269+
app_init_param.nb_devices = NO_OS_ARRAY_SIZE(app_devices);
270+
app_init_param.uart_init_params = iio_uart_ip;
271+
272+
ret = iio_app_init(&app, app_init_param);
273+
if (ret) {
274+
printf("IIO application initialization failed\n");
275+
goto cleanup;
276+
}
277+
278+
ret = iio_app_run(app);
279+
if (ret) {
280+
printf("IIO application run failed\n");
281+
}
282+
283+
cleanup:
284+
for (i = 0; i < IIO_DEV_COUNT; i++) {
285+
if (adcs[i]) {
286+
iio_axi_adc_remove(adcs[i]);
287+
}
288+
if (dacs[i]) {
289+
iio_axi_dac_remove(dacs[i]);
290+
}
291+
}
292+
return ret;
293+
}

0 commit comments

Comments
 (0)