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:
parent
e737b65a33
commit
660670bb6c
|
@ -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){;}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue