diff options
Diffstat (limited to 'host/lib/usrp/dboard/magnesium/magnesium_radio_control_cpld.cpp')
-rw-r--r-- | host/lib/usrp/dboard/magnesium/magnesium_radio_control_cpld.cpp | 297 |
1 files changed, 297 insertions, 0 deletions
diff --git a/host/lib/usrp/dboard/magnesium/magnesium_radio_control_cpld.cpp b/host/lib/usrp/dboard/magnesium/magnesium_radio_control_cpld.cpp new file mode 100644 index 000000000..41f99cd68 --- /dev/null +++ b/host/lib/usrp/dboard/magnesium/magnesium_radio_control_cpld.cpp @@ -0,0 +1,297 @@ +// +// Copyright 2017 Ettus Research, a National Instruments Company +// +// SPDX-License-Identifier: GPL-3.0-or-later +// + +#include "magnesium_constants.hpp" +#include "magnesium_cpld_ctrl.hpp" +#include "magnesium_radio_control.hpp" +#include <uhd/utils/log.hpp> + +using namespace uhd; +using namespace uhd::usrp; +using namespace uhd::rfnoc; + +void magnesium_radio_control_impl::_identify_with_leds(const int identify_duration) +{ + auto end_time = + std::chrono::steady_clock::now() + std::chrono::seconds(identify_duration); + bool led_state = true; + while (std::chrono::steady_clock::now() < end_time) { + _cpld->set_tx_atr_bits(magnesium_cpld_ctrl::BOTH, + magnesium_cpld_ctrl::ANY, + led_state, + false, + false, + true); + _cpld->set_rx_input_atr_bits(magnesium_cpld_ctrl::BOTH, + magnesium_cpld_ctrl::ANY, + magnesium_cpld_ctrl::RX_SW1_TXRXINPUT, /* whatever */ + led_state, + led_state); + led_state = !led_state; + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + } + _cpld->reset(); +} + +void magnesium_radio_control_impl::_update_atr_switches( + const magnesium_cpld_ctrl::chan_sel_t chan, + const direction_t dir, + const std::string& ant) +{ + if (dir == RX_DIRECTION or dir == DX_DIRECTION) { + // These default values work for RX2 + bool trx_led = false; + bool rx2_led = true; + auto rx_sw1 = magnesium_cpld_ctrl::RX_SW1_RX2INPUT; + // The TRX switch in TX-idle mode defaults to TX-on mode. When TX is + // off, and we're receiving on TX/RX however, we need to point TRX to + // RX SW1. In all other cases, a TX state toggle (on to idle or vice + // versa) won't trigger a change of the TRX switch. + auto sw_trx = _sw_trx[chan]; + RFNOC_LOG_TRACE("Updating all RX-ATR related switches for antenna==" << ant); + if (ant == "TX/RX") { + rx_sw1 = magnesium_cpld_ctrl::RX_SW1_TRXSWITCHOUTPUT; + sw_trx = magnesium_cpld_ctrl::SW_TRX_RXCHANNELPATH; + trx_led = true; + rx2_led = false; + } else if (ant == "CAL") { + // It makes intuitive sense to illuminate the green TX/RX LED when + // receiving on CAL (because it goes over to the TX/RX port), but + // the problem is that CAL is only useful when we're both TXing and + // RXing, and then both green and red would be on the same LED. + // So, for CAL, we light up the green RX2 LED. + trx_led = false; + rx2_led = true; + rx_sw1 = magnesium_cpld_ctrl::RX_SW1_TXRXINPUT; + } else if (ant == "LOCAL") { + rx_sw1 = magnesium_cpld_ctrl::RX_SW1_RXLOCALINPUT; + } + _cpld->set_rx_input_atr_bits(chan, + magnesium_cpld_ctrl::ON, + rx_sw1, + trx_led, + rx2_led, + true /* defer commit */ + ); + _cpld->set_rx_atr_bits(chan, + magnesium_cpld_ctrl::ON, + true, /* amp on */ + true, /* mykonos on */ + true /* defer commit */ + ); + _cpld->set_rx_atr_bits(chan, + magnesium_cpld_ctrl::IDLE, + true, /* amp stays on */ + true, /* mykonos on */ + true /* defer commit */ + ); + _cpld->set_trx_sw_atr_bits(chan, + magnesium_cpld_ctrl::IDLE, /* idle here means TX is off */ + sw_trx, + false /* don't defer commit */ + ); + } + if (dir == TX_DIRECTION or dir == DX_DIRECTION) { + RFNOC_LOG_TRACE("Updating all TX-ATR related switches..."); + _cpld->set_tx_atr_bits(chan, + magnesium_cpld_ctrl::ON, + true, /* LED on */ + true, /* PA on */ + true, /* AMP on */ + true, /* Myk on */ + true /* defer commit */ + ); + // Leaving PA on since we want shorter tx settling time. + _cpld->set_tx_atr_bits(chan, + magnesium_cpld_ctrl::IDLE, + false, /* LED off */ + true, /* PA on */ + true, /* AMP on */ + true, /* Myk on */ + false /* don't defer commit */ + ); + }; +} + +void magnesium_radio_control_impl::_update_rx_freq_switches(const double freq, + const bool bypass_lnas, + const magnesium_cpld_ctrl::chan_sel_t chan_sel) +{ + RFNOC_LOG_TRACE( + "Update all RX freq related switches. f=" << freq + << " Hz, " + "bypass LNAS: " + << (bypass_lnas ? "Yes" : "No") + << ", chan=" << chan_sel); + auto rx_sw2 = magnesium_cpld_ctrl::RX_SW2_BYPASSPATHTOSWITCH6; + auto rx_sw3 = magnesium_cpld_ctrl::RX_SW3_SHUTDOWNSW3; + auto rx_sw4 = magnesium_cpld_ctrl::RX_SW4_FILTER2100X2850MHZFROM; + auto rx_sw5 = magnesium_cpld_ctrl::RX_SW5_FILTER1100X1575MHZFROM; + auto rx_sw6 = magnesium_cpld_ctrl::RX_SW6_BYPASSPATHFROMSWITCH2; + const auto band = _map_freq_to_rx_band(_rx_band_map, freq); + const bool is_lowband = (band == rx_band::LOWBAND); + const auto select_lowband_mixer_path = + is_lowband ? magnesium_cpld_ctrl::LOWBAND_MIXER_PATH_SEL_LOBAND + : magnesium_cpld_ctrl::LOWBAND_MIXER_PATH_SEL_BYPASS; + const bool enable_lowband_mixer = is_lowband; + const bool rx_lna1_enable = + not bypass_lnas + and (band == rx_band::BAND4 or band == rx_band::BAND5 or band == rx_band::BAND6); + const bool rx_lna2_enable = not bypass_lnas and not rx_lna1_enable; + RFNOC_LOG_TRACE( + " Enabling LNA1: " << (rx_lna1_enable ? "Yes" : "No") + << " Enabling LNA2: " << (rx_lna2_enable ? "Yes" : "No")); + // All the defaults are OK when using the bypass path. + if (not bypass_lnas) { + switch (band) { + case rx_band::LOWBAND: + case rx_band::BAND0: + rx_sw2 = magnesium_cpld_ctrl::RX_SW2_LOWERFILTERBANKTOSWITCH3; + rx_sw3 = magnesium_cpld_ctrl::RX_SW3_FILTER0490LPMHZ; + rx_sw4 = magnesium_cpld_ctrl::RX_SW4_FILTER2700HPMHZ; + rx_sw5 = magnesium_cpld_ctrl::RX_SW5_FILTER0490LPMHZFROM; + rx_sw6 = magnesium_cpld_ctrl::RX_SW6_LOWERFILTERBANKFROMSWITCH5; + break; + case rx_band::BAND1: + rx_sw2 = magnesium_cpld_ctrl::RX_SW2_LOWERFILTERBANKTOSWITCH3; + rx_sw3 = magnesium_cpld_ctrl::RX_SW3_FILTER0440X0530MHZ; + rx_sw4 = magnesium_cpld_ctrl::RX_SW4_FILTER2700HPMHZ; + rx_sw5 = magnesium_cpld_ctrl::RX_SW5_FILTER0440X0530MHZFROM; + rx_sw6 = magnesium_cpld_ctrl::RX_SW6_LOWERFILTERBANKFROMSWITCH5; + break; + case rx_band::BAND2: + rx_sw2 = magnesium_cpld_ctrl::RX_SW2_LOWERFILTERBANKTOSWITCH3; + rx_sw3 = magnesium_cpld_ctrl::RX_SW3_FILTER0650X1000MHZ; + rx_sw4 = magnesium_cpld_ctrl::RX_SW4_FILTER2700HPMHZ; + rx_sw5 = magnesium_cpld_ctrl::RX_SW5_FILTER0650X1000MHZFROM; + rx_sw6 = magnesium_cpld_ctrl::RX_SW6_LOWERFILTERBANKFROMSWITCH5; + break; + case rx_band::BAND3: + rx_sw2 = magnesium_cpld_ctrl::RX_SW2_LOWERFILTERBANKTOSWITCH3; + rx_sw3 = magnesium_cpld_ctrl::RX_SW3_FILTER1100X1575MHZ; + rx_sw4 = magnesium_cpld_ctrl::RX_SW4_FILTER2700HPMHZ; + rx_sw5 = magnesium_cpld_ctrl::RX_SW5_FILTER1100X1575MHZFROM; + rx_sw6 = magnesium_cpld_ctrl::RX_SW6_LOWERFILTERBANKFROMSWITCH5; + break; + case rx_band::BAND4: + rx_sw2 = magnesium_cpld_ctrl::RX_SW2_LOWERFILTERBANKTOSWITCH3; + rx_sw3 = magnesium_cpld_ctrl::RX_SW3_FILTER1600X2250MHZ; + rx_sw4 = magnesium_cpld_ctrl::RX_SW4_FILTER1600X2250MHZFROM; + rx_sw5 = magnesium_cpld_ctrl::RX_SW5_FILTER0440X0530MHZFROM; + rx_sw6 = magnesium_cpld_ctrl::RX_SW6_UPPERFILTERBANKFROMSWITCH4; + break; + case rx_band::BAND5: + rx_sw2 = magnesium_cpld_ctrl::RX_SW2_LOWERFILTERBANKTOSWITCH3; + rx_sw3 = magnesium_cpld_ctrl::RX_SW3_FILTER2100X2850MHZ; + rx_sw4 = magnesium_cpld_ctrl::RX_SW4_FILTER2100X2850MHZFROM; + rx_sw5 = magnesium_cpld_ctrl::RX_SW5_FILTER0440X0530MHZFROM; + rx_sw6 = magnesium_cpld_ctrl::RX_SW6_UPPERFILTERBANKFROMSWITCH4; + break; + case rx_band::BAND6: + rx_sw2 = magnesium_cpld_ctrl::RX_SW2_UPPERFILTERBANKTOSWITCH4; + rx_sw3 = magnesium_cpld_ctrl::RX_SW3_SHUTDOWNSW3; + rx_sw4 = magnesium_cpld_ctrl::RX_SW4_FILTER2700HPMHZ; + rx_sw5 = magnesium_cpld_ctrl::RX_SW5_FILTER0440X0530MHZFROM; + rx_sw6 = magnesium_cpld_ctrl::RX_SW6_UPPERFILTERBANKFROMSWITCH4; + break; + case rx_band::INVALID_BAND: + RFNOC_LOG_ERROR("Cannot map RX frequency to band: " << freq); + break; + default: + UHD_THROW_INVALID_CODE_PATH(); + } + } + + _cpld->set_rx_lna_atr_bits(chan_sel, + magnesium_cpld_ctrl::ANY, + rx_lna1_enable, + rx_lna2_enable, + true /* defer commit */ + ); + _cpld->set_rx_switches(chan_sel, + rx_sw2, + rx_sw3, + rx_sw4, + rx_sw5, + rx_sw6, + select_lowband_mixer_path, + enable_lowband_mixer); +} + +void magnesium_radio_control_impl::_update_tx_freq_switches(const double freq, + const bool bypass_amp, + const magnesium_cpld_ctrl::chan_sel_t chan_sel) +{ + RFNOC_LOG_TRACE("Update all TX freq related switches. f=" + << freq + << " Hz, " + "bypass amp: " + << (bypass_amp ? "Yes" : "No") << ", chan=" << chan_sel); + auto tx_sw1 = magnesium_cpld_ctrl::TX_SW1_SHUTDOWNTXSW1; + auto tx_sw2 = magnesium_cpld_ctrl::TX_SW2_TOTXFILTERLP6400MHZ; + auto tx_sw3 = magnesium_cpld_ctrl::TX_SW3_BYPASSPATHTOTRXSW; + const auto band = _map_freq_to_tx_band(_tx_band_map, freq); + const bool is_lowband = (band == tx_band::LOWBAND); + const auto select_lowband_mixer_path = + is_lowband ? magnesium_cpld_ctrl::LOWBAND_MIXER_PATH_SEL_LOBAND + : magnesium_cpld_ctrl::LOWBAND_MIXER_PATH_SEL_BYPASS; + const bool enable_lowband_mixer = is_lowband; + // Defaults are fine for bypassing the amp stage + if (bypass_amp) { + _sw_trx[chan_sel] = magnesium_cpld_ctrl::SW_TRX_BYPASSPATHTOTXSW3; + } else { + // Set filters based on frequency + switch (band) { + case tx_band::LOWBAND: + _sw_trx[chan_sel] = magnesium_cpld_ctrl::SW_TRX_FROMLOWERFILTERBANKTXSW1; + tx_sw1 = magnesium_cpld_ctrl::TX_SW1_FROMTXFILTERLP0800MHZ; + tx_sw2 = magnesium_cpld_ctrl::TX_SW2_TOTXFILTERLP0800MHZ; + tx_sw3 = magnesium_cpld_ctrl::TX_SW3_TOTXFILTERBANKS; + break; + case tx_band::BAND0: + _sw_trx[chan_sel] = magnesium_cpld_ctrl::SW_TRX_FROMLOWERFILTERBANKTXSW1; + tx_sw1 = magnesium_cpld_ctrl::TX_SW1_FROMTXFILTERLP0800MHZ; + tx_sw2 = magnesium_cpld_ctrl::TX_SW2_TOTXFILTERLP0800MHZ; + tx_sw3 = magnesium_cpld_ctrl::TX_SW3_TOTXFILTERBANKS; + break; + case tx_band::BAND1: + _sw_trx[chan_sel] = magnesium_cpld_ctrl::SW_TRX_FROMLOWERFILTERBANKTXSW1; + tx_sw1 = magnesium_cpld_ctrl::TX_SW1_FROMTXFILTERLP1700MHZ; + tx_sw2 = magnesium_cpld_ctrl::TX_SW2_TOTXFILTERLP1700MHZ; + tx_sw3 = magnesium_cpld_ctrl::TX_SW3_TOTXFILTERBANKS; + break; + case tx_band::BAND2: + _sw_trx[chan_sel] = magnesium_cpld_ctrl::SW_TRX_FROMLOWERFILTERBANKTXSW1; + tx_sw1 = magnesium_cpld_ctrl::TX_SW1_FROMTXFILTERLP3400MHZ; + tx_sw2 = magnesium_cpld_ctrl::TX_SW2_TOTXFILTERLP3400MHZ; + tx_sw3 = magnesium_cpld_ctrl::TX_SW3_TOTXFILTERBANKS; + break; + case tx_band::BAND3: + _sw_trx[chan_sel] = + magnesium_cpld_ctrl::SW_TRX_FROMTXUPPERFILTERBANKLP6400MHZ; + tx_sw1 = magnesium_cpld_ctrl::TX_SW1_SHUTDOWNTXSW1; + tx_sw2 = magnesium_cpld_ctrl::TX_SW2_TOTXFILTERLP6400MHZ; + tx_sw3 = magnesium_cpld_ctrl::TX_SW3_TOTXFILTERBANKS; + break; + case tx_band::INVALID_BAND: + RFNOC_LOG_ERROR("Cannot map TX frequency to band: " << freq); + break; + default: + UHD_THROW_INVALID_CODE_PATH(); + } + } + + _cpld->set_trx_sw_atr_bits( + chan_sel, magnesium_cpld_ctrl::ON, _sw_trx[chan_sel], true /* defer commit */ + ); + _cpld->set_tx_switches(chan_sel, + tx_sw1, + tx_sw2, + tx_sw3, + select_lowband_mixer_path, + enable_lowband_mixer, + magnesium_cpld_ctrl::ON); +} |