diff options
Diffstat (limited to 'host/lib/usrp/e100/e100_iface.cpp')
-rw-r--r-- | host/lib/usrp/e100/e100_iface.cpp | 129 |
1 files changed, 86 insertions, 43 deletions
diff --git a/host/lib/usrp/e100/e100_iface.cpp b/host/lib/usrp/e100/e100_iface.cpp index e44e438b0..1bf33ae5b 100644 --- a/host/lib/usrp/e100/e100_iface.cpp +++ b/host/lib/usrp/e100/e100_iface.cpp @@ -23,11 +23,10 @@ #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 <boost/format.hpp> #include <linux/i2c-dev.h> #include <linux/i2c.h> -#include <iostream> #include <fstream> using namespace uhd; @@ -168,6 +167,12 @@ public: "The module build is not compatible with the host code build." ) % USRP_E_COMPAT_NUMBER % module_compat_num)); } + + //perform a global reset after opening + this->poke32(E100_REG_GLOBAL_RESET, 0); + + //and now is a good time to init the i2c + this->i2c_init(); } void close(void){ @@ -193,7 +198,7 @@ public: * IOCTL: provides the communication base for all other calls ******************************************************************/ void ioctl(int request, void *mem){ - boost::mutex::scoped_lock lock(_ctrl_mutex); + boost::mutex::scoped_lock lock(_ioctl_mutex); if (::ioctl(_node_fd, request, mem) < 0){ throw uhd::os_error(str( @@ -261,46 +266,84 @@ public: /******************************************************************* * I2C ******************************************************************/ - static const size_t max_i2c_data_bytes = 10; + static const boost::uint32_t i2c_datarate = 400000; + static const boost::uint32_t wishbone_clk = 64000000; //FIXME should go somewhere else + + void i2c_init(void) { + //init I2C FPGA interface. + poke16(E100_REG_I2C_CTRL, 0x0000); + //set prescalers to operate at 400kHz: WB_CLK is 64MHz... + boost::uint16_t prescaler = wishbone_clk / (i2c_datarate*5) - 1; + poke16(E100_REG_I2C_PRESCALER_LO, prescaler & 0xFF); + poke16(E100_REG_I2C_PRESCALER_HI, (prescaler >> 8) & 0xFF); + poke16(E100_REG_I2C_CTRL, I2C_CTRL_EN); //enable I2C core + } + + void i2c_wait(void){ + for (size_t i = 0; i < 100; i++){ + if ((this->peek16(E100_REG_I2C_CMD_STATUS) & I2C_ST_TIP) == 0) return; + boost::this_thread::sleep(boost::posix_time::milliseconds(1)); + } + UHD_MSG(error) << "i2c_wait: timeout" << std::endl; + } + + bool wait_chk_ack(void){ + i2c_wait(); + return (this->peek16(E100_REG_I2C_CMD_STATUS) & I2C_ST_RXACK) == 0; + } void write_i2c(boost::uint8_t addr, const byte_vector_t &bytes){ - //allocate some memory for this transaction - UHD_ASSERT_THROW(bytes.size() <= max_i2c_data_bytes); - boost::uint8_t mem[sizeof(usrp_e_i2c) + max_i2c_data_bytes]; + poke16(E100_REG_I2C_DATA, (addr << 1) | 0); //addr and read bit (0) + poke16(E100_REG_I2C_CMD_STATUS, I2C_CMD_WR | I2C_CMD_START | (bytes.size() == 0 ? I2C_CMD_STOP : 0)); - //load the data struct - usrp_e_i2c *data = reinterpret_cast<usrp_e_i2c*>(mem); - data->addr = addr; - data->len = bytes.size(); - std::copy(bytes.begin(), bytes.end(), data->data); + //wait for previous transfer to complete + if(!wait_chk_ack()) { + poke16(E100_REG_I2C_CMD_STATUS, I2C_CMD_STOP); + return; + } - //call the spi ioctl - this->ioctl(USRP_E_I2C_WRITE, data); + for(size_t i = 0; i < bytes.size(); i++) { + poke16(E100_REG_I2C_DATA, bytes[i]); + poke16(E100_REG_I2C_CMD_STATUS, I2C_CMD_WR | ((i == (bytes.size() - 1)) ? I2C_CMD_STOP : 0)); + if(!wait_chk_ack()) { + poke16(E100_REG_I2C_CMD_STATUS, I2C_CMD_STOP); + return; + } + } } byte_vector_t read_i2c(boost::uint8_t addr, size_t num_bytes){ - //allocate some memory for this transaction - UHD_ASSERT_THROW(num_bytes <= max_i2c_data_bytes); - boost::uint8_t mem[sizeof(usrp_e_i2c) + max_i2c_data_bytes]; - - //load the data struct - usrp_e_i2c *data = reinterpret_cast<usrp_e_i2c*>(mem); - data->addr = addr; - data->len = num_bytes; + byte_vector_t bytes; + if(num_bytes == 0) return bytes; - //call the spi ioctl - this->ioctl(USRP_E_I2C_READ, data); + while (peek16(E100_REG_I2C_CMD_STATUS) & I2C_ST_BUSY); - //unload the data - byte_vector_t bytes(data->len); - UHD_ASSERT_THROW(bytes.size() == num_bytes); - std::copy(data->data, data->data+bytes.size(), bytes.begin()); + poke16(E100_REG_I2C_DATA, (addr << 1) | 1); //addr and read bit (1) + poke16(E100_REG_I2C_CMD_STATUS, I2C_CMD_WR | I2C_CMD_START); + //wait for previous transfer to complete + if(!wait_chk_ack()) { + poke16(E100_REG_I2C_CMD_STATUS, I2C_CMD_STOP); + } + for(; num_bytes > 0; num_bytes--) { + poke16(E100_REG_I2C_CMD_STATUS, I2C_CMD_RD | ((num_bytes == 1) ? (I2C_CMD_STOP | I2C_CMD_NACK) : 0)); + i2c_wait(); + boost::uint8_t readback = peek16(E100_REG_I2C_DATA) & 0xFF; + bytes.push_back(readback); + } return bytes; } /******************************************************************* * SPI ******************************************************************/ + void spi_wait(void) { + for (size_t i = 0; i < 100; i++){ + if ((this->peek16(E100_REG_SPI_CTRL) & SPI_CTRL_GO_BSY) == 0) return; + boost::this_thread::sleep(boost::posix_time::milliseconds(1)); + } + UHD_MSG(error) << "spi_wait: timeout" << std::endl; + } + boost::uint32_t transact_spi( int which_slave, const spi_config_t &config, @@ -312,23 +355,23 @@ public: bits, num_bits, readback ); - //load data struct - usrp_e_spi data; - data.readback = (readback)? UE_SPI_TXRX : UE_SPI_TXONLY; - data.slave = which_slave; - data.length = num_bits; - data.data = bits; + UHD_ASSERT_THROW(num_bits <= 32 and (num_bits % 8) == 0); - //load the flags - data.flags = 0; - data.flags |= (config.miso_edge == spi_config_t::EDGE_RISE)? UE_SPI_LATCH_RISE : UE_SPI_LATCH_FALL; - data.flags |= (config.mosi_edge == spi_config_t::EDGE_RISE)? UE_SPI_PUSH_FALL : UE_SPI_PUSH_RISE; + int edge_flags = ((config.miso_edge==spi_config_t::EDGE_FALL) ? SPI_CTRL_RXNEG : 0) | + ((config.mosi_edge==spi_config_t::EDGE_FALL) ? 0 : SPI_CTRL_TXNEG) + ; + boost::uint16_t ctrl = SPI_CTRL_ASS | (SPI_CTRL_CHAR_LEN_MASK & num_bits) | edge_flags; - //call the spi ioctl - this->ioctl(USRP_E_SPI, &data); + spi_wait(); + poke16(E100_REG_SPI_DIV, 0x0001); // = fpga_clk / 4 + poke32(E100_REG_SPI_SS, which_slave & 0xFFFF); + poke32(E100_REG_SPI_TXRX0, bits); + poke16(E100_REG_SPI_CTRL, ctrl); + poke16(E100_REG_SPI_CTRL, ctrl | SPI_CTRL_GO_BSY); - //unload the data - return data.data; + if (not readback) return 0; + spi_wait(); + return peek32(E100_REG_SPI_TXRX0); } boost::uint32_t bitbang_spi( @@ -369,7 +412,7 @@ public: private: int _node_fd; i2c_dev_iface _i2c_dev_iface; - boost::mutex _ctrl_mutex; + boost::mutex _ioctl_mutex; iface_gpios_type::sptr _gpios; }; |