I2C. Merge patch from ahaczewski.

git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@4497 35acf78f-673a-0410-8e92-d51de3d6d3f4
This commit is contained in:
barthess 2012-08-02 18:30:22 +00:00
parent e737b65a33
commit 660670bb6c
1 changed files with 16 additions and 3 deletions

View File

@ -290,6 +290,9 @@ static void i2c_lld_set_opmode(I2CDriver *i2cp) {
* @details Important but implicit destination of this function is * @details Important but implicit destination of this function is
* clearing interrupts flags. * clearing interrupts flags.
* @note Internal use only. * @note Internal use only.
* @note Function reads SR2 <b>before</b> SR1. This is workaround, not a bug.
* ADDR was not cleared and it was possible to clear ADDR after
* transfer is properly setup (enabled DMA stream).
* *
* @param[in] i2cp pointer to the @p I2CDriver object * @param[in] i2cp pointer to the @p I2CDriver object
* *
@ -297,8 +300,8 @@ static void i2c_lld_set_opmode(I2CDriver *i2cp) {
*/ */
static uint32_t i2c_get_event(I2CDriver *i2cp) { static uint32_t i2c_get_event(I2CDriver *i2cp) {
I2C_TypeDef *dp = i2cp->i2c; I2C_TypeDef *dp = i2cp->i2c;
uint16_t regSR1 = dp->SR1;
uint16_t regSR2 = dp->SR2; uint16_t regSR2 = dp->SR2;
uint16_t regSR1 = dp->SR1;
#if CH_DBG_ENABLE_ASSERTS #if CH_DBG_ENABLE_ASSERTS
dbgSR1 = regSR1; dbgSR1 = regSR1;
@ -319,15 +322,21 @@ static uint32_t i2c_get_event(I2CDriver *i2cp) {
*/ */
static void i2c_lld_serve_event_interrupt(I2CDriver *i2cp) { static void i2c_lld_serve_event_interrupt(I2CDriver *i2cp) {
I2C_TypeDef *dp = i2cp->i2c; I2C_TypeDef *dp = i2cp->i2c;
uint32_t event = i2c_get_event(i2cp);
uint32_t rxlen = dmaStreamGetTransactionSize(i2cp->dmarx);
/* Interrupts are disabled just before dmaStreamEnable() because there /* Interrupts are disabled just before dmaStreamEnable() because there
is no need of interrupts until next transaction begin. All the work is is no need of interrupts until next transaction begin. All the work is
done by the DMA.*/ done by the DMA.*/
switch (i2c_get_event(i2cp)) { switch (event) {
case I2C_EV5_MASTER_MODE_SELECT: case I2C_EV5_MASTER_MODE_SELECT:
dp->DR = i2cp->addr; dp->DR = i2cp->addr;
break; break;
case I2C_EV6_MASTER_REC_MODE_SELECTED: case I2C_EV6_MASTER_REC_MODE_SELECTED:
if (rxlen <= 2)
dp->CR1 &= ~I2C_CR1_ACK;
if (rxlen == 2)
dp->CR1 |= I2C_CR1_POS;
dp->CR2 &= ~I2C_CR2_ITEVTEN; dp->CR2 &= ~I2C_CR2_ITEVTEN;
dmaStreamEnable(i2cp->dmarx); dmaStreamEnable(i2cp->dmarx);
dp->CR2 |= I2C_CR2_LAST; /* Needed in receiver mode. */ dp->CR2 |= I2C_CR2_LAST; /* Needed in receiver mode. */
@ -338,7 +347,7 @@ static void i2c_lld_serve_event_interrupt(I2CDriver *i2cp) {
break; break;
case I2C_EV8_2_MASTER_BYTE_TRANSMITTED: case I2C_EV8_2_MASTER_BYTE_TRANSMITTED:
/* Catches BTF event after the end of transmission.*/ /* Catches BTF event after the end of transmission.*/
if (dmaStreamGetTransactionSize(i2cp->dmarx) > 0) { if (rxlen > 0) {
/* Starts "read after write" operation, LSB = 1 -> receive.*/ /* Starts "read after write" operation, LSB = 1 -> receive.*/
i2cp->addr |= 0x01; i2cp->addr |= 0x01;
dp->CR1 |= I2C_CR1_START | I2C_CR1_ACK; dp->CR1 |= I2C_CR1_START | I2C_CR1_ACK;
@ -351,6 +360,10 @@ static void i2c_lld_serve_event_interrupt(I2CDriver *i2cp) {
default: default:
break; break;
} }
/* Clear ADDR flag. Last part of workaround
(see comments to i2c_get_event() function). */
if (event & (I2C_SR1_ADDR | I2C_SR1_ADD10))
if (dp->SR2){;}
} }
/** /**