I2C: don't block on reset

when resetting the GPIO lines are toggles.
when this is not effective it used to block.
not it just warns the used it failed.
This commit is contained in:
King Kévin 2019-03-26 18:05:15 +01:00
parent 396c7852e7
commit ef4685a9a3
2 changed files with 12 additions and 8 deletions

View File

@ -252,34 +252,37 @@ bool i2c_master_check_signals(uint32_t i2c)
return to_return;
}
void i2c_master_reset(uint32_t i2c)
bool i2c_master_reset(uint32_t i2c)
{
// check I2C peripheral
if (I2C1!=i2c && I2C2!=i2c) {
while (true);
}
bool to_return = true;
// follow procedure described in STM32F10xxC/D/E Errata sheet, Section 2.14.7
i2c_peripheral_disable(i2c); // disable i2c peripheral
gpio_set_mode(GPIO_PORT_SCL(i2c), GPIO_MODE_OUTPUT_10_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, GPIO_PIN_SCL(i2c)); // put I2C I/O pins to general output
gpio_set(GPIO_PORT_SCL(i2c), GPIO_PIN_SCL(i2c)); // set high
while (!gpio_get(GPIO_PORT_SCL(i2c), GPIO_PIN_SCL(i2c))); // ensure it is high
to_return &= !gpio_get(GPIO_PORT_SCL(i2c), GPIO_PIN_SCL(i2c)); // ensure it is high
gpio_set_mode(GPIO_PORT_SDA(i2c), GPIO_MODE_OUTPUT_10_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, GPIO_PIN_SDA(i2c)); // put I2C I/O pins to general output
gpio_set(GPIO_PORT_SDA(i2c), GPIO_PIN_SDA(i2c)); // set high
while (!gpio_get(GPIO_PORT_SDA(i2c), GPIO_PIN_SDA(i2c))); // ensure it is high
to_return &= !gpio_get(GPIO_PORT_SDA(i2c), GPIO_PIN_SDA(i2c)); // ensure it is high
gpio_clear(GPIO_PORT_SDA(i2c), GPIO_PIN_SDA(i2c)); // set low (try first transition)
while (gpio_get(GPIO_PORT_SDA(i2c), GPIO_PIN_SDA(i2c))); // ensure it is low
to_return &= gpio_get(GPIO_PORT_SDA(i2c), GPIO_PIN_SDA(i2c)); // ensure it is low
gpio_clear(GPIO_PORT_SCL(i2c), GPIO_PIN_SCL(i2c)); // set low (try first transition)
while (gpio_get(GPIO_PORT_SCL(i2c), GPIO_PIN_SCL(i2c))); // ensure it is low
to_return &= gpio_get(GPIO_PORT_SCL(i2c), GPIO_PIN_SCL(i2c)); // ensure it is low
gpio_set(GPIO_PORT_SCL(i2c), GPIO_PIN_SCL(i2c)); // set high (try second transition)
while (!gpio_get(GPIO_PORT_SCL(i2c), GPIO_PIN_SCL(i2c))); // ensure it is high
to_return &= !gpio_get(GPIO_PORT_SCL(i2c), GPIO_PIN_SCL(i2c)); // ensure it is high
gpio_set(GPIO_PORT_SDA(i2c), GPIO_PIN_SDA(i2c)); // set high (try second transition)
while (!gpio_get(GPIO_PORT_SDA(i2c), GPIO_PIN_SDA(i2c))); // ensure it is high
to_return &= !gpio_get(GPIO_PORT_SDA(i2c), GPIO_PIN_SDA(i2c)); // ensure it is high
gpio_set_mode(GPIO_PORT_SCL(i2c), GPIO_MODE_OUTPUT_10_MHZ, GPIO_CNF_OUTPUT_ALTFN_OPENDRAIN, GPIO_PIN_SCL(i2c)); // set I2C I/O pins back
gpio_set_mode(GPIO_PORT_SDA(i2c), GPIO_MODE_OUTPUT_10_MHZ, GPIO_CNF_OUTPUT_ALTFN_OPENDRAIN, GPIO_PIN_SDA(i2c)); // set I2C I/O pins back
I2C_CR1(i2c) |= I2C_CR1_SWRST; // reset device
I2C_CR1(i2c) &= ~I2C_CR1_SWRST; // reset device
i2c_peripheral_enable(i2c); // re-enable device
return to_return;
}
enum i2c_master_rc i2c_master_start(uint32_t i2c)

View File

@ -46,8 +46,9 @@ void i2c_master_release(uint32_t i2c);
* @warning the I2C peripheral needs to be re-setup
* @note to be used after failed start or stop, and bus error
* @param[in] i2c I2C base address
* return true if complete reset is successful, false if the lines could not be set
*/
void i2c_master_reset(uint32_t i2c);
bool i2c_master_reset(uint32_t i2c);
/** check if SDA and SCL signals are high
* @param[in] i2c I2C base address
* @return SDA and SCL signals are high