From 3a8577aeb3c76dce0d0dcf0c9c7ce8d9aaf0a1d8 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Thu, 29 Apr 2010 11:50:56 +0000 Subject: work on clock control init, added dummy spi slaves: must fix --- host/lib/ic_reg_maps/.gitignore | 1 + host/lib/ic_reg_maps/gen_ad9522_regs.py | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'host/lib/ic_reg_maps') diff --git a/host/lib/ic_reg_maps/.gitignore b/host/lib/ic_reg_maps/.gitignore index a74b07aee..053049d05 100644 --- a/host/lib/ic_reg_maps/.gitignore +++ b/host/lib/ic_reg_maps/.gitignore @@ -1 +1,2 @@ /*.pyc +/*.pyo diff --git a/host/lib/ic_reg_maps/gen_ad9522_regs.py b/host/lib/ic_reg_maps/gen_ad9522_regs.py index 63d8abe24..9da51205b 100755 --- a/host/lib/ic_reg_maps/gen_ad9522_regs.py +++ b/host/lib/ic_reg_maps/gen_ad9522_regs.py @@ -42,7 +42,7 @@ reset_all_counters 0x016[4] 0 b_counter_bypass 0x016[3] 0 normal, div1 prescaler_p 0x016[2:0] 6 div1, div2, div2_3, div4_5, div8_9, div16_17, div32_33, div3 status_pin_control 0x017[7:2] 0 -antibacklash_pulse_width 0x017[1:0] 0 2_9ns, 1_3ns, 6_0ns, 2_9ns +antibacklash_pulse_width 0x017[1:0] 0 2_9ns, 1_3ns, 6_0ns enb_cmos_ref_input_dc_off 0x018[7] 0 lock_detect_counter 0x018[6:5] 0 5cyc, 16cyc, 64cyc, 255cyc digital_lock_detect_window 0x018[4] 0 high_range, low_range @@ -60,7 +60,7 @@ enable_ref2_freq_monitor 0x01B[6] 0 enable_ref1_freq_monitor 0x01B[5] 0 refmon_pin_control 0x01B[4:0] 0 disable_switchover_deglitch 0x01C[7] 0 -select_ref2 0x01C[6] 0 ref1, ref2 +select_ref 0x01C[6] 0 ref1, ref2 use_ref_sel_pin 0x01C[5] 0 register, ref_sel enb_auto_ref_switchover 0x01C[4] 0 manual, auto stay_on_ref2 0x01C[3] 0 return_ref1, stay_ref2 -- cgit v1.2.3 From 8f21adbed40db490bec8ead6b8d50d2b3d1a4136 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Tue, 4 May 2010 09:32:38 +0000 Subject: created codec control for ad9862, wip --- host/lib/CMakeLists.txt | 1 + host/lib/ic_reg_maps/gen_ad9862_regs.py | 16 ++--- host/lib/usrp/usrp_e/clock_ctrl.cpp | 39 +++++++++- host/lib/usrp/usrp_e/codec_ctrl.cpp | 122 ++++++++++++++++++++++++++++++++ host/lib/usrp/usrp_e/codec_ctrl.hpp | 73 +++++++++++++++++++ host/lib/usrp/usrp_e/usrp_e_iface.cpp | 7 +- host/lib/usrp/usrp_e/usrp_e_impl.cpp | 8 ++- host/lib/usrp/usrp_e/usrp_e_impl.hpp | 8 +++ 8 files changed, 259 insertions(+), 15 deletions(-) create mode 100644 host/lib/usrp/usrp_e/codec_ctrl.cpp create mode 100644 host/lib/usrp/usrp_e/codec_ctrl.hpp (limited to 'host/lib/ic_reg_maps') diff --git a/host/lib/CMakeLists.txt b/host/lib/CMakeLists.txt index 20373cd59..be57699fc 100644 --- a/host/lib/CMakeLists.txt +++ b/host/lib/CMakeLists.txt @@ -185,6 +185,7 @@ IF(HAVE_USRP_E_REQUIRED_HEADERS) MESSAGE(STATUS " Building usrp-e support.") LIST(APPEND libuhd_sources usrp/usrp_e/clock_ctrl.cpp + usrp/usrp_e/codec_ctrl.cpp usrp/usrp_e/dboard_impl.cpp usrp/usrp_e/dboard_iface.cpp usrp/usrp_e/dsp_impl.cpp diff --git a/host/lib/ic_reg_maps/gen_ad9862_regs.py b/host/lib/ic_reg_maps/gen_ad9862_regs.py index fdbea5828..2094f5e4b 100755 --- a/host/lib/ic_reg_maps/gen_ad9862_regs.py +++ b/host/lib/ic_reg_maps/gen_ad9862_regs.py @@ -30,14 +30,14 @@ soft_reset 0[5] 0 ######################################################################## ## Rx Power Down ######################################################################## -pd_vref_diff 1[7] 0 -pd_vref 1[6] 0 -pd_rx_digital 1[5] 0 -pd_rx_channel_b 1[4] 0 -pd_rx_channel_a 1[3] 0 -pd_buffer_b 1[2] 0 -pd_buffer_a 1[1] 0 -pd_all_rx 1[0] 0 +vref_diff_pd 1[7] 0 +vref_pd 1[6] 0 +rx_digital_pd 1[5] 0 +rx_channel_b_pd 1[4] 0 +rx_channel_a_pd 1[3] 0 +buffer_b_pd 1[2] 0 +buffer_a_pd 1[1] 0 +all_rx_pd 1[0] 0 ######################################################################## ## Rx A and B ######################################################################## diff --git a/host/lib/usrp/usrp_e/clock_ctrl.cpp b/host/lib/usrp/usrp_e/clock_ctrl.cpp index fa4028cc5..2fe3c9294 100644 --- a/host/lib/usrp/usrp_e/clock_ctrl.cpp +++ b/host/lib/usrp/usrp_e/clock_ctrl.cpp @@ -37,6 +37,7 @@ 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; @@ -79,10 +80,22 @@ clock_ctrl_impl::clock_ctrl_impl(usrp_e_iface::sptr iface){ _ad9522_regs.vco_divider = ad9522_regs_t::VCO_DIVIDER_DIV5; _ad9522_regs.select_vco_or_clock = ad9522_regs_t::SELECT_VCO_OR_CLOCK_VCO; + //setup fpga master clock _ad9522_regs.out0_format = ad9522_regs_t::OUT0_FORMAT_LVDS; _ad9522_regs.divider0_low_cycles = 2; //3 low _ad9522_regs.divider0_high_cycles = 1; //2 high + //setup codec clock + _ad9522_regs.out3_format = ad9522_regs_t::OUT3_FORMAT_LVDS; + _ad9522_regs.divider1_low_cycles = 2; //3 low + _ad9522_regs.divider1_high_cycles = 1; //2 high + + //setup test clock (same divider as codec clock) + _ad9522_regs.out4_format = ad9522_regs_t::OUT4_FORMAT_CMOS; + _ad9522_regs.out4_cmos_configuration = (true)? + ad9522_regs_t::OUT4_CMOS_CONFIGURATION_A_ON : + ad9522_regs_t::OUT4_CMOS_CONFIGURATION_OFF; + //setup a list of register ranges to write typedef std::pair range_t; static const std::vector ranges = boost::assign::list_of @@ -106,6 +119,8 @@ clock_ctrl_impl::clock_ctrl_impl(usrp_e_iface::sptr iface){ // reg, 24, true /*no*/ //); //std::cout << "result " << std::hex << result << std::endl; + this->enable_rx_dboard_clock(false); + this->enable_tx_dboard_clock(false); } clock_ctrl_impl::~clock_ctrl_impl(void){ @@ -114,16 +129,34 @@ clock_ctrl_impl::~clock_ctrl_impl(void){ } void clock_ctrl_impl::enable_rx_dboard_clock(bool enb){ - + _ad9522_regs.out9_format = ad9522_regs_t::OUT9_FORMAT_CMOS; + _ad9522_regs.out9_cmos_configuration = (enb)? + ad9522_regs_t::OUT9_CMOS_CONFIGURATION_B_ON : + ad9522_regs_t::OUT9_CMOS_CONFIGURATION_OFF; + this->send_reg(0x0F9); + + _ad9522_regs.divider3_low_cycles = 2; //3 low + _ad9522_regs.divider3_high_cycles = 1; //2 high + this->send_reg(0x199); + this->latch_regs(); } void clock_ctrl_impl::enable_tx_dboard_clock(bool enb){ - + _ad9522_regs.out6_format = ad9522_regs_t::OUT6_FORMAT_CMOS; + _ad9522_regs.out6_cmos_configuration = (enb)? + ad9522_regs_t::OUT6_CMOS_CONFIGURATION_B_ON : + ad9522_regs_t::OUT6_CMOS_CONFIGURATION_OFF; + this->send_reg(0x0F6); + + _ad9522_regs.divider2_low_cycles = 2; //3 low + _ad9522_regs.divider2_high_cycles = 1; //2 high + this->send_reg(0x196); + this->latch_regs(); } void clock_ctrl_impl::send_reg(boost::uint16_t addr){ boost::uint32_t reg = _ad9522_regs.get_write_reg(addr); - std::cout << "clock control write reg: " << std::hex << reg << std::endl; + //std::cout << "clock control write reg: " << std::hex << reg << std::endl; _iface->transact_spi( UE_SPI_SS_AD9522, spi_config_t::EDGE_RISE, diff --git a/host/lib/usrp/usrp_e/codec_ctrl.cpp b/host/lib/usrp/usrp_e/codec_ctrl.cpp new file mode 100644 index 000000000..daa6ed3e3 --- /dev/null +++ b/host/lib/usrp/usrp_e/codec_ctrl.cpp @@ -0,0 +1,122 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +#include "codec_ctrl.hpp" +#include "ad9862_regs.hpp" +#include +#include "usrp_e_regs.hpp" //spi slave constants +#include +//#include +//#include +#include + + //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; + +/*********************************************************************** + * Codec Control Implementation + **********************************************************************/ +class codec_ctrl_impl : public codec_ctrl{ +public: + //structors + codec_ctrl_impl(usrp_e_iface::sptr iface); + ~codec_ctrl_impl(void); + + //aux adc and dac control + float read_aux_adc(aux_adc_t which); + void read_aux_adc(aux_dac_t which, float volts); + +private: + usrp_e_iface::sptr _iface; + ad9862_regs_t _ad9862_regs; + void send_reg(boost::uint8_t addr); +}; + +/*********************************************************************** + * Codec Control Methods + **********************************************************************/ +codec_ctrl_impl::codec_ctrl_impl(usrp_e_iface::sptr iface){ + _iface = iface; + + //soft reset + _ad9862_regs.soft_reset = 1; + this->send_reg(0); + + //initialize the codec register settings + _ad9862_regs.sdio_bidir = ad9862_regs_t::SDIO_BIDIR_SDIO_SDO; + _ad9862_regs.lsb_first = ad9862_regs_t::LSB_FIRST_MSB; + _ad9862_regs.soft_reset = 0; + + //write the register settings to the codec + for (uint8_t addr = 0; addr <= 50; addr++){ + this->send_reg(addr); + } +} + +codec_ctrl_impl::~codec_ctrl_impl(void){ + _ad9862_regs.all_rx_pd = 1; + this->send_reg(1); + _ad9862_regs.tx_digital_pd = 1; + _ad9862_regs.tx_analog_pd = ad9862_regs_t::TX_ANALOG_PD_BOTH; + this->send_reg(8); +} + +float codec_ctrl_impl::read_aux_adc(aux_adc_t which){ + return 0; + +} + +void codec_ctrl_impl::read_aux_adc(aux_dac_t which, float volts){ + +} + +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*/ + ); +} + +/*********************************************************************** + * Codec Control Make + **********************************************************************/ +codec_ctrl::sptr codec_ctrl::make(usrp_e_iface::sptr iface){ + return sptr(new codec_ctrl_impl(iface)); +} diff --git a/host/lib/usrp/usrp_e/codec_ctrl.hpp b/host/lib/usrp/usrp_e/codec_ctrl.hpp new file mode 100644 index 000000000..0fe70c4a2 --- /dev/null +++ b/host/lib/usrp/usrp_e/codec_ctrl.hpp @@ -0,0 +1,73 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +#ifndef INCLUDED_USRP_E_CODEC_CTRL_HPP +#define INCLUDED_USRP_E_CODEC_CTRL_HPP + +#include "usrp_e_iface.hpp" +#include +#include + +/*! + * The usrp-e codec control: + * - Init/power down codec. + * - Read aux adc, write aux dac. + */ +class codec_ctrl : boost::noncopyable{ +public: + typedef boost::shared_ptr sptr; + + /*! + * Make a new clock control object. + * \param iface the usrp_e iface object + * \return the clock control object + */ + static sptr make(usrp_e_iface::sptr iface); + + //! aux adc identifier constants + enum aux_adc_t{ + AUX_ADC_A2 = 0xA2, + AUX_ADC_A1 = 0xA1, + AUX_ADC_B2 = 0xB2, + AUX_ADC_B1 = 0xB1 + }; + + /*! + * Read the aux adc. + * \param which which of the 4 adcs + * \return a value in volts + */ + virtual float read_aux_adc(aux_adc_t which) = 0; + + //! aux dac identifier constants + enum aux_dac_t{ + AUX_DAC_A = 0xA, + AUX_DAC_B = 0xB, + AUX_DAC_C = 0xC, + AUX_DAC_D = 0xD + }; + + /*! + * Write the aux 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; + +}; + +#endif /* INCLUDED_USRP_E_CODEC_CTRL_HPP */ diff --git a/host/lib/usrp/usrp_e/usrp_e_iface.cpp b/host/lib/usrp/usrp_e/usrp_e_iface.cpp index 41737a716..1dbe383fa 100644 --- a/host/lib/usrp/usrp_e/usrp_e_iface.cpp +++ b/host/lib/usrp/usrp_e/usrp_e_iface.cpp @@ -20,6 +20,7 @@ #include //ioctl #include //ioctl structures and constants #include +#include //mutex #include using namespace uhd; @@ -42,6 +43,8 @@ public: * IOCTL: provides the communication base for all other calls ******************************************************************/ void ioctl(int request, void *mem){ + boost::mutex::scoped_lock lock(_ctrl_mutex); + if (::ioctl(_node_fd, request, mem) < 0){ throw std::runtime_error(str( boost::format("ioctl failed with request %d") % request @@ -167,7 +170,9 @@ public: return data.data; } -private: int _node_fd; +private: + int _node_fd; + boost::mutex _ctrl_mutex; }; /*********************************************************************** diff --git a/host/lib/usrp/usrp_e/usrp_e_impl.cpp b/host/lib/usrp/usrp_e/usrp_e_impl.cpp index 52bbcdd32..b6fed6a74 100644 --- a/host/lib/usrp/usrp_e/usrp_e_impl.cpp +++ b/host/lib/usrp/usrp_e/usrp_e_impl.cpp @@ -23,7 +23,6 @@ #include #include #include //open -#include "clock_ctrl.hpp" using namespace uhd; using namespace uhd::usrp; @@ -84,9 +83,12 @@ usrp_e_impl::usrp_e_impl(const std::string &node){ )); } - _iface = usrp_e_iface::make(_node_fd); + sleep(1); //FIXME sleep here until the kernel driver stops hanging - clock_ctrl::sptr my_clk_ctrl = clock_ctrl::make(_iface); + //setup various interfaces into hardware + _iface = usrp_e_iface::make(_node_fd); + _clock_ctrl = clock_ctrl::make(_iface); + _codec_ctrl = codec_ctrl::make(_iface); //initialize the mboard mboard_init(); diff --git a/host/lib/usrp/usrp_e/usrp_e_impl.hpp b/host/lib/usrp/usrp_e/usrp_e_impl.hpp index 23e36ed05..6746e012a 100644 --- a/host/lib/usrp/usrp_e/usrp_e_impl.hpp +++ b/host/lib/usrp/usrp_e/usrp_e_impl.hpp @@ -16,6 +16,8 @@ // #include "usrp_e_iface.hpp" +#include "clock_ctrl.hpp" +#include "codec_ctrl.hpp" #include #include #include @@ -91,6 +93,12 @@ private: uhd::clock_config_t _clock_config; + //ad9522 clock control + clock_ctrl::sptr _clock_ctrl; + + //ad9862 codec control + codec_ctrl::sptr _codec_ctrl; + //device functions and settings void get(const wax::obj &, wax::obj &); void set(const wax::obj &, const wax::obj &); -- cgit v1.2.3 From 272b08ce9a66b3ba1b9dc91922afff410145231f Mon Sep 17 00:00:00 2001 From: Josh Blum 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/ic_reg_maps') 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 +#include +#include #include +#include +#include #include "usrp_e_regs.hpp" //spi slave constants #include -//#include -//#include #include - //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_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 dac_params_t; + uhd::dict 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 From 3a26c45c69ea61bb1e2cc4dbfb7a605abbd7ca4b Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 10 May 2010 19:00:56 +0000 Subject: ad9862 transmit working --- host/lib/ic_reg_maps/gen_ad9862_regs.py | 2 +- host/lib/usrp/usrp_e/codec_ctrl.cpp | 13 +++++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) (limited to 'host/lib/ic_reg_maps') diff --git a/host/lib/ic_reg_maps/gen_ad9862_regs.py b/host/lib/ic_reg_maps/gen_ad9862_regs.py index 4444c6240..00340224c 100755 --- a/host/lib/ic_reg_maps/gen_ad9862_regs.py +++ b/host/lib/ic_reg_maps/gen_ad9862_regs.py @@ -123,7 +123,7 @@ ftw_23_16 23[0:7] 0 ######################################################################## ## DLL ######################################################################## -input_clk_ctrl 24[6] 0 external, internal +input_clk_ctrl 24[6] 0 internal, external adc_div2 24[5] 0 normal, div2 dll_mult 24[3:4] 0 1, 2, 4 dll_pd 24[2] 0 diff --git a/host/lib/usrp/usrp_e/codec_ctrl.cpp b/host/lib/usrp/usrp_e/codec_ctrl.cpp index 3f3523ddf..ce05ac9eb 100644 --- a/host/lib/usrp/usrp_e/codec_ctrl.cpp +++ b/host/lib/usrp/usrp_e/codec_ctrl.cpp @@ -82,7 +82,7 @@ codec_ctrl_impl::codec_ctrl_impl(usrp_e_iface::sptr iface){ //setup tx side of codec _ad9862_regs.two_data_paths = ad9862_regs_t::TWO_DATA_PATHS_BOTH; - _ad9862_regs.interleaved = ad9862_regs_t::INTERLEAVED_SINGLE; //FIXME should be interleaved + _ad9862_regs.interleaved = ad9862_regs_t::INTERLEAVED_INTERLEAVED; _ad9862_regs.tx_pga_gain = 199; //TODO bring under api control _ad9862_regs.tx_hilbert = ad9862_regs_t::TX_HILBERT_DIS; _ad9862_regs.interp = ad9862_regs_t::INTERP_4; @@ -92,10 +92,19 @@ codec_ctrl_impl::codec_ctrl_impl(usrp_e_iface::sptr iface){ _ad9862_regs.dac_a_coarse_gain = 0x3; _ad9862_regs.dac_b_coarse_gain = 0x3; + //setup the dll + _ad9862_regs.input_clk_ctrl = ad9862_regs_t::INPUT_CLK_CTRL_EXTERNAL; + _ad9862_regs.dll_mult = ad9862_regs_t::DLL_MULT_2; + _ad9862_regs.dll_mode = ad9862_regs_t::DLL_MODE_FAST; + //write the register settings to the codec - for (uint8_t addr = 0; addr <= 50; addr++){ + for (uint8_t addr = 0; addr <= 25; addr++){ this->send_reg(addr); } + + //aux adc clock + _ad9862_regs.clk_4 = ad9862_regs_t::CLK_4_1_4; + this->send_reg(34); } codec_ctrl_impl::~codec_ctrl_impl(void){ -- cgit v1.2.3 From 2ff1a854669a0fe5c8029f0c013e38faade6b826 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Wed, 23 Jun 2010 01:43:25 +0000 Subject: usrp-e: clock control constants to easily change dividers and counters, tweaks to ic reg maps common --- host/lib/ic_reg_maps/common.py | 4 +-- host/lib/ic_reg_maps/gen_ad9522_regs.py | 2 ++ host/lib/usrp/usrp_e/clock_ctrl.cpp | 50 ++++++++++++++++++++------------- 3 files changed, 34 insertions(+), 22 deletions(-) (limited to 'host/lib/ic_reg_maps') diff --git a/host/lib/ic_reg_maps/common.py b/host/lib/ic_reg_maps/common.py index 173186eb1..47325a7e3 100644 --- a/host/lib/ic_reg_maps/common.py +++ b/host/lib/ic_reg_maps/common.py @@ -59,7 +59,7 @@ public: delete _state; } -$body + $body void save_state(void){ if (_state == NULL) _state = new $(name)_t(); @@ -181,7 +181,7 @@ def generate(name, regs_tmpl, body_tmpl='', file=__file__): else: regs.append(reg(entry)) #evaluate the body template with the list of registers - body = parse_tmpl(body_tmpl, regs=regs).replace('\n', '\n ').strip() + body = '\n '.join(parse_tmpl(body_tmpl, regs=regs).splitlines()) #evaluate the code template with the parsed registers and arguments code = parse_tmpl(COMMON_TMPL, diff --git a/host/lib/ic_reg_maps/gen_ad9522_regs.py b/host/lib/ic_reg_maps/gen_ad9522_regs.py index 9da51205b..ed6b5f48d 100755 --- a/host/lib/ic_reg_maps/gen_ad9522_regs.py +++ b/host/lib/ic_reg_maps/gen_ad9522_regs.py @@ -32,9 +32,11 @@ cp_mode 0x010[3:2] 3 high_imp, force pll_power_down 0x010[1:0] 1 normal=0, async=1, sync=3 r_counter_lsb 0x011[7:0] 1 r_counter_msb 0x012[5:0] 0 +~r_counter r_counter_lsb, r_counter_msb a_counter 0x013[5:0] 0 b_counter_lsb 0x014[7:0] 3 b_counter_msb 0x015[4:0] 0 +~b_counter b_counter_lsb, b_counter_msb set_cp_pin_to_vcp_2 0x016[7] 0 normal, vcp_2 reset_r_counter 0x016[6] 0 reset_a_and_b_counters 0x016[5] 0 diff --git a/host/lib/usrp/usrp_e/clock_ctrl.cpp b/host/lib/usrp/usrp_e/clock_ctrl.cpp index bf38db8a6..0b18763a4 100644 --- a/host/lib/usrp/usrp_e/clock_ctrl.cpp +++ b/host/lib/usrp/usrp_e/clock_ctrl.cpp @@ -27,19 +27,31 @@ using namespace uhd; -template static void set_clock_divider( - size_t divider, div_type &low, div_type &high +template static void set_clock_divider( + size_t divider, div_type &low, div_type &high, bypass_type &bypass ){ high = divider/2 - 1; low = divider - high - 2; + bypass = (divider == 1)? 1 : 0; } /*********************************************************************** * Constants **********************************************************************/ -static const double master_clock_rate = 320e6; -static const size_t fpga_clock_divider = 5; //64 MHz -static const size_t codec_clock_divider = 5; //64 MHz +static const double ref_clock_rate = 10e6; + +static const size_t r_counter = 1; +static const size_t a_counter = 0; +static const size_t b_counter = 20; +static const size_t prescaler = 8; //set below with enum +static const size_t vco_divider = 5; //set below with enum + +static const size_t n_counter = prescaler * b_counter + a_counter; +static const size_t vco_clock_rate = ref_clock_rate/r_counter * n_counter; +static const double master_clock_rate = vco_clock_rate/vco_divider; + +static const size_t fpga_clock_divider = size_t(master_clock_rate/64e6); +static const size_t codec_clock_divider = size_t(master_clock_rate/64e6); /*********************************************************************** * Clock Control Implementation @@ -59,11 +71,9 @@ public: _ad9522_regs.enable_ref2 = 1; _ad9522_regs.select_ref = ad9522_regs_t::SELECT_REF_REF2; - _ad9522_regs.r_counter_lsb = 1; - _ad9522_regs.r_counter_msb = 0; - _ad9522_regs.a_counter = 0; - _ad9522_regs.b_counter_lsb = 20; - _ad9522_regs.b_counter_msb = 0; + _ad9522_regs.set_r_counter(r_counter); + _ad9522_regs.a_counter = a_counter; + _ad9522_regs.set_b_counter(b_counter); _ad9522_regs.prescaler_p = ad9522_regs_t::PRESCALER_P_DIV8_9; _ad9522_regs.pll_power_down = ad9522_regs_t::PLL_POWER_DOWN_NORMAL; @@ -77,14 +87,16 @@ public: _ad9522_regs.out0_format = ad9522_regs_t::OUT0_FORMAT_LVDS; set_clock_divider(fpga_clock_divider, _ad9522_regs.divider0_low_cycles, - _ad9522_regs.divider0_high_cycles + _ad9522_regs.divider0_high_cycles, + _ad9522_regs.divider0_bypass ); //setup codec clock _ad9522_regs.out3_format = ad9522_regs_t::OUT3_FORMAT_LVDS; set_clock_divider(codec_clock_divider, _ad9522_regs.divider1_low_cycles, - _ad9522_regs.divider1_high_cycles + _ad9522_regs.divider1_high_cycles, + _ad9522_regs.divider1_bypass ); //setup test clock (same divider as codec clock) @@ -150,15 +162,14 @@ public: void set_rx_dboard_clock_rate(double rate){ assert_has(get_rx_dboard_clock_rates(), rate, "rx dboard clock rate"); size_t divider = size_t(rate/master_clock_rate); - //bypass when the divider ratio is one - _ad9522_regs.divider3_bypass = (divider == 1)? 1 : 0; - this->send_reg(0x19a); //set the divider registers set_clock_divider(divider, _ad9522_regs.divider3_low_cycles, - _ad9522_regs.divider3_high_cycles + _ad9522_regs.divider3_high_cycles, + _ad9522_regs.divider3_bypass ); this->send_reg(0x199); + this->send_reg(0x19a); this->latch_regs(); } @@ -181,15 +192,14 @@ public: void set_tx_dboard_clock_rate(double rate){ assert_has(get_tx_dboard_clock_rates(), rate, "tx dboard clock rate"); size_t divider = size_t(rate/master_clock_rate); - //bypass when the divider ratio is one - _ad9522_regs.divider2_bypass = (divider == 1)? 1 : 0; - this->send_reg(0x197); //set the divider registers set_clock_divider(divider, _ad9522_regs.divider2_low_cycles, - _ad9522_regs.divider2_high_cycles + _ad9522_regs.divider2_high_cycles, + _ad9522_regs.divider2_bypass ); this->send_reg(0x196); + this->send_reg(0x197); this->latch_regs(); } -- cgit v1.2.3 From f0db419b8c6366503542c3e97f8556bbb6ca94cd Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Thu, 9 Sep 2010 16:27:53 -0700 Subject: usrp-e: typo fix for ad9522 regs size --- host/lib/ic_reg_maps/gen_ad9522_regs.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'host/lib/ic_reg_maps') diff --git a/host/lib/ic_reg_maps/gen_ad9522_regs.py b/host/lib/ic_reg_maps/gen_ad9522_regs.py index ed6b5f48d..a5debe568 100755 --- a/host/lib/ic_reg_maps/gen_ad9522_regs.py +++ b/host/lib/ic_reg_maps/gen_ad9522_regs.py @@ -134,8 +134,8 @@ reg2eeprom 0xB03[0] 0 # Template for methods in the body of the struct ######################################################################## BODY_TMPL="""\ -boost::uint8_t get_reg(boost::uint16_t addr){ - boost::uint8_t reg = 0; +boost::uint32_t get_reg(boost::uint16_t addr){ + boost::uint32_t reg = 0; switch(addr){ #for $addr in sorted(set(map(lambda r: r.get_addr(), $regs))) case $addr: @@ -154,7 +154,7 @@ boost::uint8_t get_reg(boost::uint16_t addr){ return reg; } -void set_reg(boost::uint8_t addr, boost::uint32_t reg){ +void set_reg(boost::uint16_t addr, boost::uint32_t reg){ switch(addr){ #for $addr in sorted(set(map(lambda r: r.get_addr(), $regs))) case $addr: -- cgit v1.2.3