1
0
Fork 0
mirror of https://git.rwth-aachen.de/acs/public/villas/node/ synced 2025-03-09 00:00:00 +01:00

improve i2c IP

more code reuse, add function for reading from a register i.e. combined
write and read

Signed-off-by: Niklas Eiling <niklas.eiling@eonerc.rwth-aachen.de>
This commit is contained in:
Niklas Eiling 2024-01-08 12:22:11 +01:00 committed by Niklas Eiling
parent 08b666a548
commit acaa4dd9de
3 changed files with 110 additions and 68 deletions

View file

@ -35,6 +35,7 @@ public:
virtual bool reset() override;
bool write(u8 address, std::vector<u8> &data);
bool read(u8 address, std::vector<u8> &data, size_t max_read);
bool readRegister(u8 address, u8 reg, std::vector<u8> &data, size_t max_read);
int transmitIntrs;
int receiveIntrs;
@ -84,6 +85,8 @@ private:
return {registerMemory};
}
void waitForBusNotBusy();
void driverWriteBlocking(u8 *dataPtr, size_t size);
void driverReadBlocking(u8 *dataPtr, size_t max_read);
};
class I2cFactory : NodeFactory {

View file

@ -37,9 +37,8 @@ Dino::IoextPorts Dino::getIoextDir() {
if (i2cdev == nullptr) {
throw RuntimeError("I2C device not set");
}
std::vector<u8> data = {I2C_IOEXT_REG_DIR};
i2cdev->write(I2C_IOEXT_ADDR, data);
i2cdev->read(I2C_IOEXT_ADDR, data, 1);
std::vector<u8> data = {0};
i2cdev->readRegister(I2C_IOEXT_ADDR, I2C_IOEXT_REG_DIR, data, 1);
IoextPorts ports;
ports.raw = data[0];
return ports;
@ -49,9 +48,8 @@ Dino::IoextPorts Dino::getIoextOut() {
if (i2cdev == nullptr) {
throw RuntimeError("I2C device not set");
}
std::vector<u8> data = {I2C_IOEXT_REG_OUT};
i2cdev->write(I2C_IOEXT_ADDR, data);
i2cdev->read(I2C_IOEXT_ADDR, data, 1);
std::vector<u8> data = {0};
i2cdev->readRegister(I2C_IOEXT_ADDR, I2C_IOEXT_REG_OUT, data, 1);
IoextPorts ports;
ports.raw = data[0];
return ports;

View file

@ -65,52 +65,57 @@ bool I2c::reset() {
return true;
}
bool I2c::write(u8 address, std::vector<u8> &data) {
void I2c::driverWriteBlocking(u8 *dataPtr, size_t size) {
int ret;
if (!initDone) {
throw RuntimeError("I2C not initialized");
}
ret =
XIic_SetAddress(&xIic, XII_ADDR_TO_SEND_TYPE, static_cast<int>(address));
if (ret != XST_SUCCESS) {
throw RuntimeError("Failed to set I2C address");
}
int intrRetries = 1;
transmitIntrs = 0;
xIic.Stats.TxErrors = 0;
int retries = 10;
while (transmitIntrs == 0 && xIic.Stats.TxErrors == 0 && retries > 0) {
ret = XIic_Start(&xIic);
if (ret != XST_SUCCESS) {
throw RuntimeError("Failed to start I2C");
do {
ret = XIic_MasterSend(&xIic, dataPtr, size);
if (ret == XST_IIC_BUS_BUSY) {
waitForBusNotBusy();
} else if (ret != XST_SUCCESS) {
throw RuntimeError("Failed to send I2C data. code: {}", ret);
}
} while (ret == XST_IIC_BUS_BUSY && --intrRetries >= 0);
intrRetries = 10;
while (transmitIntrs == 0 && intrRetries > 0) {
irqs[i2cInterrupt].irqController->waitForInterrupt(irqs[i2cInterrupt].num);
XIic_InterruptHandler(&xIic);
--intrRetries;
}
if (intrRetries == 0) {
throw RuntimeError(
"Failed to send I2C data: No transmit interrupt after 10 tries.");
}
if (xIic.Stats.TxErrors > 0) {
throw RuntimeError("Failed to send I2C data: {} TX errors",
xIic.Stats.TxErrors);
}
}
ret = XIic_MasterSend(&xIic, data.data(), data.size());
if (ret != XST_SUCCESS) {
throw RuntimeError("Failed to send I2C data");
void I2c::driverReadBlocking(u8 *dataPtr, size_t max_read) {
int ret;
int intrRetries = 1;
receiveIntrs = 0;
do {
ret = XIic_MasterRecv(&xIic, dataPtr, max_read);
if (ret == XST_IIC_BUS_BUSY) {
waitForBusNotBusy();
} else if (ret != XST_SUCCESS) {
throw RuntimeError("Failed to receive I2C data: code {}", ret);
}
int intrRetries = 10;
while (transmitIntrs == 0 && intrRetries > 0) {
irqs[i2cInterrupt].irqController->waitForInterrupt(
irqs[i2cInterrupt].num);
XIic_InterruptHandler(&xIic);
--intrRetries;
}
--retries;
} while (ret == XST_IIC_BUS_BUSY && --intrRetries >= 0);
intrRetries = 10;
while (receiveIntrs == 0 && intrRetries > 0) {
irqs[i2cInterrupt].irqController->waitForInterrupt(irqs[i2cInterrupt].num);
XIic_InterruptHandler(&xIic);
--intrRetries;
}
ret = XIic_Stop(&xIic);
if (ret != XST_SUCCESS) {
throw RuntimeError("Failed to stop I2C");
if (intrRetries == 0) {
throw RuntimeError(
"Failed to receive I2C data: No receive interrupt after 10 tries.");
}
if (retries == 0 || xIic.Stats.TxErrors != 0) {
throw RuntimeError("Failed to send I2C data: {} retries, {} errors",
retries, xIic.Stats.TxErrors);
}
return true;
}
void I2c::waitForBusNotBusy() {
@ -129,6 +134,33 @@ void I2c::waitForBusNotBusy() {
}
}
bool I2c::write(u8 address, std::vector<u8> &data) {
int ret;
if (!initDone) {
throw RuntimeError("I2C not initialized");
}
ret =
XIic_SetAddress(&xIic, XII_ADDR_TO_SEND_TYPE, static_cast<int>(address));
if (ret != XST_SUCCESS) {
throw RuntimeError("Failed to set I2C address");
}
ret = XIic_Start(&xIic);
if (ret != XST_SUCCESS) {
throw RuntimeError("Failed to start I2C");
}
driverWriteBlocking(data.data(), data.size());
ret = XIic_Stop(&xIic);
if (ret != XST_SUCCESS) {
throw RuntimeError("Failed to stop I2C");
}
return true;
}
bool I2c::read(u8 address, std::vector<u8> &data, size_t max_read) {
int ret;
@ -145,41 +177,50 @@ bool I2c::read(u8 address, std::vector<u8> &data, size_t max_read) {
throw RuntimeError("Failed to set I2C address");
}
receiveIntrs = 0;
ret = XIic_Start(&xIic);
if (ret != XST_SUCCESS) {
throw RuntimeError("Failed to start I2C");
}
driverReadBlocking(dataPtr, max_read);
ret = XIic_Stop(&xIic);
if (ret != XST_SUCCESS) {
throw RuntimeError("Failed to stop I2C");
}
return XST_SUCCESS;
}
bool I2c::readRegister(u8 address, u8 reg, std::vector<u8> &data,
size_t max_read) {
int ret;
if (!initDone) {
throw RuntimeError("I2C not initialized");
}
data.resize(data.size() + max_read);
u8 *dataPtr = data.data() + data.size() - max_read;
ret =
XIic_SetAddress(&xIic, XII_ADDR_TO_SEND_TYPE, static_cast<int>(address));
if (ret != XST_SUCCESS) {
throw RuntimeError("Failed to set I2C address");
}
ret = XIic_Start(&xIic);
if (ret != XST_SUCCESS) {
throw RuntimeError("Failed to start I2C");
}
int retries = 10;
while (receiveIntrs == 0 && retries > 0) {
int intrRetries = 1;
do {
ret = XIic_MasterRecv(&xIic, dataPtr, max_read);
if (ret == XST_IIC_BUS_BUSY) {
waitForBusNotBusy();
} else if (ret != XST_SUCCESS) {
throw RuntimeError("Failed to receive I2C data: code {}", ret);
}
} while (ret == XST_IIC_BUS_BUSY && --intrRetries >= 0);
intrRetries = 10;
while (receiveIntrs == 0 && intrRetries > 0) {
irqs[i2cInterrupt].irqController->waitForInterrupt(
irqs[i2cInterrupt].num);
XIic_InterruptHandler(&xIic);
--intrRetries;
}
--retries;
}
driverWriteBlocking(&reg, sizeof(reg));
driverReadBlocking(dataPtr, max_read);
ret = XIic_Stop(&xIic);
if (ret != XST_SUCCESS) {
throw RuntimeError("Failed to stop I2C");
}
if (retries == 0) {
throw RuntimeError("Failed to send I2C data");
}
return XST_SUCCESS;
}