no-os sample code to synchronize AD9361 chips on a FMComms5 board

I am using a FMComms5 board with a Xilinx ZC702 FPGA board in a beamforming application. The application is bare metal (no-os) that uses ad9361.c, ad9361.h, ad9361_api.c, ad9361_api.h and the other .c and .h files that make up the AD9361 no-os library which was downloaded from github. I am able to operate both AD9361 chips successfully and everything seems to work fine.

I am attempting to synchronize the received signals from both AD9361 chips as described here wiki.analog.com/.../multi-chip-sync
This page provides sample code to synchronize the chips on the FMComms5 board github.com/.../fmcomms2_adv.c

The example code has a function called trx_phase_rotation(struct iio_device *dev, gdouble val); which computes the phase rotation needed to synchronize the two AD9361's and then sets the phase rotation by calling iio_channel_attr_write_double(out0, "calibscale", (double) vcos); and iio_channel_attr_write_double(out0, "calibphase", (double) (-1.0 * vsin));

The example code looks like it was built to run on linux with these functions calling into the IIO driver. My application is a bare metal (no os) with no IIO driver and no Linux operating system.
I have been trying to find out exactly what iio_channel_attr_write_double() actually does when called with the parameters "calibscale" and "calibphase", but I have not been able to find it anywhere in any of the example C code on the ADI web site.
The function must write the desired phase angle somwehere, but where? Does this function write to the AD9361 chip over the SPI port or does it write to the axi_ad9361 component in the Vivado FPGA design (also downloaded from github and successfully built).
Can you provide information on exactly what iio_channel_attr_write_double() does, and what register addresses "calibphase" and "calibscale" map to? Do you have source code for this function?
I have searched the AD9361 datasheet, the AD9361 Register Map (UG671), the AD9361 Reference Manual (UG570), ad9361_api.h and ad9361.h for a clue but have not been able to find anything.

Any information you can provide would be most appreciated.

Top Replies

    •  Analog Employees 
    Sep 29, 2020 +1 verified

    Hi ,

    That example code is an IIO client application running on PC.

    At some point it issues that iio_channel_attr_write_double() call and writes to "calibphase" and "calibscale" IIO channel attributes…

  • +2
    •  Analog Employees 
    on Sep 29, 2020 8:56 AM 2 months ago

    Hi ,

    That example code is an IIO client application running on PC.

    At some point it issues that iio_channel_attr_write_double() call and writes to "calibphase" and "calibscale" IIO channel attributes on the board that runns the IIO server.

    If the IIO server runs on Linux, these calls ends up here:

    https://github.com/analogdevicesinc/linux/blob/master/drivers/iio/adc/cf_axi_adc_core.c#L534 

    Follow the code to see what you need to replace that call with when running bare metal no-OS.

    Hope this helps

  • I have been studying the code in the link you provided at github.com/.../cf_axi_adc_core.c trying to figure out how to convert it from an IIO client application that runs on Linux to my bare metal (no-os) application.
    From what I can tell, the phase rotation is done in the axi_ad9361.v component in the FPGA. The ad_iqcor.v module has two inputs (iqcor_coeff_1 and iqcor_coeff_2) which feed multipliers that are used to multiply the I, Q data from the AD9361 before being read by the Xilinx Zynq processor before being sent to the PC.

    In ad9361_phase_sync.c, the function trx_phase_rotation(struct iio_device *dev, double val) is called to adjust the phases of the AD9361 chips on the FMComms5 board.

    Eventually, the phase rotation values must be written to the FPGA. It looks like these two functions in adc_core.c, which write to the axi_AD9361 component in the FPGA over the AXI bus are used:

    adc_set_calib_scale(struct ad9361_rf_phy *phy, uuint32_t chan, int32_t val, int32_t val2)
    adc_set_calib_phase(struct ad9361_rf_phy *phy, uint32_t chan, int32_t val, int32_t val2)

    These functions take an integer value for the phase rotation and scale (val and val2). But trx_phase_rotation() takes a floating point number.
    Where does the floating point number get converted to integers for adc_set_calib_phase() and adc_set_calib_scale()?
    I have looked all through lib-iio-master, lib-ad9361iio-master and the linux-master directories can not find where the conversion from floating point to integer is made.

    If you follow the calls made inside trx_phase_rotation, you eventually get to a point where the floating point number is converted to a string and written to a file!

    I have similar for dds_tx_phase_rotation(). It computes an integer value for I and Q, and then calls  iio_channel_attr_write_longlong()  to write the I and Q values. But what address in the FPGA are these values written to? 

    Any info you can provide would be most appreciated.

  • 0
    •  Analog Employees 
    on Oct 23, 2020 7:46 AM 1 month ago in reply to fpga_man

    Hi,

    IIO sysfs accepts floating point numbers, but since the kernel can only handle integers, the floating point number ASCII string is converted. So, two numbers will be available in kernel: one for integer part and the other one for the fractional part. The reverse is true when IIO needs to display floating point numbers.

    To better understand this, I would search for examples that are using: https://github.com/analogdevicesinc/linux/blob/master/include/linux/iio/types.h#L24-L31

    Thanks,
    Dragos