summaryrefslogtreecommitdiffstats
path: root/host/lib
diff options
context:
space:
mode:
authorJosh Blum <josh@joshknows.com>2011-06-15 16:45:46 -0700
committerJosh Blum <josh@joshknows.com>2011-06-15 16:45:46 -0700
commit4802b02463cd8d3a3adde2c38f6936936fe80571 (patch)
treed4acd48d29347a718385a63bb3f9b83d70ffbc88 /host/lib
parentb9a32f31acee6fc0852763f2f30d98206430d52b (diff)
parent8da2d8426e2a668b9fde31773a9e313a4ce1c2bb (diff)
downloaduhd-4802b02463cd8d3a3adde2c38f6936936fe80571.tar.gz
uhd-4802b02463cd8d3a3adde2c38f6936936fe80571.tar.bz2
uhd-4802b02463cd8d3a3adde2c38f6936936fe80571.zip
Merge branch 'usrp_e100_aux_spi' into frontend_work
Diffstat (limited to 'host/lib')
-rw-r--r--host/lib/usrp/usrp_e100/clock_ctrl.cpp21
-rw-r--r--host/lib/usrp/usrp_e100/fpga_downloader.cpp12
-rw-r--r--host/lib/usrp/usrp_e100/usrp_e100_iface.cpp141
-rw-r--r--host/lib/usrp/usrp_e100/usrp_e100_iface.hpp14
-rw-r--r--host/lib/usrp/usrp_e100/usrp_e100_impl.cpp64
-rw-r--r--host/lib/usrp/usrp_e100/usrp_e100_impl.hpp22
6 files changed, 196 insertions, 78 deletions
diff --git a/host/lib/usrp/usrp_e100/clock_ctrl.cpp b/host/lib/usrp/usrp_e100/clock_ctrl.cpp
index f1b29840a..742959ae3 100644
--- a/host/lib/usrp/usrp_e100/clock_ctrl.cpp
+++ b/host/lib/usrp/usrp_e100/clock_ctrl.cpp
@@ -172,6 +172,12 @@ public:
_chan_rate = 0.0;
_out_rate = 0.0;
+ //perform soft-reset
+ _ad9522_regs.soft_reset = 1;
+ this->send_reg(0x000);
+ this->latch_regs();
+ _ad9522_regs.soft_reset = 0;
+
//init the clock gen registers
//Note: out0 should already be clocking the FPGA or this isnt going to work
_ad9522_regs.sdo_active = ad9522_regs_t::SDO_ACTIVE_SDO_SDIO;
@@ -437,8 +443,6 @@ private:
}
void calibrate_now(void){
- set_ignore_sync_fpga_plus_codec(false); //want vco cal to sync
-
//vco calibration routine:
_ad9522_regs.vco_calibration_now = 0;
this->send_reg(0x18);
@@ -467,20 +471,9 @@ private:
_ad9522_regs.get_read_reg(addr), 24
);
_ad9522_regs.set_reg(addr, reg);
- if (_ad9522_regs.digital_lock_detect) goto finalize;
+ if (_ad9522_regs.digital_lock_detect) return;
}
UHD_MSG(error) << "USRP-E100 clock control: lock detection timeout" << std::endl;
- finalize:
-
- set_ignore_sync_fpga_plus_codec(true); //never loose sync between these two
- }
-
- void set_ignore_sync_fpga_plus_codec(bool enb){
- _ad9522_regs.divider0_ignore_sync = (enb)?1:0; // master FPGA clock ignores sync (always on, cannot be disabled by sync pulse)
- _ad9522_regs.divider1_ignore_sync = (enb)?1:0; // codec clock ignores sync (always on, cannot be disabled by sync pulse)
- this->send_reg(0x191);
- this->send_reg(0x194);
- this->latch_regs();
}
void soft_sync(void){
diff --git a/host/lib/usrp/usrp_e100/fpga_downloader.cpp b/host/lib/usrp/usrp_e100/fpga_downloader.cpp
index a7449d3b1..b8420796f 100644
--- a/host/lib/usrp/usrp_e100/fpga_downloader.cpp
+++ b/host/lib/usrp/usrp_e100/fpga_downloader.cpp
@@ -254,9 +254,9 @@ void usrp_e100_load_fpga(const std::string &bin_file){
UHD_MSG(status) << "Loading FPGA image: " << bin_file << "... " << std::flush;
- if(std::system("/sbin/rmmod usrp_e") != 0){
- UHD_MSG(warning) << "USRP-E100 FPGA downloader: could not unload usrp_e module" << std::endl;
- }
+// if(std::system("/sbin/rmmod usrp_e") != 0){
+// UHD_MSG(warning) << "USRP-E100 FPGA downloader: could not unload usrp_e module" << std::endl;
+// }
prepare_fpga_for_configuration(gpio_prog_b, gpio_init_b);
@@ -264,9 +264,9 @@ void usrp_e100_load_fpga(const std::string &bin_file){
send_file_to_fpga(bin_file, gpio_init_b, gpio_done);
- if(std::system("/sbin/modprobe usrp_e") != 0){
- UHD_MSG(warning) << "USRP-E100 FPGA downloader: could not load usrp_e module" << std::endl;
- }
+// if(std::system("/sbin/modprobe usrp_e") != 0){
+// UHD_MSG(warning) << "USRP-E100 FPGA downloader: could not load usrp_e module" << std::endl;
+// }
}
diff --git a/host/lib/usrp/usrp_e100/usrp_e100_iface.cpp b/host/lib/usrp/usrp_e100/usrp_e100_iface.cpp
index 55446da63..93c8cc7b5 100644
--- a/host/lib/usrp/usrp_e100/usrp_e100_iface.cpp
+++ b/host/lib/usrp/usrp_e100/usrp_e100_iface.cpp
@@ -18,14 +18,17 @@
#include "usrp_e100_iface.hpp"
#include "usrp_e100_regs.hpp"
#include <uhd/exception.hpp>
+#include <uhd/utils/msg.hpp>
#include <sys/ioctl.h> //ioctl
#include <fcntl.h> //open, close
#include <linux/usrp_e.h> //ioctl structures and constants
+#include <boost/thread/thread.hpp> //sleep
#include <boost/format.hpp>
#include <boost/thread/mutex.hpp>
#include <linux/i2c-dev.h>
#include <linux/i2c.h>
-#include <stdexcept>
+#include <iostream>
+#include <fstream>
using namespace uhd;
using namespace uhd::usrp;
@@ -98,12 +101,9 @@ public:
return _node_fd;
}
- /*******************************************************************
- * Structors
- ******************************************************************/
- usrp_e100_iface_impl(const std::string &node):
- _i2c_dev_iface(i2c_dev_iface("/dev/i2c-3"))
- {
+ void open(const std::string &node){
+ UHD_MSG(status) << "Opening device node " << node << "..." << std::endl;
+
//open the device node and check file descriptor
if ((_node_fd = ::open(node.c_str(), O_RDWR)) < 0){
throw uhd::io_error("Failed to open " + node);
@@ -112,18 +112,30 @@ public:
//check the module compatibility number
int module_compat_num = ::ioctl(_node_fd, USRP_E_GET_COMPAT_NUMBER, NULL);
if (module_compat_num != USRP_E_COMPAT_NUMBER){
- throw uhd::runtime_error(str(boost::format(
- "Expected module compatibility number 0x%x, but got 0x%x:\n"
- "The module build is not compatible with the host code build."
- ) % USRP_E_COMPAT_NUMBER % module_compat_num));
+ throw uhd::runtime_error(str(boost::format(
+ "Expected module compatibility number 0x%x, but got 0x%x:\n"
+ "The module build is not compatible with the host code build."
+ ) % USRP_E_COMPAT_NUMBER % module_compat_num));
+ }
+ }
+
+ void close(void){
+ ::close(_node_fd);
+ _node_fd = -1;
}
+ /*******************************************************************
+ * Structors
+ ******************************************************************/
+ usrp_e100_iface_impl(void):
+ _node_fd(-1),
+ _i2c_dev_iface(i2c_dev_iface("/dev/i2c-3"))
+ {
mb_eeprom = mboard_eeprom_t(get_i2c_dev_iface(), mboard_eeprom_t::MAP_E100);
}
~usrp_e100_iface_impl(void){
- //close the device node file descriptor
- ::close(_node_fd);
+ if (_node_fd >= 0) this->close();
}
/*******************************************************************
@@ -245,6 +257,10 @@ public:
size_t num_bits,
bool readback
){
+ if (which_slave == UE_SPI_SS_AD9522) return bitbang_spi(
+ bits, num_bits, readback
+ );
+
//load data struct
usrp_e_spi data;
data.readback = (readback)? UE_SPI_TXRX : UE_SPI_TXONLY;
@@ -263,11 +279,101 @@ public:
//unload the data
return data.data;
}
-
+
+ boost::uint32_t bitbang_spi(
+ boost::uint32_t bits,
+ size_t num_bits,
+ bool readback
+ ){
+ boost::uint32_t rb_bits = 0;
+
+ _spi_bitbanger.spi_sen_gpio_write(0);
+
+ for (size_t i = 0; i < num_bits; i++){
+ _spi_bitbanger.spi_sclk_gpio_write(0);
+ _spi_bitbanger.spi_mosi_gpio_write((bits >> (num_bits-i-1)) & 0x1);
+ boost::this_thread::sleep(boost::posix_time::microseconds(10));
+ if (readback) rb_bits = (rb_bits << 1) | _spi_bitbanger.spi_miso_gpio_read();
+ _spi_bitbanger.spi_sclk_gpio_write(1);
+ boost::this_thread::sleep(boost::posix_time::microseconds(10));
+ }
+
+ _spi_bitbanger.spi_sen_gpio_write(1);
+ boost::this_thread::sleep(boost::posix_time::microseconds(100));
+
+ return rb_bits;
+ }
+
+ class bitbang_spi_guts{
+ public:
+ bitbang_spi_guts(void){
+ //setup gpio pin directions
+ this->set_gpio_direction(spi_sclk_gpio, "out");
+ this->set_gpio_direction(spi_sen_gpio, "out");
+ this->set_gpio_direction(spi_mosi_gpio, "out");
+ this->set_gpio_direction(spi_miso_gpio, "in");
+
+ //open the gpio pin values
+ _spi_sclk_gpio_value.open(str(boost::format("/sys/class/gpio/gpio%d/value") % spi_sclk_gpio).c_str());
+ _spi_sen_gpio_value.open(str(boost::format("/sys/class/gpio/gpio%d/value") % spi_sen_gpio).c_str());
+ _spi_mosi_gpio_value.open(str(boost::format("/sys/class/gpio/gpio%d/value") % spi_mosi_gpio).c_str());
+ _spi_miso_gpio_value.open(str(boost::format("/sys/class/gpio/gpio%d/value") % spi_miso_gpio).c_str());
+ }
+
+ ~bitbang_spi_guts(void){
+ this->set_gpio_direction(spi_sclk_gpio, "in");
+ this->set_gpio_direction(spi_sen_gpio, "in");
+ this->set_gpio_direction(spi_mosi_gpio, "in");
+ }
+
+ void spi_sclk_gpio_write(int val){
+ _spi_sclk_gpio_value << val << std::endl << std::flush;
+ }
+
+ void spi_sen_gpio_write(int val){
+ _spi_sen_gpio_value << val << std::endl << std::flush;
+ }
+
+ void spi_mosi_gpio_write(int val){
+ _spi_mosi_gpio_value << val << std::endl << std::flush;
+ }
+
+ int spi_miso_gpio_read(void){
+ std::string val;
+ std::getline(_spi_miso_gpio_value, val);
+ _spi_miso_gpio_value.seekg(0);
+ return int(val.at(0) - '0') & 0x1;
+ }
+
+ private:
+ enum{
+ spi_sclk_gpio = 65,
+ spi_sen_gpio = 186,
+ spi_mosi_gpio = 145,
+ spi_miso_gpio = 147,
+ };
+
+ void set_gpio_direction(int gpio_num, const std::string &dir){
+ std::ofstream export_file("/sys/class/gpio/export");
+ export_file << gpio_num << std::endl << std::flush;
+ export_file.close();
+
+ std::ofstream dir_file(str(boost::format("/sys/class/gpio/gpio%d/direction") % gpio_num).c_str());
+ dir_file << dir << std::endl << std::flush;
+ dir_file.close();
+ }
+
+ std::ofstream _spi_sclk_gpio_value, _spi_sen_gpio_value, _spi_mosi_gpio_value;
+ std::ifstream _spi_miso_gpio_value;
+ };
+
+ /*******************************************************************
+ * UART
+ ******************************************************************/
void write_uart(boost::uint8_t, const std::string &) {
throw uhd::not_implemented_error("Unhandled command write_uart()");
}
-
+
std::string read_uart(boost::uint8_t) {
throw uhd::not_implemented_error("Unhandled command read_uart()");
}
@@ -276,11 +382,12 @@ private:
int _node_fd;
i2c_dev_iface _i2c_dev_iface;
boost::mutex _ctrl_mutex;
+ bitbang_spi_guts _spi_bitbanger;
};
/***********************************************************************
* Public Make Function
**********************************************************************/
-usrp_e100_iface::sptr usrp_e100_iface::make(const std::string &node){
- return sptr(new usrp_e100_iface_impl(node));
+usrp_e100_iface::sptr usrp_e100_iface::make(void){
+ return sptr(new usrp_e100_iface_impl());
}
diff --git a/host/lib/usrp/usrp_e100/usrp_e100_iface.hpp b/host/lib/usrp/usrp_e100/usrp_e100_iface.hpp
index d9fe96db7..7df99cf4e 100644
--- a/host/lib/usrp/usrp_e100/usrp_e100_iface.hpp
+++ b/host/lib/usrp/usrp_e100/usrp_e100_iface.hpp
@@ -46,10 +46,9 @@ public:
/*!
* Make a new usrp-e interface with the control transport.
- * \param node the device node name
* \return a new usrp-e interface object
*/
- static sptr make(const std::string &node);
+ static sptr make(void);
/*!
* Get the underlying file descriptor.
@@ -58,6 +57,17 @@ public:
virtual int get_file_descriptor(void) = 0;
/*!
+ * Open a device node into this iface.
+ * \param node the device node name
+ */
+ virtual void open(const std::string &node) = 0;
+
+ /*!
+ * Close the open device node in this iface.
+ */
+ virtual void close(void) = 0;
+
+ /*!
* Perform an ioctl call on the device node file descriptor.
* This will throw when the internal ioctl call fails.
* \param request the control word
diff --git a/host/lib/usrp/usrp_e100/usrp_e100_impl.cpp b/host/lib/usrp/usrp_e100/usrp_e100_impl.cpp
index 5b039aafc..36db810a8 100644
--- a/host/lib/usrp/usrp_e100/usrp_e100_impl.cpp
+++ b/host/lib/usrp/usrp_e100/usrp_e100_impl.cpp
@@ -54,7 +54,7 @@ static device_addrs_t usrp_e100_find(const device_addr_t &hint){
new_addr["type"] = "usrp-e";
new_addr["node"] = fs::system_complete(fs::path(hint["node"])).string();
try{
- usrp_e100_iface::sptr iface = usrp_e100_iface::make(new_addr["node"]);
+ usrp_e100_iface::sptr iface = usrp_e100_iface::make();
new_addr["name"] = iface->mb_eeprom["name"];
new_addr["serial"] = iface->mb_eeprom["serial"];
}
@@ -88,39 +88,43 @@ static size_t hash_fpga_file(const std::string &file_path){
static device::sptr usrp_e100_make(const device_addr_t &device_addr){
//setup the main interface into fpga
- std::string node = device_addr["node"];
- UHD_MSG(status) << boost::format("Opening USRP-E on %s") % node << std::endl;
- usrp_e100_iface::sptr iface = usrp_e100_iface::make(node);
+ const std::string node = device_addr["node"];
+ usrp_e100_iface::sptr iface = usrp_e100_iface::make();
+ iface->open(node);
- //extract the fpga path for usrp-e
- std::string usrp_e100_fpga_image = find_image_path(device_addr.get("fpga", "usrp_e100_fpga.bin"));
+ //setup clock control here to ensure that the FPGA has a good clock before we continue
+ const double master_clock_rate = device_addr.cast<double>("master_clock_rate", USRP_E_DEFAULT_CLOCK_RATE);
+ usrp_e100_clock_ctrl::sptr clock_ctrl = usrp_e100_clock_ctrl::make(iface, master_clock_rate);
- //compute a hash of the fpga file
+ //extract the fpga path for usrp-e and compute hash
+ const std::string usrp_e100_fpga_image = find_image_path(device_addr.get("fpga", USRP_E_FPGA_FILE_NAME));
const boost::uint32_t file_hash = boost::uint32_t(hash_fpga_file(usrp_e100_fpga_image));
//When the hash does not match:
- // - unload the iface to free the node
- // - load the fpga configuration file
- // - re-open the iface on the node
+ // - close the device node
+ // - load the fpga bin file
+ // - re-open the device node
if (iface->peek32(UE_REG_RB_MISC_TEST32) != file_hash){
- iface.reset();
+ iface->close();
usrp_e100_load_fpga(usrp_e100_fpga_image);
- sleep(1); ///\todo do this better one day.
- UHD_MSG(status) << boost::format("re-Opening USRP-E on %s") % node << std::endl;
- iface = usrp_e100_iface::make(node);
+ iface->open(node);
}
- //store the hash into the FPGA register
- iface->poke32(UE_REG_SR_MISC_TEST32, file_hash);
-
- //check that the hash can be readback correctly
- if (iface->peek32(UE_REG_RB_MISC_TEST32) != file_hash){
- UHD_MSG(error) << boost::format(
- "The FPGA hash readback failed!\n"
- "The FPGA is either clocked improperly\n"
- "or the FPGA build is not compatible.\n"
- );
+ //Perform wishbone readback tests, these tests also write the hash
+ bool test_fail = false;
+ UHD_MSG(status) << "Performing wishbone readback test... " << std::flush;
+ for (size_t i = 0; i < 100; i++){
+ iface->poke32(UE_REG_SR_MISC_TEST32, file_hash);
+ test_fail = iface->peek32(UE_REG_RB_MISC_TEST32) != file_hash;
+ if (test_fail) break; //exit loop on any failure
}
+ UHD_MSG(status) << ((test_fail)? " fail" : "pass") << std::endl;
+
+ if (test_fail) UHD_MSG(error) << boost::format(
+ "The FPGA is either clocked improperly\n"
+ "or the FPGA build is not compatible.\n"
+ "Subsequent errors may follow...\n"
+ );
//check that the compatibility is correct
const boost::uint16_t fpga_compat_num = iface->peek16(UE_REG_MISC_COMPAT);
@@ -133,7 +137,7 @@ static device::sptr usrp_e100_make(const device_addr_t &device_addr){
) % USRP_E_FPGA_COMPAT_NUM % fpga_compat_num));
}
- return device::sptr(new usrp_e100_impl(iface, device_addr));
+ return device::sptr(new usrp_e100_impl(device_addr, iface, clock_ctrl));
}
UHD_STATIC_BLOCK(register_usrp_e100_device){
@@ -144,20 +148,18 @@ UHD_STATIC_BLOCK(register_usrp_e100_device){
* Structors
**********************************************************************/
usrp_e100_impl::usrp_e100_impl(
+ const uhd::device_addr_t &device_addr,
usrp_e100_iface::sptr iface,
- const device_addr_t &device_addr
+ usrp_e100_clock_ctrl::sptr clock_ctrl
):
_iface(iface),
+ _clock_ctrl(clock_ctrl),
+ _codec_ctrl(usrp_e100_codec_ctrl::make(_iface)),
_data_xport(usrp_e100_make_mmap_zero_copy(_iface)),
_recv_frame_size(std::min(_data_xport->get_recv_frame_size(), size_t(device_addr.cast<double>("recv_frame_size", 1e9)))),
_send_frame_size(std::min(_data_xport->get_send_frame_size(), size_t(device_addr.cast<double>("send_frame_size", 1e9))))
{
- //setup interfaces into hardware
- const double master_clock_rate = device_addr.cast<double>("master_clock_rate", 64e6);
- _clock_ctrl = usrp_e100_clock_ctrl::make(_iface, master_clock_rate);
- _codec_ctrl = usrp_e100_codec_ctrl::make(_iface);
-
//initialize the mboard
mboard_init();
diff --git a/host/lib/usrp/usrp_e100/usrp_e100_impl.hpp b/host/lib/usrp/usrp_e100/usrp_e100_impl.hpp
index 1c17863fb..0c6087a85 100644
--- a/host/lib/usrp/usrp_e100/usrp_e100_impl.hpp
+++ b/host/lib/usrp/usrp_e100/usrp_e100_impl.hpp
@@ -33,7 +33,9 @@
uhd::transport::zero_copy_if::sptr usrp_e100_make_mmap_zero_copy(usrp_e100_iface::sptr iface);
-static const boost::uint16_t USRP_E_FPGA_COMPAT_NUM = 0x04;
+static const std::string USRP_E_FPGA_FILE_NAME = "usrp_e100_fpga5.bin";
+static const boost::uint16_t USRP_E_FPGA_COMPAT_NUM = 0x05;
+static const double USRP_E_DEFAULT_CLOCK_RATE = 64e6;
//! load an fpga image from a bin file into the usrp-e fpga
extern void usrp_e100_load_fpga(const std::string &bin_file);
@@ -82,7 +84,11 @@ private:
class usrp_e100_impl : public uhd::device{
public:
//structors
- usrp_e100_impl(usrp_e100_iface::sptr, const uhd::device_addr_t &);
+ usrp_e100_impl(
+ const uhd::device_addr_t &,
+ usrp_e100_iface::sptr,
+ usrp_e100_clock_ctrl::sptr
+ );
~usrp_e100_impl(void);
//the io interface
@@ -96,6 +102,12 @@ private:
//interface to ioctls and file descriptor
usrp_e100_iface::sptr _iface;
+ //ad9522 clock control
+ usrp_e100_clock_ctrl::sptr _clock_ctrl;
+
+ //ad9862 codec control
+ usrp_e100_codec_ctrl::sptr _codec_ctrl;
+
//handle io stuff
uhd::transport::zero_copy_if::sptr _data_xport;
UHD_PIMPL_DECL(io_impl) _io_impl;
@@ -109,12 +121,6 @@ private:
//configuration shadows
uhd::clock_config_t _clock_config;
- //ad9522 clock control
- usrp_e100_clock_ctrl::sptr _clock_ctrl;
-
- //ad9862 codec control
- usrp_e100_codec_ctrl::sptr _codec_ctrl;
-
//device functions and settings
void get(const wax::obj &, wax::obj &);
void set(const wax::obj &, const wax::obj &);