aboutsummaryrefslogtreecommitdiffstats
path: root/src/stm32/i2c.c
diff options
context:
space:
mode:
authorArksine <arksine.code@gmail.com>2020-05-02 17:52:24 -0400
committerKevinOConnor <kevin@koconnor.net>2020-05-05 11:44:19 -0400
commit72b3ab8b2973d0b7d2917086b0e74bc38de933ed (patch)
tree5cb3594e7f87484e7004b78442dcd66d779d81cc /src/stm32/i2c.c
parent2d4b52026034c74e395b2825541097e41f304b07 (diff)
downloadkutter-72b3ab8b2973d0b7d2917086b0e74bc38de933ed.tar.gz
kutter-72b3ab8b2973d0b7d2917086b0e74bc38de933ed.tar.xz
kutter-72b3ab8b2973d0b7d2917086b0e74bc38de933ed.zip
stm32: add support for i2c read
Signed-off-by: Eric Callahan <arksine.code@gmail.com>
Diffstat (limited to 'src/stm32/i2c.c')
-rw-r--r--src/stm32/i2c.c42
1 files changed, 39 insertions, 3 deletions
diff --git a/src/stm32/i2c.c b/src/stm32/i2c.c
index d4ab6a46..72e3d251 100644
--- a/src/stm32/i2c.c
+++ b/src/stm32/i2c.c
@@ -10,6 +10,7 @@
#include "gpio.h" // i2c_setup
#include "internal.h" // GPIO
#include "sched.h" // sched_shutdown
+#include "board/irq.h" //irq_disable
struct i2c_info {
I2C_TypeDef *i2c;
@@ -81,13 +82,20 @@ i2c_wait(I2C_TypeDef *i2c, uint32_t set, uint32_t clear, uint32_t timeout)
}
static void
-i2c_start(I2C_TypeDef *i2c, uint8_t addr, uint32_t timeout)
+i2c_start(I2C_TypeDef *i2c, uint8_t addr, uint8_t xfer_len,
+ uint32_t timeout)
{
i2c->CR1 = I2C_CR1_START | I2C_CR1_PE;
i2c_wait(i2c, I2C_SR1_SB, 0, timeout);
i2c->DR = addr;
+ if (addr & 0x01)
+ i2c->CR1 |= I2C_CR1_ACK;
i2c_wait(i2c, I2C_SR1_ADDR, 0, timeout);
+ irqstatus_t flag = irq_save();
uint32_t sr2 = i2c->SR2;
+ if (addr & 0x01 && xfer_len == 1)
+ i2c->CR1 = I2C_CR1_STOP | I2C_CR1_PE;
+ irq_restore(flag);
if (!(sr2 & I2C_SR2_MSL))
shutdown("Failed to send i2c addr");
}
@@ -99,6 +107,18 @@ i2c_send_byte(I2C_TypeDef *i2c, uint8_t b, uint32_t timeout)
i2c_wait(i2c, I2C_SR1_TXE, 0, timeout);
}
+static uint8_t
+i2c_read_byte(I2C_TypeDef *i2c, uint32_t timeout, uint8_t remaining)
+{
+ i2c_wait(i2c, I2C_SR1_RXNE, 0, timeout);
+ irqstatus_t flag = irq_save();
+ uint8_t b = i2c->DR;
+ if (remaining == 1)
+ i2c->CR1 = I2C_CR1_STOP | I2C_CR1_PE;
+ irq_restore(flag);
+ return b;
+}
+
static void
i2c_stop(I2C_TypeDef *i2c, uint32_t timeout)
{
@@ -112,7 +132,7 @@ 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, timeout);
+ i2c_start(i2c, config.addr, write_len, timeout);
while (write_len--)
i2c_send_byte(i2c, *write++, timeout);
i2c_stop(i2c, timeout);
@@ -122,5 +142,21 @@ void
i2c_read(struct i2c_config config, uint8_t reg_len, uint8_t *reg
, uint8_t read_len, uint8_t *read)
{
- shutdown("i2c_read not supported on stm32");
+ I2C_TypeDef *i2c = config.i2c;
+ uint32_t timeout = timer_read_time() + timer_from_us(5000);
+ uint8_t addr = config.addr | 0x01;
+
+ if (reg_len) {
+ // write the register
+ i2c_start(i2c, config.addr, reg_len, timeout);
+ while(reg_len--)
+ i2c_send_byte(i2c, *reg++, timeout);
+ }
+ // start/re-start and read data
+ i2c_start(i2c, addr, read_len, timeout);
+ while(read_len--) {
+ *read = i2c_read_byte(i2c, timeout, read_len);
+ read++;
+ }
+ i2c_wait(i2c, 0, I2C_SR1_RXNE, timeout);
}