mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
cpu/stm32_common: various improvements in i2c_1 driver
- dont send stop if bus is busy and before any action is done on bus - and bus check that looks for bus error, arbitration and nack events - check for ACK (TXIS) before writing bytes on bus and not between each write
This commit is contained in:
parent
11356f602f
commit
5f1d5e0d83
@ -57,10 +57,11 @@
|
||||
/* static function definitions */
|
||||
static inline void _i2c_init(I2C_TypeDef *i2c, uint32_t timing);
|
||||
static inline int _start(I2C_TypeDef *dev, uint16_t address, size_t length,
|
||||
uint8_t rw_flag, uint8_t flags);
|
||||
uint8_t rw_flag, uint8_t flags);
|
||||
static inline int _read(I2C_TypeDef *dev, uint8_t *data, size_t length);
|
||||
static inline int _write(I2C_TypeDef *i2c, const uint8_t *data, size_t length);
|
||||
static inline int _stop(I2C_TypeDef *i2c);
|
||||
static inline int _check_bus(I2C_TypeDef *i2c);
|
||||
|
||||
/**
|
||||
* @brief Array holding one pre-initialized mutex for each I2C device
|
||||
@ -169,10 +170,11 @@ int i2c_read_bytes(i2c_t dev, uint16_t address, void *data,
|
||||
int ret = 0;
|
||||
|
||||
if (!(flags & I2C_NOSTART)) {
|
||||
DEBUG("[i2c] read_bytes: start transmission\n");
|
||||
DEBUG("[i2c] read_bytes: send start condition\n");
|
||||
/* start reception and send slave address */
|
||||
ret = _start(i2c, address, length, I2C_FLAG_READ, flags);
|
||||
if (ret < 0) {
|
||||
_stop(i2c);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
@ -181,6 +183,7 @@ int i2c_read_bytes(i2c_t dev, uint16_t address, void *data,
|
||||
/* read the data bytes */
|
||||
ret = _read(i2c, data, length);
|
||||
if (ret < 0) {
|
||||
_stop(i2c);
|
||||
DEBUG("[i2c] read_bytes: error while reading\n");
|
||||
return ret;
|
||||
}
|
||||
@ -212,20 +215,17 @@ int i2c_read_regs(i2c_t dev, uint16_t address, uint16_t reg, void *data,
|
||||
I2C_TypeDef *i2c = i2c_config[dev].dev;
|
||||
|
||||
/* Check to see if the bus is busy */
|
||||
while ((i2c->ISR & I2C_ISR_BUSY) && tick--) {
|
||||
if ((i2c->ISR & ERROR_FLAG) || !tick) {
|
||||
/* end transmission */
|
||||
_stop(i2c);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
while ((i2c->ISR & I2C_ISR_BUSY) && tick--) {}
|
||||
if ((i2c->ISR & ERROR_FLAG) || !tick) {
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
DEBUG("[i2c] read_regs: send start sequence\n");
|
||||
|
||||
if (!(flags & I2C_NOSTART)) {
|
||||
DEBUG("[i2c] read_regs: send start sequence\n");
|
||||
/* send start sequence and slave address */
|
||||
int ret = _start(i2c, address, 1, 0, flags);
|
||||
if (ret < 0) {
|
||||
_stop(i2c);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
@ -236,7 +236,7 @@ int i2c_read_regs(i2c_t dev, uint16_t address, uint16_t reg, void *data,
|
||||
if ((i2c->ISR & ERROR_FLAG) || !tick) {
|
||||
/* end transmission */
|
||||
_stop(i2c);
|
||||
return -ETIMEDOUT;
|
||||
return -ENXIO;
|
||||
}
|
||||
}
|
||||
|
||||
@ -266,14 +266,16 @@ int i2c_write_bytes(i2c_t dev, uint16_t address, const void *data,
|
||||
/* start transmission and send slave address */
|
||||
ret = _start(i2c, address, length, I2C_FLAG_WRITE, flags);
|
||||
if (ret < 0) {
|
||||
_stop(i2c);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG("[i2c] write_bytes: write the data\n");
|
||||
DEBUG("[i2c] write_bytes: write the data (%d bytes)\n", length);
|
||||
/* send out data bytes */
|
||||
ret = _write(i2c, data, length);
|
||||
if (ret < 0) {
|
||||
_stop(i2c);
|
||||
DEBUG("[i2c] write_bytes: nothing was written\n");
|
||||
return ret;
|
||||
}
|
||||
@ -305,10 +307,9 @@ int i2c_write_regs(i2c_t dev, uint16_t address, uint16_t reg, const void *data,
|
||||
}
|
||||
|
||||
/* Check to see if the bus is busy */
|
||||
while ((i2c->ISR & I2C_ISR_BUSY) && tick--) {
|
||||
if ((i2c->ISR & ERROR_FLAG) || !tick) {
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
while ((i2c->ISR & I2C_ISR_BUSY) && tick--) {}
|
||||
if ((i2c->ISR & ERROR_FLAG) || !tick) {
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
if (!(flags & I2C_NOSTART)) {
|
||||
@ -316,6 +317,7 @@ int i2c_write_regs(i2c_t dev, uint16_t address, uint16_t reg, const void *data,
|
||||
/* increase length because our data is register+data */
|
||||
ret = _start(i2c, address, length + 1, I2C_FLAG_WRITE, flags);
|
||||
if (ret < 0) {
|
||||
_stop(i2c);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
@ -327,6 +329,7 @@ int i2c_write_regs(i2c_t dev, uint16_t address, uint16_t reg, const void *data,
|
||||
/* write out data bytes */
|
||||
ret = _write(i2c, data, length);
|
||||
if (ret < 0) {
|
||||
_stop(i2c);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -342,7 +345,7 @@ int i2c_write_regs(i2c_t dev, uint16_t address, uint16_t reg, const void *data,
|
||||
}
|
||||
|
||||
static inline int _start(I2C_TypeDef *i2c, uint16_t address,
|
||||
size_t length, uint8_t rw_flag, uint8_t flags)
|
||||
size_t length, uint8_t rw_flag, uint8_t flags)
|
||||
{
|
||||
/* 10 bit address not supported for now */
|
||||
if (flags & I2C_ADDR10) {
|
||||
@ -351,8 +354,6 @@ static inline int _start(I2C_TypeDef *i2c, uint16_t address,
|
||||
|
||||
assert(i2c != NULL);
|
||||
|
||||
uint16_t tick = TICK_TIMEOUT;
|
||||
|
||||
i2c->CR2 = 0;
|
||||
|
||||
DEBUG("[i2c] start: set address mode\n");
|
||||
@ -385,10 +386,15 @@ static inline int _start(I2C_TypeDef *i2c, uint16_t address,
|
||||
i2c->CR2 |= I2C_CR2_START;
|
||||
|
||||
/* Wait for the start followed by the address to be sent */
|
||||
while (!(i2c->CR2 & I2C_CR2_START) && tick--) {
|
||||
if (!tick) {
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
uint16_t tick = TICK_TIMEOUT;
|
||||
while (!(i2c->CR2 & I2C_CR2_START) && tick--) {}
|
||||
if (!tick) {
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
int ret = _check_bus(i2c);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -402,10 +408,9 @@ static inline int _read(I2C_TypeDef *i2c, uint8_t *data, size_t length)
|
||||
/* wait for transfer to finish */
|
||||
DEBUG("[i2c] read: Waiting for DR to be full\n");
|
||||
uint16_t tick = TICK_TIMEOUT;
|
||||
while (!(i2c->ISR & I2C_ISR_RXNE) && tick--) {
|
||||
if (i2c->ISR & ERROR_FLAG || !tick) {
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
while (!(i2c->ISR & I2C_ISR_RXNE) && tick--) {}
|
||||
if (i2c->ISR & ERROR_FLAG || !tick) {
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
DEBUG("[i2c] read: DR is now full\n");
|
||||
@ -415,6 +420,11 @@ static inline int _read(I2C_TypeDef *i2c, uint8_t *data, size_t length)
|
||||
DEBUG("[i2c] read: Read byte %i from DR\n", i);
|
||||
}
|
||||
|
||||
int ret = _check_bus(i2c);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -426,16 +436,28 @@ static inline int _write(I2C_TypeDef *i2c, const uint8_t *data, size_t length)
|
||||
/* wait for ack */
|
||||
DEBUG("[i2c] write: Waiting for ACK\n");
|
||||
uint16_t tick = TICK_TIMEOUT;
|
||||
while (!(i2c->ISR & I2C_ISR_TXIS) && tick--) {
|
||||
if (i2c->ISR & ERROR_FLAG || !tick) {
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
while (!(i2c->ISR & I2C_ISR_TXIS) && tick--) {}
|
||||
if (i2c->ISR & ERROR_FLAG || !tick) {
|
||||
DEBUG("[i2c] write: TXIS timeout\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
/* write data to data register */
|
||||
DEBUG("[i2c] write: Write byte %i to DR\n", i);
|
||||
DEBUG("[i2c] write: Write byte %02X to DR\n", data[i]);
|
||||
i2c->TXDR = data[i];
|
||||
DEBUG("[i2c] write: Sending data\n");
|
||||
|
||||
int ret = _check_bus(i2c);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG("[i2c] write: Waiting for write to complete\n");
|
||||
uint16_t tick = TICK_TIMEOUT;
|
||||
while (!(i2c->ISR & I2C_ISR_TC) && tick--) {}
|
||||
if (i2c->ISR & ERROR_FLAG || !tick) {
|
||||
DEBUG("[i2c] write: write didn't complete\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -449,19 +471,53 @@ static inline int _stop(I2C_TypeDef *i2c)
|
||||
|
||||
/* make sure transfer is complete */
|
||||
DEBUG("[i2c] stop: Wait for transfer to be complete\n");
|
||||
while (!(i2c->ISR & I2C_ISR_TC) && tick--) {
|
||||
if (i2c->ISR & ERROR_FLAG || !tick) {
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
while (!(i2c->ISR & I2C_ISR_TC) && tick--) {}
|
||||
if (i2c->ISR & ERROR_FLAG || !tick) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* send STOP condition */
|
||||
DEBUG("[i2c] stop: Generate stop condition\n");
|
||||
i2c->CR2 |= I2C_CR2_STOP;
|
||||
|
||||
/* Wait for the stop to complete */
|
||||
tick = TICK_TIMEOUT;
|
||||
while (!(i2c->CR2 & I2C_CR2_STOP) && tick--) {}
|
||||
if (!tick) {
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int _check_bus(I2C_TypeDef *i2c)
|
||||
{
|
||||
assert(i2c != NULL);
|
||||
|
||||
int ret = 0;
|
||||
|
||||
/* wait a bit for any potential error to arrive */
|
||||
uint16_t tick = TICK_TIMEOUT;
|
||||
while (tick--) {}
|
||||
|
||||
if (i2c->ISR & I2C_ISR_NACKF) {
|
||||
DEBUG("[i2c] check_bus: NACK received\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
if (i2c->ISR & I2C_ISR_ARLO) {
|
||||
DEBUG("[i2c] check_bus: arbitration lost\n");
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
if (i2c->ISR & I2C_ISR_BERR) {
|
||||
DEBUG("[i2c] check_bus: bus error\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void irq_handler(i2c_t dev)
|
||||
{
|
||||
assert(dev < I2C_NUMOF);
|
||||
|
Loading…
Reference in New Issue
Block a user