Skip to content
Snippets Groups Projects
Commit e542ba6e authored by EmilioCorigliano's avatar EmilioCorigliano Committed by Alberto Nidasio
Browse files

[I2C] Now repeated start works properly

For the repeated start, we have to keep the AUTOEND flag reset for both the transactions before and after the reStart. Not doing so would lead to a premature STOP condition and the failure of the reStart
parent fb14e04a
Branches
No related tags found
No related merge requests found
......@@ -412,11 +412,16 @@ bool I2CDriver::doOperation(const I2CSlaveConfig &slaveConfig)
setupPeripheral(slaveConfig);
}
reStarting = false;
// Setting up transaction
setupTransaction();
// Sending STOP condition and wake up thread
reStarting = false;
// clearing pending flags
i2c->ICR |= (I2C_ICR_ADDRCF | I2C_ICR_ARLOCF | I2C_ICR_BERRCF |
I2C_ICR_OVRCF | I2C_ICR_STOPCF);
// Starting the transaction with the START bit
// From the wait till the end of transaction it will all be executed in the
// event Interrupt Service Routine
......@@ -506,8 +511,13 @@ void I2CDriver::setupTransaction()
i2c->CR2 &= ~I2C_CR2_RD_WRN;
}
// setting automatic stop generation if we won't generate a reStart
if (transaction.generateStop)
// setting automatic stop generation if we won't generate a reStart.
// For a bug in the peripheral (or a behaviour not explained in the
// datasheet), when we have to issue a reStart condition, we can't set the
// AUTOEND flag because it will generate the STOP condition prematurely. So,
// in this case, we will generate the STOP condition manually at the end of
// the transaction.
if (transaction.generateStop && !reStarting)
{
i2c->CR2 |= I2C_CR2_AUTOEND;
}
......@@ -522,17 +532,17 @@ void I2CDriver::setupTransaction()
void I2CDriver::setupReload()
{
if (transaction.nBytes - transaction.nBytesDone <= 0xffu)
if ((transaction.nBytes - transaction.nBytesDone) <= 0xffu)
{
i2c->CR2 &= ~I2C_CR2_RELOAD;
i2c->CR2 |= (transaction.nBytes - transaction.nBytesDone)
<< I2C_CR2_NBYTES_Pos;
i2c->CR2 |= ((transaction.nBytes - transaction.nBytesDone)
<< I2C_CR2_NBYTES_Pos);
}
else
{
i2c->CR2 |=
I2C_CR2_RELOAD | // There must be a reload
0xff << I2C_CR2_NBYTES_Pos; // maximum bytes that can be sent
(I2C_CR2_RELOAD | // There must be a reload
(0xff << I2C_CR2_NBYTES_Pos)); // maximum bytes that can be sent
}
}
......@@ -632,7 +642,9 @@ inline void I2CDriver::IRQwakeUpWaitingThread()
i2c->CR1 &= ~(I2C_CR1_ERRIE | // interrupt for errors
I2C_CR1_NACKIE | // interrupt for NACKs
I2C_CR1_TCIE | // interrupt for TC and TCR
I2C_CR1_STOPIE); // interrupt for STOP detected
I2C_CR1_STOPIE | // interrupt for STOP detected
I2C_CR1_TXIE | // interrupt for tx buffer
I2C_CR1_RXIE); // interrupt for rx buffer
if (waiting)
{
......@@ -650,12 +662,6 @@ inline void I2CDriver::IRQwakeUpWaitingThread()
void I2CDriver::IRQhandleInterrupt()
{
// Transfer complete reload: setting registers for the remaining bytes
if (i2c->ISR & I2C_ISR_TCR)
{
setupReload();
}
// If NACK reception, return error
if (i2c->ISR & I2C_ISR_NACKF)
{
......@@ -677,39 +683,63 @@ void I2CDriver::IRQhandleInterrupt()
transaction.buffRead[transaction.nBytesDone] = i2c->RXDR;
transaction.nBytesDone++;
}
else if (i2c->ISR & I2C_ISR_TXIS)
else if (i2c->ISR & (I2C_ISR_TXIS | I2C_ISR_TXE))
{
// WRITE
i2c->TXDR = transaction.buffWrite[transaction.nBytesDone];
transaction.nBytesDone++;
}
}
else
// Transfer complete reload: setting registers for the remaining bytes
if (i2c->ISR & I2C_ISR_TCR)
{
// Sending STOP condition and wake up thread
if (!transaction.generateStop)
setupReload();
}
// when stop detected on the bus
if (i2c->ISR & I2C_ISR_STOPF)
{
reStarting = true;
// clearing STOPF
i2c->ICR |= I2C_ICR_STOPCF;
if (transaction.nBytesDone < transaction.nBytes)
{
error = 1 << 14;
lastError |= Errors::BERR;
}
// waking up the waiting thread
IRQwakeUpWaitingThread();
}
return;
}
if (i2c->ISR & I2C_ISR_STOPF)
// Transfer complete (RELOAD = 0, AUTOEND = 0, NBYTES transferred)
if ((i2c->ISR & I2C_ISR_TC) &&
(transaction.nBytesDone >= transaction.nBytes))
{
if (transaction.generateStop)
{
// stop and wait for STOPF event
i2c->CR2 |= I2C_CR2_STOP;
}
else
{
// waking up the waiting thread after stop condition generated
reStarting = true;
// waking up the waiting thread
IRQwakeUpWaitingThread();
return;
}
}
}
void I2CDriver::IRQhandleErrInterrupt()
{
error = i2c->ISR | (1 << 24);
error = (i2c->ISR | (1 << 24));
// Clearing all the errors in the register
i2c->ICR |= I2C_ICR_ADDRCF | I2C_ICR_ARLOCF | I2C_ICR_BERRCF |
I2C_ICR_OVRCF | I2C_ICR_STOPCF;
i2c->ICR |= (I2C_ICR_ADDRCF | I2C_ICR_ARLOCF | I2C_ICR_BERRCF |
I2C_ICR_OVRCF | I2C_ICR_STOPCF);
// Waking up the waiting thread
IRQwakeUpWaitingThread();
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment