mirror of
https://github.com/DCC-EX/CommandStation-EX.git
synced 2024-12-24 13:21:23 +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
|
// Add following line to config.h to enable Wire library instead of native I2C drivers
|
||||||
//#define I2C_USE_WIRE
|
//#define I2C_USE_WIRE
|
||||||
|
|
||||||
@ -265,6 +270,7 @@ private:
|
|||||||
static volatile unsigned long startTime;
|
static volatile unsigned long startTime;
|
||||||
|
|
||||||
static unsigned long timeout; // Transaction timeout in microseconds. 0=disabled.
|
static unsigned long timeout; // Transaction timeout in microseconds. 0=disabled.
|
||||||
|
static uint8_t retryCounter; // Count of retries
|
||||||
|
|
||||||
void startTransaction();
|
void startTransaction();
|
||||||
|
|
||||||
|
@ -223,16 +223,15 @@ void I2CManagerClass::handleInterrupt() {
|
|||||||
// Update hardware state machine
|
// Update hardware state machine
|
||||||
I2C_handleInterrupt();
|
I2C_handleInterrupt();
|
||||||
|
|
||||||
// Enable interrupts to minimise effect on other interrupt code
|
|
||||||
interrupts();
|
|
||||||
|
|
||||||
// Check if current request has completed. If there's a current request
|
// 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.
|
// and state isn't active then state contains the completion status of the request.
|
||||||
if (state != I2C_STATE_ACTIVE && currentRequest != NULL) {
|
if (state != I2C_STATE_ACTIVE && currentRequest != NULL) {
|
||||||
// Remove completed request from head of queue
|
// Operation has completed.
|
||||||
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
|
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;
|
I2CRB * t = queueHead;
|
||||||
if (t == queueHead) {
|
if (t == currentRequest) {
|
||||||
queueHead = t->nextRequest;
|
queueHead = t->nextRequest;
|
||||||
if (!queueHead) queueTail = queueHead;
|
if (!queueHead) queueTail = queueHead;
|
||||||
t->nBytes = rxCount;
|
t->nBytes = rxCount;
|
||||||
@ -241,12 +240,21 @@ void I2CManagerClass::handleInterrupt() {
|
|||||||
// I2C state machine is now free for next request
|
// I2C state machine is now free for next request
|
||||||
currentRequest = NULL;
|
currentRequest = NULL;
|
||||||
state = I2C_STATE_FREE;
|
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.
|
// Fields in I2CManager class specific to Non-blocking implementation.
|
||||||
@ -261,5 +269,6 @@ volatile uint8_t I2CManagerClass::bytesToSend;
|
|||||||
volatile uint8_t I2CManagerClass::bytesToReceive;
|
volatile uint8_t I2CManagerClass::bytesToReceive;
|
||||||
volatile unsigned long I2CManagerClass::startTime;
|
volatile unsigned long I2CManagerClass::startTime;
|
||||||
unsigned long I2CManagerClass::timeout = 0;
|
unsigned long I2CManagerClass::timeout = 0;
|
||||||
|
uint8_t I2CManagerClass::retryCounter = 0;
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -49,9 +49,14 @@ void I2CManagerClass::_setClock(unsigned long i2cClockSpeed) {
|
|||||||
* Initiate a write to an I2C device (blocking operation on Wire)
|
* 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) {
|
uint8_t I2CManagerClass::write(uint8_t address, const uint8_t buffer[], uint8_t size, I2CRB *rb) {
|
||||||
Wire.beginTransmission(address);
|
uint8_t status = I2C_STATUS_OK;
|
||||||
if (size > 0) Wire.write(buffer, size);
|
uint8_t retryCount = 0;
|
||||||
rb->status = Wire.endTransmission();
|
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;
|
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 status = I2C_STATUS_OK;
|
||||||
uint8_t nBytes = 0;
|
uint8_t nBytes = 0;
|
||||||
if (writeSize > 0) {
|
uint8_t retryCount = 0;
|
||||||
Wire.beginTransmission(address);
|
do {
|
||||||
Wire.write(writeBuffer, writeSize);
|
if (writeSize > 0) {
|
||||||
status = Wire.endTransmission(false); // Don't free bus yet
|
Wire.beginTransmission(address);
|
||||||
}
|
Wire.write(writeBuffer, writeSize);
|
||||||
if (status == I2C_STATUS_OK) {
|
status = Wire.endTransmission(false); // Don't free bus yet
|
||||||
Wire.requestFrom(address, (size_t)readSize);
|
}
|
||||||
while (Wire.available() && nBytes < readSize)
|
if (status == I2C_STATUS_OK) {
|
||||||
readBuffer[nBytes++] = Wire.read();
|
Wire.requestFrom(address, (size_t)readSize);
|
||||||
if (nBytes < readSize) status = I2C_STATUS_TRUNCATED;
|
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->nBytes = nBytes;
|
||||||
rb->status = status;
|
rb->status = status;
|
||||||
return I2C_STATUS_OK;
|
return I2C_STATUS_OK;
|
||||||
|
Loading…
Reference in New Issue
Block a user