From 6c8f24a9ca136c78fd73e94e937b3325a26a1fab Mon Sep 17 00:00:00 2001 From: Martin Braun Date: Thu, 16 Sep 2021 13:33:23 +0200 Subject: ad9361: Modify set-tx-gain procedure to update gain in one go The previous behaviour of UHD for setting gain was: 1. Set "Mask Clr Atten Update". This will avoid "Immediately Update TPC Atten" to be cleared. 2. Then, assert "Immediately Update TPC Atten". 3. Poke the LSBs of the attenuation value. 4. Poke the MSB of the attenuation value. This order of operations has the downside of causing large Tx power spikes when setting the attenuation, because you need both registers to properly set the attenuation, but we are updating the gain immediately, even between the two attenuation register's update. Moreover, the upstream Linux driver for AD9361 by ADI also does not do this. We therefore change the procedure to match the kernel driver behaviour, which is: 0. [During initialization: Clear "Mask Clr Atten Update" 1. Poke the attenuation registers 2. Then, assert "Immediately Update TPC Atten". This avoids Tx power spikes. It also reduces the Tx-gain procedure to 3 pokes instead of 4. --- host/lib/usrp/common/ad9361_driver/ad9361_device.cpp | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) (limited to 'host') diff --git a/host/lib/usrp/common/ad9361_driver/ad9361_device.cpp b/host/lib/usrp/common/ad9361_driver/ad9361_device.cpp index 9275c83f5..5574022b6 100644 --- a/host/lib/usrp/common/ad9361_driver/ad9361_device.cpp +++ b/host/lib/usrp/common/ad9361_driver/ad9361_device.cpp @@ -1817,6 +1817,10 @@ void ad9361_device_t::initialize() /* Set TXers & RXers on (only works in FDD mode) */ _io_iface->poke8(0x014, 0x21); + + /* We won't be using immediate-Tx-attenuation, so we de-assert "Mask Clr + * Atten Update". */ + _io_iface->poke8(0x077, 0x00); } void ad9361_device_t::set_io_iface(ad9361_io::sptr io_iface) @@ -2203,11 +2207,6 @@ double ad9361_device_t::set_gain(direction_t direction, chain_t chain, const dou return gain_index; } else { - /* Setting the below bits causes a change in the TX attenuation word - * to immediately take effect. */ - _io_iface->poke8(0x077, 0x40); - _io_iface->poke8(0x07c, 0x40); - /* Each gain step is -0.25dB. Calculate the attenuation necessary * for the requested gain, convert it into gain steps, then write * the attenuation word. Max gain (so zero attenuation) is 89.75. @@ -2215,8 +2214,8 @@ double ad9361_device_t::set_gain(direction_t direction, chain_t chain, const dou * "value" is out of bounds, so range checking must be performed * outside this function. */ - double atten = AD9361_MAX_GAIN - value; - uint32_t attenreg = uint32_t(atten * 4); + const double atten = AD9361_MAX_GAIN - value; + const uint32_t attenreg = uint32_t(atten * 4); if (chain == CHAIN_1) { _tx1_gain = value; _io_iface->poke8(0x073, attenreg & 0xFF); @@ -2226,6 +2225,13 @@ double ad9361_device_t::set_gain(direction_t direction, chain_t chain, const dou _io_iface->poke8(0x075, attenreg & 0xFF); _io_iface->poke8(0x076, (attenreg >> 8) & 0x01); } + + /* After we've set both registers for the new gain, we apply it (assert + * "Immediately Update TPC Atten"). This avoids the attenuation from + * intermediately becoming very small (i.e., high output power) during + * the set-gain cycle. + */ + _io_iface->poke8(0x07c, 0x40); return AD9361_MAX_GAIN - ((double)(attenreg) / 4); } } -- cgit v1.2.3