aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xhost/lib/ic_reg_maps/gen_ad9862_regs.py2
-rw-r--r--host/lib/usrp/usrp_e/CMakeLists.txt28
-rw-r--r--host/lib/usrp/usrp_e/clock_ctrl.cpp1
-rw-r--r--host/lib/usrp/usrp_e/codec_ctrl.cpp145
-rw-r--r--host/lib/usrp/usrp_e/codec_ctrl.hpp10
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;
};