// // Copyright 2011,2014 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 . // #include "spi_core_100.hpp" #include #include #include //sleep #define REG_SPI_TXRX0 _base + 0 #define REG_SPI_TXRX1 _base + 4 #define REG_SPI_TXRX2 _base + 8 #define REG_SPI_TXRX3 _base + 12 #define REG_SPI_CTRL _base + 16 #define REG_SPI_DIV _base + 20 #define REG_SPI_SS _base + 24 //spi ctrl register bit definitions #define SPI_CTRL_ASS (1<<13) #define SPI_CTRL_IE (1<<12) #define SPI_CTRL_LSB (1<<11) #define SPI_CTRL_TXNEG (1<<10) //mosi edge, push on falling edge when 1 #define SPI_CTRL_RXNEG (1<< 9) //miso edge, latch on falling edge when 1 #define SPI_CTRL_GO_BSY (1<< 8) #define SPI_CTRL_CHAR_LEN_MASK 0x7F using namespace uhd; spi_core_100::~spi_core_100(void){ /* NOP */ } class spi_core_100_impl : public spi_core_100{ public: spi_core_100_impl(wb_iface::sptr iface, const size_t base): _iface(iface), _base(base) { /* NOP */} uint32_t transact_spi( int which_slave, const spi_config_t &config, uint32_t data, size_t num_bits, bool readback ){ UHD_ASSERT_THROW(num_bits <= 32 and (num_bits % 8) == 0); 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) ; uint16_t ctrl = SPI_CTRL_ASS | (SPI_CTRL_CHAR_LEN_MASK & num_bits) | edge_flags; spi_wait(); _iface->poke16(REG_SPI_DIV, 0x0001); // = fpga_clk / 4 _iface->poke32(REG_SPI_SS, which_slave & 0xFFFF); _iface->poke32(REG_SPI_TXRX0, data); _iface->poke16(REG_SPI_CTRL, ctrl); _iface->poke16(REG_SPI_CTRL, ctrl | SPI_CTRL_GO_BSY); if (not readback) return 0; spi_wait(); return _iface->peek32(REG_SPI_TXRX0); } private: void spi_wait(void) { for (size_t i = 0; i < 100; i++){ if ((_iface->peek16(REG_SPI_CTRL) & SPI_CTRL_GO_BSY) == 0) return; boost::this_thread::sleep(boost::posix_time::milliseconds(1)); } UHD_LOGGER_ERROR("CORES") << "spi_core_100: spi_wait timeout" ; } wb_iface::sptr _iface; const size_t _base; }; spi_core_100::sptr spi_core_100::make(wb_iface::sptr iface, const size_t base){ return sptr(new spi_core_100_impl(iface, base)); }