diff options
-rw-r--r-- | mpm/include/mpm/spi/spi_iface.hpp | 8 | ||||
-rw-r--r-- | mpm/include/mpm/spi/spi_python.hpp | 3 | ||||
-rw-r--r-- | mpm/include/mpm/spi/spi_regs_iface.hpp | 8 | ||||
-rw-r--r-- | mpm/include/mpm/types/regs_iface.hpp | 8 | ||||
-rw-r--r-- | mpm/include/mpm/types/types_python.hpp | 4 | ||||
-rw-r--r-- | mpm/lib/i2c/i2c_regs_iface.cpp | 12 | ||||
-rw-r--r-- | mpm/lib/spi/spi_regs_iface.cpp | 59 | ||||
-rw-r--r-- | mpm/lib/spi/spidev_iface.cpp | 32 |
8 files changed, 120 insertions, 14 deletions
diff --git a/mpm/include/mpm/spi/spi_iface.hpp b/mpm/include/mpm/spi/spi_iface.hpp index e295d1bb7..39390f7e2 100644 --- a/mpm/include/mpm/spi/spi_iface.hpp +++ b/mpm/include/mpm/spi/spi_iface.hpp @@ -36,6 +36,14 @@ public: */ virtual uint32_t transfer24_16(const uint32_t data) = 0; + /*! Convenience function: SPI xfer is 64 bits write, 40 bits read. + * + * \param data The write data for this xfer + * + * \return 40 bits worth of the return xfer + */ + virtual uint64_t transfer64_40(const uint64_t data) = 0; + /*! * \param device The path to the spidev used (e.g. "/dev/spidev0.0") * \param speed_hz Transaction speed in Hz diff --git a/mpm/include/mpm/spi/spi_python.hpp b/mpm/include/mpm/spi/spi_python.hpp index 464df8d8b..0cadcad53 100644 --- a/mpm/include/mpm/spi/spi_python.hpp +++ b/mpm/include/mpm/spi/spi_python.hpp @@ -18,5 +18,6 @@ void export_spi(py::module& top_module) m.def("make_spidev", &mpm::spi::spi_iface::make_spidev); py::class_<mpm::spi::spi_iface, std::shared_ptr<mpm::spi::spi_iface>>(m, "spi_iface") - .def("transfer24_8", &mpm::spi::spi_iface::transfer24_8); + .def("transfer24_8", &mpm::spi::spi_iface::transfer24_8) + .def("transfer64_40", &mpm::spi::spi_iface::transfer64_40); } diff --git a/mpm/include/mpm/spi/spi_regs_iface.hpp b/mpm/include/mpm/spi/spi_regs_iface.hpp index 6351cf9b5..c731946fe 100644 --- a/mpm/include/mpm/spi/spi_regs_iface.hpp +++ b/mpm/include/mpm/spi/spi_regs_iface.hpp @@ -14,8 +14,8 @@ namespace mpm { namespace spi { mpm::types::regs_iface::sptr make_spi_regs_iface(mpm::spi::spi_iface::sptr spi_iface, uint32_t addr_shift, uint32_t data_shift, - uint32_t read_flags, - uint32_t write_flags = 0); + uint64_t read_flags, + uint64_t write_flags = 0); /*! Convenience factory for regs_iface based on SPI based on spidev */ @@ -24,7 +24,7 @@ mpm::types::regs_iface::sptr make_spidev_regs_iface(const std::string& device, const int spi_mode, uint32_t addr_shift, uint32_t data_shift, - uint32_t read_flags, - uint32_t write_flags = 0); + uint64_t read_flags, + uint64_t write_flags = 0); }}; /* namespace mpm::spi */ diff --git a/mpm/include/mpm/types/regs_iface.hpp b/mpm/include/mpm/types/regs_iface.hpp index b47c31821..97fdd232c 100644 --- a/mpm/include/mpm/types/regs_iface.hpp +++ b/mpm/include/mpm/types/regs_iface.hpp @@ -33,6 +33,14 @@ public: /*! Write a 16-bit value to a given address */ virtual void poke16(const uint32_t addr, const uint16_t data) = 0; + + /*! Return a 32-bit value from a given address + */ + virtual uint32_t peek32(const uint64_t addr) = 0; + + /*! Write a 32-bit value to a given address + */ + virtual void poke32(const uint64_t addr, const uint32_t data) = 0; }; }}; // namespace mpm::types diff --git a/mpm/include/mpm/types/types_python.hpp b/mpm/include/mpm/types/types_python.hpp index cb2af5c4b..1c4c1c3b5 100644 --- a/mpm/include/mpm/types/types_python.hpp +++ b/mpm/include/mpm/types/types_python.hpp @@ -25,7 +25,9 @@ void export_types(py::module& top_module) .def("peek8", ®s_iface::peek8) .def("poke8", ®s_iface::poke8) .def("peek16", ®s_iface::peek16) - .def("poke16", ®s_iface::poke16); + .def("poke16", ®s_iface::poke16) + .def("peek32", ®s_iface::peek32) + .def("poke32", ®s_iface::poke32); py::class_<log_buf, std::shared_ptr<log_buf>>(m, "log_buf") .def_static("make_singleton", &log_buf::make_singleton) diff --git a/mpm/lib/i2c/i2c_regs_iface.cpp b/mpm/lib/i2c/i2c_regs_iface.cpp index 575e19d26..0fd5e716c 100644 --- a/mpm/lib/i2c/i2c_regs_iface.cpp +++ b/mpm/lib/i2c/i2c_regs_iface.cpp @@ -93,6 +93,18 @@ public: } } + uint32_t peek32(const uint64_t addr) + { + throw mpm::not_implemented_error( + "I2C regs iface does not implement 32 bit transactions."); + } + + void poke32(const uint64_t addr, const uint32_t data) + { + throw mpm::not_implemented_error( + "I2C regs iface does not implement 32 bit transactions."); + } + private: mpm::i2c::i2c_iface::sptr _i2c_iface; diff --git a/mpm/lib/spi/spi_regs_iface.cpp b/mpm/lib/spi/spi_regs_iface.cpp index 842f45d42..d4776d859 100644 --- a/mpm/lib/spi/spi_regs_iface.cpp +++ b/mpm/lib/spi/spi_regs_iface.cpp @@ -21,8 +21,8 @@ public: spi_regs_iface_impl(mpm::spi::spi_iface::sptr spi_iface, uint32_t addr_shift, uint32_t data_shift, - uint32_t read_flags, - uint32_t write_flags = 0) + uint64_t read_flags, + uint64_t write_flags = 0) : _spi_iface(spi_iface) , _addr_shift(addr_shift) , _data_shift(data_shift) @@ -72,20 +72,63 @@ public: _spi_iface->transfer24_16(transaction); } + uint32_t peek32(const uint64_t addr) + { + /* Note: _addr_shift and _read_flags will be offset from the + * TX portion of the message (first 2 bytes) rather than the + * end of the message as is done with smaller transfers. + */ + uint64_t transaction = 0 | (addr << _addr_shift) | _read_flags; + + uint64_t data = _spi_iface->transfer64_40(transaction); + + // Actual RX data is the last 5 bytes + if ((data & 0xFFFFFF00000000F8) != 0) { + throw mpm::runtime_error("SPI read returned too much data"); + } + + // Status data is the last byte + bool ack = (data >> 2) & 0x1; + uint8_t status = data & 0x3; + if (!ack) { + throw mpm::runtime_error("Ctrlport SPI read had no ACK"); + } + if (status != 0) { + // TODO: Differentiate error codes + throw mpm::runtime_error("Ctrlport SPI error"); + } + + // Register data is the 4 bytes above the last one + data = (data >> 8) & 0xFFFFFFFF; + return data; + } + + void poke32(const uint64_t addr, const uint32_t data) + { + /* Note: _addr_shift and _write_flags will be offset from the + * TX portion of the message (first 6 bytes) rather than the + * end of the message as is done with smaller transfers. + */ + uint64_t transaction = 0 | _write_flags | (addr << _addr_shift) + | (data << _data_shift); + + _spi_iface->transfer64_40(transaction); + } + private: mpm::spi::spi_iface::sptr _spi_iface; uint32_t _addr_shift; uint32_t _data_shift; - uint32_t _read_flags; - uint32_t _write_flags; + uint64_t _read_flags; + uint64_t _write_flags; }; regs_iface::sptr mpm::spi::make_spi_regs_iface(mpm::spi::spi_iface::sptr spi_iface, uint32_t addr_shift, uint32_t data_shift, - uint32_t read_flags, - uint32_t write_flags) + uint64_t read_flags, + uint64_t write_flags) { return std::make_shared<spi_regs_iface_impl>( spi_iface, addr_shift, data_shift, read_flags, write_flags); @@ -96,8 +139,8 @@ mpm::types::regs_iface::sptr mpm::spi::make_spidev_regs_iface(const std::string& const int spi_mode, uint32_t addr_shift, uint32_t data_shift, - uint32_t read_flags, - uint32_t write_flags) + uint64_t read_flags, + uint64_t write_flags) { auto spi_iface_sptr = mpm::spi::spi_iface::make_spidev(device, speed_hz, spi_mode); return std::make_shared<spi_regs_iface_impl>( diff --git a/mpm/lib/spi/spidev_iface.cpp b/mpm/lib/spi/spidev_iface.cpp index c8a2133e8..c706725b8 100644 --- a/mpm/lib/spi/spidev_iface.cpp +++ b/mpm/lib/spi/spidev_iface.cpp @@ -79,6 +79,38 @@ public: return uint32_t(rx[1] << 8 | rx[2]); } + uint64_t transfer64_40(const uint64_t data_) + { + uint64_t data = data_; + uint8_t* tx_data = reinterpret_cast<uint8_t*>(&data); + + // Create tx and rx buffers: + /* Address and TX data only represents up to 6 out of 8 bytes to + transfer. The remaining bytes are buffer for processing gap + and response status. */ + uint8_t tx[] = {tx_data[5], + tx_data[4], + tx_data[3], + tx_data[2], + tx_data[1], + tx_data[0], + 0, + 0}; + uint8_t rx[8]; // Buffer length must match tx buffer + + if (transfer(_fd, &tx[0], &rx[0], 8, _speed, _bits, _delay) != 0) { + throw mpm::runtime_error(str(boost::format("SPI Transaction failed!"))); + } + + uint64_t result = rx[3]; + result = (result << 8) | rx[4]; + result = (result << 8) | rx[5]; + result = (result << 8) | rx[6]; + result = (result << 8) | rx[7]; + + return result; + } + private: int _fd; const uint32_t _mode; |