Post Go back to editing

AD9361 initialisation sequence


I am developing a SDR via SIMULINK, starting wiit the Tx. 

The simulink models are fine, generate code and also work via the AD963x block to give an OFDM signal. I can download the HDL and verify that I see digital output on a Logic Analyser

I now need to cut loose from SIMULINK, Once I do this the AD9361 is transmits nothing - expected as there is no longer the SIMULINK block setting it up.

I have a script that reads the status of the ADI chip, it's ensm is in "alert" mode and it reports that both internal and external LOs are off.

So my question is basic.

Is the next step to create a Linux Script that intialises / sets up the ADI chip ?

If so, is there a good starting example to do this.

I'm worried that the device has to go through a calibration loop initially and hence jsut plodding through register settings won't work properly.

I have found an eclectic mix of scripts for ADI devices that cover numerous topics accross numerous devices, but I expected to find a few

starting scripts for the ADI9361.

I don't know how much set up is involved to get it to just transmit,, Do I just need to set frequencies, for the RF Output / LOs.

or do I need to define and load filters, switch them on etc and/or load define Gain tables or does the device have some defaults

to drive a signal out say at 2.4GHz, -10dB gain.

i.e. Is there a minimum few-line 'get started' script that will jsut turn on a single Tx channel and run the DAC to give some OP.

I'm then happy to add and refine a script to what I need.

I wrote a simple reporting script that I'm happy to 'donate' which seems to show status okay'.

I can't see why there can't be a pro-forma get-started Tx and get-started Rx script, where developers can just tweak some values....

Also, I take it that writing a Linux Script is the correct most simple next step. ( as opposed to a C applicaion say )

{ I am considering trying to drop my HDL-Coder generated .bitstream file into ADI's Linux,

  which offers IIOscScope & plugins to allow AD936I GUI access, which may be an easier path }


Mike Brewin.

