diff options
-rwxr-xr-x | host/lib/ic_reg_maps/gen_ad9862_regs.py | 2 | ||||
-rw-r--r-- | host/lib/usrp/usrp_e/CMakeLists.txt | 28 | ||||
-rw-r--r-- | host/lib/usrp/usrp_e/clock_ctrl.cpp | 1 | ||||
-rw-r--r-- | host/lib/usrp/usrp_e/codec_ctrl.cpp | 145 | ||||
-rw-r--r-- | host/lib/usrp/usrp_e/codec_ctrl.hpp | 10 |
5 files changed, 141 insertions, 45 deletions
diff --git a/host/lib/ic_reg_maps/gen_ad9862_regs.py b/host/lib/ic_reg_maps/gen_ad9862_regs.py index 2094f5e4b..4444c6240 100755 --- a/host/lib/ic_reg_maps/gen_ad9862_regs.py +++ b/host/lib/ic_reg_maps/gen_ad9862_regs.py @@ -233,7 +233,7 @@ boost::uint16_t get_write_reg(boost::uint8_t addr){ } boost::uint16_t get_read_reg(boost::uint8_t addr){ - return (boost::uint16_t(addr) << 8) | (1 << 7); + return (boost::uint16_t(addr) << 8) | (1 << 15); } """ diff --git a/host/lib/usrp/usrp_e/CMakeLists.txt b/host/lib/usrp/usrp_e/CMakeLists.txt index 2eff3147d..c25b2cba4 100644 --- a/host/lib/usrp/usrp_e/CMakeLists.txt +++ b/host/lib/usrp/usrp_e/CMakeLists.txt @@ -17,18 +17,26 @@ #This file will be included by cmake, use absolute paths! +######################################################################## +# Helpful macro to check for required headers +######################################################################## +INCLUDE(CheckIncludeFileCXX) +SET(HAVE_USRP_E_REQUIRED_HEADERS TRUE) +MACRO(USRP_E_REQUIRE_HEADER header variable) + CHECK_INCLUDE_FILE_CXX(${header} ${variable}) + IF(NOT ${variable}) + SET(HAVE_USRP_E_REQUIRED_HEADERS FALSE) + ENDIF(NOT ${variable}) +ENDMACRO(USRP_E_REQUIRE_HEADER) + +######################################################################## +# Conditionally configure the USRP-E support +######################################################################## MESSAGE(STATUS "Configuring usrp-e support...") -INCLUDE(CheckIncludeFiles) -SET(usrp_e_required_headers - linux/ioctl.h - linux/spi/spidev.h - linux/usrp_e.h -) -CHECK_INCLUDE_FILES( - "${usrp_e_required_headers}" - HAVE_USRP_E_REQUIRED_HEADERS -) +USRP_E_REQUIRE_HEADER(linux/ioctl.h HAVE_LINUX_IOCTL_H) +USRP_E_REQUIRE_HEADER(linux/spi/spidev.h HAVE_LINUX_SPI_SPIDEV_H) +USRP_E_REQUIRE_HEADER(linux/usrp_e.h HAVE_LINUX_USRP_E_H) IF(HAVE_USRP_E_REQUIRED_HEADERS) MESSAGE(STATUS " Building usrp-e support.") diff --git a/host/lib/usrp/usrp_e/clock_ctrl.cpp b/host/lib/usrp/usrp_e/clock_ctrl.cpp index 2fe3c9294..9c2ddf670 100644 --- a/host/lib/usrp/usrp_e/clock_ctrl.cpp +++ b/host/lib/usrp/usrp_e/clock_ctrl.cpp @@ -37,7 +37,6 @@ public: void enable_rx_dboard_clock(bool enb); void enable_tx_dboard_clock(bool enb); - void enable_codec_clock(bool enb); private: usrp_e_iface::sptr _iface; diff --git a/host/lib/usrp/usrp_e/codec_ctrl.cpp b/host/lib/usrp/usrp_e/codec_ctrl.cpp index daa6ed3e3..a430f2c6f 100644 --- a/host/lib/usrp/usrp_e/codec_ctrl.cpp +++ b/host/lib/usrp/usrp_e/codec_ctrl.cpp @@ -17,34 +17,16 @@ #include "codec_ctrl.hpp" #include "ad9862_regs.hpp" +#include <uhd/types/dict.hpp> +#include <uhd/utils/assert.hpp> +#include <uhd/utils/algorithm.hpp> #include <boost/cstdint.hpp> +#include <boost/tuple/tuple.hpp> +#include <boost/math/special_functions/round.hpp> #include "usrp_e_regs.hpp" //spi slave constants #include <boost/assign/list_of.hpp> -//#include <boost/foreach.hpp> -//#include <utility> #include <iostream> - //test out codec ls dac/adc - //ad9862_regs_t ad9862_regs; - //ad9862_regs.select_a = ad9862_regs_t::SELECT_A_AUX_ADC1; - //ad9862_regs.aux_dac_a = 0xff/2; - //_iface->transact_spi( - // UE_SPI_SS_AD9862, - // spi_config_t::EDGE_RISE, - // ad9862_regs.get_write_reg(34), 16, false /*no rb*/ - //); - //_iface->transact_spi( - // UE_SPI_SS_AD9862, - // spi_config_t::EDGE_RISE, - // ad9862_regs.get_write_reg(36), 16, false /*no rb*/ - //); - //boost::uint32_t val = _iface->transact_spi( - // UE_SPI_SS_AD9862, - // spi_config_t::EDGE_RISE, - // ad9862_regs.get_read_reg(29), 16, true - //); - //std::cout << "value: " << std::hex << val << std::endl; - using namespace uhd; /*********************************************************************** @@ -58,16 +40,18 @@ public: //aux adc and dac control float read_aux_adc(aux_adc_t which); - void read_aux_adc(aux_dac_t which, float volts); + void write_aux_dac(aux_dac_t which, float volts); private: usrp_e_iface::sptr _iface; ad9862_regs_t _ad9862_regs; + aux_adc_t _last_aux_adc_a, _last_aux_adc_b; void send_reg(boost::uint8_t addr); + void recv_reg(boost::uint8_t addr); }; /*********************************************************************** - * Codec Control Methods + * Codec Control Structors **********************************************************************/ codec_ctrl_impl::codec_ctrl_impl(usrp_e_iface::sptr iface){ _iface = iface; @@ -88,6 +72,13 @@ codec_ctrl_impl::codec_ctrl_impl(usrp_e_iface::sptr iface){ } codec_ctrl_impl::~codec_ctrl_impl(void){ + //set aux dacs to zero + this->write_aux_dac(AUX_DAC_A, 0); + this->write_aux_dac(AUX_DAC_B, 0); + this->write_aux_dac(AUX_DAC_C, 0); + this->write_aux_dac(AUX_DAC_D, 0); + + //power down _ad9862_regs.all_rx_pd = 1; this->send_reg(1); _ad9862_regs.tx_digital_pd = 1; @@ -95,23 +86,119 @@ codec_ctrl_impl::~codec_ctrl_impl(void){ this->send_reg(8); } +/*********************************************************************** + * Codec Control AUX ADC Methods + **********************************************************************/ +static float aux_adc_to_volts(boost::uint8_t high, boost::uint8_t low){ + return float((boost::uint16_t(high) << 2) | low)*3.3/0x3ff; +} + float codec_ctrl_impl::read_aux_adc(aux_adc_t which){ - return 0; + //check to see if the switch needs to be set + bool write_switch = false; + switch(which){ + + case AUX_ADC_A1: + case AUX_ADC_A2: + if (which != _last_aux_adc_a){ + _ad9862_regs.select_a = (which == AUX_ADC_A1)? + ad9862_regs_t::SELECT_A_AUX_ADC1: ad9862_regs_t::SELECT_A_AUX_ADC2; + _last_aux_adc_a = which; + write_switch = true; + } + break; + + case AUX_ADC_B1: + case AUX_ADC_B2: + if (which != _last_aux_adc_b){ + _ad9862_regs.select_b = (which == AUX_ADC_B1)? + ad9862_regs_t::SELECT_B_AUX_ADC1: ad9862_regs_t::SELECT_B_AUX_ADC2; + _last_aux_adc_b = which; + write_switch = true; + } + break; + + } + //write the switch if it changed + if(write_switch) this->send_reg(34); + + //map aux adcs to register values to read + static const uhd::dict<aux_adc_t, boost::uint8_t> aux_dac_to_addr = boost::assign::map_list_of + (AUX_ADC_A2, 26) (AUX_ADC_A1, 28) + (AUX_ADC_B2, 30) (AUX_ADC_B1, 32) + ; + + //read the value + this->recv_reg(aux_dac_to_addr[which]+0); + this->recv_reg(aux_dac_to_addr[which]+1); + + //return the value scaled to volts + switch(which){ + case AUX_ADC_A1: return aux_adc_to_volts(_ad9862_regs.aux_adc_a1_9_2, _ad9862_regs.aux_adc_a1_1_0); + case AUX_ADC_A2: return aux_adc_to_volts(_ad9862_regs.aux_adc_a2_9_2, _ad9862_regs.aux_adc_a2_1_0); + case AUX_ADC_B1: return aux_adc_to_volts(_ad9862_regs.aux_adc_b1_9_2, _ad9862_regs.aux_adc_b1_1_0); + case AUX_ADC_B2: return aux_adc_to_volts(_ad9862_regs.aux_adc_b2_9_2, _ad9862_regs.aux_adc_b2_1_0); + } + UHD_ASSERT_THROW(false); } -void codec_ctrl_impl::read_aux_adc(aux_dac_t which, float volts){ - +/*********************************************************************** + * Codec Control AUX DAC Methods + **********************************************************************/ +void codec_ctrl_impl::write_aux_dac(aux_dac_t which, float volts){ + //special case for aux dac d (aka sigma delta word) + if (which == AUX_DAC_D){ + boost::uint16_t dac_word = std::clip(boost::math::iround(volts*0xfff/3.3), 0, 0xfff); + _ad9862_regs.sig_delt_11_4 = boost::uint8_t(dac_word >> 4); + _ad9862_regs.sig_delt_3_0 = boost::uint8_t(dac_word & 0xf); + this->send_reg(42); + this->send_reg(43); + return; + } + + //calculate the dac word for aux dac a, b, c + boost::uint8_t dac_word = std::clip(boost::math::iround(volts*0xff/3.3), 0, 0xff); + + //setup a lookup table for the aux dac params (reg ref, reg addr) + typedef boost::tuple<boost::uint8_t*, boost::uint8_t> dac_params_t; + uhd::dict<aux_dac_t, dac_params_t> aux_dac_to_params = boost::assign::map_list_of + (AUX_DAC_A, dac_params_t(&_ad9862_regs.aux_dac_a, 36)) + (AUX_DAC_B, dac_params_t(&_ad9862_regs.aux_dac_b, 37)) + (AUX_DAC_C, dac_params_t(&_ad9862_regs.aux_dac_c, 38)) + ; + + //set the aux dac register + UHD_ASSERT_THROW(aux_dac_to_params.has_key(which)); + boost::uint8_t *reg_ref, reg_addr; + boost::tie(reg_ref, reg_addr) = aux_dac_to_params[which]; + *reg_ref = dac_word; + this->send_reg(reg_addr); } +/*********************************************************************** + * Codec Control SPI Methods + **********************************************************************/ void codec_ctrl_impl::send_reg(boost::uint8_t addr){ boost::uint32_t reg = _ad9862_regs.get_write_reg(addr); //std::cout << "codec control write reg: " << std::hex << reg << std::endl; _iface->transact_spi( UE_SPI_SS_AD9862, spi_config_t::EDGE_RISE, - reg, 24, false /*no rb*/ + reg, 16, false /*no rb*/ + ); +} + +void codec_ctrl_impl::recv_reg(boost::uint8_t addr){ + boost::uint32_t reg = _ad9862_regs.get_read_reg(addr); + //std::cout << "codec control read reg: " << std::hex << reg << std::endl; + boost::uint32_t ret = _iface->transact_spi( + UE_SPI_SS_AD9862, + spi_config_t::EDGE_RISE, + reg, 16, true /*rb*/ ); + //std::cout << "codec control read ret: " << std::hex << ret << std::endl; + _ad9862_regs.set_reg(addr, boost::uint16_t(ret)); } /*********************************************************************** diff --git a/host/lib/usrp/usrp_e/codec_ctrl.hpp b/host/lib/usrp/usrp_e/codec_ctrl.hpp index 0fe70c4a2..efdcd7142 100644 --- a/host/lib/usrp/usrp_e/codec_ctrl.hpp +++ b/host/lib/usrp/usrp_e/codec_ctrl.hpp @@ -47,7 +47,9 @@ public: }; /*! - * Read the aux adc. + * Read an auxiliary adc: + * The internals remember which aux adc was read last. + * Therefore, the aux adc switch is only changed as needed. * \param which which of the 4 adcs * \return a value in volts */ @@ -58,15 +60,15 @@ public: AUX_DAC_A = 0xA, AUX_DAC_B = 0xB, AUX_DAC_C = 0xC, - AUX_DAC_D = 0xD + AUX_DAC_D = 0xD //really the sigma delta output }; /*! - * Write the aux dac. + * Write an auxiliary dac. * \param which which of the 4 dacs * \param volts the level in in volts */ - virtual void read_aux_adc(aux_dac_t which, float volts) = 0; + virtual void write_aux_dac(aux_dac_t which, float volts) = 0; }; |