I needed to use DS3231, I remember that in past it worked ok, but now for stm32f4xx is used another driver (chip specific, stm32f40xxx_i2c.c) and DS3231 driver doesn't work. After investigating a problem I found that I2C driver (isr routine) has a few places there it sends stop bit even if not all messages are managed. So, e.g., removing stm32_i2c_sendstop (#1744) and adding stm32_i2c_sendstart after data reading helps to make DS3231 working. Verified by David Sidrane.

This commit is contained in:
Alexander Oryshchenko 2017-03-24 06:43:40 -06:00 committed by Gregory Nutt
parent 809588b254
commit 61ff3c6b84
1 changed files with 46 additions and 10 deletions

View File

@ -1261,6 +1261,15 @@ static int stm32_i2c_isr(struct stm32_i2c_priv_s *priv)
priv->status = status;
/* Any new message should begin with "Start" condition
* Situation priv->msgc == 0 came from DMA RX handler and should be managed
*/
if (priv->dcnt == -1 && priv->msgc != 0 && (status & I2C_SR1_SB) == 0)
{
return OK;
}
/* Check if this is a new transmission so to set up the
* trace table accordingly.
*/
@ -1516,9 +1525,16 @@ static int stm32_i2c_isr(struct stm32_i2c_priv_s *priv)
status |= (stm32_i2c_getreg(priv, STM32_I2C_SR2_OFFSET) << 16);
/* Send Stop */
/* Send Stop/Restart */
stm32_i2c_sendstop(priv);
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");
@ -1828,7 +1844,17 @@ static int stm32_i2c_isr(struct stm32_i2c_priv_s *priv)
{
i2cinfo("short read N=2: DR and SR full setting stop bit and reading twice\n");
stm32_i2c_sendstop(priv);
/* Send Stop/Restart */
if (priv->msgc > 0)
{
stm32_i2c_sendstart(priv);
}
else
{
stm32_i2c_sendstop(priv);
}
*priv->ptr++ = stm32_i2c_getreg(priv, STM32_I2C_DR_OFFSET);
priv->dcnt--;
*priv->ptr++ = stm32_i2c_getreg(priv, STM32_I2C_DR_OFFSET);
@ -1905,9 +1931,16 @@ static int stm32_i2c_isr(struct stm32_i2c_priv_s *priv)
stm32_i2c_traceevent(priv, I2CEVENT_READ_3, priv->dcnt);
/* Program stop */
/* Program Stop/Restart */
stm32_i2c_sendstop(priv);
if (priv->msgc > 0)
{
stm32_i2c_sendstart(priv);
}
else
{
stm32_i2c_sendstop(priv);
}
/* read dcnt = 2 */
@ -2061,7 +2094,14 @@ static void stm32_i2c_dmarxcallback(DMA_HANDLE handle, uint8_t status, void *arg
* interrupt routine if enabled.
*/
stm32_i2c_sendstop(priv);
if (priv->msgc > 0)
{
stm32_i2c_sendstart(priv);
}
else
{
stm32_i2c_sendstop(priv);
}
/* Let the I2C periph know to stop DMA transfers, also is used by ISR to check
* if DMA is done.
@ -2115,10 +2155,6 @@ static void stm32_i2c_dmatxcallback(DMA_HANDLE handle, uint8_t status, void *arg
regval |= (I2C_CR2_ITERREN | I2C_CR2_ITEVFEN);
stm32_i2c_putreg(priv, STM32_I2C_CR2_OFFSET, regval);
#endif
/* let the ISR routine take care of shutting down or switching to next msg */
stm32_i2c_isr(priv);
}
#endif /* ifdef CONFIG_STM32_I2C_DMA */