Many thanks for any replies.

  • Maybe I can explain how the system works so you can better understand what might be necessary.

    Simulink, MATLAB, GNU Radio, C, python ... all will interact with the IIO drivers for the transceiver with libIIO. The drivers will handle calibrations and state dependency on modes inside the part so you can pretty much ignore those things. You simply just need to interact with the driver's attributes.

    If you do not use the data ports in your Simulink model, then all you need is some code to configure the transceiver in the way you want. You can interact with the buffers TX or RX but it will require more code.

    We'll just consider the case where you want to just configure the transceiver, where eventually you want everything to run on the ARM. To do this you want to move everything to just use the libIIO API for the driver or Python which can run on the board as well. Fortunately, libIIO has this ability to work remotely and locally, so you can develop code on your host machine, then move it to the board itself. This is done by using a remote "Context", then when you move the code to the board use a local/default "Context".

    Here is some basic info on libIIO:

    Here is the API doc for libIIO:

    Here are the possible attributes you can change for the transceiver:

    There are a few C examples here using libIIO:

    and here:


    Hopefully that helps.


  • Hi travis.

    Your answer has helped somewhat, I have looked atall  the URLs.

    I have found more about Libiio, more and scripts,and I have managed to use the DDS and create some RF tx output, swpeeing from one value to another.

    It looks like ther are only a few parameters or so to set up to achieve this

    [ Sample rate, RF port, RF bandwidth and RF frequency. & switch dds on ]

    Hence I am able to set up these and other parameters of the "adi9361-phy" device.

    I am good with Linux scripting as precursor to C or python,, given it can be used to set everything.

    But, I don't understand the line in your answer below....

    "If you do not use the data ports in your Simulink model, then all you need is some code to configure the transceiver in the way you want. You can interact with the buffers TX or RX but it will require more code"

    1) By "Buffers" are you implying these are the DMA-TX/RX buffers in the ADI-HDL which connect into the ARM processor?

    Given I have got a SIMLINK-HDLcoder genrated OFDM transmitter that transmits a sine waveform as a test output itself then I am using the output of the FPGA-HDL to drive the AD9361 transmitter. However I don't require the use of the DMA Rx or TX buffers, becuase my HDL is generates the transmission test signal at this stage, hence no need to transfer anything to or from the ARM processor block.

    But I do need to pass the input that the AD9361 is receiving on LVDS pins through its transmit DAC/Fitler chain, rather than invoke the dds. Hence, I need whatever there is extra to set up the transmit path to do this.

    As far as I have got, I have found that I have device1: ad9361-phy and now realise there is "device4:cf-ad9361-dds-core-lpc" and "device5: cd-adi9361-lpc"  which I believe mean CONFIGARUTION of the ADi Tx and rx path blocks. So far, I have not set up these up. ( I thought the cf-ad9361-dds-core-lpc related only to the dds block that I don't want to use )

    Should I set up these devices too and can you explain their names a litte 

    "cf-adi9361-dds-core-lpc...."?    Guess is that "cf"  means "config",

    eg : is "cf-adi9361-dds-core-lpc" the transmit path that happens to include a possible dds, or is it dds-only..?

    Is the general scheme to set set "common" values in adi9361 phy, such as the local oscillator frequency and then set up the transmit path and.or the receive path, which are actually treated as seperate devices in libiio/iio.

    When I look at device4, I don't know where to can find the documetation that tells me what these various device files   relate to. e.g. I though voltage0 related to channel 1, but there is set_up voltage0 for I-data, but not for q-data ?

    Can you point me to where I can find this info for the device-files below.

    zynq> cd iio:device4
    zynq> ls
    buffer                              out_altvoltage5_TX2_I_F2_phase
    dev                                 out_altvoltage5_TX2_I_F2_raw
    name                                out_altvoltage5_TX2_I_F2_scale
    of_node                             out_altvoltage6_TX2_Q_F1_frequency
    out_altvoltage0_TX1_I_F1_frequency  out_altvoltage6_TX2_Q_F1_phase
    out_altvoltage0_TX1_I_F1_phase      out_altvoltage6_TX2_Q_F1_raw
    out_altvoltage0_TX1_I_F1_raw        out_altvoltage6_TX2_Q_F1_scale
    out_altvoltage0_TX1_I_F1_scale      out_altvoltage7_TX2_Q_F2_frequency
    out_altvoltage1_TX1_I_F2_frequency  out_altvoltage7_TX2_Q_F2_phase
    out_altvoltage1_TX1_I_F2_phase      out_altvoltage7_TX2_Q_F2_raw
    out_altvoltage1_TX1_I_F2_raw        out_altvoltage7_TX2_Q_F2_scale
    out_altvoltage1_TX1_I_F2_scale      out_altvoltage_sampling_frequency
    out_altvoltage2_TX1_Q_F1_frequency  out_voltage0_calibphase
    out_altvoltage2_TX1_Q_F1_phase      out_voltage0_calibscale
    out_altvoltage2_TX1_Q_F1_raw        out_voltage1_calibphase
    out_altvoltage2_TX1_Q_F1_scale      out_voltage1_calibscale
    out_altvoltage3_TX1_Q_F2_frequency  out_voltage2_calibphase
    out_altvoltage3_TX1_Q_F2_phase      out_voltage2_calibscale
    out_altvoltage3_TX1_Q_F2_raw        out_voltage3_calibphase
    out_altvoltage3_TX1_Q_F2_scale      out_voltage3_calibscale
    out_altvoltage4_TX2_I_F1_frequency  out_voltage_sampling_frequency
    out_altvoltage4_TX2_I_F1_phase      power
    out_altvoltage4_TX2_I_F1_raw        scan_elements
    out_altvoltage4_TX2_I_F1_scale      subsystem
    out_altvoltage5_TX2_I_F2_frequency  uevent



  • cf-ad9361-lpc is the Rx driver, but its has really no control over the transceiver, just the data path in the FPGA.

    cf-ad9361-dds-core-lpc is the same for TX but includes optional DDSs you can control.

    Both are responsible for buffers transferred to and from the FPGA.

    Both these drivers are actually generics drivers used for all our HDL designs:

    DAC driver:

    ADC driver:

    But I do need to pass the input that the AD9361 is receiving on LVDS pins through its transmit DAC/Fitler chain, rather than invoke the dds. Hence, I need whatever there is extra to set up the transmit path to do this.

    DDSs are actually in the FPGA, not the transceiver. To switch between the DMA/IP source vs DDS, see the state diagram in this section:

    By addressing the "raw" attribute you can switch these modes, like in this example:


  • #!/bin/sh
    # #################################################################################
    # Filename :                                                   #
    # purpose  : set up AD9361-phy and ADI-DAC                                        #
    # Author   : mike Brewin :                                                        #
    # Created  : 17/9/2019                                                            #
    # MATLAB lInux, theses are iio:device1 ( ad9361-phy) and iio:device4 (ADI HDL DAC)#
    # the ADI LINUX driver name for the ADI AD9361 device is 'ad9361-phy'             #
    # the ADI LINUX driver name for the ADI HDL component is 'cf-ad9361-dds-core-lpc' #
    # revision control 	: step 0.0, written : WIP                                     #
    # #################################################################################
    # NOT YET WORKING....!!!!!
    echo --------------------------------------------------
    echo - script :                   -
    echo - setup iio:device4 , ADI HDL DAC                -
    echo --------------------------------------------------
    cd /sys/bus/iio/devices/iio:device1
    # show device name - the ADI9361 is a device, with a device driver..
    echo "  "
    echo -e "\e[31m AD9361 Find Current Parameters Script \e[0m"
    echo " "
    echo -n -e "\e[32m Device Name  =  : \e[0m"
    cat name
    echo -n -e "\e[32m Set RF frequency : \e[0m"
    echo 2400000000 >  out_altvoltage1_TX_LO_frequency
    cat out_altvoltage1_TX_LO_frequency
    # is this relating to dds or not..
    echo -n -e "\e[32m Set Tx sampling rate in Hz : \e[0m"
    echo 10000000 >  out_voltage_sampling_frequency
    cat out_voltage_sampling_frequency
    echo -n -e "\e[32m Set hardware gain : \e[0m"
    echo -10.0 >  out_voltage0_hardwaregain
    cat out_voltage0_hardwaregain
    ###########  IIO: DEVICE4 ADI HDL DAC setup ############################  
    cd /
    cd /sys/bus/iio/devices/iio:device4
    echo change directory to /sys/bus/iio/devices/iio:device4
    # cat buffer					- directory 
    cat dev
    cat name
    #pretend to set my own dds, but don't turn it on...
    echo 500000 > out_altvoltage0_TX1_I_F1_frequency
    echo 91000  > out_altvoltage0_TX1_I_F1_phase
    echo 0.5    > out_altvoltage0_TX1_I_F1_scale
    ## echo 0   > out_altvoltage0_TX1_I_F1_raw 
    cd scan_elements
    ls -l 
    #I think this might be channel 0 both (I & Q)
    #echo out_voltage0_index
    #echo out_voltage0_type
    echo 1 > out_voltage0_en
    #I think this might be channel 1 both (I & Q
    #echo out_voltage1_index
    #echo out_voltage1_type
    echo 1 > out_voltage1_en
    #I think this might be channel 1 both (I & Q
    #echo out_voltage2_index
    #echo out_voltage2_type
    echo 1 > out_voltage2_en
    #I think this might be channel 1 both (I & Q
    #echo out_voltage3_index
    #echo out_voltage3_type
    echo 1 > out_voltage3_en
    cd ..
    cd buffer
    ls -l 
    echo 1 > enable
    read -p "press key to disable scan buffer and end :" key
    echo script finished
    #echo scan-buffers left in enabled state
    echo disable scan_buffers
    echo 0 > enable

    Hi Travis, thanks for your help so far, (i've read all the info) but I'm not yet putting together the

    Linux names with the API names and the device-tree names.                                                                     ( sent you a bit of a script to show what i am trying)

    1)  Looking at your documentation in the link reagarding switching from DDS to DMA.

    There are 2 state diagrams. the second one, for the newer code seems to indicate no matter waht tthe state of the 'raw' signal, the DMA state will exit. This diagram must be wrong, but does it imply that setting raw to 1 is DDS and raw to 0 is the DMA channel. ?

    I expected a signal named somehtign like "mux" or "enable" ?

    2) So I now have the concept to get myu output fro mthe FPGA into the ADI9361,                                            I need to set up both the ADI9361 device  (iio:device1 ad9361-phy) and (iio:device4 cf-ad9361-dds-core-lpc)

    3) It shouldn't be too hard, my concept is that the only things to do are :

    Switch trough the DMA path from the "cf-ad9361-dds-core-lpc" and then set jsut a few things in the ADI device, like the transmit frequency.

    When I now look into the AD9361-phy,,,, I see that the "TX_LO_frequency" exists as only aout_voltage1_TX_LO_frequency. 

    The documentation points to 'altvoltage' meaning for (only) dds, while voltage is for the main channel AND, 0 means output 1 and 1 means output2.  So as I think about it, I can only set a frequency for dds and for the other channel to channel I want to use ?

    4) Am I going along the right lines of setting up scan-elements ? . It doesn't feel right.        

     (I thought triggered things were for small DACs). If so, can I say set these up to capture 10000 sampels of my HDL output into a buffer and cycle that, at this point I just need to see output from my code rather than dds.

    5) finally, what does "-lpc" stand for. I'm from intel hardware, where it stands for "low-pin-count"

    Many Thanks,

    Mike Brewin.

  • Hi Travis, any update on my questions - amy be you are away on vacation.

    Are you in the US, what's your time-zone.

    Anyway : I am getting to grips with the ADi-MATLAB HDL blocks and Linux IIO

    MATAB have a multiplexor block bypass_tx which exists as 2 iio devices. I have asked them for their register map of these blocks.   I can find all the device base addreses using cat /proc/iomem }

    I need to ensure that the mATLAB multiplexor in their tx_bypass block is set correctly.

    { MATLAB add in these bypass_blocks so they can mux in or out  any user-IP. It is not part of ADI's HDL code.This allows them to acces the radio chip direct from a simulation model regardless of any loaded user IP }

    These MATLAB blocks appear as iio:device10  and 11 and they look like they allow direct access.

    echo -n -e "\e[32m device10 : MATLAB tx_bypass read \n \e[0m"
    cd /sys/bus/iio/devices/iio:device10
    cat name
    cd /sys/kernel/debug//iio/iio:device10
    ls direct_reg_access

    echo -n -e "\e[32m device11 : MATLAB tx_bypass write \n \e[0m"
    cd /sys/bus/iio/devices/iio:device11
    cat name
    cd /sys/kernel/debug/iio/iio:device11
    ls direct_reg_access

    I know my simple MATLAB model is emmitting signals ( simple Sinewave transmission which

    works fine if I use the MATLAB AD936x block ) and definately conforms to the requirements of

    the HDL coder, it issues a INT16 ranging from +/ 32768 and I also transmit TX_VLAID_OUT as 1,

    indicating a constantly valid stream.

    Onto your ADI blocks.

    Well I can get the radio chip to issue outoput from the DSS module in the FPGA with a few lines,

    set using either Linux Echo commands OR iio-driver iio_attr commands.

    #iio_attr -a -q -c cf-ad9361-dds-core-lpc TX1_I_F1 frequency 1000000
    #iio_attr -a -q -c cf-ad9361-dds-core-lpc TX1_Q_F1 frequency 1000000
    #iio_attr -a -q -c cf-ad9361-dds-core-lpc TX1_I_F1 scale 0.707947
    #iio_attr -a -q -c cf-ad9361-dds-core-lpc TX1_Q_F1 scale 0.707947
    #iio_attr -a -q -c cf-ad9361-dds-core-lpc TX1_Q_F1 raw 1
    #iio_attr -a -q -c cf-ad9361-dds-core-lpc TX1_Q_F1 raw 1

    Toggling the "raw" between 0 and 1 switches in DDS (1) or DMA(0), I get no ouput when I switch to DMA

    When I set the DDS, there is nothing further to set to get a radio output. ( I cvan add in filters )

    I can set the RF output frquency using

    iio_attr -a -q -c ad9361-phy TX_LO frequency 2500000000 >/dev/null



    My first question is :

    Q ) IS THIS ONLY for DDS, or is "The TX LO" RF-ouptu freq, and hence does not matter if the input is source from the DDS or DMA input.

    MY second question is

    Q) What else should I need to set other than Output frequency (hardware gain at abouit -10Db) and set the 'raw' signal to 0 for the DMA-boarne input just to see something output from the AD9361 device ?



  • 1.) As in the name this is only for TX LO. Anything relating to the DDSs will be in the cf-ad9361-dds-core-lpc IIO device.

    2.) If you are in DDS mode setting raw to 0 does not go to DMA mode. Writing raw to 0 goes to zero mode. This what the DMA diagram shows as well. If you are in DDS mode and want to get the DMA mode, data must be available for the Tx DMA and enabled. This basically what happens when to create TX buffer in libiio. Alternatively you can manually control the DAC core data source through registers.

    Looking at the regmap for "DAC Channel" here:

    the byte 0x418 (add 40 to this index for each additional channel) controls the data source. 0 for DDS, 2 for DMA, 3 for zero.

    Changing them on the board can be done with iio_reg, and changing these channels for I and Q would be

    # I+Q channel 1 DMA mode

    iio_reg cf-ad9361-dds-core-lpc 0x418 2

    iio_reg cf-ad9361-dds-core-lpc 0x458 2

    # I+Q channel 2 DMA mode

    iio_reg cf-ad9361-dds-core-lpc 0x498 2

    iio_reg cf-ad9361-dds-core-lpc 0x4D8 2

    # I+Q channel 1 DDS mode

    iio_reg cf-ad9361-dds-core-lpc 0x418 0

    iio_reg cf-ad9361-dds-core-lpc 0x458 0

    # I+Q channel 2 DDS mode

    iio_reg cf-ad9361-dds-core-lpc 0x498 0

    iio_reg cf-ad9361-dds-core-lpc 0x4D8 0


  • Hi Travis, that worked great, so I now have radio output, a big help, so I have verfied your answer.

    I need to conitnue this thread though.

    Fisrtly as a point, I believe that your state-diagram is illegal, it implies that no matter waht the state of the raw signal, the machine will transition out of the DMA state. There is no mention of the 'SEL' signal, which is the name of the signal that really controls the mux according to your register map.

    I find that the explanation of the LINUX drivers for the HDL insufficient, meanwhile the actual description of the HDL block and register maps is okay. 

    For the AD9361 device, the "iio:deviceX adi9361-phy",  I think the Linux names to interface to this HDL block are okay. There is sufficient coverage of each attribute on the WIKI page

    For the DAC channel HDL, which is explained here for the HDL, which you pointed me to, all is good

    ,,,but for the Linux DAC HDL decription, which his explained here,

    There is not enough proper description of waht the LINUX terms relate to in the device/channel.

    e.g these attributes are not explained though they are in the list.....

    -rw-rw-rw- 1 root root 4096 Jan  1 00:00 out_voltage0_calibphase
    -rw-rw-rw- 1 root root 4096 Jan  1 00:00 out_voltage0_calibscale
    -rw-rw-rw- 1 root root 4096 Jan  1 00:00 out_voltage1_calibphase
    -rw-rw-rw- 1 root root 4096 Jan  1 00:00 out_voltage1_calibscale
    -rw-rw-rw- 1 root root 4096 Jan  1 00:00 out_voltage2_calibphase
    -rw-rw-rw- 1 root root 4096 Jan  1 00:00 out_voltage2_calibscale
    -rw-rw-rw- 1 root root 4096 Jan  1 00:00 out_voltage3_calibphase
    -rw-rw-rw- 1 root root 4096 Jan  1 00:00 out_voltage3_calibscale

    Question : Waht are these ?

    I can't find ANY documetation, description or example of what these are : I can't decide if they

    relate to the MAIN DAC, plus the auxillary DACS ( there are 2 in the AD9361) or If they realte to

    DDS, but I think DDS set up is covered fully by the other entries.

    Why is there no formal documentation for each LINUX device attribute,                                                   like there is for the HDL block registers.

    PLEASE improve the WIKI entries to better explain the attirbutes of the DAC HDL as seen from LINUX


    Similar thing is seen in IIOSCOPE application, which in my view lists voltages 0,1,2,3

    Question )

    What are voltages 0,1,2,3 ?  ( are they Rx I1, RxQ1, Rx I2, RxQ2) : Also the IIOSCOPE shows the device as "cf-ad9361-lpc", and offers no other devices  (such as cf-ad9361-dds-core-lpc). Does this mean the 'scope can only show signals in the receive path.  If so that's okay, though I would like to    switch to device "cf-ad9361-dds-core0-lpc" and see what I am transmitting.


     I was going to do a bunch of memory dumps, thinking I could use

    dd if=/dev/iio:deviceX  bs= 128  ( where X is the device number 1,4 etc) , but this doesn't seem to work on my (MATLAB) Linux, saying " dd: /dev/iio:device4: Invalid argument".

    I admit, I may now have ot try it on ADI's Linux, but I am using MATLAB's HDL-coder to create HDL to work with the ADI radio devices, I'm surprised that this doesn't work, its looks to be fundamental to IIO.

    Q) Should this work, does it work on ADI's Linux.


    Finally, if I do a /proc/iomem, there is only 1 entry for

    "79020000-79025fff : /fpga-axi@0/cf-ad9361-lpc"

    Question ) Does this mean that both parts of the LINUX DAC driver are only 1 thing in this list and I can just acces DAC or ADC parts by using the offset 0x4000 that is mentioned between the DAC and the ADC channels. This is confusing, since in the iio devices list, the DAC and the ADC channel paths list as separate named devices.

    Best Regards,


  • Question : Waht are these ?

    Anything listed on cf-ad9361-lpc or cf-ad9361-dds-core-lpc are related to FPGA components or resources. The calib* properties are additional phase and gain changes you can make to the datapaths. Generally, they are not used on AD9361 since it has its own calibration. These are more documented on the ADC side (they are identical on DAC) but yes it is not totally complete.

    What are voltages 0,1,2,3 ? 

    These are the individual ADCs from the transceiver I1,Q1, I2, Q2. They have the voltage naming since this is the standard way of naming ADC channels in the IIO kernel framework. Newer devices have name extensions like voltage0_i and voltage0_q, but this was not available when the AD9361 driver was built.

    Also the IIOSCOPE shows the device as "cf-ad9361-lpc", and offers no other devices  (such as cf-ad9361-dds-core-lpc)

    This is the only device which will show up in the capture window since the window only does data captures. If you want to interface with the cf-ad9361-dds-core-lpc (TX) you can use the "FPGA Settings" section in the main control tab of IIO-Scope, which is in the FMComms2/3/4 (or AD936X depending on the version) tab. You can also interact with it through the Debug tabs for more advanced control.

    I'm surprised that this doesn't work, its looks to be fundamental to IIO.

    I'm not really sure what you are trying to achieve with this command. dd is typically used to address block devices not the root of a driver. If you are trying to interface with the buffers see these tools:

    Should this work, does it work on ADI's Linux.

    The command will not work on either. See above comment.

    Does this mean that both parts of the LINUX DAC driver are only 1 thing in this list and I can just acces DAC or ADC parts by using the offset 0x4000 that is mentioned between the DAC and the ADC channels.

    This is related to the first response of this post. If you want to access buffers (TX or RX) or additional phase and gain shifts available in the FPGA use the cf-ad9361* drivers. If you want to control the transceiver use the ad9361-phy driver.