From 538519dd9df13caa66dab93f85d992282f808a7e Mon Sep 17 00:00:00 2001 From: Neil McKechnie Date: Sat, 14 Jan 2023 18:58:06 +0000 Subject: [PATCH] Add option to suppress I2C retries. I2CRB method suppressRetries() added to allow retries to be suppressed. --- I2CManager.cpp | 13 ++++++++++++- I2CManager.h | 3 +++ I2CManager_NonBlocking.h | 8 +++++--- I2CManager_Wire.h | 12 +++++++++--- 4 files changed, 29 insertions(+), 7 deletions(-) diff --git a/I2CManager.cpp b/I2CManager.cpp index a951a87..d7be935 100644 --- a/I2CManager.cpp +++ b/I2CManager.cpp @@ -81,8 +81,13 @@ void I2CManagerClass::forceClock(uint32_t speed) { // Check if specified I2C address is responding (blocking operation) // Returns I2C_STATUS_OK (0) if OK, or error code. +// Suppress retries. If it doesn't respond first time it's out of the running. uint8_t I2CManagerClass::checkAddress(uint8_t address) { - return write(address, NULL, 0); + I2CRB rb; + rb.setWriteParams(address, NULL, 0); + rb.suppressRetries(true); + queueRequest(&rb); + return rb.wait(); } @@ -244,3 +249,9 @@ void I2CRB::setWriteParams(uint8_t i2cAddress, const uint8_t *writeBuffer, uint8 this->status = I2C_STATUS_OK; } +void I2CRB::suppressRetries(bool suppress) { + if (suppress) + this->operation |= OPERATION_NORETRY; + else + this->operation &= ~OPERATION_NORETRY; +} diff --git a/I2CManager.h b/I2CManager.h index f966d77..bcb7092 100644 --- a/I2CManager.h +++ b/I2CManager.h @@ -157,6 +157,8 @@ typedef enum : uint8_t OPERATION_REQUEST = 2, OPERATION_SEND = 3, OPERATION_SEND_P = 4, + OPERATION_NORETRY = 0x80, // OR with operation to suppress retries. + OPERATION_MASK = 0x7f, // mask for extracting the operation code } OperationEnum; @@ -178,6 +180,7 @@ public: void setReadParams(uint8_t i2cAddress, uint8_t *readBuffer, uint8_t readLen); void setRequestParams(uint8_t i2cAddress, uint8_t *readBuffer, uint8_t readLen, const uint8_t *writeBuffer, uint8_t writeLen); void setWriteParams(uint8_t i2cAddress, const uint8_t *writeBuffer, uint8_t writeLen); + void suppressRetries(bool suppress); uint8_t writeLen; uint8_t readLen; diff --git a/I2CManager_NonBlocking.h b/I2CManager_NonBlocking.h index 2793823..7769d17 100644 --- a/I2CManager_NonBlocking.h +++ b/I2CManager_NonBlocking.h @@ -105,7 +105,7 @@ void I2CManagerClass::startTransaction() { currentRequest = queueHead; rxCount = txCount = 0; // Copy key fields to static data for speed. - operation = currentRequest->operation; + operation = currentRequest->operation & OPERATION_MASK; // Start the I2C process going. I2C_sendStart(); startTime = micros(); @@ -227,8 +227,10 @@ void I2CManagerClass::handleInterrupt() { // and state isn't active then state contains the completion status of the request. if (state != I2C_STATE_ACTIVE && currentRequest != NULL) { // Operation has completed. - if (state == I2C_STATUS_OK || ++retryCounter > MAX_I2C_RETRIES) { - // Status is OK, or has failed and retry count exceeded. + if (state == I2C_STATUS_OK || ++retryCounter > MAX_I2C_RETRIES + || currentRequest->operation & OPERATION_NORETRY) + { + // Status is OK, or has failed and retry count exceeded, or retries disabled. // Remove completed request from head of queue I2CRB * t = queueHead; if (t == currentRequest) { diff --git a/I2CManager_Wire.h b/I2CManager_Wire.h index aa0189f..aea91aa 100644 --- a/I2CManager_Wire.h +++ b/I2CManager_Wire.h @@ -51,11 +51,14 @@ void I2CManagerClass::_setClock(unsigned long i2cClockSpeed) { uint8_t I2CManagerClass::write(uint8_t address, const uint8_t buffer[], uint8_t size, I2CRB *rb) { uint8_t status = I2C_STATUS_OK; uint8_t retryCount = 0; + // If request fails, retry up to the defined limit, unless the NORETRY flag is set + // in the request block. do { Wire.beginTransmission(address); if (size > 0) Wire.write(buffer, size); status = Wire.endTransmission(); - } while (!(status == I2C_STATUS_OK || ++retryCount > MAX_I2C_RETRIES)); + } while (!(status == I2C_STATUS_OK || ++retryCount > MAX_I2C_RETRIES + || rb->operation & OPERATION_NORETRY)); rb->status = status; return I2C_STATUS_OK; } @@ -81,6 +84,8 @@ uint8_t I2CManagerClass::read(uint8_t address, uint8_t readBuffer[], uint8_t rea uint8_t status = I2C_STATUS_OK; uint8_t nBytes = 0; uint8_t retryCount = 0; + // If request fails, retry up to the defined limit, unless the NORETRY flag is set + // in the request block. do { if (writeSize > 0) { Wire.beginTransmission(address); @@ -93,7 +98,8 @@ uint8_t I2CManagerClass::read(uint8_t address, uint8_t readBuffer[], uint8_t rea readBuffer[nBytes++] = Wire.read(); if (nBytes < readSize) status = I2C_STATUS_TRUNCATED; } - } while (!(status == I2C_STATUS_OK || ++retryCount > MAX_I2C_RETRIES)); + } while (!(status == I2C_STATUS_OK || ++retryCount > MAX_I2C_RETRIES + || rb->operation & OPERATION_NORETRY)); rb->nBytes = nBytes; rb->status = status; @@ -109,7 +115,7 @@ uint8_t I2CManagerClass::read(uint8_t address, uint8_t readBuffer[], uint8_t rea * the non-blocking version. ***************************************************************************/ void I2CManagerClass::queueRequest(I2CRB *req) { - switch (req->operation) { + switch (req->operation & OPERATION_MASK) { case OPERATION_READ: read(req->i2cAddress, req->readBuffer, req->readLen, NULL, 0, req); break;