mirror of https://github.com/ARMmbed/mbed-os.git
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
parent
79504a6a38
commit
42d89b0665
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue