1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

Merge pull request #5927 from keestux/sam21_i2c_wait_for_response

sam21_common:i2c refactor a function to wait for response
This commit is contained in:
Peter Kietzmann 2017-01-19 09:23:03 +01:00 committed by GitHub
commit 224e4f50a7

View File

@ -44,10 +44,11 @@
static void _i2c_poweron(SercomI2cm *sercom);
static void _i2c_poweroff(SercomI2cm *sercom);
static inline int _start(SercomI2cm *dev, uint8_t address, uint8_t rw_flag);
static int _start(SercomI2cm *dev, uint8_t address, uint8_t rw_flag);
static inline int _write(SercomI2cm *dev, const uint8_t *data, int length);
static inline int _read(SercomI2cm *dev, uint8_t *data, int length);
static inline void _stop(SercomI2cm *dev);
static inline int _wait_for_response(SercomI2cm *dev, uint32_t max_timeout_counter);
/**
* @brief Array holding one pre-initialized mutex for each I2C device
@ -224,9 +225,13 @@ int i2c_read_bytes(i2c_t dev, uint8_t address, void *data, int length)
}
/* start transmission and send slave address */
if(_start(i2c, address, I2C_FLAG_READ) < 0) return 0;
if (_start(i2c, address, I2C_FLAG_READ) < 0) {
return 0;
}
/* read data to register */
if(_read(i2c, data, length) < 0) return 0;
if (_read(i2c, data, length) < 0) {
return 0;
}
_stop(i2c);
/* return number of bytes sent */
return length;
@ -252,10 +257,14 @@ int i2c_read_regs(i2c_t dev, uint8_t address, uint8_t reg, void *data, int lengt
}
/* start transmission and send slave address */
if (_start(i2c, address, I2C_FLAG_WRITE) < 0) return 0;
if (_start(i2c, address, I2C_FLAG_WRITE) < 0) {
return 0;
}
/* send register address/command and wait for complete transfer to
* be finished */
if (_write(i2c, &reg, 1) < 0) return 0;
if (_write(i2c, &reg, 1) < 0) {
return 0;
}
return i2c_read_bytes(dev, address, data, length);
}
@ -278,8 +287,12 @@ int i2c_write_bytes(i2c_t dev, uint8_t address, const void *data, int length)
return -1;
}
if(_start(I2CSercom, address, I2C_FLAG_WRITE) < 0) return 0;
if(_write(I2CSercom, data, length) < 0) return 0;
if (_start(I2CSercom, address, I2C_FLAG_WRITE) < 0) {
return 0;
}
if (_write(I2CSercom, data, length) < 0) {
return 0;
}
_stop(I2CSercom);
return length;
}
@ -305,11 +318,17 @@ int i2c_write_regs(i2c_t dev, uint8_t address, uint8_t reg, const void *data, in
}
/* start transmission and send slave address */
if (_start(i2c, address, I2C_FLAG_WRITE) < 0) return 0;
if (_start(i2c, address, I2C_FLAG_WRITE) < 0) {
return 0;
}
/* send register address and wait for complete transfer to be finished */
if (_write(i2c, &reg, 1) < 0) return 0;
if (_write(i2c, &reg, 1) < 0) {
return 0;
}
/* write data to register */
if (_write(i2c, data, length) < 0) return 0;
if (_write(i2c, data, length) < 0) {
return 0;
}
/* finish transfer */
_stop(i2c);
return length;
@ -361,8 +380,6 @@ void i2c_poweroff(i2c_t dev)
static int _start(SercomI2cm *dev, uint8_t address, uint8_t rw_flag)
{
uint32_t timeout_counter = 0;
/* Wait for hardware module to sync */
DEBUG("Wait for device to be ready\n");
while (dev->SYNCBUSY.reg & SERCOM_I2CM_SYNCBUSY_MASK) {}
@ -375,12 +392,14 @@ static int _start(SercomI2cm *dev, uint8_t address, uint8_t rw_flag)
dev->ADDR.reg = (address << 1) | rw_flag | (0 << SERCOM_I2CM_ADDR_HS_Pos);
/* Wait for response on bus. */
while (!(dev->INTFLAG.reg & SERCOM_I2CM_INTFLAG_MB)
&& !(dev->INTFLAG.reg & SERCOM_I2CM_INTFLAG_SB)) {
if (++timeout_counter >= SAMD21_I2C_TIMEOUT) {
DEBUG("STATUS_ERR_TIMEOUT\n");
if (rw_flag == I2C_FLAG_READ) {
/* Some devices (e.g. SHT2x) can hold the bus while preparing the reply */
if (_wait_for_response(dev, 100 * SAMD21_I2C_TIMEOUT) < 0)
return -1;
}
else {
if (_wait_for_response(dev, SAMD21_I2C_TIMEOUT) < 0)
return -1;
}
/* Check for address response error unless previous error is detected. */
@ -408,7 +427,6 @@ static int _start(SercomI2cm *dev, uint8_t address, uint8_t rw_flag)
static inline int _write(SercomI2cm *dev, const uint8_t *data, int length)
{
uint16_t tmp_data_length = length;
uint32_t timeout_counter = 0;
uint16_t buffer_counter = 0;
/* Write data buffer until the end. */
@ -426,15 +444,9 @@ static inline int _write(SercomI2cm *dev, const uint8_t *data, int length)
DEBUG("Written byte #%i to data reg, now waiting for DR to be empty again\n", buffer_counter);
dev->DATA.reg = data[buffer_counter++];
DEBUG("Wait for response.\n");
timeout_counter = 0;
while (!(dev->INTFLAG.reg & SERCOM_I2CM_INTFLAG_MB)
&& !(dev->INTFLAG.reg & SERCOM_I2CM_INTFLAG_SB)) {
if (++timeout_counter >= SAMD21_I2C_TIMEOUT) {
DEBUG("STATUS_ERR_TIMEOUT\n");
/* Wait for response on bus. */
if (_wait_for_response(dev, SAMD21_I2C_TIMEOUT) < 0)
return -1;
}
}
/* Check for NACK from slave. */
if (dev->STATUS.reg & SERCOM_I2CM_STATUS_RXNACK) {
@ -447,7 +459,6 @@ static inline int _write(SercomI2cm *dev, const uint8_t *data, int length)
static inline int _read(SercomI2cm *dev, uint8_t *data, int length)
{
uint32_t timeout_counter = 0;
uint8_t count = 0;
/* Set action to ack. */
@ -466,15 +477,10 @@ static inline int _read(SercomI2cm *dev, uint8_t *data, int length)
/* Save data to buffer. */
data[count] = dev->DATA.reg;
/* Wait for response. */
timeout_counter = 0;
while (!(dev->INTFLAG.reg & SERCOM_I2CM_INTFLAG_MB)
&& !(dev->INTFLAG.reg & SERCOM_I2CM_INTFLAG_SB)) {
if (++timeout_counter >= SAMD21_I2C_TIMEOUT) {
DEBUG("STATUS_ERR_TIMEOUT\n");
/* Wait for response on bus. */
if (_wait_for_response(dev, SAMD21_I2C_TIMEOUT) < 0)
return -1;
}
}
count++;
}
/* Send NACK before STOP */
@ -493,4 +499,18 @@ static inline void _stop(SercomI2cm *dev)
DEBUG("Stop sent\n");
}
static inline int _wait_for_response(SercomI2cm *dev, uint32_t max_timeout_counter)
{
uint32_t timeout_counter = 0;
DEBUG("Wait for response.\n");
while (!(dev->INTFLAG.reg & SERCOM_I2CM_INTFLAG_MB)
&& !(dev->INTFLAG.reg & SERCOM_I2CM_INTFLAG_SB)) {
if (++timeout_counter >= max_timeout_counter) {
DEBUG("STATUS_ERR_TIMEOUT\n");
return -1;
}
}
return 0;
}
#endif /* I2C_NUMOF */