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:
commit
d660888150
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user