diff options
author | Damien George <damien.p.george@gmail.com> | 2019-08-16 13:34:04 +1000 |
---|---|---|
committer | Damien George <damien.p.george@gmail.com> | 2019-08-16 13:34:04 +1000 |
commit | 3eff81288cb494c7d1a9fcf0a82d4e21bbd92dd8 (patch) | |
tree | af030ea191e19d8e226f40ebf70e0042b3fb7567 | |
parent | eb7eed5d920748f8222efbd16bfb24c3d1798e83 (diff) |
stm32/i2c: Fix generation of restart condition for hw I2C on F0/F7.
Before this patch I2C transactions using a hardware I2C peripheral on F0/F7
MCUs would not correctly generate the I2C restart condition, and instead
would generate a stop followed by a start. This is because the CR2 AUTOEND
bit was being set before CR2 START when the peripheral already had the I2C
bus from a previous transaction that did not generate a stop.
As a consequence all combined transactions, eg read-then-write for an I2C
memory transfer, generated a stop condition after the first transaction and
didn't generate a stop at the very end (but still released the bus). Some
I2C devices require a repeated start to function correctly.
This patch fixes this by making sure the CR2 AUTOEND bit is set after the
start condition and slave address have been fully transferred out.
-rw-r--r-- | ports/stm32/i2c.c | 8 |
1 files changed, 6 insertions, 2 deletions
diff --git a/ports/stm32/i2c.c b/ports/stm32/i2c.c index 06e26d912..5981df11c 100644 --- a/ports/stm32/i2c.c +++ b/ports/stm32/i2c.c @@ -340,8 +340,7 @@ STATIC int i2c_wait_isr_set(i2c_t *i2c, uint32_t mask) { int i2c_start_addr(i2c_t *i2c, int rd_wrn, uint16_t addr, size_t len, bool stop) { // Enable the peripheral and send the START condition with slave address i2c->CR1 |= I2C_CR1_PE; - i2c->CR2 = stop << I2C_CR2_AUTOEND_Pos - | (len > 1) << I2C_CR2_RELOAD_Pos + i2c->CR2 = (len > 1) << I2C_CR2_RELOAD_Pos | (len > 0) << I2C_CR2_NBYTES_Pos | rd_wrn << I2C_CR2_RD_WRN_Pos | (addr & 0x7f) << 1; @@ -361,6 +360,11 @@ int i2c_start_addr(i2c_t *i2c, int rd_wrn, uint16_t addr, size_t len, bool stop) return -MP_ENODEV; } + // Configure automatic STOP if needed + if (stop) { + i2c->CR2 |= I2C_CR2_AUTOEND; + } + // Repurpose OAR1 to indicate that we loaded CR2 i2c->OAR1 = 1; |