in arch/arm/src/stm32/stm32f40xxx_i2c.c [1152:1989]
static int stm32_i2c_isr_process(struct stm32_i2c_priv_s *priv)
{
uint32_t status;
#ifndef CONFIG_I2C_POLLED
uint32_t regval;
#endif
#ifdef CONFIG_STM32_I2C_DMA
uint16_t cr2;
#endif
i2cinfo("I2C ISR called\n");
/* Get state of the I2C controller (register SR1 only)
*
* Get control register SR1 only as reading both SR1 and SR2 clears the
* ADDR flag(possibly others) causing the hardware to advance to the next
* state without the proper action being taken.
*/
status = stm32_i2c_getreg(priv, STM32_I2C_SR1_OFFSET);
/* Update private version of the state */
priv->status = status;
/* Check if this is a new transmission so to set up the
* trace table accordingly.
*/
stm32_i2c_tracenew(priv, status);
stm32_i2c_traceevent(priv, I2CEVENT_ISR_CALL, 0);
/* Messages handling (1/2)
*
* Message handling should only operate when a message has been completely
* sent and after the ISR had the chance to run to set bits after the last
* written/read byte, i.e. priv->dcnt == -1. This is also the case in when
* the ISR is called for the first time. This can seen in
* stm32_i2c_process() before entering the stm32_i2c_sem_waitdone() waiting
* process.
*
* Message handling should only operate when:
* - A message has been completely sent and there are still messages
* to send(i.e. msgc > 0).
* - After the ISR had the chance to run to set start bit or
* termination flags after the last written/read byte(after last byte
* dcnt=0, msg handling dcnt = -1).
*
* When the ISR is called for the first time the same conditions hold.
* This can seen in stm32_i2c_process() before entering the
* stm32_i2c_sem_waitdone() waiting process.
*/
#ifdef CONFIG_STM32_I2C_DMA
/* If ISR gets called (ex. polling mode) while DMA is still in
* progress, we should just return and let the DMA finish.
*/
cr2 = stm32_i2c_getreg(priv, STM32_I2C_CR2_OFFSET);
if ((cr2 & I2C_CR2_DMAEN) != 0)
{
#ifdef CONFIG_DEBUG_I2C_INFO
size_t left = stm32_dmaresidual(priv->rxdma);
i2cinfo("DMA in progress: %ld [bytes] remainining. Returning.\n",
left);
#endif
return OK;
}
#endif
if (priv->dcnt == -1 && priv->msgc > 0)
{
/* Any new message should begin with "Start" condition
* However there were 2 situations where that was not true
* Situation 1:
* Next message continue transmission sequence of previous message
*
* Situation 2: If an error is injected that looks like a STOP the
* interrupt will be reentered with some status that will be incorrect.
* This will ensure that the error handler will clear the interrupt
* enables and return the error to the waiting task.
*/
if (((priv->msgv[0].flags & I2C_M_NOSTART) != 0 &&
(status & I2C_SR1_TXE) == 0) ||
((priv->msgv[0].flags & I2C_M_NOSTART) == 0 &&
(status & I2C_SR1_SB) == 0))
{
#if defined(CONFIG_STM32_I2C_DMA) || defined(CONFIG_I2C_POLLED)
return OK;
#else
priv->status |= I2C_SR1_TIMEOUT;
goto state_error;
#endif
}
i2cinfo("Switch to new message\n");
/* Get current message to process data and copy to private structure */
priv->ptr = priv->msgv->buffer; /* Copy buffer to private struct */
priv->dcnt = priv->msgv->length; /* Set counter of current msg length */
priv->flags = priv->msgv->flags; /* Copy flags to private struct */
i2cinfo("Current flags %i\n", priv->flags);
/* Decrease counter to indicate the number of messages left to
* process
*/
priv->msgc--;
/* Decrease message pointer.
* If last message set next message vector to null
*/
if (priv->msgc == 0)
{
/* No more messages, don't need to increment msgv. This pointer
* will be set to zero when reaching the termination of the ISR
* calls, i.e. Messages handling(2/2).
*/
}
else
{
/* If not last message increment to next message to process */
priv->msgv++;
}
/* Trace event */
stm32_i2c_traceevent(priv, I2CEVENT_MSG_HANDLING, priv->msgc);
}
/* Note the event where we are on the last message and after the last
* byte is handled at the bottom of this function, as it terminates
* the repeated calls to the ISR.
*/
/* I2C protocol logic
*
* I2C protocol logic follows. It's organized in an if else chain such that
* only one mode of operation is executed every time the ISR is called.
*/
/* Address Handling
*
* Check if a start bit was set and transmit address with proper format.
*
* Note:
* On first call the start bit has been set by stm32_i2c_waitdone()
* Otherwise it will be set from this ISR.
*
* Remember that after a start bit an address has always to be sent.
*/
if ((status & I2C_SR1_SB) != 0)
{
/* Start bit is set */
i2cinfo("Entering address handling, status = %" PRIi32 "\n", status);
/* Check for empty message (for robustness) */
if (priv->dcnt > 0)
{
/* Set POS bit to zero (can be up from a previous 2 byte receive) */
stm32_i2c_modifyreg(priv, STM32_I2C_CR1_OFFSET, I2C_CR1_POS, 0);
/* ACK is the expected answer for N>=3 reads and writes */
stm32_i2c_modifyreg(priv, STM32_I2C_CR1_OFFSET, 0, I2C_CR1_ACK);
/* Send address byte with correct 8th bit set
* (for writing or reading)
* Transmission happens after having written to the data register
* STM32_I2C_DR
*/
stm32_i2c_putreg(priv, STM32_I2C_DR_OFFSET,
(priv->flags & I2C_M_TEN) ?
0 : ((priv->msgv->addr << 1) |
(priv->flags & I2C_M_READ)));
i2cinfo("Address sent. Addr=%#02x Write/Read bit=%i\n",
priv->msgv->addr, (priv->flags & I2C_M_READ));
/* Flag that address has just been sent */
priv->check_addr_ack = true;
stm32_i2c_traceevent(priv, I2CEVENT_SENDADDR, priv->msgv->addr);
}
else
{
/* TODO: untested!! */
i2cwarn(" An empty message has been detected, "
"ignoring and passing to next message.\n");
/* Trace event */
stm32_i2c_traceevent(priv, I2CEVENT_EMPTY_MSG, 0);
/* Set condition to activate msg handling */
priv->dcnt = -1;
#ifndef CONFIG_I2C_POLLED
/* Restart ISR by setting an interrupt buffer bit */
stm32_i2c_modifyreg(priv,
STM32_I2C_CR2_OFFSET, 0, I2C_CR2_ITBUFEN);
#endif
}
}
/* Address cleared event
*
* Check if the address cleared, i.e. the driver found a valid address.
* If a NACK was received the address is invalid, if an ACK was
* received the address is valid and transmission can continue.
*/
/* Check for NACK after an address */
#ifndef CONFIG_I2C_POLLED
/* When polling the i2c ISR it's not possible to determine when
* an address has been ACKed(i.e. the address is valid).
*
* The mechanism to deal a NACKed address is to wait for the I2C
* call to timeout (value defined in defconfig by one of the
* following: CONFIG_STM32_I2C_DYNTIMEO, CONFIG_STM32_I2CTIMEOSEC,
* CONFIG_STM32_I2CTIMEOMS, CONFIG_STM32_I2CTIMEOTICKS).
*
* To be safe in the case of a timeout/NACKed address a stop bit
* is set on the bus to clear it. In POLLED operation it's done
* stm32_i2c_process() after the call to stm32_i2c_sem_waitdone().
*
* In ISR driven operation the stop bit in case of a NACKed address
* is set in the ISR itself.
*
* Note: this commentary is found in both places.
*/
else if ((status & I2C_SR1_ADDR) == 0 && priv->check_addr_ack)
{
i2cinfo("Invalid Address. Setting stop bit and clearing message\n");
i2cinfo("status %" PRIi32 "\n", status);
/* Set condition to terminate msg chain transmission as address is
* invalid.
*/
priv->dcnt = -1;
priv->msgc = 0;
i2cinfo("dcnt %i , msgc %i\n", priv->dcnt, priv->msgc);
/* Reset flag to check for valid address */
priv->check_addr_ack = false;
/* Send stop bit to clear bus */
stm32_i2c_sendstop(priv);
/* Trace event */
stm32_i2c_traceevent(priv, I2CEVENT_ADDRESS_NACKED, priv->msgv->addr);
}
#endif
/* ACK in read mode, ACK in write mode is handled separately */
else if ((priv->flags & I2C_M_READ) != 0 && (status & I2C_SR1_ADDR) != 0 &&
priv->check_addr_ack)
{
/* Reset check addr flag as we are handling this event */
priv->check_addr_ack = false;
/* Note:
*
* When reading a single byte the stop condition has to be set
* immediately after clearing the state flags, which happens
* when reading SR2(as SR1 has already been read).
*
* Similarly when reading 2 bytes the NACK bit has to be set as just
* after the clearing of the address.
*/
if (priv->dcnt == 1)
{
/* this should only happen when receiving a message of length 1 */
i2cinfo("short read N=1: setting NACK\n");
/* Set POS bit to zero (can be up from a previous 2 byte receive) */
stm32_i2c_modifyreg(priv, STM32_I2C_CR1_OFFSET, I2C_CR1_POS, 0);
/* Immediately set NACK */
stm32_i2c_modifyreg(priv, STM32_I2C_CR1_OFFSET, I2C_CR1_ACK, 0);
#ifndef CONFIG_I2C_POLLED
/* Enable RxNE and TxE buffers in order to receive one or multiple
* bytes
*/
stm32_i2c_modifyreg(priv,
STM32_I2C_CR2_OFFSET, 0, I2C_CR2_ITBUFEN);
#endif
/* Clear ADDR flag by reading SR2 and adding it to status */
status |= (stm32_i2c_getreg(priv, STM32_I2C_SR2_OFFSET) << 16);
/* Send Stop/Restart */
if (priv->msgc > 0)
{
stm32_i2c_sendstart(priv);
}
else
{
stm32_i2c_sendstop(priv);
}
i2cinfo("Address ACKed beginning data reception\n");
i2cinfo("short read N=1: programming stop bit\n");
/* Trace */
stm32_i2c_traceevent(priv, I2CEVENT_ADDRESS_ACKED_READ_1, 0);
}
else if (priv->dcnt == 2)
{
/* This should only happen when receiving a message of length 2 */
/* Set POS bit to zero (can be up from a previous 2 byte receive) */
stm32_i2c_modifyreg(priv, STM32_I2C_CR1_OFFSET, 0, I2C_CR1_POS);
/* Immediately set NACK */
stm32_i2c_modifyreg(priv, STM32_I2C_CR1_OFFSET, I2C_CR1_ACK, 0);
/* Clear ADDR flag by reading SR2 and adding it to status */
status |= (stm32_i2c_getreg(priv, STM32_I2C_SR2_OFFSET) << 16);
i2cinfo("Address ACKed beginning data reception\n");
i2cinfo("short read N=2: programming NACK\n");
/* Trace */
stm32_i2c_traceevent(priv, I2CEVENT_ADDRESS_ACKED_READ_2, 0);
}
else
{
i2cinfo("Address ACKed beginning data reception\n");
/* Clear ADDR flag by reading SR2 and adding it to status */
status |= (stm32_i2c_getreg(priv, STM32_I2C_SR2_OFFSET) << 16);
/* Trace */
stm32_i2c_traceevent(priv, I2CEVENT_ADDRESS_ACKED, 0);
#ifdef CONFIG_STM32_I2C_DMA
/* DMA only when not doing a short read */
i2cinfo("Starting dma transfer and disabling interrupts\n");
/* The DMA must be initialized and enabled before the I2C data
* transfer.
* The DMAEN bit must be set in the I2C_CR2 register before the
* ADDR event.
*/
stm32_dmasetup(priv->rxdma,
priv->config->base + STM32_I2C_DR_OFFSET,
(uint32_t)priv->ptr, priv->dcnt,
DMA_SCR_DIR_P2M |
DMA_SCR_MSIZE_8BITS |
DMA_SCR_PSIZE_8BITS |
DMA_SCR_MINC |
I2C_DMA_PRIO);
/* Do not enable the ITBUFEN bit in the I2C_CR2 register if DMA is
* used.
*/
stm32_i2c_modifyreg(priv,
STM32_I2C_CR2_OFFSET, I2C_CR2_ITBUFEN, 0);
#ifndef CONFIG_I2C_POLLED
/* Now let DMA do all the work, disable i2c interrupts */
regval = stm32_i2c_getreg(priv, STM32_I2C_CR2_OFFSET);
regval &= ~I2C_CR2_ALLINTS;
stm32_i2c_putreg(priv, STM32_I2C_CR2_OFFSET, regval);
#endif
/* The user can generate a Stop condition in the DMA Transfer
* Complete interrupt routine if enabled. This will be done in
* the dma rx callback Start DMA.
*/
stm32_dmastart(priv->rxdma, stm32_i2c_dmarxcallback, priv, false);
stm32_i2c_modifyreg(priv, STM32_I2C_CR2_OFFSET, 0, I2C_CR2_DMAEN);
#else
#ifndef CONFIG_I2C_POLLED
if (priv->dcnt > 3)
{
/* Don't enable I2C_CR2_ITBUFEN for messages longer than 3
* bytes
*/
stm32_i2c_modifyreg(priv,
STM32_I2C_CR2_OFFSET, 0, I2C_CR2_ITBUFEN);
}
#endif
#endif
}
}
/* Write mode
*
* Handles all write related I2C protocol logic. Also handles the
* ACK event after clearing the ADDR flag as the write has to
* begin immediately after.
*/
else if ((priv->flags & I2C_M_READ) == 0 &&
(status & I2C_SR1_BTF) != 0 &&
priv->dcnt == 0)
{
/* After last byte, check what to do based on next message flags */
if (priv->msgc == 0)
{
/* If last message send stop bit */
stm32_i2c_sendstop(priv);
i2cinfo("Stop sent dcnt = %i msgc = %i\n", priv->dcnt, priv->msgc);
/* Decrease counter to get to next message */
priv->dcnt--;
i2cinfo("dcnt %i\n", priv->dcnt);
stm32_i2c_traceevent(priv, I2CEVENT_WRITE_STOP, priv->dcnt);
}
/* If there is a next message with no flags or the read flag
* a restart sequence has to be sent.
* Note msgv already points to the next message.
*/
else if (priv->msgc > 0 &&
(priv->msgv->flags == 0 ||
(priv->msgv[0].flags & I2C_M_READ) != 0))
{
/* Send start */
stm32_i2c_sendstart(priv);
stm32_i2c_getreg(priv, STM32_I2C_DR_OFFSET);
i2cinfo("Restart detected!\n");
i2cinfo("Nextflag %i\n", priv->msgv[0].flags);
/* Decrease counter to get to next message */
priv->dcnt--;
i2cinfo("dcnt %i\n", priv->dcnt);
stm32_i2c_traceevent(priv, I2CEVENT_WRITE_RESTART, priv->dcnt);
}
else
{
i2cinfo("Write mode: next message has an unrecognized flag.\n");
stm32_i2c_traceevent(priv,
I2CEVENT_WRITE_FLAG_ERROR, priv->msgv->flags);
}
status |= (stm32_i2c_getreg(priv, STM32_I2C_SR2_OFFSET) << 16);
}
else if ((priv->flags & I2C_M_READ) == 0 &&
(status & (I2C_SR1_ADDR | I2C_SR1_TXE)) != 0 &&
priv->dcnt != 0)
{
/* The has cleared(ADDR is set, ACK was received after the address)
* or the transmit buffer is empty flag has been set(TxE) then we can
* transmit the next byte.
*/
i2cinfo("Entering write mode dcnt = %i msgc = %i\n",
priv->dcnt, priv->msgc);
/* Clear ADDR flag by reading SR2 and adding it to status */
status |= (stm32_i2c_getreg(priv, STM32_I2C_SR2_OFFSET) << 16);
/* Address has cleared so don't check on next call */
priv->check_addr_ack = false;
/* Check if we have transmitted the whole message or we are after
* the last byte where the stop condition or else(according to the
* msg flags) has to be set.
*/
#ifdef CONFIG_STM32_I2C_DMA
/* if DMA is enabled, only makes sense to make use of it for longer
* than 1 B transfers.
*/
if (priv->dcnt > 1)
{
i2cinfo("Starting DMA transfer and disabling interrupts\n");
/* The DMA must be initialized and enabled before the I2C data
* transfer. The DMAEN bit must be set in the I2C_CR2 register
* before the ADDR event.
*/
stm32_dmasetup(priv->txdma,
priv->config->base + STM32_I2C_DR_OFFSET,
(uint32_t) priv->ptr, priv->dcnt,
DMA_SCR_DIR_M2P |
DMA_SCR_MSIZE_8BITS |
DMA_SCR_PSIZE_8BITS |
DMA_SCR_MINC |
I2C_DMA_PRIO);
/* Do not enable the ITBUFEN bit in the I2C_CR2 register if DMA is
* used.
*/
stm32_i2c_modifyreg(priv,
STM32_I2C_CR2_OFFSET, I2C_CR2_ITBUFEN, 0);
#ifndef CONFIG_I2C_POLLED
/* Now let DMA do all the work, disable i2c interrupts */
regval = stm32_i2c_getreg(priv, STM32_I2C_CR2_OFFSET);
regval &= ~I2C_CR2_ALLINTS;
stm32_i2c_putreg(priv, STM32_I2C_CR2_OFFSET, regval);
#endif
/* In the interrupt routine after the EOT interrupt, disable DMA
* requests then wait for a BTF event before programming the Stop
* condition. To do this, we'll just call the ISR again in
* DMA tx callback, in which point we fall into the msgc==0 case
* which ultimately sends the stop..TODO: but we don't explicitly
* wait for BTF bit being set...
* Start DMA.
*/
stm32_i2c_modifyreg(priv, STM32_I2C_CR2_OFFSET, 0, I2C_CR2_DMAEN);
stm32_dmastart(priv->txdma, stm32_i2c_dmatxcallback, priv, false);
}
else
#endif /* CONFIG_STM32_I2C_DMA */
{
#ifndef CONFIG_I2C_POLLED
if (priv->dcnt == 1 &&
(priv->msgc == 0 || (priv->msgv->flags & I2C_M_NOSTART) == 0))
{
stm32_i2c_modifyreg(priv,
STM32_I2C_CR2_OFFSET, I2C_CR2_ITBUFEN, 0);
}
#endif
/* Transmitting message.
* Send byte == write data into write register
*/
stm32_i2c_putreg(priv, STM32_I2C_DR_OFFSET, *priv->ptr++);
/* Decrease current message length */
stm32_i2c_traceevent(priv, I2CEVENT_WRITE_TO_DR, priv->dcnt);
priv->dcnt--;
if ((status & I2C_SR1_ADDR) != 0 && priv->dcnt > 0)
{
/* Transmitting message.
* ADDR -> BTF & TXE - Send one more byte
*/
stm32_i2c_putreg(priv, STM32_I2C_DR_OFFSET, *priv->ptr++);
/* Decrease current message length */
stm32_i2c_traceevent(priv, I2CEVENT_WRITE_TO_DR, priv->dcnt);
priv->dcnt--;
}
#ifndef CONFIG_I2C_POLLED
if (((status & I2C_SR1_ADDR) != 0 && priv->dcnt > 0) ||
(priv->msgc > 0 && (priv->msgv->flags & I2C_M_NOSTART) != 0))
{
stm32_i2c_modifyreg(priv,
STM32_I2C_CR2_OFFSET, 0, I2C_CR2_ITBUFEN);
}
#endif
if (priv->dcnt == 0 &&
priv->msgc > 0 && (priv->msgv->flags & I2C_M_NOSTART) != 0)
{
/* Set condition to get to next message */
priv->dcnt = -1;
stm32_i2c_traceevent(priv,
I2CEVENT_WRITE_NO_RESTART, priv->dcnt);
}
}
}
/* Read mode
*
* Handles all read related I2C protocol logic.
*
* * * * * * * WARNING STM32F1xx HARDWARE ERRATA * * * * * * *
*
* source: https://github.com/hikob/openlab/blob/master/drivers/stm32/i2c.c
*
* RXNE-only events should not be handled since it sometimes
* fails. Only BTF & RXNE events should be handled (with the
* consequence of slowing down the transfer).
*
* It seems that when a RXNE interrupt is handled 'around'
* the end of the next byte reception, the DR register read
* is ignored by the i2c controller: it does not flush the
* DR with next byte
*
* Thus we read twice the same byte and we read effectively
* read one byte less than expected from the i2c slave point
* of view.
*
* Example:
* + we want to receive 6 bytes (B1 to B6)
* + the problem appear when reading B3
* -> we read B1 B2 B3 B3 B4 B5(B3 twice)
* -> the i2c transfer was B1 B2 B3 B4 B5(B6 is not sent)
*/
else if ((priv->flags & (I2C_M_READ)) != 0 &&
(status & (I2C_SR1_RXNE | I2C_SR1_BTF)) != 0)
{
/* When read flag is set and the receive buffer is not empty
* (RXNE is set) then the driver can read from the data register.
*/
status |= (stm32_i2c_getreg(priv, STM32_I2C_SR2_OFFSET) << 16);
i2cinfo("Entering read mode dcnt = %i msgc = %i, "
"status 0x%04" PRIx32 "\n",
priv->dcnt, priv->msgc, status);
/* Byte #N-3W, we don't want to manage RxNE interrupt anymore, bytes
* N, N-1, N-2 will be read with BTF:
*/
#ifndef CONFIG_I2C_POLLED
if (priv->dcnt < 5)
{
stm32_i2c_modifyreg(priv,
STM32_I2C_CR2_OFFSET, I2C_CR2_ITBUFEN, 0);
}
#else
if (priv->dcnt == 1 ||
priv->dcnt > 3 || (status & I2C_SR1_BTF) != 0)
#endif
{
/* BTF: N-2/N-1, set NACK, read N-2 */
if (priv->dcnt == 3)
{
stm32_i2c_modifyreg(priv,
STM32_I2C_CR1_OFFSET, I2C_CR1_ACK, 0);
}
/* BTF: N-1/N, STOP/START, read N-1, N */
else if (priv->dcnt == 2)
{
if (priv->msgc > 0)
{
stm32_i2c_sendstart(priv);
}
else
{
stm32_i2c_sendstop(priv);
}
/* Read byte #N-1 */
*priv->ptr++ = stm32_i2c_getreg(priv, STM32_I2C_DR_OFFSET);
priv->dcnt--;
}
/* Read last or current byte */
*priv->ptr++ = stm32_i2c_getreg(priv, STM32_I2C_DR_OFFSET);
priv->dcnt--;
if (priv->dcnt == 0)
{
priv->dcnt = -1;
}
}
}
/* Empty call handler
*
* Case to handle an empty call to the ISR where it only has to
* Shutdown
*/
else if (priv->dcnt == -1 && priv->msgc == 0)
{
/* Read rest of the state */
status |= (stm32_i2c_getreg(priv, STM32_I2C_SR2_OFFSET) << 16);
i2cinfo("Empty call to ISR: Stopping ISR\n");
stm32_i2c_traceevent(priv, I2CEVENT_ISR_EMPTY_CALL, 0);
}
/* Error handler
*
* Gets triggered if the driver does not recognize a situation(state)
* it can deal with.
* This should not happen in interrupt based operation(i.e. when
* CONFIG_I2C_POLLED is not set in the defconfig file).
* During polled operation(i.e. CONFIG_I2C_POLLED=y in defconfig)
* this case should do nothing but tracing the event that the
* device wasn't ready yet.
*/
else
{
#ifdef CONFIG_I2C_POLLED
stm32_i2c_traceevent(priv, I2CEVENT_POLL_DEV_NOT_RDY, 0);
#else
/* Read rest of the state */
status |= (stm32_i2c_getreg(priv, STM32_I2C_SR2_OFFSET) << 16);
/* No any error bit is set, but driver is in incorrect state, signal
* it with "Bus error" bit.
*/
if ((status & I2C_SR1_ERRORMASK) != 0)
{
priv->status |= I2C_SR1_BERR;
}
i2cinfo(" No correct state detected(start bit, read or write)\n");
i2cinfo(" state %" PRIi32 "\n", status);
/* Set condition to terminate ISR and wake waiting thread */
priv->dcnt = -1;
priv->msgc = 0;
stm32_i2c_traceevent(priv, I2CEVENT_STATE_ERROR, 0);
#endif
}
/* Messages handling(2/2)
*
* Transmission of the whole message chain has been completed. We have to
* terminate the ISR and wake up stm32_i2c_process() that is waiting for
* the ISR cycle to handle the sending/receiving of the messages.
*/
/* First check for errors */
if ((status & I2C_SR1_ERRORMASK) != 0)
{
stm32_i2c_traceevent(priv, I2CEVENT_ERROR, status & I2C_SR1_ERRORMASK);
/* Clear interrupt flags */
#if !defined(CONFIG_STM32_I2C_DMA) && !defined(CONFIG_I2C_POLLED)
state_error:
#endif
stm32_i2c_putreg(priv, STM32_I2C_SR1_OFFSET, 0);
priv->dcnt = -1;
priv->msgc = 0;
}
if (priv->dcnt == -1 && priv->msgc == 0)
{
i2cinfo("Shutting down I2C ISR\n");
stm32_i2c_traceevent(priv, I2CEVENT_ISR_SHUTDOWN, 0);
/* Clear internal pointer to the message content.
* Good practice + done by last implementation when messages are
* finished (compatibility concerns)
*/
priv->msgv = NULL;
#ifdef CONFIG_I2C_POLLED
priv->intstate = INTSTATE_DONE;
#else
/* Clear all interrupts */
regval = stm32_i2c_getreg(priv, STM32_I2C_CR2_OFFSET);
regval &= ~I2C_CR2_ALLINTS;
stm32_i2c_putreg(priv, STM32_I2C_CR2_OFFSET, regval);
/* Is there a thread waiting for this event(there should be) */
if (priv->intstate == INTSTATE_WAITING)
{
/* Yes.. inform the thread that the transfer is complete
* and wake it up.
*/
nxsem_post(&priv->sem_isr);
priv->intstate = INTSTATE_DONE;
}
#endif
}
return OK;
}