diff options
| author | Josh Blum <josh@joshknows.com> | 2012-03-06 16:32:58 -0800 | 
|---|---|---|
| committer | Josh Blum <josh@joshknows.com> | 2012-03-23 14:36:56 -0700 | 
| commit | 12223186e7ba8a433ef13945a0e4f4077a3a5542 (patch) | |
| tree | 2ddcdc4be2f21e9eb1faec62a366b187520845a5 | |
| parent | 08e2432cdeeabd7010252b4a747a385e1b189614 (diff) | |
| download | uhd-12223186e7ba8a433ef13945a0e4f4077a3a5542.tar.gz uhd-12223186e7ba8a433ef13945a0e4f4077a3a5542.tar.bz2 uhd-12223186e7ba8a433ef13945a0e4f4077a3a5542.zip | |
fifo ctrl: spi core work and host implementation
| -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, | 
