fix bug: I2C timeout due the clos strething by slave on nRFx SoC

Change implementation of timeout to one that is using us_ticker hal.
Timeout is now configurable by I2C_TIMEOUT_VALUE_US macro and this
value will be imported if will be defined externaly.
pull/5187/head
Andrzej Puzdrowski 2017-09-25 11:32:42 +02:00
parent 5e437fe5ea
commit 2a0d38eaf6
1 changed files with 33 additions and 13 deletions

View File

@ -50,10 +50,14 @@
#include "nrf_gpio.h" #include "nrf_gpio.h"
#include "nrf_delay.h" #include "nrf_delay.h"
// An arbitrary value used as the counter in loops waiting for given event #include "us_ticker_api.h"
// (e.g. STOPPED), needed to avoid infinite loops (and not involve any timers
// or tickers). // An arbitrary value used as the timeout in loops waiting for given event
#define TIMEOUT_VALUE 1000 // (e.g. STOPPED), needed to avoid infinite loops.
// This value might be defined externally.
#ifndef I2C_TIMEOUT_VALUE_US
#define I2C_TIMEOUT_VALUE_US 1000000
#endif
#if DEVICE_I2C_ASYNCH #if DEVICE_I2C_ASYNCH
#define TWI_IDX(obj) ((obj)->i2c.twi_idx) #define TWI_IDX(obj) ((obj)->i2c.twi_idx)
@ -371,17 +375,20 @@ int i2c_start(i2c_t *obj)
int i2c_stop(i2c_t *obj) int i2c_stop(i2c_t *obj)
{ {
NRF_TWI_Type *twi = m_twi_instances[TWI_IDX(obj)]; NRF_TWI_Type *twi = m_twi_instances[TWI_IDX(obj)];
uint32_t t0;
// The current transfer may be suspended (if it is RX), so it must be // The current transfer may be suspended (if it is RX), so it must be
// resumed before the STOP task is triggered. // resumed before the STOP task is triggered.
nrf_twi_task_trigger(twi, NRF_TWI_TASK_RESUME); nrf_twi_task_trigger(twi, NRF_TWI_TASK_RESUME);
nrf_twi_task_trigger(twi, NRF_TWI_TASK_STOP); nrf_twi_task_trigger(twi, NRF_TWI_TASK_STOP);
uint32_t remaining_time = TIMEOUT_VALUE;
t0 = ticker_read(get_us_ticker_data());
do { do {
if (nrf_twi_event_check(twi, NRF_TWI_EVENT_STOPPED)) { if (nrf_twi_event_check(twi, NRF_TWI_EVENT_STOPPED)) {
return 0; return 0;
} }
} while (--remaining_time); } while (((uint32_t)ticker_read(get_us_ticker_data()) - t0) < I2C_TIMEOUT_VALUE_US);
return 1; return 1;
} }
@ -464,11 +471,15 @@ int i2c_read(i2c_t *obj, int address, char *data, int length, int stop)
static uint8_t twi_byte_write(NRF_TWI_Type *twi, uint8_t data) static uint8_t twi_byte_write(NRF_TWI_Type *twi, uint8_t data)
{ {
uint32_t t0;
nrf_twi_event_clear(twi, NRF_TWI_EVENT_TXDSENT); nrf_twi_event_clear(twi, NRF_TWI_EVENT_TXDSENT);
nrf_twi_event_clear(twi, NRF_TWI_EVENT_ERROR); nrf_twi_event_clear(twi, NRF_TWI_EVENT_ERROR);
nrf_twi_txd_set(twi, data); nrf_twi_txd_set(twi, data);
uint32_t remaining_time = TIMEOUT_VALUE;
t0 = ticker_read(get_us_ticker_data());
do { do {
if (nrf_twi_event_check(twi, NRF_TWI_EVENT_TXDSENT)) { if (nrf_twi_event_check(twi, NRF_TWI_EVENT_TXDSENT)) {
nrf_twi_event_clear(twi, NRF_TWI_EVENT_TXDSENT); 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)
nrf_twi_event_clear(twi, NRF_TWI_EVENT_ERROR); nrf_twi_event_clear(twi, NRF_TWI_EVENT_ERROR);
return 0; // some error occurred return 0; // some error occurred
} }
} while (--remaining_time); } while (((uint32_t)ticker_read(get_us_ticker_data()) - t0) < I2C_TIMEOUT_VALUE_US);
return 2; // timeout; return 2; // timeout;
} }
@ -500,6 +511,9 @@ static void start_twi_write(NRF_TWI_Type *twi, int address)
int i2c_write(i2c_t *obj, int address, const char *data, int length, int stop) int i2c_write(i2c_t *obj, int address, const char *data, int length, int stop)
{ {
twi_info_t *twi_info = TWI_INFO(obj); twi_info_t *twi_info = TWI_INFO(obj);
bool timeout = false;
uint32_t t0, t1;
#if DEVICE_I2C_ASYNCH #if DEVICE_I2C_ASYNCH
if (twi_info->active) { if (twi_info->active) {
return I2C_ERROR_BUS_BUSY; return I2C_ERROR_BUS_BUSY;
@ -522,12 +536,16 @@ int i2c_write(i2c_t *obj, int address, const char *data, int length, int stop)
nrf_twi_event_clear(twi, event); nrf_twi_event_clear(twi, event);
nrf_twi_task_trigger(twi, NRF_TWI_TASK_SUSPEND); nrf_twi_task_trigger(twi, NRF_TWI_TASK_SUSPEND);
} }
uint32_t remaining_time = TIMEOUT_VALUE;
t0 = ticker_read(get_us_ticker_data());
do { do {
if (nrf_twi_event_check(twi, event)) { if (nrf_twi_event_check(twi, event)) {
break; break;
} }
} while (--remaining_time); t1 = ticker_read(get_us_ticker_data());
timeout = (t1 - t0) >= I2C_TIMEOUT_VALUE_US;
} while (!timeout);
uint32_t errorsrc = nrf_twi_errorsrc_get_and_clear(twi); uint32_t errorsrc = nrf_twi_errorsrc_get_and_clear(twi);
if (errorsrc & NRF_TWI_ERROR_ADDRESS_NACK) { 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)
return I2C_ERROR_NO_SLAVE; return I2C_ERROR_NO_SLAVE;
} }
return (remaining_time ? 0 : I2C_ERROR_BUS_BUSY); return (timeout ? I2C_ERROR_BUS_BUSY : 0);
} }
int result = length; int result = length;
@ -574,13 +592,15 @@ int i2c_write(i2c_t *obj, int address, const char *data, int length, int stop)
int i2c_byte_read(i2c_t *obj, int last) int i2c_byte_read(i2c_t *obj, int last)
{ {
NRF_TWI_Type *twi = m_twi_instances[TWI_IDX(obj)]; NRF_TWI_Type *twi = m_twi_instances[TWI_IDX(obj)];
uint32_t t0;
if (last) { if (last) {
nrf_twi_shorts_set(twi, NRF_TWI_SHORT_BB_STOP_MASK); nrf_twi_shorts_set(twi, NRF_TWI_SHORT_BB_STOP_MASK);
} }
nrf_twi_task_trigger(twi, NRF_TWI_TASK_RESUME); nrf_twi_task_trigger(twi, NRF_TWI_TASK_RESUME);
uint32_t remaining_time = TIMEOUT_VALUE; t0 = ticker_read(get_us_ticker_data());
do { do {
if (nrf_twi_event_check(twi, NRF_TWI_EVENT_RXDREADY)) { if (nrf_twi_event_check(twi, NRF_TWI_EVENT_RXDREADY)) {
nrf_twi_event_clear(twi, NRF_TWI_EVENT_RXDREADY); nrf_twi_event_clear(twi, NRF_TWI_EVENT_RXDREADY);
@ -590,7 +610,7 @@ int i2c_byte_read(i2c_t *obj, int last)
nrf_twi_event_clear(twi, NRF_TWI_EVENT_ERROR); nrf_twi_event_clear(twi, NRF_TWI_EVENT_ERROR);
return I2C_ERROR_NO_SLAVE; return I2C_ERROR_NO_SLAVE;
} }
} while (--remaining_time); } while (((uint32_t)ticker_read(get_us_ticker_data()) - t0) < I2C_TIMEOUT_VALUE_US);
return I2C_ERROR_BUS_BUSY; return I2C_ERROR_BUS_BUSY;
} }