AD9361
Recommended for New Designs
The AD9361 is a high performance, highly integrated radio
frequency (RF) Agile Transceiverâ„¢ designed for use in 3G and
4G base station applications....
Datasheet
AD9361 on Analog.com
Hello,
I am porting a current device to a new kernel and am having some issue with the AD9361. I am not seeing any transmits or receives in our software, where it worked before under an older kernel. I suspect it's something with the device tree. Could you double check and make sure this looks alright?
I have a TX DMA and associated dds device commented out, because the kernel panics with it, likely because I don't think we are using a TX DMA, that happens in the FPGA.
Like written, I get a boot error about the cf-ad9361-lpc device not working because TX tune failed. When I disable TX tune, eventually, when running my application, I see RX tune also failing. I also don't see anything being transmitted or received.
Thanks!
File 1:
/ {
amba: amba {
rx_dma: dma@7c400000 {
compatible = "adi,axi-dmac-1.00.a";
reg = <0x7c400000 0x10000>;
#dma-cells = <1>;
interrupt-parent = <&intc>;
interrupts = <0 33 0>;
clocks = <&clkc 16>;
dma-channel {
adi,buswidth = <64>;
adi,type = <0>;
};
};
/*
tx_dma: dma@7c420000 {
compatible = "adi,axi-dmac-1.00.a";
reg = <0x7c420000 0x10000>;
#dma-cells = <1>;
interrupt-parent = <&intc>;
interrupts = <0 56 0>;
clocks = <&clkc 16>;
dma-channel {
adi,buswidth = <64>;
adi,type = <1>;
adi,cyclic;
};
};
*/
cf_ad9361_adc_core_0: cf-ad9361-lpc@79020000 {
compatible = "adi,axi-ad9361-6.00.a";
reg = <0x79020000 0x6000>;
dmas = <&rx_dma 0>;
dma-names = "rx";
spibus-connected = <&adc0_ad9361>;
xlnx,dphase-timeout = <0x8>;
xlnx,num-mem = <0x1>;
xlnx,num-reg = <0x1>;
xlnx,s-axi-min-size = <0x1ff>;
xlnx,slv-awidth = <0x20>;
xlnx,slv-dwidth = <0x20>;
xlnx,use-wstrb = <0x0>;
};
/*
cf_ad9361_dac_core_0: cf-ad9361-dds-core-lpc@79024000 {
compatible = "adi,axi-ad9361-dds-6.00.a";
reg = <0x79024000 0x1000>;
clocks = <&adc0_ad9361 13>;
clock-names = "sampl_clk";
dmas = <&tx_dma 0>;
dma-names = "tx";
dac-sample-frequency = <491520000>;
xlnx,dphase-timeout = <0x8>;
xlnx,num-mem = <0x1>;
xlnx,num-reg = <0x1>;
xlnx,s-axi-min-size = <0x1ff>;
xlnx,slv-awidth = <0x20>;
xlnx,slv-dwidth = <0x20>;
xlnx,use-wstrb = <0x0>;
};
*/
};
};
and:
&spi0 {
adc0_ad9361: ad9361-phy@0 {
#address-cells = <1>;
#size-cells = <0>;
#clock-cells = <1>;
compatible = "ad9361";
/* SPI Setup */
reg = <0>;
spi-cpha;
spi-max-frequency = <10000000>;
/* Clocks */
clocks = <&ad9361_clkin 0>;
clock-names = "ad9361_ext_refclk";
clock-output-names = "rx_sampl_clk", "tx_sampl_clk";
//adi,debug-mode-enable;
/* Digital Interface Control */
/* adi,digital-interface-tune-skip-mode:
* 0 = TUNE RX&TX
* 1 = SKIP TX
* 2 = SKIP ALL
*/
adi,digital-interface-tune-skip-mode = <0>;
adi,pp-tx-swap-enable;
adi,pp-rx-swap-enable;
adi,rx-frame-pulse-mode-enable;
adi,lvds-mode-enable;
adi,lvds-bias-mV = <150>;
adi,lvds-rx-onchip-termination-enable;
adi,rx-data-delay = <10>;
adi,tx-fb-clock-delay = <7>;
//adi,fdd-rx-rate-2tx-enable;
adi,dcxo-coarse-and-fine-tune = <8 5920>;
//adi,xo-disable-use-ext-refclk-enable;
/* Mode Setup */
adi,2rx-2tx-mode-enable;
//adi,split-gain-table-mode-enable;
/* ENSM Mode */
adi,frequency-division-duplex-mode-enable;
//adi,ensm-pin-pulse-mode-enable;
//adi,ensm-enable-txnrx-control-enable;
/* adi,rx-rf-port-input-select:
* 0 = (RX1A_N & RX1A_P) and (RX2A_N & RX2A_P) enabled; balanced
* 1 = (RX1B_N & RX1B_P) and (RX2B_N & RX2B_P) enabled; balanced
* 2 = (RX1C_N & RX1C_P) and (RX2C_N & RX2C_P) enabled; balanced
*
* 3 = RX1A_N and RX2A_N enabled; unbalanced
* 4 = RX1A_P and RX2A_P enabled; unbalanced
* 5 = RX1B_N and RX2B_N enabled; unbalanced
* 6 = RX1B_P and RX2B_P enabled; unbalanced
* 7 = RX1C_N and RX2C_N enabled; unbalanced
* 8 = RX1C_P and RX2C_P enabled; unbalanced
*/
adi,rx-rf-port-input-select = <0>; /* (RX1A_N & RX1A_P) and (RX2A_N & RX2A_P) enabled; balanced */
/* adi,tx-rf-port-input-select:
* 0 TX1A, TX2A
* 1 TX1B, TX2B
*/
adi,tx-rf-port-input-select = <0>; /* TX1A, TX2A */
//adi,update-tx-gain-in-alert-enable;
adi,tx-attenuation-mdB = <10000>;
adi,rf-rx-bandwidth-hz = <1000000>;
adi,rf-tx-bandwidth-hz = <1000000>;
adi,rx-synthesizer-frequency-hz = /bits/ 64 <402795000>;
adi,tx-synthesizer-frequency-hz = /bits/ 64 <402795000>;
/* BBPLL ADC R2CLK R1CLK CLKRF RSAMPL */
adi,rx-path-clock-frequencies = <819200000 12800000 12800000 6400000 3200000 1600000>;
/* BBPLL DAC T2CLK T1CLK CLKTF TSAMPL */
adi,tx-path-clock-frequencies = <819200000 12800000 12800000 6400000 3200000 1600000>;
/* Gain Control */
/* adi,gc-rx[1|2]-mode:
* 0 = RF_GAIN_MGC
* 1 = RF_GAIN_FASTATTACK_AGC
* 2 = RF_GAIN_SLOWATTACK_AGC
* 3 = RF_GAIN_HYBRID_AGC
*/
adi,gc-rx1-mode = <0>;
adi,gc-rx2-mode = <0>;
adi,gc-adc-ovr-sample-size = <4>; /* sum 4 samples */
adi,gc-adc-small-overload-thresh = <47>; /* sum of squares */
adi,gc-adc-large-overload-thresh = <58>; /* sum of squares */
adi,gc-lmt-overload-high-thresh = <800>; /* mV */
adi,gc-lmt-overload-low-thresh = <704>; /* mV */
adi,gc-dec-pow-measurement-duration = <8192>; /* 0..524288 Samples */
adi,gc-low-power-thresh = <24>; /* 0..-64 dBFS vals are set pos */
//adi,gc-dig-gain-enable;
//adi,gc-max-dig-gain = <15>;
/* Manual Gain Control Setup */
//adi,mgc-rx1-ctrl-inp-enable; /* uncomment to use ctrl inputs */
//adi,mgc-rx2-ctrl-inp-enable; /* uncomment to use ctrl inputs */
adi,mgc-inc-gain-step = <2>;
adi,mgc-dec-gain-step = <2>;
/* adi,mgc-split-table-ctrl-inp-gain-mode:
* (relevant if adi,split-gain-table-mode-enable is set)
* 0 = AGC determine this
* 1 = only in LPF
* 2 = only in LMT
*/
adi,mgc-split-table-ctrl-inp-gain-mode = <0>;
/* Automatic Gain Control Setup */
adi,agc-attack-delay-extra-margin-us= <1>; /* us */
adi,agc-outer-thresh-high = <5>; /* -dBFS */
adi,agc-outer-thresh-high-dec-steps = <2>; /* 0..15 */
adi,agc-inner-thresh-high = <10>; /* -dBFS */
adi,agc-inner-thresh-high-dec-steps = <1>; /* 0..7 */
adi,agc-inner-thresh-low = <12>; /* -dBFS */
adi,agc-inner-thresh-low-inc-steps = <1>; /* 0..7 */
adi,agc-outer-thresh-low = <18>; /* -dBFS */
adi,agc-outer-thresh-low-inc-steps = <2>; /* 0..15 */
adi,agc-adc-small-overload-exceed-counter = <10>; /* 0..15 */
adi,agc-adc-large-overload-exceed-counter = <10>; /* 0..15 */
adi,agc-adc-large-overload-inc-steps = <2>; /* 0..15 */
//adi,agc-adc-lmt-small-overload-prevent-gain-inc-enable;
adi,agc-lmt-overload-large-exceed-counter = <10>; /* 0..15 */
adi,agc-lmt-overload-small-exceed-counter = <10>; /* 0..15 */
adi,agc-lmt-overload-large-inc-steps = <2>; /* 0..7 */
//adi,agc-dig-saturation-exceed-counter = <3>; /* 0..15 */
//adi,agc-dig-gain-step-size = <4>; /* 1..8 */
//adi,agc-sync-for-gain-counter-enable;
adi,agc-gain-update-interval-us = <1000>; /* 1ms */
//adi,agc-immed-gain-change-if-large-adc-overload-enable;
//adi,agc-immed-gain-change-if-large-lmt-overload-enable;
/* Fast AGC */
adi,fagc-dec-pow-measurement-duration = <64>; /* 64 Samples */
//adi,fagc-allow-agc-gain-increase-enable;
adi,fagc-lp-thresh-increment-steps = <1>;
adi,fagc-lp-thresh-increment-time = <5>;
adi,fagc-energy-lost-stronger-sig-gain-lock-exit-cnt = <8>;
adi,fagc-final-overrange-count = <3>;
//adi,fagc-gain-increase-after-gain-lock-enable;
adi,fagc-gain-index-type-after-exit-rx-mode = <0>;
adi,fagc-lmt-final-settling-steps = <1>;
adi,fagc-lock-level = <10>;
adi,fagc-lock-level-gain-increase-upper-limit = <5>;
adi,fagc-lock-level-lmt-gain-increase-enable;
adi,fagc-lpf-final-settling-steps = <1>;
adi,fagc-optimized-gain-offset = <5>;
adi,fagc-power-measurement-duration-in-state5 = <64>;
adi,fagc-rst-gla-engergy-lost-goto-optim-gain-enable;
adi,fagc-rst-gla-engergy-lost-sig-thresh-below-ll = <10>;
adi,fagc-rst-gla-engergy-lost-sig-thresh-exceeded-enable;
adi,fagc-rst-gla-if-en-agc-pulled-high-mode = <0>;
adi,fagc-rst-gla-large-adc-overload-enable;
adi,fagc-rst-gla-large-lmt-overload-enable;
adi,fagc-rst-gla-stronger-sig-thresh-above-ll = <10>;
adi,fagc-rst-gla-stronger-sig-thresh-exceeded-enable;
adi,fagc-state-wait-time-ns = <260>;
adi,fagc-use-last-lock-level-for-set-gain-enable;
/* RSSI */
/* adi,rssi-restart-mode:
* 0 = AGC_IN_FAST_ATTACK_MODE_LOCKS_THE_GAIN,
* 1 = EN_AGC_PIN_IS_PULLED_HIGH,
* 2 = ENTERS_RX_MODE,
* 3 = GAIN_CHANGE_OCCURS,
* 4 = SPI_WRITE_TO_REGISTER,
* 5 = GAIN_CHANGE_OCCURS_OR_EN_AGC_PIN_PULLED_HIGH,
*/
adi,rssi-restart-mode = <3>;
//adi,rssi-unit-is-rx-samples-enable;
adi,rssi-delay = <1>; /* 1us */
adi,rssi-wait = <1>; /* 1us */
adi,rssi-duration = <1000>; /* 1ms */
/* Control Outputs */
adi,ctrl-outs-index = <0>;
adi,ctrl-outs-enable-mask = <0xFF>;
/* AuxADC Temp Sense Control */
adi,temp-sense-measurement-interval-ms = <1000>;
adi,temp-sense-offset-signed = <0xCE>;
adi,temp-sense-periodic-measurement-enable;
/* AuxDAC Control */
adi,aux-dac-manual-mode-enable;
adi,aux-dac1-default-value-mV = <0>;
//adi,aux-dac1-active-in-rx-enable;
//adi,aux-dac1-active-in-tx-enable;
//adi,aux-dac1-active-in-alert-enable;
adi,aux-dac1-rx-delay-us = <0>;
adi,aux-dac1-tx-delay-us = <0>;
adi,aux-dac2-default-value-mV = <0>;
//adi,aux-dac2-active-in-rx-enable;
//adi,aux-dac2-active-in-tx-enable;
//adi,aux-dac2-active-in-alert-enable;
adi,aux-dac2-rx-delay-us = <0>;
adi,aux-dac2-tx-delay-us = <0>;
};
};
&adc0_ad9361 {
reset-gpios = <&gpio0 100 0>;
};
Please see here: https://wiki.analog.com/resources/eval/user-guides/ad-fmcomms2-ebz/interface_timing_validation
If tuning fails, it's most likely an issue with your HW or HDL design.
You could use skip mode = 2, to get the device probed and then further test your system.
adi,digital-interface-tune-skip-mode = <0>;
After you have probed the ad9361-phy you can use BIST to test the transceiver.
Then try to use the digital tune runtime API to test different interface speeds.
-Michael
Please see here: https://wiki.analog.com/resources/eval/user-guides/ad-fmcomms2-ebz/interface_timing_validation
If tuning fails, it's most likely an issue with your HW or HDL design.
You could use skip mode = 2, to get the device probed and then further test your system.
adi,digital-interface-tune-skip-mode = <0>;
After you have probed the ad9361-phy you can use BIST to test the transceiver.
Then try to use the digital tune runtime API to test different interface speeds.
-Michael
Both HW and HDL have been tested and work. All I am changing is the embedded OS.
I am pretty sure the tuning setting was 0 before, and I don’t recall it complaining about tuning then, but I bet that was with a much older (3-5 years old) driver.
Alright, I verified TX is working, spectrum looks good, and I assume RX is working because I see noise. But something is still off, possibly related to timing.
I suspect tuning, but I don't understand what the driver is doing to tune, and how that changed in the last few years. If you could assist with that, I'd be grateful.
Christoph
I think I ignored a fairly important bit: We are using the axi_ad9361 IP core, but it's old (2011). I assume a new driver would require an up-to-date IP core as well, so let me try and update that.
With the new IP core, TX tuning seems to work (I get no error with the ad9361-lpc device), but RX tuning still fails when I run my application. Ideas?
Hi,
You are saying that both HDL and HW have been tested - how did you test them? If the digital tuning doesn't work, most likely the issue is caused by HDL or HW.
Dragos
Good question. The hardware has existed for a while, running an older Linux OS, and works just fine, so I think hardware can be ruled out.
As for HDL, I've been using the same bitfile we use with the legacy OS. Then I realized that we are using an old axi_ad9361 IP core in the HDL, so I just updated that to the 2018_R2_pack2 branch of the ADI HDL, along with axi_dmac and others.
My assumption is that a 2018_R2 HDL core plus the 2018_R2 branch of the ADI Linux fork as the OS should work.
Tuning was enabled in 2014/15 in our device tree, so I assume it worked then (no error messages about tuning with legacy OS).
Maybe another question that might help: Is there a list somewhere of all the changes to the AD9361 IP core since 2014 at a higher level than git commits that would show some breaking changes between then and now? Like the renaming of inputs and outputs, etc?
That would help me track down what's changed.
We always recommend using the latest HDL and latest kernel.
We try to keep them in sync.
We didn't do a really good job of keeping track of changes from one version to another, other than the git commit history.
We are also trying to upstream things.