Wiki

This version (03 Jan 2021 21:47) was approved by Robin Getz.The Previously approved version (27 Oct 2020 13:43) is available.Diff

ADAR1000 8 GHz to 16 GHz, 4-Channel, X Band and KuBand Beamformer Linux device driver

The ADAR1000 is a 4-channel, X and Ku frequency band, beamforming core chip for phased arrays. This device operates in half-duplex between receive and transmit modes. In receive mode, input signals pass through four receive channels and are combined in a common RF_IO pin. In transmit mode, the RF_IO input signal is split and passes through the four transmit channels. In both modes, the ADAR1000 provides a ≥31 dB gain adjustment range and a full 360° phase adjustment range in the radio frequency (RF) path, with 6-bit resolution (less than ≤0.5 dB and 2.8°, respectively).

Supported Devices

Evaluation Boards

Description

This is a Linux industrial I/O (IIO) subsystem driver, targeting RF Transceivers. The industrial I/O subsystem provides a unified framework for drivers for many different types of converters and sensors using a number of different physical interfaces (i2c, spi, etc). See IIO for more information.

Source Code

Status

Source Mainlined?
git No

Files

Example Linux Device-Tree Initialization

The ADAR1000 driver is a spi-bus driver and can currently only be instantiated via device tree.

Required devicetree properties:

  • compatible: Should always be “adi,adar1000”
  • reg: SPI slave select number
Function File
RPI Device Tree rpi-adar1000-overlay.dts

Enabling Linux driver support

Configure kernel with “make menuconfig” (alternatively use “make xconfig” or “make qconfig”)

The ADAR1000 driver depends on CONFIG_SPI

Adding Linux driver support

Configure kernel with “make menuconfig” (alternatively use “make xconfig” or “make qconfig”)

Linux Kernel Configuration
	Device Drivers  --->
	<*>     Industrial I/O support --->
	    --- Industrial I/O support
	    -*-   Enable ring buffer support within IIO
	    -*-     Industrial I/O lock free software ring
	    -*-   Enable triggered sampling support

	          *** Analog to digital converters ***
	    [--snip--]

		<*>   Analog Devices ADAR1000 Beamformer driver 

	    [--snip--]

Driver testing / API

Each and every IIO device, typically a hardware chip, has a device folder under /sys/bus/iio/devices/iio:deviceX. Where X is the IIO index of the device. Under every of these directory folders reside a set of files, depending on the characteristics and features of the hardware device in question. These files are consistently generalized and documented in the IIO ABI documentation. In order to determine which IIO deviceX corresponds to which hardware device, the user can read the name file /sys/bus/iio/devices/iio:deviceX/name. In case the sequence in which the iio device drivers are loaded/registered is constant, the numbering is constant and may be known in advance.

02 Mar 2011 15:16

General attribute naming convention:
in_voltage0_[…]: targets RX1
in_voltage1_[…]: targets RX2

out_voltage0_[…]: targets TX1
out_voltage1_[…]: targets TX2

This specifies any shell prompt running on the target

root:/> cd /sys/bus/iio/devices/
root:/sys/bus/iio/devices> ls
iio:device0  iio:device1  iio:device2  iio:device3 

root:/sys/bus/iio/devices> cd iio:device0

