AD9361 TDD state machine analysis and control

Recently, due to product development needs, we have been debugging the AD9361 on Zencheer's SDR platform SDR-A1. This hardware platform uses Xilinx's XC7A100T FPGA, with two MCUs, and has an Ethernet PHY interface. Its hardware architecture is shown in the figure below.

The first thing to complete is naturally the configuration of AD9361. We portd ADI's official no-OS software to the STM32 microcontroller and used FPGA for logic level conversion (in order to save a logic level conversion chip), it was completed smoothly. Then the data interface, since the target application of this product is TDD 2T2R mode, and considering supporting data rate as high as possible, so that the dual-port TDD mode was selected, and it was alse easy to completed. However, during the debugging of the AD9361 TDD state machine, many problems were encountered. In ADI's official document "AD9361 Enable State Machine Guide", we can see the following two diagrams: Figure 2 is the pulse mode, Figure 3 is the level mode, and we selected the level mode. In level mode, the document describes this: the Enable pin controls the state of ENSM. The falling edge of Enable moves the AD9361 to the Alert state. The TXNRX pin must be pulled high or low in the Alert state, and then the rising edge of Enable The edge moves the AD9361 to the TX state (TXNRN is high), or the RX state (TXNRX is low). If TO_ALERT in register 0x014 is 0, AD9361 will enter the wait state. We confirmed through the register?0x014 command in the microcontroller serial port command line that TO_ALERT is 1, which means that AD9361 will not enter the wait state. Under normal circumstances, it will only jump as follows:

……TX->Alert->RX-Alert->TX……

According to the above logic, we wrote the corresponding VHDL code and observed the status of AD9361 through the GPO of AD9361: pulling GPO0 high means AD9361 enters Alert or Wait state, pulling GPO1 high means AD9361 enters RX state, and pulling GPO2 high means AD9361 enters TX state. At the same time, a button is used as the switching control signal of TX and RX. It is found that every time the TX and RX states change, the AD9361 always enters the Alert state and cannot enter the expected state. After repeated simulation and analysis, no problems with the VHDL code were found. However, if you look closely at Figure 3, you will find that the time the AD9361 needs to stay in the Alert state is not shown in the figure. This is where the problem may lie.

Continue to check the "AD9361 Enable State Machine Guide" and find a description about the calibration of the state machine and VCO. The document says: In TDD mode, the frequency synthesizer is not always in the locked state. When the AD9361 is in the RX state, TX The frequency synthesizer is turned off (to save power); when the AD9631 is in the TX state, the RX frequency synthesizer is turned off. In TDD mode, ENSM will recalibrate the VCO whenever the TXNRX signal changes. For example, in the Alert state, the TXNRX signal changes from 0 (RX) to 1 (TX), the TX frequency synthesizer will power up, and when it reaches the TX Load Synth power-on delay time (0x025 register, its value must be 0x02, no detail is given in the document), ENSM will give the VCO a signal to calibrate the TX VCO. It can be imagined that the AD9361 can enter the TX state only after the TX VCO calibration is completed. Similarly, the TXNRX signal is The change from 1 (TX) to 0 (RX) must be after the RX VCO calibration is completed before the AD9361 can enter the RX state.

Following this idea, check out the instructions on VCO calibration in UG-570. The document says: In TDD mode, the RX frequency synthesizer is only enabled when TXNRX is low, and the TX frequency synthesizer is only enabled when TXNRX is high. The TX VCO or RX VCO will be recalibrated every time it is powered on, which is consistent with the description in the "AD9361 Enable State Machine Guide". The calculation formula of VCO calibration time is given in the document:

UG-570 also writes: If the frequency synthesizer is required to lock quickly, the VCO calibration can be disabled. When the VCO calibration is completed, the TX PLL and RX PLL lock signals can be read through the Control Output pin. We first try to disable VCO calibration, change the AD9361 initialization parameter tdd_skip_vco_cal_enable in the no-OS code from the default value 0 to 1, compile and download the binary file to the STM32 microcontroller, and use the button again as the switching control signal of TX and RX. We found that AD9361 can switch back and forth between Tx, Rx, and Alert states correctly, which also shows that the logic of the VHDL code is correct. In this way, based on the original VHDL code, taking into account the TX PLL or RX PLL lock status (read through the Control Output pin), the AD9361 state machine can be correctly configured. Following this idea, we modified the VHDL code and changed tdd_skip_vco_cal_enable to the default value 0, recompiled, downloaded, and tested. Finally, we can use the buttons to correctly control the TX and RX states of the AD9361.

The corresponding VHDL code is as follows. Both simulation and actual tests can pass. The TXON signal comes from external input, either MAC or button.


TDD_CTRL_001: process (RX_CLK)
begin
	if rising_edge(RX_CLK) then
	   if (MCU_CFG_DONE = '0') then
	       TXON_D <= '0';
	   elsif (MCU_CFG_DONE = '1') then
	       TXON_D <= TXON;
       end if;
    end if;   
end process;

TR_STATE_CHANGED <= '1' when (TXON_D /= TXON) else '0';

TDD_CTRL_002: if TDD_SKIP_VCO_CAL = '0' generate 
process (RX_CLK)
begin
	if rising_edge(RX_CLK) then
	   if (MCU_CFG_DONE = '0') then
	       TXEN <= '0';
	       ENABLE <= '0';
	       TDD_CNT <= (others => '1');
	   elsif (TR_STATE_CHANGED = '1') then
	       TDD_CNT <= (others => '0');
	       ENABLE <= '0';                  -- to alert, 1 clock delay
	   elsif (TDD_CNT < "1000" ) then
	       TDD_CNT <= TDD_CNT + 1;
	   elsif (TDD_CNT >= "1000" and  TDD_CNT < "1111") then
	       TDD_CNT <= TDD_CNT + 1;
	       TXEN <= TXON;                   -- make sure TXEN is changed in alert state
	   else
	       if (TXON = '1') then
	       ENABLE <= TX_PLL_LOCKED;        -- wait for tx pll lock
	       else
	       ENABLE <= RX_PLL_LOCKED;        -- wait for rx pll lock
	       end if;
	       TXEN <= TXON;
	   end if;   
	end if;    
end process;
end generate;

AD_PLL_LOCK_DET: process (RX_CLK)
begin
	if rising_edge(RX_CLK) then
	   if (MCU_CFG_DONE = '0') then
	       TX_PLL_LOCKED <= '0';
	       RX_PLL_LOCKED <= '0';
	       BB_PLL_LOCKED <= '0';
	   else
	       TX_PLL_LOCKED <= CTRL_OUT(7);
	       RX_PLL_LOCKED <= CTRL_OUT(6);
	       BB_PLL_LOCKED <= CTRL_OUT(5);
	   end if;
    end if;    
end process;