aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTimofey Titovets <nefelim4ag@gmail.com>2025-07-11 00:38:21 +0200
committerKevinOConnor <kevin@koconnor.net>2025-07-17 19:36:01 -0400
commit4e4a5c633652978c2ea6e1cabac2a2f5568e5366 (patch)
treee8c631b08ad35b4f28382dbb6e3a490ff4a3edf2
parent9323a5dfe28619a53c7f350c2e894d299c342bca (diff)
downloadkutter-4e4a5c633652978c2ea6e1cabac2a2f5568e5366.tar.gz
kutter-4e4a5c633652978c2ea6e1cabac2a2f5568e5366.tar.xz
kutter-4e4a5c633652978c2ea6e1cabac2a2f5568e5366.zip
stm32: make i2c distinguish I2C NACKs
Signed-off-by: Timofey Titovets <nefelim4ag@gmail.com>
-rw-r--r--src/stm32/i2c.c60
1 files changed, 38 insertions, 22 deletions
diff --git a/src/stm32/i2c.c b/src/stm32/i2c.c
index ccdf4fdc..7ecbcd6d 100644
--- a/src/stm32/i2c.c
+++ b/src/stm32/i2c.c
@@ -94,21 +94,21 @@ i2c_setup(uint32_t bus, uint32_t rate, uint8_t addr)
return (struct i2c_config){ .i2c=i2c, .addr=addr<<1 };
}
-static uint32_t
+static int
i2c_wait(I2C_TypeDef *i2c, uint32_t set, uint32_t clear, uint32_t timeout)
{
for (;;) {
uint32_t sr1 = i2c->SR1;
if ((sr1 & set) == set && (sr1 & clear) == 0)
- return sr1;
+ return I2C_BUS_SUCCESS;
if (sr1 & I2C_SR1_AF)
- shutdown("I2C NACK error encountered");
+ return I2C_BUS_NACK;
if (!timer_is_before(timer_read_time(), timeout))
- shutdown("i2c timeout");
+ return I2C_BUS_TIMEOUT;
}
}
-static void
+static int
i2c_start(I2C_TypeDef *i2c, uint8_t addr, uint8_t xfer_len,
uint32_t timeout)
{
@@ -117,7 +117,7 @@ i2c_start(I2C_TypeDef *i2c, uint8_t addr, uint8_t xfer_len,
i2c->DR = addr;
if (addr & 0x01)
i2c->CR1 |= I2C_CR1_ACK;
- i2c_wait(i2c, I2C_SR1_ADDR, 0, timeout);
+ int ret = i2c_wait(i2c, I2C_SR1_ADDR, 0, timeout);
irqstatus_t flag = irq_save();
uint32_t sr2 = i2c->SR2;
if (addr & 0x01 && xfer_len == 1)
@@ -125,13 +125,14 @@ i2c_start(I2C_TypeDef *i2c, uint8_t addr, uint8_t xfer_len,
irq_restore(flag);
if (!(sr2 & I2C_SR2_MSL))
shutdown("Failed to send i2c addr");
+ return ret;
}
-static void
+static int
i2c_send_byte(I2C_TypeDef *i2c, uint8_t b, uint32_t timeout)
{
i2c->DR = b;
- i2c_wait(i2c, I2C_SR1_TXE, 0, timeout);
+ return i2c_wait(i2c, I2C_SR1_TXE, 0, timeout);
}
static uint8_t
@@ -146,11 +147,11 @@ i2c_read_byte(I2C_TypeDef *i2c, uint32_t timeout, uint8_t remaining)
return b;
}
-static void
+static int
i2c_stop(I2C_TypeDef *i2c, uint32_t timeout)
{
i2c->CR1 = I2C_CR1_STOP | I2C_CR1_PE;
- i2c_wait(i2c, 0, I2C_SR1_TXE, timeout);
+ return i2c_wait(i2c, 0, I2C_SR1_TXE, timeout);
}
int
@@ -159,12 +160,16 @@ i2c_write(struct i2c_config config, uint8_t write_len, uint8_t *write)
I2C_TypeDef *i2c = config.i2c;
uint32_t timeout = timer_read_time() + timer_from_us(5000);
- i2c_start(i2c, config.addr, write_len, timeout);
- while (write_len--)
- i2c_send_byte(i2c, *write++, timeout);
- i2c_stop(i2c, timeout);
+ int ret = i2c_start(i2c, config.addr, write_len, timeout);
+ if (ret == I2C_BUS_NACK)
+ ret = I2C_BUS_START_NACK;
+ while (write_len-- && ret == I2C_BUS_SUCCESS)
+ ret = i2c_send_byte(i2c, *write++, timeout);
+ int timeout_err = i2c_stop(i2c, timeout);
- return I2C_BUS_SUCCESS;
+ if (ret == I2C_BUS_SUCCESS && timeout_err != I2C_BUS_SUCCESS)
+ ret = timeout_err;
+ return ret;
}
int
@@ -174,20 +179,31 @@ i2c_read(struct i2c_config config, uint8_t reg_len, uint8_t *reg
I2C_TypeDef *i2c = config.i2c;
uint32_t timeout = timer_read_time() + timer_from_us(5000);
uint8_t addr = config.addr | 0x01;
+ int ret;
if (reg_len) {
// write the register
- i2c_start(i2c, config.addr, reg_len, timeout);
- while(reg_len--)
- i2c_send_byte(i2c, *reg++, timeout);
+ ret = i2c_start(i2c, config.addr, reg_len, timeout);
+ if (ret == I2C_BUS_NACK)
+ ret = I2C_BUS_START_NACK;
+ while(reg_len-- && ret == I2C_BUS_SUCCESS)
+ ret = i2c_send_byte(i2c, *reg++, timeout);
+ if (ret != I2C_BUS_SUCCESS)
+ goto abrt;
}
// start/re-start and read data
- i2c_start(i2c, addr, read_len, timeout);
+ ret = i2c_start(i2c, addr, read_len, timeout);
+ if (ret == I2C_BUS_NACK)
+ ret = I2C_BUS_START_READ_NACK;
+ if (ret != I2C_BUS_SUCCESS)
+ goto abrt;
while(read_len--) {
*read = i2c_read_byte(i2c, timeout, read_len);
read++;
}
- i2c_wait(i2c, 0, I2C_SR1_RXNE, timeout);
-
- return I2C_BUS_SUCCESS;
+ // covers read timeout
+ return i2c_wait(i2c, 0, I2C_SR1_RXNE, timeout);
+abrt:
+ i2c_stop(i2c, timeout);
+ return ret;
}