root:/sys/bus/iio/devices/iio:device1# ls -l
total 0
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 bias_current_rx
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 bias_current_rx_lna
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 bias_current_tx
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 bias_current_tx_drv
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 dev
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 gen_clk_cycles
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 in_temp0_raw
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 in_voltage0_RX_beam_pos_load
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 in_voltage0_RX_beam_pos_save
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 in_voltage0_RX_hardwaregain
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 in_voltage0_RX_phase
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 in_voltage0_RX_powerdown
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 in_voltage1_RX_beam_pos_load
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 in_voltage1_RX_beam_pos_save
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 in_voltage1_RX_hardwaregain
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 in_voltage1_RX_phase
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 in_voltage1_RX_powerdown
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 in_voltage2_RX_beam_pos_load
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 in_voltage2_RX_beam_pos_save
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 in_voltage2_RX_hardwaregain
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 in_voltage2_RX_phase
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 in_voltage2_RX_powerdown
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 in_voltage3_RX_beam_pos_load
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 in_voltage3_RX_beam_pos_save
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 in_voltage3_RX_hardwaregain
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 in_voltage3_RX_phase
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 in_voltage3_RX_powerdown
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 in_voltage_bias_set_load
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 in_voltage_bias_set_save
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 in_voltage_sequence_end
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 in_voltage_sequence_start
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 label
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 lna_bias_off
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 lna_bias_on
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 name
lrwxrwxrwx 1 root root    0 Oct 27 09:10 of_node -> ../../../../../../../../firmware/devicetree/base/fpga-axi@0/axi_quad_spi@85200000/adar1000@1/dev@0
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 out_voltage0_TX_beam_pos_load
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 out_voltage0_TX_beam_pos_save
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 out_voltage0_TX_detector_en
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 out_voltage0_TX_hardwaregain
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 out_voltage0_TX_pa_bias_off
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 out_voltage0_TX_pa_bias_on
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 out_voltage0_TX_phase
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 out_voltage0_TX_powerdown
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 out_voltage0_TX_raw
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 out_voltage1_TX_beam_pos_load
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 out_voltage1_TX_beam_pos_save
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 out_voltage1_TX_detector_en
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 out_voltage1_TX_hardwaregain
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 out_voltage1_TX_pa_bias_off
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 out_voltage1_TX_pa_bias_on
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 out_voltage1_TX_phase
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 out_voltage1_TX_powerdown
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 out_voltage1_TX_raw
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 out_voltage2_TX_beam_pos_load
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 out_voltage2_TX_beam_pos_save
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 out_voltage2_TX_detector_en
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 out_voltage2_TX_hardwaregain
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 out_voltage2_TX_pa_bias_off
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 out_voltage2_TX_pa_bias_on
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 out_voltage2_TX_phase
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 out_voltage2_TX_powerdown
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 out_voltage2_TX_raw
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 out_voltage3_TX_beam_pos_load
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 out_voltage3_TX_beam_pos_save
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 out_voltage3_TX_detector_en
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 out_voltage3_TX_hardwaregain
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 out_voltage3_TX_pa_bias_off
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 out_voltage3_TX_pa_bias_on
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 out_voltage3_TX_phase
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 out_voltage3_TX_powerdown
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 out_voltage3_TX_raw
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 out_voltage_bias_set_load
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 out_voltage_bias_set_save
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 out_voltage_sequence_end
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 out_voltage_sequence_start
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 phase_table_config
drwxrwxrwx 2 root root    0 Oct 27 09:10 power
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 reset
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 rx_lna_enable
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 rx_vga_enable
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 rx_vm_enable
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 sequencer_enable
lrwxrwxrwx 1 root root    0 Oct 27 09:10 subsystem -> ../../../../../../../../bus/iio
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 tx_lna_enable
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 tx_vga_enable
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 tx_vm_enable
-rw-rw-rw- 1 root root 4096 Oct 27 09:10 uevent
root:/sys/bus/iio/devices/iio:device0#

Show device name

This specifies any shell prompt running on the target

root:/sys/bus/iio/devices/iio:device0> cat name
adar1000

RX/TX Phase Control

The default phase control is provided by table 13 of the ADAR1000 datasheet. This is the configuration used at device startup.

Standard Table:

Phase (Degrees) I Reg (Hex) Q Reg (Hex)
0 … 360 0x3F 0x20

Custom phase tables can be loaded automatically during driver probe or anytime later via the phase_table_config sysfs attribute. Tables must be stored in the /firmware folder, or compiled into the kernel using the CONFIG_FIRMWARE_IN_KERNEL, CONFIG_EXTRA_FIRMWARE config options. The table loaded during driver probe can be specified using following device tree property:

adi,phasetable-name = “adar1000_std_phasetable”;

In case no table is specified or loaded, the driver will continue to use the provided standard phase table.

Phase table is stored in a human readable file, with the format specified below.

Example: adar1000_std_phasetable

 
 <phasetable [ADAR1000] table entries=no_of_entries>
 phase_in_degrees, reg_I, reg_Q
 phase_in_degrees, reg_I, reg_Q
 phase_in_degrees, reg_I, reg_Q
 …
 </phasetable>

Assumptions:

  • phase tables must be monotonic

Loading a gain table

This specifies any shell prompt running on the target

root@analog:/sys/bus/iio/devices/iio:device0# ls /firmware/adar*
adar1000_std_phasetable  

root@analog:/sys/bus/iio/devices/iio:device0# cat /firmware/adar1000_std_phasetable > phase_table_config

Reading a gain table

Reading the phase_table_config attribute returns the current phase table that is loaded into the IC. The printed format matches the format used in the phasetable file.

This specifies any shell prompt running on the target

root@analog:/sys/bus/iio/devices/iio:device0# cat phase_table_config 
<phasetable ADAR1000 table entries=64>
0.000, 0x3F, 0x20
2.812, 0x3F, 0x21
5.625, 0x3F, 0x23
8.437, 0x3F, 0x24
11.250, 0x3F, 0x26
14.040, 0x3E, 0x27
16.875, 0x3E, 0x28
19.687, 0x3D, 0x2A
22.500, 0x3D, 0x2B
25.312, 0x3C, 0x2D

[--snip--]

165.937, 0x1E, 0x27
168.750, 0x1E, 0x26
171.562, 0x1F, 0x24
174.375, 0x1F, 0x23
177.187, 0x1F, 0x21
</phasetable>

RAM memory access

On-chip RAM is provided for storing phase and amplitude settings for up to 121 beam positions and seven bias settings for both transmit and receive modes.

Save/Load beam position

