From 72b3ab8b2973d0b7d2917086b0e74bc38de933ed Mon Sep 17 00:00:00 2001 From: Arksine Date: Sat, 2 May 2020 17:52:24 -0400 Subject: [PATCH] stm32: add support for i2c read Signed-off-by: Eric Callahan --- src/stm32/i2c.c | 42 +++++++++++++++++++++++++++++++++++++++--- 1 file 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); }