From 272b08ce9a66b3ba1b9dc91922afff410145231f Mon Sep 17 00:00:00 2001
From: Josh Blum <josh@joshknows.com>
Date: Fri, 7 May 2010 01:02:20 +0000
Subject: work on codec control, writing aux dacs, read aux adc

---
 host/lib/ic_reg_maps/gen_ad9862_regs.py |   2 +-
 host/lib/usrp/usrp_e/CMakeLists.txt     |  28 +++---
 host/lib/usrp/usrp_e/clock_ctrl.cpp     |   1 -
 host/lib/usrp/usrp_e/codec_ctrl.cpp     | 145 +++++++++++++++++++++++++-------
 host/lib/usrp/usrp_e/codec_ctrl.hpp     |  10 ++-
 5 files changed, 141 insertions(+), 45 deletions(-)

(limited to 'host/lib')

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;
 
 };
 
-- 
cgit v1.2.3