diff options
-rw-r--r-- | firmware/zpu/lib/memory_map.h | 2 | ||||
-rw-r--r-- | firmware/zpu/lib/spi.c | 24 | ||||
-rw-r--r-- | host/lib/usrp/usrp2/clock_ctrl.cpp | 13 | ||||
-rw-r--r-- | host/lib/usrp/usrp2/clock_ctrl.hpp | 7 | ||||
-rw-r--r-- | host/lib/usrp/usrp2/codec_ctrl.cpp | 14 | ||||
-rw-r--r-- | host/lib/usrp/usrp2/codec_ctrl.hpp | 7 | ||||
-rw-r--r-- | host/lib/usrp/usrp2/usrp2_fifo_ctrl.cpp | 61 | ||||
-rw-r--r-- | host/lib/usrp/usrp2/usrp2_fifo_ctrl.hpp | 3 | ||||
-rw-r--r-- | host/lib/usrp/usrp2/usrp2_impl.cpp | 6 |
9 files changed, 99 insertions, 38 deletions
diff --git a/firmware/zpu/lib/memory_map.h b/firmware/zpu/lib/memory_map.h index 8568872d0..4290ee20a 100644 --- a/firmware/zpu/lib/memory_map.h +++ b/firmware/zpu/lib/memory_map.h @@ -122,6 +122,8 @@ typedef struct { volatile uint32_t irqs; } router_status_t; +#define SPI_READY_IRQ (1 << 12) + #define router_status ((router_status_t *) READBACK_BASE) #define readback_mux ((router_status_t *) READBACK_BASE) //alias with a better name diff --git a/firmware/zpu/lib/spi.c b/firmware/zpu/lib/spi.c index de3645fe3..190658d61 100644 --- a/firmware/zpu/lib/spi.c +++ b/firmware/zpu/lib/spi.c @@ -19,17 +19,17 @@ #include "spi.h" #include "memory_map.h" #include "nonstdio.h" -#include "mdelay.h" void spi_init(void) { - spi_core->divider = 100; + spi_core->divider = 10; } void spi_wait(void) { - //assumption that divider is reasonably small - mdelay(1); + while ((readback_mux->irqs & SPI_READY_IRQ) == 0){ + //NOP + } } uint32_t spi_transact(bool readback, int slave, uint32_t data, int length, uint32_t flags) @@ -37,20 +37,14 @@ uint32_t spi_transact(bool readback, int slave, uint32_t data, int length, uint3 uint32_t control_word = 0; control_word |= (slave << SPI_CORE_SLAVE_SELECT_SHIFT); control_word |= (length << SPI_CORE_NUM_BITS_SHIFT); - if ((flags & SPI_PUSH_RISE) != 0) control_word |= (1 << SPI_CORE_DATA_IN_EDGE_SHIFT); - if ((flags & SPI_PUSH_FALL) != 0) control_word |= (0 << SPI_CORE_DATA_IN_EDGE_SHIFT); - if ((flags & SPI_LATCH_RISE) != 0) control_word |= (1 << SPI_CORE_DATA_OUT_EDGE_SHIFT); - if ((flags & SPI_LATCH_FALL) != 0) control_word |= (0 << SPI_CORE_DATA_OUT_EDGE_SHIFT); - - uint32_t data_out_rev = 0; - for (size_t i = 0; i < length; i++){ - const int bit = ((data >> i) & 0x1); - data_out_rev |= (bit << (length - i - 1)); - } + if ((flags & SPI_PUSH_RISE) != 0) control_word |= (1 << SPI_CORE_DATA_OUT_EDGE_SHIFT); + if ((flags & SPI_PUSH_FALL) != 0) control_word |= (0 << SPI_CORE_DATA_OUT_EDGE_SHIFT); + if ((flags & SPI_LATCH_RISE) != 0) control_word |= (1 << SPI_CORE_DATA_IN_EDGE_SHIFT); + if ((flags & SPI_LATCH_FALL) != 0) control_word |= (0 << SPI_CORE_DATA_IN_EDGE_SHIFT); spi_wait(); spi_core->control = control_word; - spi_core->data = data_out_rev; + spi_core->data = (data << (32 - length)); if (readback) spi_wait(); diff --git a/host/lib/usrp/usrp2/clock_ctrl.cpp b/host/lib/usrp/usrp2/clock_ctrl.cpp index 7d3ffefa2..769795aad 100644 --- a/host/lib/usrp/usrp2/clock_ctrl.cpp +++ b/host/lib/usrp/usrp2/clock_ctrl.cpp @@ -1,5 +1,5 @@ // -// Copyright 2010-2011 Ettus Research LLC +// Copyright 2010-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 @@ -35,8 +35,9 @@ static const bool enb_test_clk = false; */ class usrp2_clock_ctrl_impl : public usrp2_clock_ctrl{ public: - usrp2_clock_ctrl_impl(usrp2_iface::sptr iface){ + usrp2_clock_ctrl_impl(usrp2_iface::sptr iface, uhd::spi_iface::sptr spiface){ _iface = iface; + _spiface = spiface; clk_regs = usrp2_clk_regs_t(_iface->get_rev()); _ad9510_regs.cp_current_setting = ad9510_regs_t::CP_CURRENT_SETTING_3_0MA; @@ -331,7 +332,7 @@ private: */ void write_reg(boost::uint8_t addr){ boost::uint32_t data = _ad9510_regs.get_write_reg(addr); - _iface->write_spi(SPI_SS_AD9510, spi_config_t::EDGE_RISE, data, 24); + _spiface->write_spi(SPI_SS_AD9510, spi_config_t::EDGE_RISE, data, 24); } /*! @@ -377,7 +378,7 @@ private: } usrp2_iface::sptr _iface; - + uhd::spi_iface::sptr _spiface; usrp2_clk_regs_t clk_regs; ad9510_regs_t _ad9510_regs; }; @@ -385,6 +386,6 @@ private: /*********************************************************************** * Public make function for the ad9510 clock control **********************************************************************/ -usrp2_clock_ctrl::sptr usrp2_clock_ctrl::make(usrp2_iface::sptr iface){ - return sptr(new usrp2_clock_ctrl_impl(iface)); +usrp2_clock_ctrl::sptr usrp2_clock_ctrl::make(usrp2_iface::sptr iface, uhd::spi_iface::sptr spiface){ + return sptr(new usrp2_clock_ctrl_impl(iface, spiface)); } diff --git a/host/lib/usrp/usrp2/clock_ctrl.hpp b/host/lib/usrp/usrp2/clock_ctrl.hpp index 9ccbc959e..067e1e35d 100644 --- a/host/lib/usrp/usrp2/clock_ctrl.hpp +++ b/host/lib/usrp/usrp2/clock_ctrl.hpp @@ -1,5 +1,5 @@ // -// Copyright 2010 Ettus Research LLC +// Copyright 2010-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 @@ -29,10 +29,11 @@ public: /*! * Make a clock config for the ad9510 ic. - * \param _iface a pointer to the usrp2 interface object + * \param iface a pointer to the usrp2 interface object + * \param spiface the interface to spi * \return a new clock control object */ - static sptr make(usrp2_iface::sptr iface); + static sptr make(usrp2_iface::sptr iface, uhd::spi_iface::sptr spiface); /*! * Get the master clock frequency for the fpga. diff --git a/host/lib/usrp/usrp2/codec_ctrl.cpp b/host/lib/usrp/usrp2/codec_ctrl.cpp index 06bf83b15..b53c4d9df 100644 --- a/host/lib/usrp/usrp2/codec_ctrl.cpp +++ b/host/lib/usrp/usrp2/codec_ctrl.cpp @@ -1,5 +1,5 @@ // -// Copyright 2010-2011 Ettus Research LLC +// Copyright 2010-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 @@ -32,8 +32,9 @@ using namespace uhd; */ class usrp2_codec_ctrl_impl : public usrp2_codec_ctrl{ public: - usrp2_codec_ctrl_impl(usrp2_iface::sptr iface){ + usrp2_codec_ctrl_impl(usrp2_iface::sptr iface, uhd::spi_iface::sptr spiface){ _iface = iface; + _spiface = spiface; //setup the ad9777 dac _ad9777_regs.x_1r_2r_mode = ad9777_regs_t::X_1R_2R_MODE_1R; @@ -189,11 +190,12 @@ private: ad9777_regs_t _ad9777_regs; ads62p44_regs_t _ads62p44_regs; usrp2_iface::sptr _iface; + uhd::spi_iface::sptr _spiface; void send_ad9777_reg(boost::uint8_t addr){ boost::uint16_t reg = _ad9777_regs.get_write_reg(addr); UHD_LOGV(always) << "send_ad9777_reg: " << std::hex << reg << std::endl; - _iface->write_spi( + _spiface->write_spi( SPI_SS_AD9777, spi_config_t::EDGE_RISE, reg, 16 ); @@ -201,7 +203,7 @@ private: void send_ads62p44_reg(boost::uint8_t addr) { boost::uint16_t reg = _ads62p44_regs.get_write_reg(addr); - _iface->write_spi( + _spiface->write_spi( SPI_SS_ADS62P44, spi_config_t::EDGE_FALL, reg, 16 ); @@ -211,6 +213,6 @@ private: /*********************************************************************** * Public make function for the usrp2 codec control **********************************************************************/ -usrp2_codec_ctrl::sptr usrp2_codec_ctrl::make(usrp2_iface::sptr iface){ - return sptr(new usrp2_codec_ctrl_impl(iface)); +usrp2_codec_ctrl::sptr usrp2_codec_ctrl::make(usrp2_iface::sptr iface, uhd::spi_iface::sptr spiface){ + return sptr(new usrp2_codec_ctrl_impl(iface, spiface)); } diff --git a/host/lib/usrp/usrp2/codec_ctrl.hpp b/host/lib/usrp/usrp2/codec_ctrl.hpp index ca300e2b1..b0d815be2 100644 --- a/host/lib/usrp/usrp2/codec_ctrl.hpp +++ b/host/lib/usrp/usrp2/codec_ctrl.hpp @@ -1,5 +1,5 @@ // -// Copyright 2010-2011 Ettus Research LLC +// Copyright 2010-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 @@ -28,10 +28,11 @@ public: /*! * Make a codec control for the DAC and ADC. - * \param _iface a pointer to the usrp2 interface object + * \param iface a pointer to the usrp2 interface object + * \param spiface the interface to spi * \return a new codec control object */ - static sptr make(usrp2_iface::sptr iface); + static sptr make(usrp2_iface::sptr iface, uhd::spi_iface::sptr spiface); /*! * Set the modulation mode for the DAC. diff --git a/host/lib/usrp/usrp2/usrp2_fifo_ctrl.cpp b/host/lib/usrp/usrp2/usrp2_fifo_ctrl.cpp index 9d21c73ae..a602bfe9f 100644 --- a/host/lib/usrp/usrp2/usrp2_fifo_ctrl.cpp +++ b/host/lib/usrp/usrp2/usrp2_fifo_ctrl.cpp @@ -24,6 +24,7 @@ #include <boost/asio.hpp> //htonl #include <boost/format.hpp> +using namespace uhd; using namespace uhd::transport; static const size_t POKE32_CMD = (1 << 8); @@ -32,6 +33,14 @@ static const double ACK_TIMEOUT = 0.5; static const double MASSIVE_TIMEOUT = 10.0; //for when we wait on a timed command static const boost::uint32_t MAX_SEQS_OUT = 64; +#define SPI_DIV SR_SPI_CORE + 0 +#define SPI_CTRL SR_SPI_CORE + 1 +#define SPI_DATA SR_SPI_CORE + 2 +#define SPI_READBACK 0 +#define SPI_PERIF_MASK (1 << 10) +// spi clock rate = master_clock/(div+1)/2 (10MHz in this case) +#define SPI_DIVIDER 4 + class usrp2_fifo_ctrl_impl : public usrp2_fifo_ctrl{ public: @@ -43,6 +52,7 @@ public: while (_xport->get_recv_buff(0.0)){} //flush this->set_time(uhd::time_spec_t(0.0)); this->set_tick_rate(1.0); //something possible but bogus + this->init_spi(); } UHD_INLINE void send_pkt(wb_addr_type addr, boost::uint32_t data, int cmd){ @@ -97,7 +107,7 @@ public: return this->wait_for_ack(boost::int16_t(_seq)); } - boost::uint32_t wait_for_ack(const boost::int16_t seq_to_ack){ + UHD_INLINE boost::uint32_t wait_for_ack(const boost::int16_t seq_to_ack){ while (_last_seq_ack < seq_to_ack){ managed_recv_buffer::sptr buff = _xport->get_recv_buff(_timeout); @@ -125,6 +135,54 @@ public: throw uhd::not_implemented_error("peek16 not implemented in fifo ctrl module"); } + void init_spi(void){ + boost::mutex::scoped_lock lock(_mutex); + + this->send_pkt(SPI_DIV, SPI_DIVIDER, POKE32_CMD | SPI_PERIF_MASK); + this->wait_for_ack(boost::int16_t(_seq-MAX_SEQS_OUT)); + + _ctrl_word_cache = 0; // force update first time around + } + + boost::uint32_t transact_spi( + int which_slave, + const spi_config_t &config, + boost::uint32_t data, + size_t num_bits, + bool readback + ){ + boost::mutex::scoped_lock lock(_mutex); + + //load control word + boost::uint32_t ctrl_word = 0; + ctrl_word |= ((which_slave & 0xffffff) << 0); + ctrl_word |= ((num_bits & 0x3ff) << 24); + if (config.mosi_edge == spi_config_t::EDGE_RISE) ctrl_word |= (1 << 31); + if (config.miso_edge == spi_config_t::EDGE_FALL) ctrl_word |= (1 << 30); + + //load data word (must be in upper bits) + const boost::uint32_t data_out = data << (32 - num_bits); + + //conditionally send control word + if (_ctrl_word_cache != ctrl_word){ + this->send_pkt(SPI_CTRL, ctrl_word, POKE32_CMD | SPI_PERIF_MASK); + this->wait_for_ack(boost::int16_t(_seq-MAX_SEQS_OUT)); + _ctrl_word_cache = ctrl_word; + } + + //send data word + this->send_pkt(SPI_DATA, data_out, POKE32_CMD | SPI_PERIF_MASK); + this->wait_for_ack(boost::int16_t(_seq-MAX_SEQS_OUT)); + + //conditional readback + if (readback){ + this->send_pkt(SPI_READBACK, 0, PEEK32_CMD | SPI_PERIF_MASK); + return this->wait_for_ack(boost::int16_t(_seq)); + } + + return 0; + } + void set_time(const uhd::time_spec_t &time){ boost::mutex::scoped_lock lock(_mutex); _time = time; @@ -146,6 +204,7 @@ private: bool _use_time; double _tick_rate; double _timeout; + boost::uint32_t _ctrl_word_cache; }; diff --git a/host/lib/usrp/usrp2/usrp2_fifo_ctrl.hpp b/host/lib/usrp/usrp2/usrp2_fifo_ctrl.hpp index 0f52f523e..b48d05aa2 100644 --- a/host/lib/usrp/usrp2/usrp2_fifo_ctrl.hpp +++ b/host/lib/usrp/usrp2/usrp2_fifo_ctrl.hpp @@ -19,6 +19,7 @@ #define INCLUDED_USRP2_FIFO_CTRL_HPP #include <uhd/types/time_spec.hpp> +#include <uhd/types/serial.hpp> #include <uhd/transport/zero_copy.hpp> #include <boost/shared_ptr.hpp> #include <boost/utility.hpp> @@ -29,7 +30,7 @@ * The usrp2 FIFO control class: * Provide high-speed peek/poke interface. */ -class usrp2_fifo_ctrl : public wb_iface{ +class usrp2_fifo_ctrl : public wb_iface, public uhd::spi_iface{ public: typedef boost::shared_ptr<usrp2_fifo_ctrl> sptr; diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp index 68ee8044c..68a8c1c5f 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp/usrp2/usrp2_impl.cpp @@ -397,7 +397,7 @@ usrp2_impl::usrp2_impl(const device_addr_t &_device_addr){ //////////////////////////////////////////////////////////////// // create clock control objects //////////////////////////////////////////////////////////////// - _mbc[mb].clock = usrp2_clock_ctrl::make(_mbc[mb].iface); + _mbc[mb].clock = usrp2_clock_ctrl::make(_mbc[mb].iface, _mbc[mb].fifo_ctrl/*spi*/); _tree->create<double>(mb_path / "tick_rate") .publish(boost::bind(&usrp2_clock_ctrl::get_master_clock_rate, _mbc[mb].clock)) .subscribe(boost::bind(&usrp2_impl::update_tick_rate, this, _1)); @@ -409,7 +409,7 @@ usrp2_impl::usrp2_impl(const device_addr_t &_device_addr){ const fs_path tx_codec_path = mb_path / "tx_codecs/A"; _tree->create<int>(rx_codec_path / "gains"); //phony property so this dir exists _tree->create<int>(tx_codec_path / "gains"); //phony property so this dir exists - _mbc[mb].codec = usrp2_codec_ctrl::make(_mbc[mb].iface); + _mbc[mb].codec = usrp2_codec_ctrl::make(_mbc[mb].iface, _mbc[mb].fifo_ctrl/*spi*/); switch(_mbc[mb].iface->get_rev()){ case usrp2_iface::USRP_N200: case usrp2_iface::USRP_N210: @@ -614,7 +614,7 @@ usrp2_impl::usrp2_impl(const device_addr_t &_device_addr){ .subscribe(boost::bind(&usrp2_impl::set_db_eeprom, this, mb, "gdb", _1)); //create a new dboard interface and manager - _mbc[mb].dboard_iface = make_usrp2_dboard_iface(_mbc[mb].fifo_ctrl, _mbc[mb].iface, _mbc[mb].iface, _mbc[mb].clock); + _mbc[mb].dboard_iface = make_usrp2_dboard_iface(_mbc[mb].fifo_ctrl/*wb*/, _mbc[mb].iface/*i2c*/, _mbc[mb].fifo_ctrl/*spi*/, _mbc[mb].clock); _tree->create<dboard_iface::sptr>(mb_path / "dboards/A/iface").set(_mbc[mb].dboard_iface); _mbc[mb].dboard_manager = dboard_manager::make( rx_db_eeprom.id, tx_db_eeprom.id, gdb_eeprom.id, |