aboutsummaryrefslogtreecommitdiffstats
path: root/host/lib/usrp/cores
diff options
context:
space:
mode:
Diffstat (limited to 'host/lib/usrp/cores')
-rw-r--r--host/lib/usrp/cores/CMakeLists.txt1
-rw-r--r--host/lib/usrp/cores/gpio_core_200.cpp8
-rw-r--r--host/lib/usrp/cores/i2c_core_200.cpp158
-rw-r--r--host/lib/usrp/cores/i2c_core_200.hpp35
-rw-r--r--host/lib/usrp/cores/rx_dsp_core_200.cpp21
-rw-r--r--host/lib/usrp/cores/time64_core_200.cpp6
-rw-r--r--host/lib/usrp/cores/time64_core_200.hpp4
-rw-r--r--host/lib/usrp/cores/tx_dsp_core_200.cpp9
8 files changed, 238 insertions, 4 deletions
diff --git a/host/lib/usrp/cores/CMakeLists.txt b/host/lib/usrp/cores/CMakeLists.txt
index aa5f0bcbb..3192b0774 100644
--- a/host/lib/usrp/cores/CMakeLists.txt
+++ b/host/lib/usrp/cores/CMakeLists.txt
@@ -24,6 +24,7 @@ INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
LIBUHD_APPEND_SOURCES(
${CMAKE_CURRENT_SOURCE_DIR}/gpio_core_200.cpp
${CMAKE_CURRENT_SOURCE_DIR}/i2c_core_100.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/i2c_core_200.cpp
${CMAKE_CURRENT_SOURCE_DIR}/spi_core_100.cpp
${CMAKE_CURRENT_SOURCE_DIR}/time64_core_200.cpp
${CMAKE_CURRENT_SOURCE_DIR}/rx_dsp_core_200.cpp
diff --git a/host/lib/usrp/cores/gpio_core_200.cpp b/host/lib/usrp/cores/gpio_core_200.cpp
index d756097ff..cdab70b8d 100644
--- a/host/lib/usrp/cores/gpio_core_200.cpp
+++ b/host/lib/usrp/cores/gpio_core_200.cpp
@@ -63,6 +63,7 @@ private:
wb_iface::sptr _iface;
const size_t _base;
const size_t _rb_addr;
+ uhd::dict<size_t, boost::uint32_t> _update_cache;
uhd::dict<unit_t, boost::uint16_t> _pin_ctrl, _gpio_out, _gpio_ddr;
uhd::dict<unit_t, uhd::dict<atr_reg_t, boost::uint16_t> > _atr_regs;
@@ -90,7 +91,12 @@ private:
const boost::uint32_t ctrl =
(boost::uint32_t(_pin_ctrl[dboard_iface::UNIT_RX]) << unit2shit(dboard_iface::UNIT_RX)) |
(boost::uint32_t(_pin_ctrl[dboard_iface::UNIT_TX]) << unit2shit(dboard_iface::UNIT_TX));
- _iface->poke32(addr, (ctrl & atr_val) | ((~ctrl) & gpio_val));
+ const boost::uint32_t val = (ctrl & atr_val) | ((~ctrl) & gpio_val);
+ if (not _update_cache.has_key(addr) or _update_cache[addr] != val)
+ {
+ _iface->poke32(addr, val);
+ }
+ _update_cache[addr] = val;
}
};
diff --git a/host/lib/usrp/cores/i2c_core_200.cpp b/host/lib/usrp/cores/i2c_core_200.cpp
new file mode 100644
index 000000000..1b882c54a
--- /dev/null
+++ b/host/lib/usrp/cores/i2c_core_200.cpp
@@ -0,0 +1,158 @@
+//
+// Copyright 2011-2012 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 <http://www.gnu.org/licenses/>.
+//
+
+#include "i2c_core_200.hpp"
+#include <uhd/exception.hpp>
+#include <uhd/utils/msg.hpp>
+#include <boost/thread/thread.hpp> //sleep
+#include <boost/thread/mutex.hpp>
+
+#define REG_I2C_WR_PRESCALER_LO (1 << 3) | 0
+#define REG_I2C_WR_PRESCALER_HI (1 << 3) | 1
+#define REG_I2C_WR_CTRL (1 << 3) | 2
+#define REG_I2C_WR_DATA (1 << 3) | 3
+#define REG_I2C_WR_CMD (1 << 3) | 4
+#define REG_I2C_RD_DATA (0 << 3) | 3
+#define REG_I2C_RD_ST (0 << 3) | 4
+
+//
+// STA, STO, RD, WR, and IACK bits are cleared automatically
+//
+
+#define I2C_CTRL_EN (1 << 7) // core enable
+#define I2C_CTRL_IE (1 << 6) // interrupt enable
+
+#define I2C_CMD_START (1 << 7) // generate (repeated) start condition
+#define I2C_CMD_STOP (1 << 6) // generate stop condition
+#define I2C_CMD_RD (1 << 5) // read from slave
+#define I2C_CMD_WR (1 << 4) // write to slave
+#define I2C_CMD_NACK (1 << 3) // when a rcvr, send ACK (ACK=0) or NACK (ACK=1)
+#define I2C_CMD_RSVD_2 (1 << 2) // reserved
+#define I2C_CMD_RSVD_1 (1 << 1) // reserved
+#define I2C_CMD_IACK (1 << 0) // set to clear pending interrupt
+
+#define I2C_ST_RXACK (1 << 7) // Received acknowledgement from slave (1 = NAK, 0 = ACK)
+#define I2C_ST_BUSY (1 << 6) // 1 after START signal detected; 0 after STOP signal detected
+#define I2C_ST_AL (1 << 5) // Arbitration lost. 1 when core lost arbitration
+#define I2C_ST_RSVD_4 (1 << 4) // reserved
+#define I2C_ST_RSVD_3 (1 << 3) // reserved
+#define I2C_ST_RSVD_2 (1 << 2) // reserved
+#define I2C_ST_TIP (1 << 1) // Transfer-in-progress
+#define I2C_ST_IP (1 << 0) // Interrupt pending
+
+using namespace uhd;
+
+class i2c_core_200_impl : public i2c_core_200{
+public:
+ i2c_core_200_impl(wb_iface::sptr iface, const size_t base, const size_t readback):
+ _iface(iface), _base(base), _readback(readback)
+ {
+ //init I2C FPGA interface.
+ this->poke(REG_I2C_WR_CTRL, 0x0000);
+ //set prescalers to operate at 400kHz: WB_CLK is 64MHz...
+ static const boost::uint32_t i2c_datarate = 400000;
+ static const boost::uint32_t wishbone_clk = 64000000; //FIXME should go somewhere else
+ boost::uint16_t prescaler = wishbone_clk / (i2c_datarate*5) - 1;
+ this->poke(REG_I2C_WR_PRESCALER_LO, prescaler & 0xFF);
+ this->poke(REG_I2C_WR_PRESCALER_HI, (prescaler >> 8) & 0xFF);
+ this->poke(REG_I2C_WR_CTRL, I2C_CTRL_EN); //enable I2C core
+ }
+
+ void write_i2c(
+ boost::uint8_t addr,
+ const byte_vector_t &bytes
+ ){
+ this->poke(REG_I2C_WR_DATA, (addr << 1) | 0); //addr and read bit (0)
+ this->poke(REG_I2C_WR_CMD, I2C_CMD_WR | I2C_CMD_START | (bytes.size() == 0 ? I2C_CMD_STOP : 0));
+
+ //wait for previous transfer to complete
+ if (not wait_chk_ack()) {
+ this->poke(REG_I2C_WR_CMD, I2C_CMD_STOP);
+ return;
+ }
+
+ for (size_t i = 0; i < bytes.size(); i++) {
+ this->poke(REG_I2C_WR_DATA, bytes[i]);
+ this->poke(REG_I2C_WR_CMD, I2C_CMD_WR | ((i == (bytes.size() - 1)) ? I2C_CMD_STOP : 0));
+ if(!wait_chk_ack()) {
+ this->poke(REG_I2C_WR_CMD, I2C_CMD_STOP);
+ return;
+ }
+ }
+ }
+
+ byte_vector_t read_i2c(
+ boost::uint8_t addr,
+ size_t num_bytes
+ ){
+ byte_vector_t bytes;
+ if (num_bytes == 0) return bytes;
+
+ while (this->peek(REG_I2C_RD_ST) & I2C_ST_BUSY){
+ /* NOP */
+ }
+
+ this->poke(REG_I2C_WR_DATA, (addr << 1) | 1); //addr and read bit (1)
+ this->poke(REG_I2C_WR_CMD, I2C_CMD_WR | I2C_CMD_START);
+ //wait for previous transfer to complete
+ if (not wait_chk_ack()) {
+ this->poke(REG_I2C_WR_CMD, I2C_CMD_STOP);
+ }
+ for (size_t i = 0; i < num_bytes; i++) {
+ this->poke(REG_I2C_WR_CMD, I2C_CMD_RD | ((num_bytes == i+1) ? (I2C_CMD_STOP | I2C_CMD_NACK) : 0));
+ i2c_wait();
+ bytes.push_back(this->peek(REG_I2C_RD_DATA));
+ }
+ return bytes;
+ }
+
+private:
+ void i2c_wait(void) {
+ for (size_t i = 0; i < 100; i++){
+ if ((this->peek(REG_I2C_RD_ST) & I2C_ST_TIP) == 0) return;
+ boost::this_thread::sleep(boost::posix_time::milliseconds(1));
+ }
+ UHD_MSG(error) << "i2c_core_200: i2c_wait timeout" << std::endl;
+ }
+
+ bool wait_chk_ack(void){
+ i2c_wait();
+ return (this->peek(REG_I2C_RD_ST) & I2C_ST_RXACK) == 0;
+ }
+
+ void poke(const size_t what, const boost::uint8_t cmd)
+ {
+ boost::mutex::scoped_lock lock(_mutex);
+ _iface->poke32(_base, (what << 8) | cmd);
+ }
+
+ boost::uint8_t peek(const size_t what)
+ {
+ boost::mutex::scoped_lock lock(_mutex);
+ _iface->poke32(_base, what << 8);
+ return boost::uint8_t(_iface->peek32(_readback));
+ }
+
+ wb_iface::sptr _iface;
+ const size_t _base;
+ const size_t _readback;
+ boost::mutex _mutex;
+};
+
+i2c_core_200::sptr i2c_core_200::make(wb_iface::sptr iface, const size_t base, const size_t readback){
+ return sptr(new i2c_core_200_impl(iface, base, readback));
+}
diff --git a/host/lib/usrp/cores/i2c_core_200.hpp b/host/lib/usrp/cores/i2c_core_200.hpp
new file mode 100644
index 000000000..508855985
--- /dev/null
+++ b/host/lib/usrp/cores/i2c_core_200.hpp
@@ -0,0 +1,35 @@
+//
+// Copyright 2011-2012 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 <http://www.gnu.org/licenses/>.
+//
+
+#ifndef INCLUDED_LIBUHD_USRP_I2C_CORE_200_HPP
+#define INCLUDED_LIBUHD_USRP_I2C_CORE_200_HPP
+
+#include <uhd/config.hpp>
+#include <uhd/types/serial.hpp>
+#include <boost/utility.hpp>
+#include <boost/shared_ptr.hpp>
+#include "wb_iface.hpp"
+
+class i2c_core_200 : boost::noncopyable, public uhd::i2c_iface{
+public:
+ typedef boost::shared_ptr<i2c_core_200> sptr;
+
+ //! makes a new i2c core from iface and slave base
+ static sptr make(wb_iface::sptr iface, const size_t base, const size_t readback);
+};
+
+#endif /* INCLUDED_LIBUHD_USRP_I2C_CORE_200_HPP */
diff --git a/host/lib/usrp/cores/rx_dsp_core_200.cpp b/host/lib/usrp/cores/rx_dsp_core_200.cpp
index b73baa81e..ef6b85de9 100644
--- a/host/lib/usrp/cores/rx_dsp_core_200.cpp
+++ b/host/lib/usrp/cores/rx_dsp_core_200.cpp
@@ -19,6 +19,7 @@
#include <uhd/types/dict.hpp>
#include <uhd/exception.hpp>
#include <uhd/utils/msg.hpp>
+#include <uhd/utils/safe_call.hpp>
#include <uhd/utils/algorithm.hpp>
#include <boost/assign/list_of.hpp>
#include <boost/thread/thread.hpp> //thread sleep
@@ -76,8 +77,17 @@ public:
this->clear();
}
+ ~rx_dsp_core_200_impl(void)
+ {
+ UHD_SAFE_CALL
+ (
+ //shutdown any possible streaming
+ this->clear();
+ )
+ }
+
void clear(void){
- _iface->poke32(REG_RX_CTRL_NCHANNELS, 1); //also reset
+ _iface->poke32(REG_RX_CTRL_NCHANNELS, 0); //also reset
_iface->poke32(REG_RX_CTRL_VRT_HDR, 0
| (0x1 << 28) //if data with stream id
| (0x1 << 26) //has trailer
@@ -174,6 +184,15 @@ public:
_iface->poke32(REG_DSP_RX_DECIM, (hb1 << 9) | (hb0 << 8) | (decim & 0xff));
+ if (decim > 1 and hb0 == 0 and hb1 == 0)
+ {
+ UHD_MSG(warning) << boost::format(
+ "The requested decimation is odd; the user should expect CIC rolloff.\n"
+ "Select an even decimation to ensure that a halfband filter is enabled.\n"
+ "decimation = dsp_rate/samp_rate -> %d = (%f MHz)/(%f MHz)\n"
+ ) % decim_rate % (_tick_rate/1e6) % (rate/1e6);
+ }
+
// Calculate CIC decimation (i.e., without halfband decimators)
// Calculate closest multiplier constant to reverse gain absent scale multipliers
const double rate_pow = std::pow(double(decim & 0xff), 4);
diff --git a/host/lib/usrp/cores/time64_core_200.cpp b/host/lib/usrp/cores/time64_core_200.cpp
index e460d1106..11b310362 100644
--- a/host/lib/usrp/cores/time64_core_200.cpp
+++ b/host/lib/usrp/cores/time64_core_200.cpp
@@ -56,6 +56,10 @@ public:
if (_mimo_delay_cycles != 0) _sources.push_back("mimo");
}
+ void enable_gpsdo(void){
+ _sources.push_back("gpsdo");
+ }
+
void set_tick_rate(const double rate){
_tick_rate = rate;
}
@@ -100,7 +104,7 @@ public:
assert_has(_sources, source, "time source");
//setup pps flags
- if (source == "external"){
+ if (source == "external" or source == "gpsdo"){
_iface->poke32(REG_TIME64_FLAGS, FLAG_TIME64_PPS_SMA | FLAG_TIME64_PPS_POSEDGE);
}
else if (source == "_external_"){
diff --git a/host/lib/usrp/cores/time64_core_200.hpp b/host/lib/usrp/cores/time64_core_200.hpp
index 7571573a5..315f2ba67 100644
--- a/host/lib/usrp/cores/time64_core_200.hpp
+++ b/host/lib/usrp/cores/time64_core_200.hpp
@@ -1,5 +1,5 @@
//
-// Copyright 2011 Ettus Research LLC
+// Copyright 2011-2012 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
@@ -42,6 +42,8 @@ public:
const size_t mimo_delay_cycles = 0 // 0 means no-mimo
);
+ virtual void enable_gpsdo(void) = 0;
+
virtual void set_tick_rate(const double rate) = 0;
virtual uhd::time_spec_t get_time_now(void) = 0;
diff --git a/host/lib/usrp/cores/tx_dsp_core_200.cpp b/host/lib/usrp/cores/tx_dsp_core_200.cpp
index f905a7551..808f13028 100644
--- a/host/lib/usrp/cores/tx_dsp_core_200.cpp
+++ b/host/lib/usrp/cores/tx_dsp_core_200.cpp
@@ -126,6 +126,15 @@ public:
_iface->poke32(REG_DSP_TX_INTERP, (hb1 << 9) | (hb0 << 8) | (interp & 0xff));
+ if (interp > 1 and hb0 == 0 and hb1 == 0)
+ {
+ UHD_MSG(warning) << boost::format(
+ "The requested interpolation is odd; the user should expect CIC rolloff.\n"
+ "Select an even interpolation to ensure that a halfband filter is enabled.\n"
+ "interpolation = dsp_rate/samp_rate -> %d = (%f MHz)/(%f MHz)\n"
+ ) % interp_rate % (_tick_rate/1e6) % (rate/1e6);
+ }
+
// Calculate CIC interpolation (i.e., without halfband interpolators)
// Calculate closest multiplier constant to reverse gain absent scale multipliers
const double rate_pow = std::pow(double(interp & 0xff), 3);