Skip to content

Commit 42d89b0

Browse files
committed
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.
1 parent 79504a6 commit 42d89b0

File tree

1 file changed

+39
-20
lines changed

1 file changed

+39
-20
lines changed

targets/TARGET_STM/TARGET_STM32F4/i2c_api.c

Lines changed: 39 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
*/
3030
#include "mbed_assert.h"
3131
#include "i2c_api.h"
32+
#include "platform/wait_api.h"
3233

3334
#if DEVICE_I2C
3435

@@ -41,6 +42,18 @@
4142
not remain stuck if the I2C communication is corrupted. */
4243
#define FLAG_TIMEOUT ((int)0x1000)
4344
#define LONG_TIMEOUT ((int)0x8000)
45+
/* Timeout values are based on core clock and I2C clock.
46+
The BYTE_TIMEOUT is computed as twice the number of cycles it would
47+
take to send 10 bits over I2C. Most Flags should take less than that.
48+
This is for immediate FLAG or ACK check.
49+
*/
50+
#define BYTE_TIMEOUT ((SystemCoreClock / handle->Init.ClockSpeed) * 2 * 10)
51+
/* Timeout values based on I2C clock.
52+
The BYTE_TIMEOUT_US is computed as 3x the time in us it would
53+
take to send 10 bits over I2C. Most Flags should take less than that.
54+
This is for complete transfers check.
55+
*/
56+
#define BYTE_TIMEOUT_US ((SystemCoreClock / handle->Init.ClockSpeed) * 3 * 10)
4457

4558
#if DEVICE_I2C_ASYNCH
4659
#define I2C_S(obj) (struct i2c_s *) (&((obj)->i2c))
@@ -266,8 +279,8 @@ void i2c_frequency(i2c_t *obj, int hz)
266279
MBED_ASSERT((hz > 0) && (hz <= 400000));
267280

268281
// wait before init
269-
timeout = LONG_TIMEOUT;
270-
while ((__HAL_I2C_GET_FLAG(handle, I2C_FLAG_BUSY)) && (timeout-- != 0));
282+
timeout = BYTE_TIMEOUT;
283+
while ((__HAL_I2C_GET_FLAG(handle, I2C_FLAG_BUSY)) && (--timeout != 0));
271284

272285
// I2C configuration
273286
handle->Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
@@ -307,7 +320,7 @@ inline int i2c_start(i2c_t *obj) {
307320

308321
// Wait the STOP condition has been previously correctly sent
309322
// This timeout can be avoid in some specific cases by simply clearing the STOP bit
310-
timeout = FLAG_TIMEOUT;
323+
timeout = BYTE_TIMEOUT;
311324
while ((handle->Instance->CR1 & I2C_CR1_STOP) == I2C_CR1_STOP) {
312325
if ((timeout--) == 0) {
313326
return 1;
@@ -318,7 +331,7 @@ inline int i2c_start(i2c_t *obj) {
318331
handle->Instance->CR1 |= I2C_CR1_START;
319332

320333
// Wait the START condition has been correctly sent
321-
timeout = FLAG_TIMEOUT;
334+
timeout = BYTE_TIMEOUT;
322335
while (__HAL_I2C_GET_FLAG(handle, I2C_FLAG_SB) == RESET) {
323336
if ((timeout--) == 0) {
324337
return 1;
@@ -448,7 +461,7 @@ int i2c_byte_read(i2c_t *obj, int last) {
448461
}
449462

450463
// Wait until the byte is received
451-
timeout = FLAG_TIMEOUT;
464+
timeout = BYTE_TIMEOUT;
452465
while (__HAL_I2C_GET_FLAG(handle, I2C_FLAG_RXNE) == RESET) {
453466
if ((timeout--) == 0) {
454467
return -1;
@@ -467,7 +480,7 @@ int i2c_byte_write(i2c_t *obj, int data) {
467480
handle->Instance->DR = (uint8_t)data;
468481

469482
// Wait until the byte (might be the address) is transmitted
470-
timeout = FLAG_TIMEOUT;
483+
timeout = BYTE_TIMEOUT;
471484
while ((__HAL_I2C_GET_FLAG(handle, I2C_FLAG_TXE) == RESET) &&
472485
(__HAL_I2C_GET_FLAG(handle, I2C_FLAG_BTF) == RESET) &&
473486
(__HAL_I2C_GET_FLAG(handle, I2C_FLAG_ADDR) == RESET)) {
@@ -493,8 +506,8 @@ void i2c_reset(i2c_t *obj) {
493506
handle->Instance = (I2C_TypeDef *)(obj_s->i2c);
494507

495508
// wait before reset
496-
timeout = LONG_TIMEOUT;
497-
while ((__HAL_I2C_GET_FLAG(handle, I2C_FLAG_BUSY)) && (timeout-- != 0));
509+
timeout = BYTE_TIMEOUT;
510+
while ((__HAL_I2C_GET_FLAG(handle, I2C_FLAG_BUSY)) && (--timeout != 0));
498511

499512
if (obj_s->i2c == I2C_1) {
500513
__I2C1_FORCE_RESET();
@@ -615,17 +628,20 @@ int i2c_slave_read(i2c_t *obj, char *data, int length) {
615628
I2C_HandleTypeDef *handle = &(obj_s->handle);
616629
int count = 0;
617630
int ret = 0;
631+
uint32_t timeout = 0;
618632

619633
/* Always use I2C_NEXT_FRAME as slave will just adapt to master requests */
620634
ret = HAL_I2C_Slave_Sequential_Receive_IT(handle, (uint8_t *) data, length, I2C_NEXT_FRAME);
621635

622-
if(ret != HAL_OK) {
623-
count = 0;
624-
} else {
625-
count = length;
626-
}
636+
if(ret == HAL_OK) {
637+
timeout = BYTE_TIMEOUT_US * length;
638+
while(obj_s->pending_slave_rx_maxter_tx && (--timeout != 0)) {
639+
wait_us(1);
640+
}
627641

628-
while(obj_s->pending_slave_rx_maxter_tx);
642+
if(timeout != 0)
643+
count = length;
644+
}
629645

630646
return count;
631647
}
@@ -635,17 +651,20 @@ int i2c_slave_write(i2c_t *obj, const char *data, int length) {
635651
I2C_HandleTypeDef *handle = &(obj_s->handle);
636652
int count = 0;
637653
int ret = 0;
654+
uint32_t timeout = 0;
638655

639656
/* Always use I2C_NEXT_FRAME as slave will just adapt to master requests */
640657
ret = HAL_I2C_Slave_Sequential_Transmit_IT(handle, (uint8_t *) data, length, I2C_NEXT_FRAME);
641658

642-
if(ret != HAL_OK) {
643-
count = 0;
644-
} else {
645-
count = length;
646-
}
659+
if(ret == HAL_OK) {
660+
timeout = BYTE_TIMEOUT_US * length;
661+
while(obj_s->pending_slave_tx_master_rx && (--timeout != 0)) {
662+
wait_us(1);
663+
}
647664

648-
while(obj_s->pending_slave_tx_master_rx);
665+
if(timeout != 0)
666+
count = length;
667+
}
649668

650669
return count;
651670
}

0 commit comments

Comments
 (0)