From e4c9656ac267b05e1a19106fb1594f7ac5c37cc7 Mon Sep 17 00:00:00 2001 From: Ashish Chaudhari Date: Fri, 25 Sep 2015 01:42:14 +0000 Subject: usrp3: Added new GPIO ATR 3000 core - Refactored GPIO ATR definitions - Added new 3000 core with a more efficient API - Added a separate db_gpio_atr core to control the ATR bus - Ported b2xx, e3xx and x3xx to the new core - Minor cleanup --- host/lib/usrp/cores/CMakeLists.txt | 1 + host/lib/usrp/cores/gpio_atr_3000.cpp | 214 ++++++++++++++++++++++++++++++++++ host/lib/usrp/cores/gpio_atr_3000.hpp | 168 ++++++++++++++++++++++++++ host/lib/usrp/cores/gpio_core_200.cpp | 24 ++-- host/lib/usrp/cores/gpio_core_200.hpp | 23 +--- 5 files changed, 396 insertions(+), 34 deletions(-) create mode 100644 host/lib/usrp/cores/gpio_atr_3000.cpp create mode 100644 host/lib/usrp/cores/gpio_atr_3000.hpp (limited to 'host/lib/usrp/cores') diff --git a/host/lib/usrp/cores/CMakeLists.txt b/host/lib/usrp/cores/CMakeLists.txt index f28ae040f..909c02941 100644 --- a/host/lib/usrp/cores/CMakeLists.txt +++ b/host/lib/usrp/cores/CMakeLists.txt @@ -40,4 +40,5 @@ LIBUHD_APPEND_SOURCES( ${CMAKE_CURRENT_SOURCE_DIR}/rx_dsp_core_3000.cpp ${CMAKE_CURRENT_SOURCE_DIR}/tx_dsp_core_3000.cpp ${CMAKE_CURRENT_SOURCE_DIR}/radio_ctrl_core_3000.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/gpio_atr_3000.cpp ) diff --git a/host/lib/usrp/cores/gpio_atr_3000.cpp b/host/lib/usrp/cores/gpio_atr_3000.cpp new file mode 100644 index 000000000..d067dc590 --- /dev/null +++ b/host/lib/usrp/cores/gpio_atr_3000.cpp @@ -0,0 +1,214 @@ +// +// Copyright 2011,2014 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 "gpio_atr_3000.hpp" +#include +#include + +using namespace uhd; +using namespace usrp; + +//------------------------------------------------------------- +// gpio_atr_3000 +//------------------------------------------------------------- + +#define REG_ATR_IDLE_OFFSET (base + 0) +#define REG_ATR_RX_OFFSET (base + 4) +#define REG_ATR_TX_OFFSET (base + 8) +#define REG_ATR_FDX_OFFSET (base + 12) +#define REG_DDR_OFFSET (base + 16) +#define REG_ATR_DISABLE_OFFSET (base + 20) + +namespace uhd { namespace usrp { namespace gpio_atr { + +class gpio_atr_3000_impl : public gpio_atr_3000{ +public: + gpio_atr_3000_impl( + wb_iface::sptr iface, + const wb_iface::wb_addr_type base, + const wb_iface::wb_addr_type rb_addr = 0xFFFFFFFF + ): + _iface(iface), _rb_addr(rb_addr), + _atr_idle_reg(REG_ATR_IDLE_OFFSET), + _atr_rx_reg(REG_ATR_RX_OFFSET), + _atr_tx_reg(REG_ATR_TX_OFFSET), + _atr_fdx_reg(REG_ATR_FDX_OFFSET), + _ddr_reg(REG_DDR_OFFSET), + _atr_disable_reg(REG_ATR_DISABLE_OFFSET) + { + _atr_idle_reg.initialize(*_iface, true); + _atr_rx_reg.initialize(*_iface, true); + _atr_tx_reg.initialize(*_iface, true); + _atr_fdx_reg.initialize(*_iface, true); + _ddr_reg.initialize(*_iface, true); + _atr_disable_reg.initialize(*_iface, true); + } + + virtual void set_atr_mode(const gpio_atr_mode_t mode, const boost::uint32_t mask) + { + _atr_disable_reg.set_with_mask((mode==MODE_ATR)?0:0xFFFFFFFF, mask); + _atr_disable_reg.flush(); + } + + virtual void set_gpio_ddr(const gpio_ddr_t dir, const boost::uint32_t mask) + { + _ddr_reg.set_with_mask((dir==DDR_INPUT)?0:0xFFFFFFFF, mask); + _ddr_reg.flush(); + } + + virtual void set_atr_reg(const gpio_atr_reg_t atr, const boost::uint32_t value, const boost::uint32_t mask) + { + masked_reg_t* reg = NULL; + switch (atr) { + case ATR_REG_IDLE: reg = &_atr_idle_reg; break; + case ATR_REG_RX_ONLY: reg = &_atr_rx_reg; break; + case ATR_REG_TX_ONLY: reg = &_atr_tx_reg; break; + case ATR_REG_FULL_DUPLEX: reg = &_atr_fdx_reg; break; + default: reg = &_atr_idle_reg; break; + } + reg->set_with_mask(value, mask); + reg->flush(); + } + + virtual boost::uint32_t read_gpio() + { + if (_rb_addr != 0xFFFFFFFF) { + return _iface->peek32(_rb_addr); + } else { + throw uhd::runtime_error("read_gpio not supported for write-only interface."); + } + } + + virtual void set_gpio_attr(const gpio_attr_t attr, const boost::uint32_t value) + { + switch (attr) + { + case GPIO_CTRL: + set_atr_mode(MODE_ATR, value); + set_atr_mode(MODE_GPIO, ~value); + break; + case GPIO_DDR: + set_gpio_ddr(DDR_OUTPUT, value); + set_gpio_ddr(DDR_INPUT, ~value); + break; + case GPIO_OUT: + set_atr_reg(ATR_REG_IDLE, value, _atr_disable_reg.get(masked_reg_t::REGISTER)); + break; + case GPIO_ATR_0X: + set_atr_reg(ATR_REG_IDLE, value, ~_atr_disable_reg.get(masked_reg_t::REGISTER)); + break; + case GPIO_ATR_RX: + set_atr_reg(ATR_REG_RX_ONLY, value, ~_atr_disable_reg.get(masked_reg_t::REGISTER)); + break; + case GPIO_ATR_TX: + set_atr_reg(ATR_REG_TX_ONLY, value, ~_atr_disable_reg.get(masked_reg_t::REGISTER)); + break; + case GPIO_ATR_XX: + set_atr_reg(ATR_REG_FULL_DUPLEX, value, ~_atr_disable_reg.get(masked_reg_t::REGISTER)); + break; + default: + UHD_THROW_INVALID_CODE_PATH(); + } + } + +protected: + class masked_reg_t : public uhd::soft_reg32_wo_t { + public: + masked_reg_t(const wb_iface::wb_addr_type offset): uhd::soft_reg32_wo_t(offset) { + set(REGISTER, 0); + } + + inline void set_with_mask(const boost::uint32_t value, const boost::uint32_t mask) { + set(REGISTER, (value&mask)|(get(REGISTER)&(~mask))); + } + }; + + wb_iface::sptr _iface; + wb_iface::wb_addr_type _rb_addr; + masked_reg_t _atr_idle_reg; + masked_reg_t _atr_rx_reg; + masked_reg_t _atr_tx_reg; + masked_reg_t _atr_fdx_reg; + masked_reg_t _ddr_reg; + masked_reg_t _atr_disable_reg; +}; + +gpio_atr_3000::sptr gpio_atr_3000::make(wb_iface::sptr iface, const size_t base, const size_t rb_addr) { + return sptr(new gpio_atr_3000_impl(iface, base, rb_addr)); +} + +gpio_atr_3000::sptr gpio_atr_3000::make_write_only(wb_iface::sptr iface, const size_t base) { + gpio_atr_3000::sptr gpio_iface(new gpio_atr_3000_impl(iface, base)); + gpio_iface->set_gpio_ddr(DDR_OUTPUT, 0xFFFFFFFF); + return gpio_iface; +} + +//------------------------------------------------------------- +// db_gpio_atr_3000 +//------------------------------------------------------------- + +class db_gpio_atr_3000_impl : public gpio_atr_3000_impl, public db_gpio_atr_3000 { +public: + db_gpio_atr_3000_impl(wb_iface::sptr iface, const wb_iface::wb_addr_type base, const wb_iface::wb_addr_type rb_addr): + gpio_atr_3000_impl(iface, base, rb_addr) { /* NOP */ } + + inline void set_pin_ctrl(const db_unit_t unit, const boost::uint16_t value) + { + gpio_atr_3000_impl::set_atr_mode(MODE_ATR, compute_mask(unit, value)); + gpio_atr_3000_impl::set_atr_mode(MODE_GPIO, compute_mask(unit, ~value)); + } + + inline void set_gpio_ddr(const db_unit_t unit, const boost::uint16_t value) + { + gpio_atr_3000_impl::set_gpio_ddr(DDR_OUTPUT, compute_mask(unit, value)); + gpio_atr_3000_impl::set_gpio_ddr(DDR_INPUT, compute_mask(unit, ~value)); + } + + inline void set_atr_reg(const db_unit_t unit, const gpio_atr_reg_t atr, const boost::uint16_t value) + { + gpio_atr_3000_impl::set_atr_reg(atr, + static_cast(value) << compute_shift(unit), + compute_mask(unit, ~(_atr_disable_reg.get(masked_reg_t::REGISTER)))); + } + + inline void set_gpio_out(const db_unit_t unit, const boost::uint16_t value) + { + gpio_atr_3000_impl::set_atr_reg(ATR_REG_IDLE, + static_cast(value) << compute_shift(unit), + compute_mask(unit, _atr_disable_reg.get(masked_reg_t::REGISTER))); + } + + inline boost::uint16_t read_gpio(const db_unit_t unit) + { + return boost::uint16_t(gpio_atr_3000_impl::read_gpio() >> compute_shift(unit)); + } + +private: + inline boost::uint32_t compute_shift(const db_unit_t unit) { + return (unit == dboard_iface::UNIT_RX) ? 0 : 16; + } + + inline boost::uint32_t compute_mask(const db_unit_t unit, const boost::uint16_t mask) { + return static_cast(mask) << (compute_shift(unit)); + } +}; + +db_gpio_atr_3000::sptr db_gpio_atr_3000::make(wb_iface::sptr iface, const size_t base, const size_t rb_addr) { + return sptr(new db_gpio_atr_3000_impl(iface, base, rb_addr)); +} + +}}} diff --git a/host/lib/usrp/cores/gpio_atr_3000.hpp b/host/lib/usrp/cores/gpio_atr_3000.hpp new file mode 100644 index 000000000..b9e5168d9 --- /dev/null +++ b/host/lib/usrp/cores/gpio_atr_3000.hpp @@ -0,0 +1,168 @@ +// +// Copyright 2011,2014,2015 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_LIBUHD_USRP_GPIO_CORE_3000_HPP +#define INCLUDED_LIBUHD_USRP_GPIO_CORE_3000_HPP + +#include +#include +#include +#include +#include + +namespace uhd { namespace usrp { namespace gpio_atr { + +class gpio_atr_3000 : boost::noncopyable { +public: + typedef boost::shared_ptr sptr; + + virtual ~gpio_atr_3000(void) {}; + + /*! + * Create a read-write GPIO ATR interface object + * + * \param iface register iface to GPIO ATR registers + * \param base base settings offset for GPIO ATR registers + * \param base readback offset for GPIO ATR registers + */ + static sptr make(uhd::wb_iface::sptr iface, const size_t base, const size_t rb_addr); + + /*! + * Create a write-only GPIO ATR interface object + * + * \param iface register iface to GPIO ATR registers + * \param base base settings offset for GPIO ATR registers + */ + static sptr make_write_only(uhd::wb_iface::sptr iface, const size_t base); + + /*! + * Select the ATR mode for all bits in the mask + * + * \param mode the mode to apply {ATR = outputs driven by ATR state machine, GPIO = outputs static} + * \param mask apply the mode to all non-zero bits in the mask + */ + virtual void set_atr_mode(const gpio_atr_mode_t mode, const boost::uint32_t mask) = 0; + + /*! + * Select the data direction for all bits in the mask + * + * \param dir the direction {OUTPUT, INPUT} + * \param mask apply the mode to all non-zero bits in the mask + */ + virtual void set_gpio_ddr(const gpio_ddr_t dir, const boost::uint32_t mask) = 0; + + /*! + * Write the specified (masked) value to the ATR register + * + * \param atr the type of ATR register to write to {IDLE, RX, TX, FDX} + * \param value the value to write + * \param mask only writes to the bits where mask is non-zero + */ + virtual void set_atr_reg(const gpio_atr_reg_t atr, const boost::uint32_t value, const boost::uint32_t mask = 0xFFFFFFFF) = 0; + + /*! + * Write to a static GPIO output + * + * \param value the value to write + * \param mask only writes to the bits where mask is non-zero + */ + inline void set_gpio_out(const boost::uint32_t value, const boost::uint32_t mask = 0xFFFFFFFF) { + set_atr_reg(ATR_REG_IDLE, value, mask); + } + + /*! + * Read the state of the GPIO pins + * If a pin is configured as an input, reads the actual value of the pin + * If a pin is configured as an output, reads the last value written to the pin + * + * \return the value read back + */ + virtual boost::uint32_t read_gpio() = 0; + + /*! + * Set a GPIO attribute + * + * \param attr the attribute to set + * \param value the value to write to the attribute + */ + virtual void set_gpio_attr(const gpio_attr_t attr, const boost::uint32_t value) = 0; +}; + +class db_gpio_atr_3000 { +public: + typedef boost::shared_ptr sptr; + + typedef uhd::usrp::dboard_iface::unit_t db_unit_t; + + virtual ~db_gpio_atr_3000(void) {}; + + /*! + * Create a read-write GPIO ATR interface object for a daughterboard connector + * + * \param iface register iface to GPIO ATR registers + * \param base base settings offset for GPIO ATR registers + * \param base readback offset for GPIO ATR registers + */ + static sptr make(uhd::wb_iface::sptr iface, const size_t base, const size_t rb_addr); + + /*! + * Configure the GPIO mode for all pins in the daughterboard connector + * + * \param unit the side of the daughterboard interface to configure (TX or RX) + * \param value if value[i] is 1, the i'th bit is in ATR mode otherwise it is in GPIO mode + */ + virtual void set_pin_ctrl(const db_unit_t unit, const boost::uint16_t value) = 0; + + /*! + * Configure the direction for all pins in the daughterboard connector + * + * \param unit the side of the daughterboard interface to configure (TX or RX) + * \param value if value[i] is 1, the i'th bit is an output otherwise it is an input + */ + virtual void set_gpio_ddr(const db_unit_t unit, const boost::uint16_t value) = 0; + + /*! + * Write the specified value to the ATR register (all bits) + * + * \param atr the type of ATR register to write to {IDLE, RX, TX, FDX} + * \param unit the side of the daughterboard interface to configure (TX or RX) + * \param value the value to write + */ + virtual void set_atr_reg(const db_unit_t unit, const gpio_atr_reg_t atr, const boost::uint16_t value) = 0; + + /*! + * Write the specified value to the GPIO register (all bits) + * + * \param atr the type of ATR register to write to {IDLE, RX, TX, FDX} + * \param value the value to write + */ + virtual void set_gpio_out(const db_unit_t unit, const boost::uint16_t value) = 0; + + /*! + * Read the state of the GPIO pins + * If a pin is configured as an input, reads the actual value of the pin + * If a pin is configured as an output, reads the last value written to the pin + * + * \param unit the side of the daughterboard interface to configure (TX or RX) + * \return the value read back + */ + virtual boost::uint16_t read_gpio(const db_unit_t unit) = 0; +}; + +}}} //namespaces + +#endif /* INCLUDED_LIBUHD_USRP_GPIO_CORE_3000_HPP */ diff --git a/host/lib/usrp/cores/gpio_core_200.cpp b/host/lib/usrp/cores/gpio_core_200.cpp index 4f1c25a0b..05a689845 100644 --- a/host/lib/usrp/cores/gpio_core_200.cpp +++ b/host/lib/usrp/cores/gpio_core_200.cpp @@ -77,10 +77,10 @@ private: } void update(void){ - this->update(dboard_iface::ATR_REG_IDLE, REG_GPIO_IDLE); - this->update(dboard_iface::ATR_REG_TX_ONLY, REG_GPIO_TX_ONLY); - this->update(dboard_iface::ATR_REG_RX_ONLY, REG_GPIO_RX_ONLY); - this->update(dboard_iface::ATR_REG_FULL_DUPLEX, REG_GPIO_BOTH); + this->update(gpio_atr::ATR_REG_IDLE, REG_GPIO_IDLE); + this->update(gpio_atr::ATR_REG_TX_ONLY, REG_GPIO_TX_ONLY); + this->update(gpio_atr::ATR_REG_RX_ONLY, REG_GPIO_RX_ONLY); + this->update(gpio_atr::ATR_REG_FULL_DUPLEX, REG_GPIO_BOTH); } void update(const atr_reg_t atr, const size_t addr){ @@ -122,17 +122,17 @@ public: } void set_atr_reg(const atr_reg_t atr, const boost::uint32_t value){ - if (atr == dboard_iface::ATR_REG_IDLE) _iface->poke32(REG_GPIO_IDLE, value); - if (atr == dboard_iface::ATR_REG_TX_ONLY) _iface->poke32(REG_GPIO_TX_ONLY, value); - if (atr == dboard_iface::ATR_REG_RX_ONLY) _iface->poke32(REG_GPIO_RX_ONLY, value); - if (atr == dboard_iface::ATR_REG_FULL_DUPLEX) _iface->poke32(REG_GPIO_BOTH, value); + if (atr == gpio_atr::ATR_REG_IDLE) _iface->poke32(REG_GPIO_IDLE, value); + if (atr == gpio_atr::ATR_REG_TX_ONLY) _iface->poke32(REG_GPIO_TX_ONLY, value); + if (atr == gpio_atr::ATR_REG_RX_ONLY) _iface->poke32(REG_GPIO_RX_ONLY, value); + if (atr == gpio_atr::ATR_REG_FULL_DUPLEX) _iface->poke32(REG_GPIO_BOTH, value); } void set_all_regs(const boost::uint32_t value){ - this->set_atr_reg(dboard_iface::ATR_REG_IDLE, value); - this->set_atr_reg(dboard_iface::ATR_REG_TX_ONLY, value); - this->set_atr_reg(dboard_iface::ATR_REG_RX_ONLY, value); - this->set_atr_reg(dboard_iface::ATR_REG_FULL_DUPLEX, value); + this->set_atr_reg(gpio_atr::ATR_REG_IDLE, value); + this->set_atr_reg(gpio_atr::ATR_REG_TX_ONLY, value); + this->set_atr_reg(gpio_atr::ATR_REG_RX_ONLY, value); + this->set_atr_reg(gpio_atr::ATR_REG_FULL_DUPLEX, value); } private: diff --git a/host/lib/usrp/cores/gpio_core_200.hpp b/host/lib/usrp/cores/gpio_core_200.hpp index e22834fd9..c60507792 100644 --- a/host/lib/usrp/cores/gpio_core_200.hpp +++ b/host/lib/usrp/cores/gpio_core_200.hpp @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -27,28 +28,6 @@ #include #include -typedef enum { - GPIO_CTRL, - GPIO_DDR, - GPIO_OUT, - GPIO_ATR_0X, - GPIO_ATR_RX, - GPIO_ATR_TX, - GPIO_ATR_XX -} gpio_attr_t; - -typedef std::map gpio_attr_map_t; -static const gpio_attr_map_t gpio_attr_map = - boost::assign::map_list_of - (GPIO_CTRL, "CTRL") - (GPIO_DDR, "DDR") - (GPIO_OUT, "OUT") - (GPIO_ATR_0X, "ATR_0X") - (GPIO_ATR_RX, "ATR_RX") - (GPIO_ATR_TX, "ATR_TX") - (GPIO_ATR_XX, "ATR_XX") -; - class gpio_core_200 : boost::noncopyable{ public: typedef boost::shared_ptr sptr; -- cgit v1.2.3 From fa54d58ad82fc5d480cd03560010a6f1f97a9bf0 Mon Sep 17 00:00:00 2001 From: Ashish Chaudhari Date: Wed, 30 Sep 2015 13:36:31 -0700 Subject: usrp3: Cleaned up some GPIO ATR constants and types - Removed implicit type converstions in ATR address passing - Changed magic numbers to named constants --- host/lib/usrp/cores/gpio_atr_3000.cpp | 26 ++++++++++++++++++-------- host/lib/usrp/cores/gpio_atr_3000.hpp | 19 ++++++++++++++----- 2 files changed, 32 insertions(+), 13 deletions(-) (limited to 'host/lib/usrp/cores') diff --git a/host/lib/usrp/cores/gpio_atr_3000.cpp b/host/lib/usrp/cores/gpio_atr_3000.cpp index d067dc590..729ecb8a6 100644 --- a/host/lib/usrp/cores/gpio_atr_3000.cpp +++ b/host/lib/usrp/cores/gpio_atr_3000.cpp @@ -40,7 +40,7 @@ public: gpio_atr_3000_impl( wb_iface::sptr iface, const wb_iface::wb_addr_type base, - const wb_iface::wb_addr_type rb_addr = 0xFFFFFFFF + const wb_iface::wb_addr_type rb_addr = READBACK_DISABLED ): _iface(iface), _rb_addr(rb_addr), _atr_idle_reg(REG_ATR_IDLE_OFFSET), @@ -60,13 +60,13 @@ public: virtual void set_atr_mode(const gpio_atr_mode_t mode, const boost::uint32_t mask) { - _atr_disable_reg.set_with_mask((mode==MODE_ATR)?0:0xFFFFFFFF, mask); + _atr_disable_reg.set_with_mask((mode==MODE_ATR) ? ~MASK_SET_ALL : MASK_SET_ALL, mask); _atr_disable_reg.flush(); } virtual void set_gpio_ddr(const gpio_ddr_t dir, const boost::uint32_t mask) { - _ddr_reg.set_with_mask((dir==DDR_INPUT)?0:0xFFFFFFFF, mask); + _ddr_reg.set_with_mask((dir==DDR_INPUT) ? ~MASK_SET_ALL : MASK_SET_ALL, mask); _ddr_reg.flush(); } @@ -86,7 +86,7 @@ public: virtual boost::uint32_t read_gpio() { - if (_rb_addr != 0xFFFFFFFF) { + if (_rb_addr != READBACK_DISABLED) { return _iface->peek32(_rb_addr); } else { throw uhd::runtime_error("read_gpio not supported for write-only interface."); @@ -126,6 +126,10 @@ public: } protected: + //Special RB addr value to indicate no readback + //This value is invalid as a real address because it is not a multiple of 4 + static const wb_iface::wb_addr_type READBACK_DISABLED = 0xFFFFFFFF; + class masked_reg_t : public uhd::soft_reg32_wo_t { public: masked_reg_t(const wb_iface::wb_addr_type offset): uhd::soft_reg32_wo_t(offset) { @@ -147,13 +151,17 @@ protected: masked_reg_t _atr_disable_reg; }; -gpio_atr_3000::sptr gpio_atr_3000::make(wb_iface::sptr iface, const size_t base, const size_t rb_addr) { +gpio_atr_3000::sptr gpio_atr_3000::make( + wb_iface::sptr iface, const wb_iface::wb_addr_type base, const wb_iface::wb_addr_type rb_addr +) { return sptr(new gpio_atr_3000_impl(iface, base, rb_addr)); } -gpio_atr_3000::sptr gpio_atr_3000::make_write_only(wb_iface::sptr iface, const size_t base) { +gpio_atr_3000::sptr gpio_atr_3000::make_write_only( + wb_iface::sptr iface, const wb_iface::wb_addr_type base +) { gpio_atr_3000::sptr gpio_iface(new gpio_atr_3000_impl(iface, base)); - gpio_iface->set_gpio_ddr(DDR_OUTPUT, 0xFFFFFFFF); + gpio_iface->set_gpio_ddr(DDR_OUTPUT, MASK_SET_ALL); return gpio_iface; } @@ -207,7 +215,9 @@ private: } }; -db_gpio_atr_3000::sptr db_gpio_atr_3000::make(wb_iface::sptr iface, const size_t base, const size_t rb_addr) { +db_gpio_atr_3000::sptr db_gpio_atr_3000::make( + wb_iface::sptr iface, const wb_iface::wb_addr_type base, const wb_iface::wb_addr_type rb_addr +) { return sptr(new db_gpio_atr_3000_impl(iface, base, rb_addr)); } diff --git a/host/lib/usrp/cores/gpio_atr_3000.hpp b/host/lib/usrp/cores/gpio_atr_3000.hpp index b9e5168d9..28ec360ca 100644 --- a/host/lib/usrp/cores/gpio_atr_3000.hpp +++ b/host/lib/usrp/cores/gpio_atr_3000.hpp @@ -30,6 +30,8 @@ class gpio_atr_3000 : boost::noncopyable { public: typedef boost::shared_ptr sptr; + static const boost::uint32_t MASK_SET_ALL = 0xFFFFFFFF; + virtual ~gpio_atr_3000(void) {}; /*! @@ -39,7 +41,10 @@ public: * \param base base settings offset for GPIO ATR registers * \param base readback offset for GPIO ATR registers */ - static sptr make(uhd::wb_iface::sptr iface, const size_t base, const size_t rb_addr); + static sptr make( + uhd::wb_iface::sptr iface, + const uhd::wb_iface::wb_addr_type base, + const uhd::wb_iface::wb_addr_type rb_addr); /*! * Create a write-only GPIO ATR interface object @@ -47,7 +52,8 @@ public: * \param iface register iface to GPIO ATR registers * \param base base settings offset for GPIO ATR registers */ - static sptr make_write_only(uhd::wb_iface::sptr iface, const size_t base); + static sptr make_write_only( + uhd::wb_iface::sptr iface, const uhd::wb_iface::wb_addr_type base); /*! * Select the ATR mode for all bits in the mask @@ -72,7 +78,7 @@ public: * \param value the value to write * \param mask only writes to the bits where mask is non-zero */ - virtual void set_atr_reg(const gpio_atr_reg_t atr, const boost::uint32_t value, const boost::uint32_t mask = 0xFFFFFFFF) = 0; + virtual void set_atr_reg(const gpio_atr_reg_t atr, const boost::uint32_t value, const boost::uint32_t mask = MASK_SET_ALL) = 0; /*! * Write to a static GPIO output @@ -80,7 +86,7 @@ public: * \param value the value to write * \param mask only writes to the bits where mask is non-zero */ - inline void set_gpio_out(const boost::uint32_t value, const boost::uint32_t mask = 0xFFFFFFFF) { + inline void set_gpio_out(const boost::uint32_t value, const boost::uint32_t mask = MASK_SET_ALL) { set_atr_reg(ATR_REG_IDLE, value, mask); } @@ -117,7 +123,10 @@ public: * \param base base settings offset for GPIO ATR registers * \param base readback offset for GPIO ATR registers */ - static sptr make(uhd::wb_iface::sptr iface, const size_t base, const size_t rb_addr); + static sptr make( + uhd::wb_iface::sptr iface, + const uhd::wb_iface::wb_addr_type base, + const uhd::wb_iface::wb_addr_type rb_addr); /*! * Configure the GPIO mode for all pins in the daughterboard connector -- cgit v1.2.3 From 3fe7539f8b24f4474ed9c303ca089eed0170b44e Mon Sep 17 00:00:00 2001 From: Ashish Chaudhari Date: Wed, 7 Oct 2015 22:21:37 -0700 Subject: usrp3: Added more inline comments to gpio_atr_3000 --- host/lib/usrp/cores/gpio_atr_3000.cpp | 36 ++++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) (limited to 'host/lib/usrp/cores') diff --git a/host/lib/usrp/cores/gpio_atr_3000.cpp b/host/lib/usrp/cores/gpio_atr_3000.cpp index 729ecb8a6..d5f73988d 100644 --- a/host/lib/usrp/cores/gpio_atr_3000.cpp +++ b/host/lib/usrp/cores/gpio_atr_3000.cpp @@ -60,18 +60,34 @@ public: virtual void set_atr_mode(const gpio_atr_mode_t mode, const boost::uint32_t mask) { + //Each bit in the "ATR Disable" register determines whether the respective bit in the GPIO + //output bus is driven by the ATR engine or a static register. + //For each bit position, a 1 means that the bit is static and 0 means that the bit + //is driven by the ATR state machine. + //This setting will only get applied to all bits in the "mask" that are 1. All other + //bits will retain their old value. _atr_disable_reg.set_with_mask((mode==MODE_ATR) ? ~MASK_SET_ALL : MASK_SET_ALL, mask); _atr_disable_reg.flush(); } virtual void set_gpio_ddr(const gpio_ddr_t dir, const boost::uint32_t mask) { + //Each bit in the "DDR" register determines whether the respective bit in the GPIO + //bus is an input or an output. + //For each bit position, a 1 means that the bit is an output and 0 means that the bit + //is an input. + //This setting will only get applied to all bits in the "mask" that are 1. All other + //bits will retain their old value. _ddr_reg.set_with_mask((dir==DDR_INPUT) ? ~MASK_SET_ALL : MASK_SET_ALL, mask); _ddr_reg.flush(); } virtual void set_atr_reg(const gpio_atr_reg_t atr, const boost::uint32_t value, const boost::uint32_t mask) { + //Set the value of the specified ATR register. For bits with ATR Disable set to 1, + //the IDLE register will hold the output state + //This setting will only get applied to all bits in the "mask" that are 1. All other + //bits will retain their old value. masked_reg_t* reg = NULL; switch (atr) { case ATR_REG_IDLE: reg = &_atr_idle_reg; break; @@ -86,6 +102,9 @@ public: virtual boost::uint32_t read_gpio() { + //Read the state of the GPIO pins + //If a pin is configured as an input, reads the actual value of the pin + //If a pin is configured as an output, reads the last value written to the pin if (_rb_addr != READBACK_DISABLED) { return _iface->peek32(_rb_addr); } else { @@ -93,31 +112,38 @@ public: } } - virtual void set_gpio_attr(const gpio_attr_t attr, const boost::uint32_t value) + inline virtual void set_gpio_attr(const gpio_attr_t attr, const boost::uint32_t value) { + //An attribute based API to configure all settings for the GPIO bus in one function + //call. This API does not have a mask so it configures all bits at the same time. switch (attr) { case GPIO_CTRL: - set_atr_mode(MODE_ATR, value); - set_atr_mode(MODE_GPIO, ~value); + set_atr_mode(MODE_ATR, value); //Configure mode=ATR for all bits that are set + set_atr_mode(MODE_GPIO, ~value); //Configure mode=GPIO for all bits that are unset break; case GPIO_DDR: - set_gpio_ddr(DDR_OUTPUT, value); - set_gpio_ddr(DDR_INPUT, ~value); + set_gpio_ddr(DDR_OUTPUT, value); //Configure as output for all bits that are set + set_gpio_ddr(DDR_INPUT, ~value); //Configure as input for all bits that are unset break; case GPIO_OUT: + //Only set bits that are driven statically set_atr_reg(ATR_REG_IDLE, value, _atr_disable_reg.get(masked_reg_t::REGISTER)); break; case GPIO_ATR_0X: + //Only set bits that are driven by the ATR engine set_atr_reg(ATR_REG_IDLE, value, ~_atr_disable_reg.get(masked_reg_t::REGISTER)); break; case GPIO_ATR_RX: + //Only set bits that are driven by the ATR engine set_atr_reg(ATR_REG_RX_ONLY, value, ~_atr_disable_reg.get(masked_reg_t::REGISTER)); break; case GPIO_ATR_TX: + //Only set bits that are driven by the ATR engine set_atr_reg(ATR_REG_TX_ONLY, value, ~_atr_disable_reg.get(masked_reg_t::REGISTER)); break; case GPIO_ATR_XX: + //Only set bits that are driven by the ATR engine set_atr_reg(ATR_REG_FULL_DUPLEX, value, ~_atr_disable_reg.get(masked_reg_t::REGISTER)); break; default: -- cgit v1.2.3 From ea982f5f0d4b138f230638624c5e17fa3902706d Mon Sep 17 00:00:00 2001 From: Ashish Chaudhari Date: Sat, 10 Oct 2015 14:30:27 -0700 Subject: usrp3: Fixed issue where ATR Idle could clobber GPIO out - gpio_atr_3000 will not blindly use the mask when writing the ATR and GPIO OUT values. The mask will be ANDed with the value in the ATR Disable register --- host/lib/usrp/cores/gpio_atr_3000.cpp | 27 ++++++++++++++++++++------- host/lib/usrp/cores/gpio_atr_3000.hpp | 4 +--- 2 files changed, 21 insertions(+), 10 deletions(-) (limited to 'host/lib/usrp/cores') diff --git a/host/lib/usrp/cores/gpio_atr_3000.cpp b/host/lib/usrp/cores/gpio_atr_3000.cpp index d5f73988d..7f48abc69 100644 --- a/host/lib/usrp/cores/gpio_atr_3000.cpp +++ b/host/lib/usrp/cores/gpio_atr_3000.cpp @@ -82,7 +82,7 @@ public: _ddr_reg.flush(); } - virtual void set_atr_reg(const gpio_atr_reg_t atr, const boost::uint32_t value, const boost::uint32_t mask) + virtual void set_atr_reg(const gpio_atr_reg_t atr, const boost::uint32_t value, const boost::uint32_t mask = MASK_SET_ALL) { //Set the value of the specified ATR register. For bits with ATR Disable set to 1, //the IDLE register will hold the output state @@ -96,10 +96,23 @@ public: case ATR_REG_FULL_DUPLEX: reg = &_atr_fdx_reg; break; default: reg = &_atr_idle_reg; break; } - reg->set_with_mask(value, mask); + //For protection we only write to bits that have the mode ATR by masking the user + //specified "mask" with ~atr_disable. + reg->set_with_mask(value, mask & (~_atr_disable_reg.get(masked_reg_t::REGISTER))); reg->flush(); } + virtual void set_gpio_out(const boost::uint32_t value, const boost::uint32_t mask = MASK_SET_ALL) { + //Set the value of the specified GPIO output register. + //This setting will only get applied to all bits in the "mask" that are 1. All other + //bits will retain their old value. + + //For protection we only write to bits that have the mode GPIO by masking the user + //specified "mask" with atr_disable. + _atr_idle_reg.set_with_mask(value, mask & _atr_disable_reg.get(masked_reg_t::REGISTER)); + _atr_idle_reg.flush(); + } + virtual boost::uint32_t read_gpio() { //Read the state of the GPIO pins @@ -128,23 +141,23 @@ public: break; case GPIO_OUT: //Only set bits that are driven statically - set_atr_reg(ATR_REG_IDLE, value, _atr_disable_reg.get(masked_reg_t::REGISTER)); + set_atr_reg(ATR_REG_IDLE, value); break; case GPIO_ATR_0X: //Only set bits that are driven by the ATR engine - set_atr_reg(ATR_REG_IDLE, value, ~_atr_disable_reg.get(masked_reg_t::REGISTER)); + set_atr_reg(ATR_REG_IDLE, value); break; case GPIO_ATR_RX: //Only set bits that are driven by the ATR engine - set_atr_reg(ATR_REG_RX_ONLY, value, ~_atr_disable_reg.get(masked_reg_t::REGISTER)); + set_atr_reg(ATR_REG_RX_ONLY, value); break; case GPIO_ATR_TX: //Only set bits that are driven by the ATR engine - set_atr_reg(ATR_REG_TX_ONLY, value, ~_atr_disable_reg.get(masked_reg_t::REGISTER)); + set_atr_reg(ATR_REG_TX_ONLY, value); break; case GPIO_ATR_XX: //Only set bits that are driven by the ATR engine - set_atr_reg(ATR_REG_FULL_DUPLEX, value, ~_atr_disable_reg.get(masked_reg_t::REGISTER)); + set_atr_reg(ATR_REG_FULL_DUPLEX, value); break; default: UHD_THROW_INVALID_CODE_PATH(); diff --git a/host/lib/usrp/cores/gpio_atr_3000.hpp b/host/lib/usrp/cores/gpio_atr_3000.hpp index 28ec360ca..b30cd3b85 100644 --- a/host/lib/usrp/cores/gpio_atr_3000.hpp +++ b/host/lib/usrp/cores/gpio_atr_3000.hpp @@ -86,9 +86,7 @@ public: * \param value the value to write * \param mask only writes to the bits where mask is non-zero */ - inline void set_gpio_out(const boost::uint32_t value, const boost::uint32_t mask = MASK_SET_ALL) { - set_atr_reg(ATR_REG_IDLE, value, mask); - } + virtual void set_gpio_out(const boost::uint32_t value, const boost::uint32_t mask = MASK_SET_ALL) = 0; /*! * Read the state of the GPIO pins -- cgit v1.2.3