mirror of
https://github.com/DCC-EX/CommandStation-EX.git
synced 2024-11-22 15:46:14 +01:00
I2CManager: Update native drivers for MUX support from the common code.
This commit is contained in:
parent
553a94bf67
commit
0b307a67e4
157
I2CManager_AVR.h
157
I2CManager_AVR.h
|
@ -95,17 +95,16 @@ void I2CManagerClass::I2C_init()
|
|||
* Initiate a start bit for transmission.
|
||||
***************************************************************************/
|
||||
void I2CManagerClass::I2C_sendStart() {
|
||||
bytesToSend = currentRequest->writeLen;
|
||||
bytesToReceive = currentRequest->readLen;
|
||||
rxCount = 0;
|
||||
txCount = 0;
|
||||
#if defined(I2C_EXTENDED_ADDRESS)
|
||||
#if defined(I2C_EXTENDED_ADDRESSXXXXXXXXXXXX)
|
||||
if (currentRequest->i2cAddress.muxNumber() != I2CMux_None) {
|
||||
// Send request to multiplexer
|
||||
muxPhase = MuxPhase_PROLOG; // When start bit interrupt comes in, send SLA+W to MUX
|
||||
} else
|
||||
muxPhase = 0;
|
||||
#endif
|
||||
while(TWCR & (1<<TWSTO)) {} // Wait for any in-progress stop to finish
|
||||
TWCR = (1<<TWEN)|ENABLE_TWI_INTERRUPT|(1<<TWINT)|(1<<TWEA)|(1<<TWSTA); // Send Start
|
||||
|
||||
}
|
||||
|
@ -138,134 +137,30 @@ void I2CManagerClass::I2C_handleInterrupt() {
|
|||
|
||||
uint8_t twsr = TWSR & 0xF8;
|
||||
|
||||
#if defined(I2C_EXTENDED_ADDRESS)
|
||||
// First process the MUX state machine.
|
||||
if (muxPhase > MuxPhase_OFF) {
|
||||
switch (twsr) {
|
||||
case TWI_MTX_ADR_ACK: // SLA+W has been transmitted and ACK received
|
||||
if (muxPhase == MuxPhase_PROLOG) {
|
||||
// Send MUX selecter mask to follow address
|
||||
I2CSubBus subBus = currentRequest->i2cAddress.subBus();
|
||||
TWDR = (subBus==SubBus_All) ? 0xff :
|
||||
(subBus==SubBus_None) ? 0x00 :
|
||||
1 << subBus;
|
||||
TWCR = (1<<TWEN)|ENABLE_TWI_INTERRUPT|(1<<TWINT);
|
||||
return;
|
||||
} else if (muxPhase == MuxPhase_EPILOG) {
|
||||
TWDR = 0x00; // Disable all subbuses
|
||||
TWCR = (1<<TWEN)|ENABLE_TWI_INTERRUPT|(1<<TWINT);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case TWI_MTX_DATA_ACK: // Data byte has been transmitted and ACK received
|
||||
if (muxPhase == MuxPhase_PASSTHRU && !bytesToSend && !bytesToReceive) {
|
||||
if (_muxCount > 1) {
|
||||
// Device transaction complete, prepare to deselect MUX by sending start bit
|
||||
TWCR = (1<<TWEN)|ENABLE_TWI_INTERRUPT|(1<<TWINT)|(1<<TWSTO)|(1<<TWSTA);
|
||||
muxPhase = MuxPhase_EPILOG;
|
||||
return;
|
||||
} else {
|
||||
// Only one MUX so no need to deselect it. Just finish off
|
||||
TWCR = (1<<TWEN)|(1<<TWINT)|(1<<TWSTO);
|
||||
state = I2C_STATE_COMPLETED;
|
||||
muxPhase = MuxPhase_OFF;
|
||||
return;
|
||||
}
|
||||
} else if (muxPhase == MuxPhase_PROLOG) {
|
||||
// If device address is zero, then finish here (i.e. send mux subBus mask only)
|
||||
if (currentRequest->i2cAddress.deviceAddress() == 0) {
|
||||
// Send stop and post rb.
|
||||
TWDR = 0xff;
|
||||
TWCR = (1<<TWEN)|(1<<TWINT)|(1<<TWSTO);
|
||||
state = I2C_STATE_COMPLETED;
|
||||
muxPhase = MuxPhase_OFF;
|
||||
return;
|
||||
} else {
|
||||
// Send stop followed by start, preparing to send device address
|
||||
TWCR = (1<<TWEN)|ENABLE_TWI_INTERRUPT|(1<<TWINT)|(1<<TWSTO)|(1<<TWSTA);
|
||||
muxPhase = MuxPhase_PASSTHRU;
|
||||
return;
|
||||
}
|
||||
} else if (muxPhase == MuxPhase_EPILOG) {
|
||||
// Send stop and allow RB to be posted.
|
||||
TWDR = 0xff;
|
||||
TWCR = (1<<TWEN)|(1<<TWINT)|(1<<TWSTO);
|
||||
state = I2C_STATE_COMPLETED;
|
||||
muxPhase = MuxPhase_OFF;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case TWI_MRX_DATA_NACK: // Last data byte has been received and NACK transmitted
|
||||
// We must read the data before processing the MUX, so do this here.
|
||||
if (bytesToReceive > 0) {
|
||||
currentRequest->readBuffer[rxCount++] = TWDR;
|
||||
bytesToReceive--;
|
||||
}
|
||||
if (muxPhase == MuxPhase_PASSTHRU && _muxCount > 1) {
|
||||
// Prepare to transmit epilog to mux - first send the stop bit and start bit
|
||||
// (we don't need to reset mux if there is only one.
|
||||
TWCR = (1<<TWEN)|ENABLE_TWI_INTERRUPT|(1<<TWINT)|(1<<TWSTO)|(1<<TWSTA);
|
||||
muxPhase = MuxPhase_EPILOG;
|
||||
return;
|
||||
} else {
|
||||
// Finish up.
|
||||
TWCR = (1<<TWEN)|(1<<TWINT)|(1<<TWSTO); // Send Stop
|
||||
state = I2C_STATE_COMPLETED;
|
||||
muxPhase = MuxPhase_OFF;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case TWI_START: // START has been transmitted
|
||||
case TWI_REP_START: // Repeated START has been transmitted
|
||||
if (muxPhase == MuxPhase_PROLOG || muxPhase == MuxPhase_EPILOG) {
|
||||
// Send multiplexer address first
|
||||
uint8_t muxAddress = I2C_MUX_BASE_ADDRESS + currentRequest->i2cAddress.muxNumber();
|
||||
TWDR = (muxAddress << 1) | 0; // MUXaddress+Write
|
||||
TWCR = (1<<TWEN)|ENABLE_TWI_INTERRUPT|(1<<TWINT);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case TWI_MTX_ADR_NACK: // SLA+W has been transmitted and NACK received
|
||||
case TWI_MRX_ADR_NACK: // SLA+R has been transmitted and NACK received
|
||||
case TWI_MTX_DATA_NACK: // Data byte has been transmitted and NACK received
|
||||
if (muxPhase == MuxPhase_PASSTHRU) {
|
||||
// Data transaction was nak'd, update RB status but continue with mux cleardown
|
||||
completionStatus = I2C_STATUS_NEGATIVE_ACKNOWLEDGE;
|
||||
TWCR = (1<<TWEN)|ENABLE_TWI_INTERRUPT|(1<<TWINT)|(1<<TWSTO)|(1<<TWSTA); // Send Stop and start
|
||||
muxPhase = MuxPhase_EPILOG;
|
||||
return;
|
||||
} else if (muxPhase > MuxPhase_EPILOG) {
|
||||
// Mux Cleardown was NAK'd, send stop and then finish.
|
||||
TWCR = (1<<TWEN)|(1<<TWINT)|(1<<TWSTO); // Send Stop
|
||||
state = I2C_STATE_COMPLETED;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Now the main I2C interrupt handler, used for the device communications.
|
||||
//
|
||||
// Main I2C interrupt handler, used for the device communications.
|
||||
// The following variables are used:
|
||||
// bytesToSend, bytesToReceive (R/W)
|
||||
// txCount, rxCount (W)
|
||||
// deviceAddress (R)
|
||||
// sendBuffer, receiveBuffer (R)
|
||||
// operation (R)
|
||||
// state, completionStatus (W)
|
||||
//
|
||||
// Cases are ordered so that the most frequently used ones are tested first.
|
||||
switch (twsr) {
|
||||
case TWI_MTX_DATA_ACK: // Data byte has been transmitted and ACK received
|
||||
case TWI_MTX_ADR_ACK: // SLA+W has been transmitted and ACK received
|
||||
if (bytesToSend) { // Send first.
|
||||
if (operation == OPERATION_SEND_P)
|
||||
TWDR = GETFLASH(currentRequest->writeBuffer + (txCount++));
|
||||
TWDR = GETFLASH(sendBuffer + (txCount++));
|
||||
else
|
||||
TWDR = currentRequest->writeBuffer[txCount++];
|
||||
TWDR = sendBuffer[txCount++];
|
||||
bytesToSend--;
|
||||
TWCR = (1<<TWEN)|ENABLE_TWI_INTERRUPT|(1<<TWINT);
|
||||
} else if (bytesToReceive) { // All sent, anything to receive?
|
||||
// Don't need to wait for stop, as the interface won't send the start until
|
||||
// any in-progress stop condition has been sent.
|
||||
// any in-progress stop condition from previous interrupts has been sent.
|
||||
TWCR = (1<<TWEN)|ENABLE_TWI_INTERRUPT|(1<<TWINT)|(1<<TWSTA); // Send Start
|
||||
} else {
|
||||
// Nothing left to send or receive
|
||||
|
@ -276,7 +171,7 @@ void I2CManagerClass::I2C_handleInterrupt() {
|
|||
|
||||
case TWI_MRX_DATA_ACK: // Data byte has been received and ACK transmitted
|
||||
if (bytesToReceive > 0) {
|
||||
currentRequest->readBuffer[rxCount++] = TWDR;
|
||||
receiveBuffer[rxCount++] = TWDR;
|
||||
bytesToReceive--;
|
||||
}
|
||||
/* fallthrough */
|
||||
|
@ -292,7 +187,7 @@ void I2CManagerClass::I2C_handleInterrupt() {
|
|||
|
||||
case TWI_MRX_DATA_NACK: // Data byte has been received and NACK transmitted
|
||||
if (bytesToReceive > 0) {
|
||||
currentRequest->readBuffer[rxCount++] = TWDR;
|
||||
receiveBuffer[rxCount++] = TWDR;
|
||||
bytesToReceive--;
|
||||
}
|
||||
TWCR = (1<<TWEN)|(1<<TWINT)|(1<<TWEA)|(1<<TWSTO); // Send Stop
|
||||
|
@ -301,15 +196,12 @@ void I2CManagerClass::I2C_handleInterrupt() {
|
|||
|
||||
case TWI_START: // START has been transmitted
|
||||
case TWI_REP_START: // Repeated START has been transmitted
|
||||
{
|
||||
// Set up address and R/W
|
||||
uint8_t deviceAddress = currentRequest->i2cAddress;
|
||||
if (operation == OPERATION_READ || (operation==OPERATION_REQUEST && !bytesToSend))
|
||||
TWDR = (deviceAddress << 1) | 1; // SLA+R
|
||||
else
|
||||
TWDR = (deviceAddress << 1) | 0; // SLA+W
|
||||
TWCR = (1<<TWEN)|ENABLE_TWI_INTERRUPT|(1<<TWINT)|(1<<TWEA);
|
||||
}
|
||||
// Set up address and R/W
|
||||
if (operation == OPERATION_READ || (operation==OPERATION_REQUEST && !bytesToSend))
|
||||
TWDR = (deviceAddress << 1) | 1; // SLA+R
|
||||
else
|
||||
TWDR = (deviceAddress << 1) | 0; // SLA+W
|
||||
TWCR = (1<<TWEN)|ENABLE_TWI_INTERRUPT|(1<<TWINT)|(1<<TWEA);
|
||||
break;
|
||||
|
||||
case TWI_MTX_ADR_NACK: // SLA+W has been transmitted and NACK received
|
||||
|
@ -336,7 +228,10 @@ void I2CManagerClass::I2C_handleInterrupt() {
|
|||
|
||||
#if defined(I2C_USE_INTERRUPTS)
|
||||
ISR(TWI_vect) {
|
||||
I2CManagerClass::handleInterrupt();
|
||||
// pinMode(2,OUTPUT);
|
||||
// digitalWrite(2,1);
|
||||
I2CManager.handleInterrupt();
|
||||
// digitalWrite(2,0);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -68,8 +68,6 @@ void I2CManagerClass::I2C_init()
|
|||
* Initiate a start bit for transmission, followed by address and R/W
|
||||
***************************************************************************/
|
||||
void I2CManagerClass::I2C_sendStart() {
|
||||
bytesToSend = currentRequest->writeLen;
|
||||
bytesToReceive = currentRequest->readLen;
|
||||
txCount = 0;
|
||||
rxCount = 0;
|
||||
|
||||
|
@ -123,11 +121,11 @@ void I2CManagerClass::I2C_handleInterrupt() {
|
|||
|
||||
} else if (bytesToSend) {
|
||||
// Acked, so send next byte (don't need to use GETFLASH)
|
||||
TWI0.MDATA = currentRequest->writeBuffer[txCount++];
|
||||
TWI0.MDATA = sendBuffer[txCount++];
|
||||
bytesToSend--;
|
||||
} else if (bytesToReceive) {
|
||||
// Last sent byte acked and no more to send. Send repeated start, address and read bit.
|
||||
TWI0.MADDR = (currentRequest->i2cAddress << 1) | 1;
|
||||
TWI0.MADDR = (deviceAddress << 1) | 1;
|
||||
} else {
|
||||
// No more data to send/receive. Initiate a STOP condition.
|
||||
TWI0.MCTRLB = TWI_MCMD_STOP_gc;
|
||||
|
@ -136,7 +134,7 @@ void I2CManagerClass::I2C_handleInterrupt() {
|
|||
} else if (currentStatus & TWI_RIF_bm) {
|
||||
// Master read completed without errors
|
||||
if (bytesToReceive) {
|
||||
currentRequest->readBuffer[rxCount++] = TWI0.MDATA; // Store received byte
|
||||
receiveBuffer[rxCount++] = TWI0.MDATA; // Store received byte
|
||||
bytesToReceive--;
|
||||
}
|
||||
if (bytesToReceive) {
|
||||
|
@ -155,7 +153,7 @@ void I2CManagerClass::I2C_handleInterrupt() {
|
|||
* Interrupt handler.
|
||||
***************************************************************************/
|
||||
ISR(TWI0_TWIM_vect) {
|
||||
I2CManagerClass::handleInterrupt();
|
||||
I2CManager.handleInterrupt();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -79,7 +79,7 @@ for ( MY_ATOMIC_RESTORESTATE, _done = my_iCliRetVal(); \
|
|||
enum MuxPhase: uint8_t {
|
||||
MuxPhase_OFF = 0,
|
||||
MuxPhase_PROLOG,
|
||||
MuxPhase_PASSTHRU,
|
||||
MuxPhase_PAYLOAD,
|
||||
MuxPhase_EPILOG,
|
||||
} ;
|
||||
|
||||
|
@ -107,7 +107,7 @@ void I2CManagerClass::_setClock(unsigned long i2cClockSpeed) {
|
|||
}
|
||||
|
||||
/***************************************************************************
|
||||
* Helper function to start operations, if the I2C interface is free and
|
||||
* Start an I2C transaction, if the I2C interface is free and
|
||||
* there is a queued request to be processed.
|
||||
* If there's an I2C clock speed change pending, then implement it before
|
||||
* starting the operation.
|
||||
|
@ -126,9 +126,47 @@ void I2CManagerClass::startTransaction() {
|
|||
startTime = micros();
|
||||
currentRequest = queueHead;
|
||||
rxCount = txCount = 0;
|
||||
// Copy key fields to static data for speed.
|
||||
operation = currentRequest->operation & OPERATION_MASK;
|
||||
|
||||
// Start the I2C process going.
|
||||
#if defined(I2C_EXTENDED_ADDRESS)
|
||||
I2CMux muxNumber = currentRequest->i2cAddress.muxNumber();
|
||||
if (muxNumber != I2CMux_None) {
|
||||
muxPhase = MuxPhase_PROLOG;
|
||||
uint8_t subBus = currentRequest->i2cAddress.subBus();
|
||||
muxData[0] = (subBus == SubBus_All) ? 0xff :
|
||||
(subBus == SubBus_None) ? 0x00 :
|
||||
#if defined(I2CMUX_PCA9547)
|
||||
0x08 | subBus;
|
||||
#elif defined(I2CMUX_PCA9542) || defined(I2CMUX_PCA9544)
|
||||
0x04 | subBus; // NB Only 2 or 4 subbuses respectively
|
||||
#else
|
||||
// Default behaviour for most MUXs is to use a mask
|
||||
// with a bit set for the subBus to be enabled
|
||||
1 << subBus;
|
||||
#endif
|
||||
deviceAddress = I2C_MUX_BASE_ADDRESS + muxNumber;
|
||||
sendBuffer = &muxData[0];
|
||||
bytesToSend = 1;
|
||||
bytesToReceive = 0;
|
||||
operation = OPERATION_SEND;
|
||||
} else {
|
||||
// Send/receive payload for device only.
|
||||
muxPhase = MuxPhase_OFF;
|
||||
deviceAddress = currentRequest->i2cAddress;
|
||||
sendBuffer = currentRequest->writeBuffer;
|
||||
bytesToSend = currentRequest->writeLen;
|
||||
receiveBuffer = currentRequest->readBuffer;
|
||||
bytesToReceive = currentRequest->readLen;
|
||||
operation = currentRequest->operation & OPERATION_MASK;
|
||||
}
|
||||
#else
|
||||
deviceAddress = currentRequest->i2cAddress;
|
||||
sendBuffer = currentRequest->writeBuffer;
|
||||
bytesToSend = currentRequest->writeLen;
|
||||
receiveBuffer = currentRequest->readBuffer;
|
||||
bytesToReceive = currentRequest->readLen;
|
||||
operation = currentRequest->operation & OPERATION_MASK;
|
||||
#endif
|
||||
I2C_sendStart();
|
||||
}
|
||||
}
|
||||
|
@ -194,7 +232,7 @@ uint8_t I2CManagerClass::read(I2CAddress i2cAddress, uint8_t *readBuffer, uint8_
|
|||
* reset before the read.
|
||||
***************************************************************************/
|
||||
void I2CManagerClass::setTimeout(unsigned long value) {
|
||||
timeout = value;
|
||||
_timeout = value;
|
||||
};
|
||||
|
||||
/***************************************************************************
|
||||
|
@ -205,12 +243,12 @@ void I2CManagerClass::setTimeout(unsigned long value) {
|
|||
void I2CManagerClass::checkForTimeout() {
|
||||
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
|
||||
I2CRB *t = queueHead;
|
||||
if (state==I2C_STATE_ACTIVE && t!=0 && t==currentRequest && timeout > 0) {
|
||||
if (state==I2C_STATE_ACTIVE && t!=0 && t==currentRequest && _timeout > 0) {
|
||||
// Check for timeout
|
||||
unsigned long elapsed = micros() - startTime;
|
||||
if (elapsed > timeout) {
|
||||
if (elapsed > _timeout) {
|
||||
#ifdef DIAG_IO
|
||||
//DIAG(F("I2CManager Timeout on %s, I2CRB=%s"), t->i2cAddress.toString(), currentRequest);
|
||||
//DIAG(F("I2CManager Timeout on %s"), t->i2cAddress.toString());
|
||||
#endif
|
||||
// Excessive time. Dequeue request
|
||||
queueHead = t->nextRequest;
|
||||
|
@ -267,19 +305,58 @@ void I2CManagerClass::handleInterrupt() {
|
|||
|
||||
// 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) {
|
||||
if (state == I2C_STATE_COMPLETED && currentRequest != NULL) {
|
||||
// Operation has completed.
|
||||
if (completionStatus == I2C_STATUS_OK || ++retryCounter > MAX_I2C_RETRIES
|
||||
|| currentRequest->operation & OPERATION_NORETRY)
|
||||
{
|
||||
// Status is OK, or has failed and retry count exceeded, or retries disabled.
|
||||
#if defined(I2C_EXTENDED_ADDRESS)
|
||||
if (muxPhase == MuxPhase_PROLOG ) {
|
||||
overallStatus = completionStatus;
|
||||
uint8_t rbAddress = currentRequest->i2cAddress.deviceAddress();
|
||||
if (completionStatus == I2C_STATUS_OK && rbAddress != 0) {
|
||||
// Mux request OK, start handling application request.
|
||||
muxPhase = MuxPhase_PAYLOAD;
|
||||
deviceAddress = rbAddress;
|
||||
sendBuffer = currentRequest->writeBuffer;
|
||||
bytesToSend = currentRequest->writeLen;
|
||||
bytesToReceive = currentRequest->readLen;
|
||||
operation = currentRequest->operation & OPERATION_MASK;
|
||||
state = I2C_STATE_ACTIVE;
|
||||
I2C_sendStart();
|
||||
return;
|
||||
}
|
||||
} else if (muxPhase == MuxPhase_PAYLOAD) {
|
||||
// Application request completed, now send epilogue to mux
|
||||
overallStatus = completionStatus;
|
||||
currentRequest->nBytes = rxCount; // Save number of bytes read into rb
|
||||
muxPhase = MuxPhase_EPILOG;
|
||||
deviceAddress = I2C_MUX_BASE_ADDRESS + currentRequest->i2cAddress.muxNumber();
|
||||
muxData[0] = 0x00;
|
||||
sendBuffer = &muxData[0];
|
||||
bytesToSend = 1;
|
||||
bytesToReceive = 0;
|
||||
operation = OPERATION_SEND;
|
||||
state = I2C_STATE_ACTIVE;
|
||||
I2C_sendStart();
|
||||
return;
|
||||
} else if (muxPhase == MuxPhase_EPILOG) {
|
||||
// Epilog finished, ignore completionStatus
|
||||
muxPhase = MuxPhase_OFF;
|
||||
} else
|
||||
overallStatus = completionStatus;
|
||||
#else
|
||||
overallStatus = completionStatus;
|
||||
currentRequest->nBytes = rxCount;
|
||||
#endif
|
||||
|
||||
// Remove completed request from head of queue
|
||||
I2CRB * t = queueHead;
|
||||
if (t == currentRequest) {
|
||||
queueHead = t->nextRequest;
|
||||
if (!queueHead) queueTail = queueHead;
|
||||
t->nBytes = rxCount;
|
||||
t->status = completionStatus;
|
||||
t->status = overallStatus;
|
||||
|
||||
// I2C state machine is now free for next request
|
||||
currentRequest = NULL;
|
||||
|
@ -295,28 +372,10 @@ void I2CManagerClass::handleInterrupt() {
|
|||
|
||||
if (state == I2C_STATE_FREE && queueHead != NULL) {
|
||||
// Allow any pending interrupts before starting the next request.
|
||||
interrupts();
|
||||
//interrupts();
|
||||
// Start next request
|
||||
I2CManager.startTransaction();
|
||||
}
|
||||
}
|
||||
|
||||
// Fields in I2CManager class specific to Non-blocking implementation.
|
||||
I2CRB * volatile I2CManagerClass::queueHead = NULL;
|
||||
I2CRB * volatile I2CManagerClass::queueTail = NULL;
|
||||
I2CRB * volatile I2CManagerClass::currentRequest = NULL;
|
||||
volatile uint8_t I2CManagerClass::state = I2C_STATE_FREE;
|
||||
uint8_t I2CManagerClass::completionStatus;
|
||||
volatile uint8_t I2CManagerClass::txCount;
|
||||
volatile uint8_t I2CManagerClass::rxCount;
|
||||
volatile uint8_t I2CManagerClass::operation;
|
||||
volatile uint8_t I2CManagerClass::bytesToSend;
|
||||
volatile uint8_t I2CManagerClass::bytesToReceive;
|
||||
volatile unsigned long I2CManagerClass::startTime;
|
||||
uint8_t I2CManagerClass::retryCounter = 0;
|
||||
|
||||
#if defined(I2C_EXTENDED_ADDRESS)
|
||||
volatile uint8_t I2CManagerClass::muxPhase = 0;
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -153,8 +153,6 @@ void I2CManagerClass::I2C_init()
|
|||
void I2CManagerClass::I2C_sendStart() {
|
||||
|
||||
// Set counters here in case this is a retry.
|
||||
bytesToSend = currentRequest->writeLen;
|
||||
bytesToReceive = currentRequest->readLen;
|
||||
txCount = 0;
|
||||
rxCount = 0;
|
||||
|
||||
|
@ -220,11 +218,11 @@ void I2CManagerClass::I2C_handleInterrupt() {
|
|||
state = I2C_STATE_COMPLETED; // Completed with error
|
||||
} else if (bytesToSend) {
|
||||
// Acked, so send next byte
|
||||
s->I2CM.DATA.bit.DATA = currentRequest->writeBuffer[txCount++];
|
||||
s->I2CM.DATA.bit.DATA = sendBuffer[txCount++];
|
||||
bytesToSend--;
|
||||
} else if (bytesToReceive) {
|
||||
// Last sent byte acked and no more to send. Send repeated start, address and read bit.
|
||||
s->I2CM.ADDR.bit.ADDR = (currentRequest->i2cAddress << 1) | 1;
|
||||
s->I2CM.ADDR.bit.ADDR = (deviceAddress << 1) | 1;
|
||||
} else {
|
||||
// No more data to send/receive. Initiate a STOP condition
|
||||
I2C_sendStop();
|
||||
|
@ -235,12 +233,12 @@ void I2CManagerClass::I2C_handleInterrupt() {
|
|||
if (bytesToReceive == 1) {
|
||||
s->I2CM.CTRLB.bit.ACKACT = 1; // NAK final byte
|
||||
I2C_sendStop(); // send stop
|
||||
currentRequest->readBuffer[rxCount++] = s->I2CM.DATA.bit.DATA; // Store received byte
|
||||
receiveBuffer[rxCount++] = s->I2CM.DATA.bit.DATA; // Store received byte
|
||||
bytesToReceive = 0;
|
||||
state = I2C_STATE_COMPLETED; // Completed OK
|
||||
} else if (bytesToReceive) {
|
||||
s->I2CM.CTRLB.bit.ACKACT = 0; // ACK all but final byte
|
||||
currentRequest->readBuffer[rxCount++] = s->I2CM.DATA.bit.DATA; // Store received byte
|
||||
receiveBuffer[rxCount++] = s->I2CM.DATA.bit.DATA; // Store received byte
|
||||
bytesToReceive--;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
***************************************************************************/
|
||||
#if defined(I2C_USE_INTERRUPTS) && defined(ARDUINO_ARCH_STM32)
|
||||
void I2C1_IRQHandler() {
|
||||
I2CManagerClass::handleInterrupt();
|
||||
I2CManager.handleInterrupt();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -151,8 +151,7 @@ void I2CManagerClass::I2C_init()
|
|||
void I2CManagerClass::I2C_sendStart() {
|
||||
|
||||
// Set counters here in case this is a retry.
|
||||
bytesToSend = currentRequest->writeLen;
|
||||
bytesToReceive = currentRequest->readLen;
|
||||
rxCount = txCount = 0;
|
||||
uint8_t temp;
|
||||
|
||||
// On a single-master I2C bus, the start bit won't be sent until the bus
|
||||
|
@ -168,7 +167,7 @@ void I2CManagerClass::I2C_sendStart() {
|
|||
s->CR1 |= (1<<10); // Enable the ACK
|
||||
s->CR1 |= (1<<8); // Generate START
|
||||
// Send address with read flag (1) or'd in
|
||||
s->DR = (currentRequest->i2cAddress << 1) | 1; // send the address
|
||||
s->DR = (deviceAddress << 1) | 1; // send the address
|
||||
while (!(s->SR1 & (1<<1))); // wait for ADDR bit to set
|
||||
// Special case for 1 byte reads!
|
||||
if (bytesToReceive == 1)
|
||||
|
@ -185,7 +184,7 @@ void I2CManagerClass::I2C_sendStart() {
|
|||
s->CR1 |= (1<<10); // Enable the ACK
|
||||
s->CR1 |= (1<<8); // Generate START
|
||||
// Send address with write flag (0) or'd in
|
||||
s->DR = (currentRequest->i2cAddress << 1) | 0; // send the address
|
||||
s->DR = (deviceAddress << 1) | 0; // send the address
|
||||
while (!(s->SR1 & (1<<1))); // wait for ADDR bit to set
|
||||
temp = s->SR1 | s->SR2; // read SR1 and SR2 to clear the ADDR bit
|
||||
}
|
||||
|
@ -219,44 +218,48 @@ void I2CManagerClass::I2C_close() {
|
|||
***************************************************************************/
|
||||
void I2CManagerClass::I2C_handleInterrupt() {
|
||||
|
||||
if (!s) return;
|
||||
|
||||
if (s->SR1 && (1<<9)) {
|
||||
// Arbitration lost, restart
|
||||
I2C_sendStart(); // Reinitiate request
|
||||
} else if (s->SR1 && (1<<8)) {
|
||||
// Bus error
|
||||
state = I2C_STATUS_BUS_ERROR;
|
||||
completionStatus = I2C_STATUS_BUS_ERROR;
|
||||
state = I2C_STATE_COMPLETED;
|
||||
} else if (s->SR1 && (1<<7)) {
|
||||
// Master write completed
|
||||
if (s->SR1 && (1<<10)) {
|
||||
// Nacked, send stop.
|
||||
I2C_sendStop();
|
||||
state = I2C_STATUS_NEGATIVE_ACKNOWLEDGE;
|
||||
completionStatus = I2C_STATUS_NEGATIVE_ACKNOWLEDGE;
|
||||
state = I2C_STATE_COMPLETED;
|
||||
} else if (bytesToSend) {
|
||||
// Acked, so send next byte
|
||||
s->DR = currentRequest->writeBuffer[txCount++];
|
||||
s->DR = sendBuffer[txCount++];
|
||||
bytesToSend--;
|
||||
} else if (bytesToReceive) {
|
||||
// Last sent byte acked and no more to send. Send repeated start, address and read bit.
|
||||
// s->I2CM.ADDR.bit.ADDR = (currentRequest->i2cAddress << 1) | 1;
|
||||
// s->I2CM.ADDR.bit.ADDR = (deviceAddress << 1) | 1;
|
||||
} else {
|
||||
// Check both TxE/BTF == 1 before generating stop
|
||||
while (!(s->SR1 && (1<<7))); // Check TxE
|
||||
while (!(s->SR1 && (1<<2))); // Check BTF
|
||||
// No more data to send/receive. Initiate a STOP condition.
|
||||
// No more data to send/receive. Initiate a STOP condition and finish
|
||||
I2C_sendStop();
|
||||
state = I2C_STATUS_OK; // Done
|
||||
state = I2C_STATE_COMPLETED;
|
||||
}
|
||||
} else if (s->SR1 && (1<<6)) {
|
||||
// Master read completed without errors
|
||||
if (bytesToReceive == 1) {
|
||||
// s->I2CM.CTRLB.bit.ACKACT = 1; // NAK final byte
|
||||
I2C_sendStop(); // send stop
|
||||
currentRequest->readBuffer[rxCount++] = s->DR; // Store received byte
|
||||
receiveBuffer[rxCount++] = s->DR; // Store received byte
|
||||
bytesToReceive = 0;
|
||||
state = I2C_STATUS_OK; // done
|
||||
state = I2C_STATE_COMPLETED;
|
||||
} else if (bytesToReceive) {
|
||||
// s->I2CM.CTRLB.bit.ACKACT = 0; // ACK all but final byte
|
||||
currentRequest->readBuffer[rxCount++] = s->DR; // Store received byte
|
||||
receiveBuffer[rxCount++] = s->DR; // Store received byte
|
||||
bytesToReceive--;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user