STM32: I2C: Update Timeout computation

The timeout values are based on for loops and therefore should depend
on the core frequency and the I2C interface frequency.

This patch introduces this computation and base the timeout on the time
it should take to send a byte over the I2C interface. When sending a
number of bytes, this value can also be used.

In the loops, the timeout should also be decreased before the while
condition so that its value is 0 in case the timeout elapsed and this
can be treated as an error.
pull/3238/head
Laurent MEUNIER 2016-10-20 13:43:52 +02:00
parent 79504a6a38
commit 42d89b0665
1 changed files with 39 additions and 20 deletions

View File

@ -29,6 +29,7 @@
*/
#include "mbed_assert.h"
#include "i2c_api.h"
#include "platform/wait_api.h"
#if DEVICE_I2C
@ -41,6 +42,18 @@
not remain stuck if the I2C communication is corrupted. */
#define FLAG_TIMEOUT ((int)0x1000)
#define LONG_TIMEOUT ((int)0x8000)
/* Timeout values are based on core clock and I2C clock.
The BYTE_TIMEOUT is computed as twice the number of cycles it would
take to send 10 bits over I2C. Most Flags should take less than that.
This is for immediate FLAG or ACK check.
*/
#define BYTE_TIMEOUT ((SystemCoreClock / handle->Init.ClockSpeed) * 2 * 10)
/* Timeout values based on I2C clock.
The BYTE_TIMEOUT_US is computed as 3x the time in us it would
take to send 10 bits over I2C. Most Flags should take less than that.
This is for complete transfers check.
*/
#define BYTE_TIMEOUT_US ((SystemCoreClock / handle->Init.ClockSpeed) * 3 * 10)
#if DEVICE_I2C_ASYNCH
#define I2C_S(obj) (struct i2c_s *) (&((obj)->i2c))
@ -266,8 +279,8 @@ void i2c_frequency(i2c_t *obj, int hz)
MBED_ASSERT((hz > 0) && (hz <= 400000));
// wait before init
timeout = LONG_TIMEOUT;
while ((__HAL_I2C_GET_FLAG(handle, I2C_FLAG_BUSY)) && (timeout-- != 0));
timeout = BYTE_TIMEOUT;
while ((__HAL_I2C_GET_FLAG(handle, I2C_FLAG_BUSY)) && (--timeout != 0));
// I2C configuration
handle->Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
@ -307,7 +320,7 @@ inline int i2c_start(i2c_t *obj) {
// Wait the STOP condition has been previously correctly sent
// This timeout can be avoid in some specific cases by simply clearing the STOP bit
timeout = FLAG_TIMEOUT;
timeout = BYTE_TIMEOUT;
while ((handle->Instance->CR1 & I2C_CR1_STOP) == I2C_CR1_STOP) {
if ((timeout--) == 0) {
return 1;
@ -318,7 +331,7 @@ inline int i2c_start(i2c_t *obj) {
handle->Instance->CR1 |= I2C_CR1_START;
// Wait the START condition has been correctly sent
timeout = FLAG_TIMEOUT;
timeout = BYTE_TIMEOUT;
while (__HAL_I2C_GET_FLAG(handle, I2C_FLAG_SB) == RESET) {
if ((timeout--) == 0) {
return 1;
@ -448,7 +461,7 @@ int i2c_byte_read(i2c_t *obj, int last) {
}
// Wait until the byte is received
timeout = FLAG_TIMEOUT;
timeout = BYTE_TIMEOUT;
while (__HAL_I2C_GET_FLAG(handle, I2C_FLAG_RXNE) == RESET) {
if ((timeout--) == 0) {
return -1;
@ -467,7 +480,7 @@ int i2c_byte_write(i2c_t *obj, int data) {
handle->Instance->DR = (uint8_t)data;
// Wait until the byte (might be the address) is transmitted
timeout = FLAG_TIMEOUT;
timeout = BYTE_TIMEOUT;
while ((__HAL_I2C_GET_FLAG(handle, I2C_FLAG_TXE) == RESET) &&
(__HAL_I2C_GET_FLAG(handle, I2C_FLAG_BTF) == RESET) &&
(__HAL_I2C_GET_FLAG(handle, I2C_FLAG_ADDR) == RESET)) {
@ -493,8 +506,8 @@ void i2c_reset(i2c_t *obj) {
handle->Instance = (I2C_TypeDef *)(obj_s->i2c);
// wait before reset
timeout = LONG_TIMEOUT;
while ((__HAL_I2C_GET_FLAG(handle, I2C_FLAG_BUSY)) && (timeout-- != 0));
timeout = BYTE_TIMEOUT;
while ((__HAL_I2C_GET_FLAG(handle, I2C_FLAG_BUSY)) && (--timeout != 0));
if (obj_s->i2c == I2C_1) {
__I2C1_FORCE_RESET();
@ -615,17 +628,20 @@ int i2c_slave_read(i2c_t *obj, char *data, int length) {
I2C_HandleTypeDef *handle = &(obj_s->handle);
int count = 0;
int ret = 0;
uint32_t timeout = 0;
/* Always use I2C_NEXT_FRAME as slave will just adapt to master requests */
ret = HAL_I2C_Slave_Sequential_Receive_IT(handle, (uint8_t *) data, length, I2C_NEXT_FRAME);
if(ret != HAL_OK) {
count = 0;
} else {
count = length;
}
if(ret == HAL_OK) {
timeout = BYTE_TIMEOUT_US * length;
while(obj_s->pending_slave_rx_maxter_tx && (--timeout != 0)) {
wait_us(1);
}
while(obj_s->pending_slave_rx_maxter_tx);
if(timeout != 0)
count = length;
}
return count;
}
@ -635,17 +651,20 @@ int i2c_slave_write(i2c_t *obj, const char *data, int length) {
I2C_HandleTypeDef *handle = &(obj_s->handle);
int count = 0;
int ret = 0;
uint32_t timeout = 0;
/* Always use I2C_NEXT_FRAME as slave will just adapt to master requests */
ret = HAL_I2C_Slave_Sequential_Transmit_IT(handle, (uint8_t *) data, length, I2C_NEXT_FRAME);
if(ret != HAL_OK) {
count = 0;
} else {
count = length;
}
if(ret == HAL_OK) {
timeout = BYTE_TIMEOUT_US * length;
while(obj_s->pending_slave_tx_master_rx && (--timeout != 0)) {
wait_us(1);
}
while(obj_s->pending_slave_tx_master_rx);
if(timeout != 0)
count = length;
}
return count;
}