A beam position can be written to ram and loaded afterwards from that memory location (index).

Save beam position command

 
echo 0, -11.0, 15.4 > /sys/bus/iio/devices/iio\:device0/in_voltage1_RX_beam_pos_save

This command can be decoded using this enumeration:

beam_position, gain_value, phase_value

Values for gain_value and phase_value must be in integer and fractional part. beam_position can take values from 0 to 120.

Load beam position command

 
echo 10 > in_voltage1_RX_beam_pos_load

To load a position just write the position number in the load attribute for the required channel.

Save/Load bias settings

Seven memory locations are also provided for storing bias settings for all the transmit and receive channel subcircuits.

Save RX bias settings

 
echo 0, 1, 2, 3, 4 > in_voltage_bias_set_save

The values written here correspond the the following diagram:

bias_setting_index, LNA_BIAS_OFF, LNA_BIAS_ON, BIAS_CURRENT_RX, BIAS_CURRENT_RX_LNA

Save TX bias settings

 
echo 1, 10, 2, 3, 5, 6, 7, 8, 9, 10, 11 > out_voltage_bias_set_save

The values written here correspond the the following diagram:

bias_setting_index, CH1_PA_BIAS_OFF, CH2_PA_BIAS_OFF, CH3_PA_BIAS_OFF, CH1_PA_BIAS_ON, CH2_PA_BIAS_ON, CH3_PA_BIAS_ON, CH4_PA_BIAS_OFF, CH4_PA_BIAS_ON, BIAS_CURRENT_TX, BIAS_CURRENT_TX_DRV

Load bias settings

 
echo 5 > out_voltage_bias_set_load
echo  > in_voltage_bias_set_load

For loading a different bias setting the operations is the same for RX and TX channels.

Memory sequencer

The beam can be stepped sequentially through the positions stored in memory. To use this feature the following steps must be executed:

  1. load sequence start
  2. load sequence end
  3. enable sequencer
  4. generate clock cycles
  5. pulse TX/RX Load pin
echo 10 > in_voltage_sequence_start
echo 20 > in_voltage_sequence_end
echo 1 > sequencer_enable
echo 1 > gen_clk_cycles

Low level register access via debugfs (direct_reg_access)

Some IIO drivers feature an optional debug facility, allowing users to read or write registers directly. Special care needs to be taken when using this feature, since you can modify registers on the back of the driver.

To simplify direct register access you may want to use the libiio iio_reg command line utility.

Accessing debugfs requires root privileges.

In order to identify if the IIO device in question feature this option you first need to identify the IIO device number.

Therefore read the name attribute of each IIO device

This specifies any shell prompt running on the target

root@analog:~# grep "" /sys/bus/iio/devices/iio\:device*/name
/sys/bus/iio/devices/iio:device0/name:ad7291
/sys/bus/iio/devices/iio:device1/name:ad9361-phy
/sys/bus/iio/devices/iio:device2/name:xadc
/sys/bus/iio/devices/iio:device3/name:adf4351-udc-rx-pmod
/sys/bus/iio/devices/iio:device4/name:adf4351-udc-tx-pmod
/sys/bus/iio/devices/iio:device5/name:cf-ad9361-dds-core-lpc
/sys/bus/iio/devices/iio:device6/name:cf-ad9361-lpc
root@analog:~# 

Change directory to /sys/kernel/debug/iio/ iio:deviceX and check if the direct_reg_access file exists.

This specifies any shell prompt running on the target

root@analog:~# cd /sys/kernel/debug/iio/iio\:device1
root@analog:/sys/kernel/debug/iio/iio:device1# ls direct_reg_access 
direct_reg_access

Reading

This specifies any shell prompt running on the target

root@analog:/sys/kernel/debug/iio/iio:device1# echo 0x7 > direct_reg_access                                                                                                                                 
root@analog:/sys/kernel/debug/iio/iio:device1# cat direct_reg_access 
0x40

Writing

Write ADDRESS VALUE

This specifies any shell prompt running on the target

root@analog:/sys/kernel/debug/iio/iio:device1# echo 0x7 0x50  > direct_reg_access                                                                                                                            
root@analog:/sys/kernel/debug/iio/iio:device1# cat direct_reg_access 
0x50

Accessing HDL CORE registers

Special ADI device driver convention for devices that have both:

  • a SPI/I2C control interface
  • and some sort of HDL Core with registers (AXI)

In this case when accessing the HDL Core Registers always set BIT31.

The register map for typical ADI HDL cores can be found here: Register Map

This specifies any shell prompt running on the target

root@analog:/sys/kernel/debug/iio/iio:device6# echo 0x80000000 > direct_reg_access                                                                                                                           
root@analog:/sys/kernel/debug/iio/iio:device6# cat direct_reg_access 
0x80062

02 Mar 2011 15:16

More Information

resources/tools-software/linux-drivers/iio-transceiver/adar1000.txt · Last modified: 03 Jan 2021 21:46 by Robin Getz