mirror of
https://github.com/DCC-EX/CommandStation-EX.git
synced 2024-12-23 12:51:24 +01:00
Add I2C retries to Wire and to non-blocking I2CManager.
This commit is contained in:
parent
3c5b7bbcfe
commit
6e69df2da8
@ -111,6 +111,11 @@
|
||||
*
|
||||
*/
|
||||
|
||||
// Maximum number of retries on an I2C operation
|
||||
// A value of zero will disable retries.
|
||||
// Maximum value is 254 (unsigned byte counter)
|
||||
#define MAX_I2C_RETRIES 2
|
||||
|
||||
// Add following line to config.h to enable Wire library instead of native I2C drivers
|
||||
//#define I2C_USE_WIRE
|
||||
|
||||
@ -265,6 +270,7 @@ private:
|
||||
static volatile unsigned long startTime;
|
||||
|
||||
static unsigned long timeout; // Transaction timeout in microseconds. 0=disabled.
|
||||
static uint8_t retryCounter; // Count of retries
|
||||
|
||||
void startTransaction();
|
||||
|
||||
|
@ -223,16 +223,15 @@ void I2CManagerClass::handleInterrupt() {
|
||||
// Update hardware state machine
|
||||
I2C_handleInterrupt();
|
||||
|
||||
// Enable interrupts to minimise effect on other interrupt code
|
||||
interrupts();
|
||||
|
||||
// Check if current request has completed. If there's a current request
|
||||
// and state isn't active then state contains the completion status of the request.
|
||||
if (state != I2C_STATE_ACTIVE && currentRequest != NULL) {
|
||||
// Remove completed request from head of queue
|
||||
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
|
||||
// Operation has completed.
|
||||
if (state == I2C_STATUS_OK || ++retryCounter > MAX_I2C_RETRIES) {
|
||||
// Status is OK, or has failed and retry count exceeded.
|
||||
// Remove completed request from head of queue
|
||||
I2CRB * t = queueHead;
|
||||
if (t == queueHead) {
|
||||
if (t == currentRequest) {
|
||||
queueHead = t->nextRequest;
|
||||
if (!queueHead) queueTail = queueHead;
|
||||
t->nBytes = rxCount;
|
||||
@ -241,12 +240,21 @@ void I2CManagerClass::handleInterrupt() {
|
||||
// I2C state machine is now free for next request
|
||||
currentRequest = NULL;
|
||||
state = I2C_STATE_FREE;
|
||||
|
||||
// Start next request (if any)
|
||||
I2CManager.startTransaction();
|
||||
}
|
||||
retryCounter = 0;
|
||||
} else {
|
||||
// Status is failed and retry permitted.
|
||||
// Retry previous request.
|
||||
state = I2C_STATE_FREE;
|
||||
}
|
||||
}
|
||||
|
||||
if (state == I2C_STATE_FREE && queueHead != NULL) {
|
||||
// Allow any pending interrupts before starting the next request.
|
||||
interrupts();
|
||||
// Start next request
|
||||
I2CManager.startTransaction();
|
||||
}
|
||||
}
|
||||
|
||||
// Fields in I2CManager class specific to Non-blocking implementation.
|
||||
@ -261,5 +269,6 @@ volatile uint8_t I2CManagerClass::bytesToSend;
|
||||
volatile uint8_t I2CManagerClass::bytesToReceive;
|
||||
volatile unsigned long I2CManagerClass::startTime;
|
||||
unsigned long I2CManagerClass::timeout = 0;
|
||||
uint8_t I2CManagerClass::retryCounter = 0;
|
||||
|
||||
#endif
|
@ -49,9 +49,14 @@ void I2CManagerClass::_setClock(unsigned long i2cClockSpeed) {
|
||||
* Initiate a write to an I2C device (blocking operation on Wire)
|
||||
***************************************************************************/
|
||||
uint8_t I2CManagerClass::write(uint8_t address, const uint8_t buffer[], uint8_t size, I2CRB *rb) {
|
||||
Wire.beginTransmission(address);
|
||||
if (size > 0) Wire.write(buffer, size);
|
||||
rb->status = Wire.endTransmission();
|
||||
uint8_t status = I2C_STATUS_OK;
|
||||
uint8_t retryCount = 0;
|
||||
do {
|
||||
Wire.beginTransmission(address);
|
||||
if (size > 0) Wire.write(buffer, size);
|
||||
status = Wire.endTransmission();
|
||||
} while (!(status == I2C_STATUS_OK || ++retryCount > MAX_I2C_RETRIES));
|
||||
rb->status = status;
|
||||
return I2C_STATUS_OK;
|
||||
}
|
||||
|
||||
@ -75,17 +80,21 @@ uint8_t I2CManagerClass::read(uint8_t address, uint8_t readBuffer[], uint8_t rea
|
||||
{
|
||||
uint8_t status = I2C_STATUS_OK;
|
||||
uint8_t nBytes = 0;
|
||||
if (writeSize > 0) {
|
||||
Wire.beginTransmission(address);
|
||||
Wire.write(writeBuffer, writeSize);
|
||||
status = Wire.endTransmission(false); // Don't free bus yet
|
||||
}
|
||||
if (status == I2C_STATUS_OK) {
|
||||
Wire.requestFrom(address, (size_t)readSize);
|
||||
while (Wire.available() && nBytes < readSize)
|
||||
readBuffer[nBytes++] = Wire.read();
|
||||
if (nBytes < readSize) status = I2C_STATUS_TRUNCATED;
|
||||
}
|
||||
uint8_t retryCount = 0;
|
||||
do {
|
||||
if (writeSize > 0) {
|
||||
Wire.beginTransmission(address);
|
||||
Wire.write(writeBuffer, writeSize);
|
||||
status = Wire.endTransmission(false); // Don't free bus yet
|
||||
}
|
||||
if (status == I2C_STATUS_OK) {
|
||||
Wire.requestFrom(address, (size_t)readSize);
|
||||
while (Wire.available() && nBytes < readSize)
|
||||
readBuffer[nBytes++] = Wire.read();
|
||||
if (nBytes < readSize) status = I2C_STATUS_TRUNCATED;
|
||||
}
|
||||
} while (!(status == I2C_STATUS_OK || ++retryCount > MAX_I2C_RETRIES));
|
||||
|
||||
rb->nBytes = nBytes;
|
||||
rb->status = status;
|
||||
return I2C_STATUS_OK;
|
||||
|
Loading…
Reference in New Issue
Block a user