diff --git a/fpga/include/villas/fpga/ips/i2c.hpp b/fpga/include/villas/fpga/ips/i2c.hpp index 1579d41e0..d342b4cc8 100644 --- a/fpga/include/villas/fpga/ips/i2c.hpp +++ b/fpga/include/villas/fpga/ips/i2c.hpp @@ -43,9 +43,10 @@ public: class Switch { public: - Switch(I2c *i2c, uint8_t address) - : i2c(i2c), address(address), channel(0), readOnce(false), - switchLock(){}; + Switch(I2c *i2c, uint8_t address, + Logger logger = villas::logging.get("i2c")) + : i2c(i2c), address(address), channel(0), readOnce(false), switchLock(), + logger(logger){}; Switch(const Switch &other) = delete; Switch &operator=(const Switch &other) = delete; void setChannel(uint8_t channel); @@ -57,6 +58,7 @@ public: uint8_t getChannel(); void setAddress(uint8_t address) { this->address = address; } uint8_t getAddress() { return address; } + bool selfTest(); private: I2c *i2c; @@ -64,10 +66,11 @@ public: uint8_t channel; bool readOnce; std::mutex switchLock; + Logger logger; }; Switch &getSwitch(uint8_t address = I2C_SWTICH_ADDR) { if (switchInstance == nullptr) { - switchInstance = std::make_unique(this, address); + switchInstance = std::make_unique(this, address, logger); } else { switchInstance->setAddress(address); } diff --git a/fpga/lib/ips/dino.cpp b/fpga/lib/ips/dino.cpp index 252dfd5b0..6de5340ce 100644 --- a/fpga/lib/ips/dino.cpp +++ b/fpga/lib/ips/dino.cpp @@ -87,6 +87,12 @@ void DinoAdc::configureHardware() { IoextPorts ioext = {.raw = 0}; ioext.fields.sat_detect = true; setIoextDir(ioext); + auto readback = getIoextDir(); + if (readback.raw != ioext.raw) { + logger->error("Ioext direction register readback incorrect: {:#x} != {:#x}", + readback.raw, ioext.raw); + throw RuntimeError("Failed to set IOEXT direction register"); + } ioext.raw = 0; ioext.fields.data_dir = true; ioext.fields.status_led = true; @@ -95,6 +101,12 @@ void DinoAdc::configureHardware() { setIoextOut(ioext); ioext.fields.n_we = false; setIoextOut(ioext); + readback = getIoextOut(); + if (readback.raw != ioext.raw) { + logger->error("Ioext output register readback incorrect: {:#x} != {:#x}", + readback.raw, ioext.raw); + throw RuntimeError("Failed to set IOEXT output register"); + } i2cdev->getSwitch().unlockChannel(); } @@ -109,10 +121,24 @@ void DinoDac::configureHardware() { i2cdev->getSwitch().setAndLockChannel(i2c_channel); IoextPorts ioext = {.raw = 0}; setIoextDir(ioext); + auto readback = getIoextDir(); + if (readback.raw != ioext.raw) { + logger->error("Ioext direction register readback incorrect: {:#x} != {:#x}", + readback.raw, ioext.raw); + throw RuntimeError("Failed to set IOEXT direction register"); + } ioext.fields.status_led = true; + // Default gain is 1. Although not really necessary, let's be explicit here + ioext.fields.gain_lsb = 0x00 & 0x1; + ioext.fields.gain_msb = 0x00 & 0x2; setIoextOut(ioext); + readback = getIoextOut(); + if (readback.raw != ioext.raw) { + logger->error("Ioext output register readback incorrect: {:#x} != {:#x}", + readback.raw, ioext.raw); + throw RuntimeError("Failed to set IOEXT output register"); + } i2cdev->getSwitch().unlockChannel(); - setGain(GAIN_1); } void DinoDac::setGain(Gain gain) { diff --git a/fpga/lib/ips/i2c.cpp b/fpga/lib/ips/i2c.cpp index 2f8aa362b..186c96f89 100644 --- a/fpga/lib/ips/i2c.cpp +++ b/fpga/lib/ips/i2c.cpp @@ -12,6 +12,7 @@ #include #include +#include using namespace villas::fpga::ip; @@ -220,7 +221,7 @@ void I2c::Switch::setChannel(uint8_t channel) { } uint8_t I2c::Switch::getChannel() { - std::vector data(1); + std::vector data; int retries = 10; do { i2c->read(address, data, 1); @@ -242,6 +243,26 @@ uint8_t I2c::Switch::getChannel() { return channel; } +bool I2c::Switch::selfTest() { + uint8_t readback; + logger->debug("I2c::Switch self test. Testing {} channels of device {:#x}", + sizeof(CHANNEL_MAP) / sizeof(CHANNEL_MAP[0]), address); + for (size_t i = 0; i < sizeof(CHANNEL_MAP) / sizeof(CHANNEL_MAP[0]); ++i) { + logger->debug("Setting switch to channel {}, data byte {:#x}", i, + CHANNEL_MAP[i]); + setAndLockChannel(i); + try { + readback = getChannel(); + logger->debug("Readback channel: {}", readback); + } catch (const RuntimeError &e) { + logger->debug("Encoutered error on readback: {}", e.what()); + return false; + } + unlockChannel(); + } + return true; +} + void I2cFactory::parse(Core &ip, json_t *cfg) { NodeFactory::parse(ip, cfg);