Skip to content

Commit 0b796cd

Browse files
Merge pull request #5187 from nvlsianpu/fix_i2c_timeout
nRFx: Use us ticker for I2C timeout
2 parents 84f2d08 + 2a0d38e commit 0b796cd

File tree

1 file changed

+33
-13
lines changed

1 file changed

+33
-13
lines changed

targets/TARGET_NORDIC/TARGET_NRF5/i2c_api.c

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,14 @@
5050
#include "nrf_gpio.h"
5151
#include "nrf_delay.h"
5252

53-
// An arbitrary value used as the counter in loops waiting for given event
54-
// (e.g. STOPPED), needed to avoid infinite loops (and not involve any timers
55-
// or tickers).
56-
#define TIMEOUT_VALUE 1000
53+
#include "us_ticker_api.h"
54+
55+
// An arbitrary value used as the timeout in loops waiting for given event
56+
// (e.g. STOPPED), needed to avoid infinite loops.
57+
// This value might be defined externally.
58+
#ifndef I2C_TIMEOUT_VALUE_US
59+
#define I2C_TIMEOUT_VALUE_US 1000000
60+
#endif
5761

5862
#if DEVICE_I2C_ASYNCH
5963
#define TWI_IDX(obj) ((obj)->i2c.twi_idx)
@@ -371,17 +375,20 @@ int i2c_start(i2c_t *obj)
371375
int i2c_stop(i2c_t *obj)
372376
{
373377
NRF_TWI_Type *twi = m_twi_instances[TWI_IDX(obj)];
378+
uint32_t t0;
374379

375380
// The current transfer may be suspended (if it is RX), so it must be
376381
// resumed before the STOP task is triggered.
377382
nrf_twi_task_trigger(twi, NRF_TWI_TASK_RESUME);
378383
nrf_twi_task_trigger(twi, NRF_TWI_TASK_STOP);
379-
uint32_t remaining_time = TIMEOUT_VALUE;
384+
385+
t0 = ticker_read(get_us_ticker_data());
386+
380387
do {
381388
if (nrf_twi_event_check(twi, NRF_TWI_EVENT_STOPPED)) {
382389
return 0;
383390
}
384-
} while (--remaining_time);
391+
} while (((uint32_t)ticker_read(get_us_ticker_data()) - t0) < I2C_TIMEOUT_VALUE_US);
385392

386393
return 1;
387394
}
@@ -464,11 +471,15 @@ int i2c_read(i2c_t *obj, int address, char *data, int length, int stop)
464471

465472
static uint8_t twi_byte_write(NRF_TWI_Type *twi, uint8_t data)
466473
{
474+
uint32_t t0;
475+
467476
nrf_twi_event_clear(twi, NRF_TWI_EVENT_TXDSENT);
468477
nrf_twi_event_clear(twi, NRF_TWI_EVENT_ERROR);
469478

470479
nrf_twi_txd_set(twi, data);
471-
uint32_t remaining_time = TIMEOUT_VALUE;
480+
481+
t0 = ticker_read(get_us_ticker_data());
482+
472483
do {
473484
if (nrf_twi_event_check(twi, NRF_TWI_EVENT_TXDSENT)) {
474485
nrf_twi_event_clear(twi, NRF_TWI_EVENT_TXDSENT);
@@ -478,7 +489,7 @@ static uint8_t twi_byte_write(NRF_TWI_Type *twi, uint8_t data)
478489
nrf_twi_event_clear(twi, NRF_TWI_EVENT_ERROR);
479490
return 0; // some error occurred
480491
}
481-
} while (--remaining_time);
492+
} while (((uint32_t)ticker_read(get_us_ticker_data()) - t0) < I2C_TIMEOUT_VALUE_US);
482493

483494
return 2; // timeout;
484495
}
@@ -500,6 +511,9 @@ static void start_twi_write(NRF_TWI_Type *twi, int address)
500511
int i2c_write(i2c_t *obj, int address, const char *data, int length, int stop)
501512
{
502513
twi_info_t *twi_info = TWI_INFO(obj);
514+
bool timeout = false;
515+
uint32_t t0, t1;
516+
503517
#if DEVICE_I2C_ASYNCH
504518
if (twi_info->active) {
505519
return I2C_ERROR_BUS_BUSY;
@@ -522,12 +536,16 @@ int i2c_write(i2c_t *obj, int address, const char *data, int length, int stop)
522536
nrf_twi_event_clear(twi, event);
523537
nrf_twi_task_trigger(twi, NRF_TWI_TASK_SUSPEND);
524538
}
525-
uint32_t remaining_time = TIMEOUT_VALUE;
539+
540+
t0 = ticker_read(get_us_ticker_data());
541+
526542
do {
527543
if (nrf_twi_event_check(twi, event)) {
528544
break;
529545
}
530-
} while (--remaining_time);
546+
t1 = ticker_read(get_us_ticker_data());
547+
timeout = (t1 - t0) >= I2C_TIMEOUT_VALUE_US;
548+
} while (!timeout);
531549

532550
uint32_t errorsrc = nrf_twi_errorsrc_get_and_clear(twi);
533551
if (errorsrc & NRF_TWI_ERROR_ADDRESS_NACK) {
@@ -537,7 +555,7 @@ int i2c_write(i2c_t *obj, int address, const char *data, int length, int stop)
537555
return I2C_ERROR_NO_SLAVE;
538556
}
539557

540-
return (remaining_time ? 0 : I2C_ERROR_BUS_BUSY);
558+
return (timeout ? I2C_ERROR_BUS_BUSY : 0);
541559
}
542560

543561
int result = length;
@@ -574,13 +592,15 @@ int i2c_write(i2c_t *obj, int address, const char *data, int length, int stop)
574592
int i2c_byte_read(i2c_t *obj, int last)
575593
{
576594
NRF_TWI_Type *twi = m_twi_instances[TWI_IDX(obj)];
595+
uint32_t t0;
577596

578597
if (last) {
579598
nrf_twi_shorts_set(twi, NRF_TWI_SHORT_BB_STOP_MASK);
580599
}
581600
nrf_twi_task_trigger(twi, NRF_TWI_TASK_RESUME);
582601

583-
uint32_t remaining_time = TIMEOUT_VALUE;
602+
t0 = ticker_read(get_us_ticker_data());
603+
584604
do {
585605
if (nrf_twi_event_check(twi, NRF_TWI_EVENT_RXDREADY)) {
586606
nrf_twi_event_clear(twi, NRF_TWI_EVENT_RXDREADY);
@@ -590,7 +610,7 @@ int i2c_byte_read(i2c_t *obj, int last)
590610
nrf_twi_event_clear(twi, NRF_TWI_EVENT_ERROR);
591611
return I2C_ERROR_NO_SLAVE;
592612
}
593-
} while (--remaining_time);
613+
} while (((uint32_t)ticker_read(get_us_ticker_data()) - t0) < I2C_TIMEOUT_VALUE_US);
594614

595615
return I2C_ERROR_BUS_BUSY;
596616
}

0 commit comments

Comments
 (0)