diff options
Diffstat (limited to 'nuttx/arch/arm')
-rw-r--r-- | nuttx/arch/arm/src/stm32/Kconfig | 4 | ||||
-rw-r--r-- | nuttx/arch/arm/src/stm32/stm32_i2c.c | 115 |
2 files changed, 117 insertions, 2 deletions
diff --git a/nuttx/arch/arm/src/stm32/Kconfig b/nuttx/arch/arm/src/stm32/Kconfig index 8b0cea32e..a0f9a4892 100644 --- a/nuttx/arch/arm/src/stm32/Kconfig +++ b/nuttx/arch/arm/src/stm32/Kconfig @@ -1623,12 +1623,12 @@ config STM32_I2C_DYNTIMEO config STM32_I2C_DYNTIMEO_USECPERBYTE int "Timeout Microseconds per Byte" - default 0 + default 500 depends on STM32_I2C_DYNTIMEO config STM32_I2C_DYNTIMEO_STARTSTOP int "Timeout for Start/Stop (Milliseconds)" - default 5000 + default 1000 depends on STM32_I2C_DYNTIMEO config STM32_I2CTIMEOSEC diff --git a/nuttx/arch/arm/src/stm32/stm32_i2c.c b/nuttx/arch/arm/src/stm32/stm32_i2c.c index 2d1c365cd..12a036f80 100644 --- a/nuttx/arch/arm/src/stm32/stm32_i2c.c +++ b/nuttx/arch/arm/src/stm32/stm32_i2c.c @@ -1967,4 +1967,119 @@ int up_i2cuninitialize(FAR struct i2c_dev_s * dev) return OK; } +/************************************************************************************ + * Name: up_i2creset + * + * Description: + * Reset an I2C bus + * + ************************************************************************************/ + +#ifdef CONFIG_I2C_RESET +int up_i2creset(FAR struct i2c_dev_s * dev) +{ + struct stm32_i2c_priv_s * priv; + unsigned int clock_count; + unsigned int stretch_count; + unit32_ scl_gpio; + unit32_ sda_gpio; + int ret = ERROR; + irqstate_t state; + + ASSERT(dev); + + /* Get I2C private structure */ + + priv = ((struct stm32_i2c_inst_s *)dev)->priv; + + /* Our caller must own a ref */ + + ASSERT(priv->refs > 0); + + /* Lock out other clients */ + + stm32_i2c_sem_wait(dev); + + /* De-init the port */ + + stm32_i2c_deinit(priv); + + /* Use GPIO configuration to un-wedge the bus */ + + scl_gpio = MKI2C_OUTPUT(priv->config->scl_pin); + sda_gpio = MKI2C_OUTPUT(priv->config->sda_pin); + + /* Clock the bus until any slaves currently driving it let it go. */ + + clock_count = 0; + while (!stm32_gpioread(sda_gpio)) + { + /* Give up if we have tried too hard */ + + if (clock_count++ > 1000) + { + goto out; + } + + /* Sniff to make sure that clock stretching has finished. + * + * If the bus never relaxes, the reset has failed. + */ + + stretch_count = 0; + while (!stm32_gpioread(scl_gpio)) + { + /* Give up if we have tried too hard */ + + if (stretch_count++ > 1000) + { + goto out; + } + + up_udelay(10); + } + + /* Drive SCL low */ + + stm32_gpiowrite(scl_gpio, 0); + up_udelay(10); + + /* Drive SCL high again */ + + stm32_gpiowrite(scl_gpio, 1); + up_udelay(10); + } + + /* Generate a start followed by a stop to reset slave + * state machines. + */ + + stm32_gpiowrite(sda_gpio, 0); + up_udelay(10); + stm32_gpiowrite(scl_gpio, 0); + up_udelay(10); + stm32_gpiowrite(scl_gpio, 1); + up_udelay(10); + stm32_gpiowrite(sda_gpio, 1); + up_udelay(10); + + /* Revert the GPIO configuration. */ + + stm32_unconfiggpio(sda_gpio); + stm32_unconfiggpio(scl_gpio); + + /* Re-init the port */ + + stm32_i2c_init(priv); + ret = OK; + +out: + + /* Release the port for re-use by other clients */ + + stm32_i2c_sem_post(dev); + return ret; +} +#endif /* CONFIG_I2C_RESET */ + #endif /* CONFIG_STM32_I2C1 || CONFIG_STM32_I2C2 || CONFIG_STM32_I2C3 */ |