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:
parent
08b666a548
commit
acaa4dd9de
3 changed files with 110 additions and 68 deletions
|
@ -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 {
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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(®, 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;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue