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_delay.h"
// An arbitrary value used as the counter in loops waiting for given event
// (e.g. STOPPED), needed to avoid infinite loops (and not involve any timers
// or tickers).
#define TIMEOUT_VALUE 1000
#include "us_ticker_api.h"
// An arbitrary value used as the timeout in loops waiting for given event
// (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
#define TWI_IDX(obj) ((obj)->i2c.twi_idx)
@ -371,17 +375,20 @@ int i2c_start(i2c_t *obj)
int i2c_stop(i2c_t *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
// resumed before the STOP task is triggered.
nrf_twi_task_trigger(twi, NRF_TWI_TASK_RESUME);
nrf_twi_task_trigger(twi, NRF_TWI_TASK_STOP);
uint32_t remaining_time = TIMEOUT_VALUE;
t0 = ticker_read(get_us_ticker_data());
do {
if (nrf_twi_event_check(twi, NRF_TWI_EVENT_STOPPED)) {
return 0;
}
} while (--remaining_time);
} while (((uint32_t)ticker_read(get_us_ticker_data()) - t0) < I2C_TIMEOUT_VALUE_US);
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)
{
uint32_t t0;
nrf_twi_event_clear(twi, NRF_TWI_EVENT_TXDSENT);
nrf_twi_event_clear(twi, NRF_TWI_EVENT_ERROR);
nrf_twi_txd_set(twi, data);
uint32_t remaining_time = TIMEOUT_VALUE;
t0 = ticker_read(get_us_ticker_data());
do {
if (nrf_twi_event_check(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);
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;
}
@ -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)
{
twi_info_t *twi_info = TWI_INFO(obj);
bool timeout = false;
uint32_t t0, t1;
#if DEVICE_I2C_ASYNCH
if (twi_info->active) {
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_task_trigger(twi, NRF_TWI_TASK_SUSPEND);
}
uint32_t remaining_time = TIMEOUT_VALUE;
t0 = ticker_read(get_us_ticker_data());
do {
if (nrf_twi_event_check(twi, event)) {
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);
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 (remaining_time ? 0 : I2C_ERROR_BUS_BUSY);
return (timeout ? I2C_ERROR_BUS_BUSY : 0);
}
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)
{
NRF_TWI_Type *twi = m_twi_instances[TWI_IDX(obj)];
uint32_t t0;
if (last) {
nrf_twi_shorts_set(twi, NRF_TWI_SHORT_BB_STOP_MASK);
}
nrf_twi_task_trigger(twi, NRF_TWI_TASK_RESUME);
uint32_t remaining_time = TIMEOUT_VALUE;
t0 = ticker_read(get_us_ticker_data());
do {
if (nrf_twi_event_check(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);
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;
}