1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2025-01-18 12:52:44 +01:00

Merge pull request #11082 from OTAkeys/pr/stm32_i2c_2_restart_error

cpu/stm32_common/i2c_2: reset i2c when timeout during start condition
This commit is contained in:
Kevin "Bear Puncher" Weiss 2019-03-25 13:20:11 +01:00 committed by GitHub
commit d660888150
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -59,12 +59,14 @@
#define ERROR_FLAG (I2C_SR1_AF | I2C_SR1_ARLO | I2C_SR1_BERR)
/* static function definitions */
static void _init(i2c_t dev);
static void _i2c_init(I2C_TypeDef *i2c, uint32_t clk, uint32_t ccr);
static int _start(I2C_TypeDef *dev, uint8_t address_byte, uint8_t flags,
size_t length);
static int _stop(I2C_TypeDef *dev);
static int _is_sr1_mask_set(I2C_TypeDef *i2c, uint32_t mask, uint8_t flags);
static inline int _wait_for_bus(I2C_TypeDef *i2c);
static void _init_pins(i2c_t dev);
/**
* @brief Array holding one pre-initialized mutex for each I2C device
@ -81,31 +83,33 @@ void i2c_init(i2c_t dev)
assert(i2c != NULL);
uint32_t ccr;
/* read speed configuration */
switch (i2c_config[dev].speed) {
case I2C_SPEED_LOW:
/* 10Kbit/s */
ccr = i2c_config[dev].clk / 20000;
break;
case I2C_SPEED_NORMAL:
/* 100Kbit/s */
ccr = i2c_config[dev].clk / 200000;
break;
case I2C_SPEED_FAST:
ccr = i2c_config[dev].clk / 800000;
break;
default:
return;
}
periph_clk_en(i2c_config[dev].bus, i2c_config[dev].rcc_mask);
NVIC_SetPriority(i2c_config[dev].irqn, I2C_IRQ_PRIO);
NVIC_EnableIRQ(i2c_config[dev].irqn);
_init(dev);
#if defined(CPU_FAM_STM32F4)
/* make sure the analog filters don't hang -> see errata sheet 2.14.7 */
if (i2c->SR2 & I2C_SR2_BUSY) {
/* disable peripheral */
i2c->CR1 &= ~I2C_CR1_PE;
/* toggle both pins to reset analog filter */
gpio_init(i2c_config[dev].scl_pin, GPIO_OD);
gpio_init(i2c_config[dev].sda_pin, GPIO_OD);
gpio_set(i2c_config[dev].sda_pin);
gpio_set(i2c_config[dev].scl_pin);
gpio_clear(i2c_config[dev].sda_pin);
gpio_clear(i2c_config[dev].scl_pin);
gpio_set(i2c_config[dev].sda_pin);
gpio_set(i2c_config[dev].scl_pin);
_init(dev);
}
#endif
}
static void _init_pins(i2c_t dev)
{
/* configure pins */
gpio_init(i2c_config[dev].scl_pin, GPIO_OD_PU);
gpio_init(i2c_config[dev].sda_pin, GPIO_OD_PU);
@ -124,36 +128,6 @@ void i2c_init(i2c_t dev)
gpio_init_af(i2c_config[dev].scl_pin, i2c_config[dev].scl_af);
gpio_init_af(i2c_config[dev].sda_pin, i2c_config[dev].sda_af);
#endif
/* configure device */
_i2c_init(i2c, i2c_config[dev].clk, ccr);
#if defined(CPU_FAM_STM32F4)
/* make sure the analog filters don't hang -> see errata sheet 2.14.7 */
if (i2c->SR2 & I2C_SR2_BUSY) {
/* disable peripheral */
i2c->CR1 &= ~I2C_CR1_PE;
/* toggle both pins to reset analog filter */
gpio_init(i2c_config[dev].scl_pin, GPIO_OD);
gpio_init(i2c_config[dev].sda_pin, GPIO_OD);
gpio_set(i2c_config[dev].sda_pin);
gpio_set(i2c_config[dev].scl_pin);
gpio_clear(i2c_config[dev].sda_pin);
gpio_clear(i2c_config[dev].scl_pin);
gpio_set(i2c_config[dev].sda_pin);
gpio_set(i2c_config[dev].scl_pin);
/* reset pins for alternate function */
gpio_init(i2c_config[dev].scl_pin, GPIO_OD_PU);
gpio_init(i2c_config[dev].sda_pin, GPIO_OD_PU);
gpio_init_af(i2c_config[dev].scl_pin, i2c_config[dev].scl_af);
gpio_init_af(i2c_config[dev].sda_pin, i2c_config[dev].sda_af);
/* make peripheral soft reset */
i2c->CR1 |= I2C_CR1_SWRST;
i2c->CR1 &= ~I2C_CR1_SWRST;
/* enable device */
_i2c_init(i2c, i2c_config[dev].clk, ccr);
}
#endif
}
static void _i2c_init(I2C_TypeDef *i2c, uint32_t clk, uint32_t ccr)
@ -174,6 +148,39 @@ static void _i2c_init(I2C_TypeDef *i2c, uint32_t clk, uint32_t ccr)
i2c->CR1 |= I2C_CR1_PE;
}
static void _init(i2c_t dev)
{
I2C_TypeDef *i2c = i2c_config[dev].dev;
uint32_t ccr = 0;
/* read speed configuration */
switch (i2c_config[dev].speed) {
case I2C_SPEED_LOW:
/* 10Kbit/s */
ccr = i2c_config[dev].clk / 20000;
break;
case I2C_SPEED_NORMAL:
/* 100Kbit/s */
ccr = i2c_config[dev].clk / 200000;
break;
case I2C_SPEED_FAST:
ccr = i2c_config[dev].clk / 800000;
break;
}
/* make peripheral soft reset */
i2c->CR1 |= I2C_CR1_SWRST;
_init_pins(dev);
i2c->CR1 &= ~I2C_CR1_SWRST;
/* configure device */
_i2c_init(i2c, i2c_config[dev].clk, ccr);
}
int i2c_acquire(i2c_t dev)
{
assert(dev < I2C_NUMOF);
@ -215,6 +222,9 @@ int i2c_read_bytes(i2c_t dev, uint16_t address, void *data, size_t length,
int ret = _start(i2c, (address << 1) | I2C_FLAG_READ, flags, length);
if (ret < 0) {
if (ret == -ETIMEDOUT) {
_init(dev);
}
return ret;
}
@ -260,6 +270,9 @@ int i2c_write_bytes(i2c_t dev, uint16_t address, const void *data,
/* Length is 0 in start since we don't need to preset the stop bit */
ret = _start(i2c, (address << 1) | I2C_FLAG_WRITE, flags, 0);
if (ret < 0) {
if (ret == -ETIMEDOUT) {
_init(dev);
}
return ret;
}