aboutsummaryrefslogtreecommitdiff
path: root/ports
diff options
context:
space:
mode:
authorDamien George2019-08-16 13:34:04 +1000
committerDamien George2019-08-16 13:34:04 +1000
commit3eff81288cb494c7d1a9fcf0a82d4e21bbd92dd8 (patch)
treeaf030ea191e19d8e226f40ebf70e0042b3fb7567 /ports
parenteb7eed5d920748f8222efbd16bfb24c3d1798e83 (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.
Diffstat (limited to 'ports')
-rw-r--r--ports/stm32/i2c.c8
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;