Merge pull request #7864 from Marc-Aurele/i2c_timeout_l0

cpu/stm32l0: implement i2C non blocking mode
This commit is contained in:
Alexandre Abadie 2017-11-09 14:50:13 +01:00 committed by GitHub
commit 283c207c55
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -31,8 +31,15 @@
#include "periph_conf.h" #include "periph_conf.h"
#define ENABLE_DEBUG (0) #define ENABLE_DEBUG (0)
#define TICK_TIMEOUT (0xFFFF)
#include "debug.h" #include "debug.h"
#define CLEAR_FLAG(dev) dev->ICR |= I2C_ICR_NACKCF | \
I2C_ICR_ARLOCF | \
I2C_ICR_BERRCF
#define ERROR_FLAG (I2C_ISR_NACKF | I2C_ISR_ARLO | I2C_ISR_BERR)
/* guard file in case no I2C device is defined */ /* guard file in case no I2C device is defined */
#if I2C_NUMOF #if I2C_NUMOF
@ -41,8 +48,8 @@ static void _i2c_init(I2C_TypeDef *i2c, uint32_t presc, uint32_t scll,
uint32_t sclh, uint32_t sdadel, uint32_t scldel, uint32_t sclh, uint32_t sdadel, uint32_t scldel,
uint32_t timing); uint32_t timing);
static void _start(I2C_TypeDef *dev, uint8_t address, uint8_t length, uint8_t rw_flag); static void _start(I2C_TypeDef *dev, uint8_t address, uint8_t length, uint8_t rw_flag);
static inline void _read(I2C_TypeDef *dev, uint8_t *data, int length); static inline int _read(I2C_TypeDef *dev, uint8_t *data, int length);
static inline void _write(I2C_TypeDef *i2c, const uint8_t *data, int length); static inline int _write(I2C_TypeDef *i2c, const uint8_t *data, int length);
static inline void _stop(I2C_TypeDef *i2c); static inline void _stop(I2C_TypeDef *i2c);
/** /**
@ -187,6 +194,8 @@ static void _i2c_init(I2C_TypeDef *i2c, uint32_t presc, uint32_t scll,
/* configure clock stretching */ /* configure clock stretching */
i2c->CR1 &= ~(I2C_CR1_NOSTRETCH); i2c->CR1 &= ~(I2C_CR1_NOSTRETCH);
CLEAR_FLAG(i2c);
/* enable device */ /* enable device */
i2c->CR1 |= I2C_CR1_PE; i2c->CR1 |= I2C_CR1_PE;
} }
@ -243,7 +252,9 @@ int i2c_read_bytes(i2c_t dev, uint8_t address, void *data, int length)
_start(i2c, address, length, I2C_FLAG_READ); _start(i2c, address, length, I2C_FLAG_READ);
/* read the data bytes */ /* read the data bytes */
_read(i2c, data, length); if (_read(i2c, data, length) < 0) {
length = 0;
}
/* end transmission */ /* end transmission */
_stop(i2c); _stop(i2c);
@ -258,6 +269,7 @@ int i2c_read_reg(i2c_t dev, uint8_t address, uint8_t reg, void *data)
int i2c_read_regs(i2c_t dev, uint8_t address, uint8_t reg, void *data, int length) int i2c_read_regs(i2c_t dev, uint8_t address, uint8_t reg, void *data, int length)
{ {
uint16_t tick = TICK_TIMEOUT;
I2C_TypeDef *i2c; I2C_TypeDef *i2c;
switch (dev) { switch (dev) {
@ -282,14 +294,27 @@ int i2c_read_regs(i2c_t dev, uint8_t address, uint8_t reg, void *data, int lengt
} }
/* Check to see if the bus is busy */ /* Check to see if the bus is busy */
while((i2c->ISR & I2C_ISR_BUSY) == I2C_ISR_BUSY) {} while ((i2c->ISR & I2C_ISR_BUSY) && tick--) {
if ((i2c->ISR & ERROR_FLAG) || !tick) {
/* end transmission */
_stop(i2c);
return -1;
}
}
/* send start sequence and slave address */ /* send start sequence and slave address */
_start(i2c, address, 1, I2C_FLAG_WRITE); _start(i2c, address, 1, I2C_FLAG_WRITE);
tick = TICK_TIMEOUT;
/* wait for ack */ /* wait for ack */
DEBUG("Waiting for ACK\n"); DEBUG("Waiting for ACK\n");
while (!(i2c->ISR & I2C_ISR_TXIS)) {} while (!(i2c->ISR & I2C_ISR_TXIS) && tick--) {
if ((i2c->ISR & ERROR_FLAG) || !tick) {
/* end transmission */
_stop(i2c);
return -1;
}
}
DEBUG("Write register to read\n"); DEBUG("Write register to read\n");
i2c->TXDR = reg; i2c->TXDR = reg;
@ -333,7 +358,9 @@ int i2c_write_bytes(i2c_t dev, uint8_t address, const void *data, int length)
_start(i2c, address, length, I2C_FLAG_WRITE); _start(i2c, address, length, I2C_FLAG_WRITE);
/* send out data bytes */ /* send out data bytes */
_write(i2c, data, length); if (_write(i2c, data, length) < 0) {
length = 0;
}
/* end transmission */ /* end transmission */
_stop(i2c); _stop(i2c);
@ -348,6 +375,7 @@ int i2c_write_reg(i2c_t dev, uint8_t address, uint8_t reg, uint8_t data)
int i2c_write_regs(i2c_t dev, uint8_t address, uint8_t reg, const void *data, int length) int i2c_write_regs(i2c_t dev, uint8_t address, uint8_t reg, const void *data, int length)
{ {
uint16_t tick = TICK_TIMEOUT;
I2C_TypeDef *i2c; I2C_TypeDef *i2c;
switch (dev) { switch (dev) {
@ -372,7 +400,11 @@ int i2c_write_regs(i2c_t dev, uint8_t address, uint8_t reg, const void *data, in
} }
/* Check to see if the bus is busy */ /* Check to see if the bus is busy */
while((i2c->ISR & I2C_ISR_BUSY) == I2C_ISR_BUSY); while ((i2c->ISR & I2C_ISR_BUSY) & tick--) {
if ((i2c->ISR & ERROR_FLAG) || !tick) {
return -1;
}
}
/* start transmission and send slave address */ /* start transmission and send slave address */
/* increase length because our data is register+data */ /* increase length because our data is register+data */
@ -383,7 +415,9 @@ int i2c_write_regs(i2c_t dev, uint8_t address, uint8_t reg, const void *data, in
i2c->TXDR = reg; i2c->TXDR = reg;
/* write out data bytes */ /* write out data bytes */
_write(i2c, data, length); if (_write(i2c, data, length) < 0) {
length = 0;
}
/* end transmission */ /* end transmission */
_stop(i2c); _stop(i2c);
@ -460,6 +494,8 @@ static void _start(I2C_TypeDef *dev, uint8_t address, uint8_t length, uint8_t rw
/* configure autoend configuration */ /* configure autoend configuration */
dev->CR2 &= ~(I2C_CR2_AUTOEND); dev->CR2 &= ~(I2C_CR2_AUTOEND);
CLEAR_FLAG(dev);
/* generate start condition */ /* generate start condition */
DEBUG("Generate start condition\n"); DEBUG("Generate start condition\n");
dev->CR2 |= I2C_CR2_START; dev->CR2 |= I2C_CR2_START;
@ -468,43 +504,65 @@ static void _start(I2C_TypeDef *dev, uint8_t address, uint8_t length, uint8_t rw
while (!(dev->CR2 & I2C_CR2_START)) {} while (!(dev->CR2 & I2C_CR2_START)) {}
} }
static inline void _read(I2C_TypeDef *dev, uint8_t *data, int length) static inline int _read(I2C_TypeDef *dev, uint8_t *data, int length)
{ {
uint16_t tick = TICK_TIMEOUT;
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
/* wait for transfer to finish */ /* wait for transfer to finish */
DEBUG("Waiting for DR to be full\n"); DEBUG("Waiting for DR to be full\n");
while (!(dev->ISR & I2C_ISR_RXNE)) {} while (!(dev->ISR & I2C_ISR_RXNE) && tick--) {
if (dev->ISR & ERROR_FLAG || !tick) {
return -1;
}
}
DEBUG("DR is now full\n"); DEBUG("DR is now full\n");
/* read data from data register */ /* read data from data register */
data[i] = dev->RXDR; data[i] = dev->RXDR;
DEBUG("Read byte %i from DR\n", i); DEBUG("Read byte %i from DR\n", i);
} }
return 0;
} }
static inline void _write(I2C_TypeDef *dev, const uint8_t *data, int length) static inline int _write(I2C_TypeDef *dev, const uint8_t *data, int length)
{ {
uint16_t tick = TICK_TIMEOUT;
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
/* wait for ack */ /* wait for ack */
DEBUG("Waiting for ACK\n"); DEBUG("Waiting for ACK\n");
while (!(dev->ISR & I2C_ISR_TXIS)) {} while (!(dev->ISR & I2C_ISR_TXIS) && tick--) {
if (dev->ISR & ERROR_FLAG || !tick) {
return -1;
}
}
/* write data to data register */ /* write data to data register */
DEBUG("Write byte %i to DR\n", i); DEBUG("Write byte %i to DR\n", i);
dev->TXDR = data[i]; dev->TXDR = data[i];
DEBUG("Sending data\n"); DEBUG("Sending data\n");
} }
return 0;
} }
static inline void _stop(I2C_TypeDef *dev) static inline void _stop(I2C_TypeDef *dev)
{ {
uint16_t tick = TICK_TIMEOUT;
/* make sure transfer is complete */ /* make sure transfer is complete */
DEBUG("Wait for transfer to be complete\n"); DEBUG("Wait for transfer to be complete\n");
while (!(dev->ISR & I2C_ISR_TC)) {} while (!(dev->ISR & I2C_ISR_TC) && tick--) {
if (dev->ISR & ERROR_FLAG || !tick) {
break;
}
}
/* send STOP condition */ /* send STOP condition */
DEBUG("Generate stop condition\n"); DEBUG("Generate stop condition\n");
dev->CR2 |= I2C_CR2_STOP; dev->CR2 |= I2C_CR2_STOP;
} }
#endif /* I2C_NUMOF */ #endif /* I2C_NUMOF */