aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--mpm/include/mpm/spi/spi_iface.hpp8
-rw-r--r--mpm/include/mpm/spi/spi_python.hpp3
-rw-r--r--mpm/include/mpm/spi/spi_regs_iface.hpp8
-rw-r--r--mpm/include/mpm/types/regs_iface.hpp8
-rw-r--r--mpm/include/mpm/types/types_python.hpp4
-rw-r--r--mpm/lib/i2c/i2c_regs_iface.cpp12
-rw-r--r--mpm/lib/spi/spi_regs_iface.cpp59
-rw-r--r--mpm/lib/spi/spidev_iface.cpp32
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", &regs_iface::peek8)
.def("poke8", &regs_iface::poke8)
.def("peek16", &regs_iface::peek16)
- .def("poke16", &regs_iface::poke16);
+ .def("poke16", &regs_iface::poke16)
+ .def("peek32", &regs_iface::peek32)
+ .def("poke32", &regs_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;