Merge pull request #2138 from atiselsts/bugfix/cc26xx/limited_busywait

CC26xx IEEE mode driver fixes and robustness improvements
This commit is contained in:
George Oikonomou 2017-03-17 23:09:11 +00:00 committed by GitHub
commit 6d51c1a9f9
2 changed files with 58 additions and 25 deletions

View file

@ -163,6 +163,18 @@ static uint8_t rf_stats[16] = { 0 };
/* How long to wait for the RF to enter RX in rf_cmd_ieee_rx */ /* How long to wait for the RF to enter RX in rf_cmd_ieee_rx */
#define ENTER_RX_WAIT_TIMEOUT (RTIMER_SECOND >> 10) #define ENTER_RX_WAIT_TIMEOUT (RTIMER_SECOND >> 10)
/* How long to wait for the RF to react on CMD_ABORT: around 1 msec */
#define RF_TURN_OFF_WAIT_TIMEOUT (RTIMER_SECOND >> 10)
#define LIMITED_BUSYWAIT(cond, timeout) do { \
rtimer_clock_t end_time = RTIMER_NOW() + timeout; \
while(cond) { \
if(!RTIMER_CLOCK_LT(RTIMER_NOW(), end_time)) { \
break; \
} \
} \
} while(0)
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
/* TX Power dBm lookup table - values from SmartRF Studio */ /* TX Power dBm lookup table - values from SmartRF Studio */
typedef struct output_config { typedef struct output_config {
@ -211,7 +223,7 @@ static uint64_t last_rat_timestamp64 = 0;
/* For RAT overflow handling */ /* For RAT overflow handling */
static struct ctimer rat_overflow_timer; static struct ctimer rat_overflow_timer;
static uint32_t rat_overflow_counter = 0; static volatile uint32_t rat_overflow_counter = 0;
static rtimer_clock_t last_rat_overflow = 0; static rtimer_clock_t last_rat_overflow = 0;
/* RAT has 32-bit register, overflows once 18 minutes */ /* RAT has 32-bit register, overflows once 18 minutes */
@ -516,7 +528,6 @@ static uint8_t
rf_cmd_ieee_rx() rf_cmd_ieee_rx()
{ {
uint32_t cmd_status; uint32_t cmd_status;
rtimer_clock_t t0;
int ret; int ret;
ret = rf_core_send_cmd((uint32_t)cmd_ieee_rx_buf, &cmd_status); ret = rf_core_send_cmd((uint32_t)cmd_ieee_rx_buf, &cmd_status);
@ -527,10 +538,8 @@ rf_cmd_ieee_rx()
return RF_CORE_CMD_ERROR; return RF_CORE_CMD_ERROR;
} }
t0 = RTIMER_NOW(); LIMITED_BUSYWAIT(RF_RADIO_OP_GET_STATUS(cmd_ieee_rx_buf) != RF_CORE_RADIO_OP_STATUS_ACTIVE,
ENTER_RX_WAIT_TIMEOUT);
while(RF_RADIO_OP_GET_STATUS(cmd_ieee_rx_buf) != RF_CORE_RADIO_OP_STATUS_ACTIVE &&
(RTIMER_CLOCK_LT(RTIMER_NOW(), t0 + ENTER_RX_WAIT_TIMEOUT)));
/* Wait to enter RX */ /* Wait to enter RX */
if(RF_RADIO_OP_GET_STATUS(cmd_ieee_rx_buf) != RF_CORE_RADIO_OP_STATUS_ACTIVE) { if(RF_RADIO_OP_GET_STATUS(cmd_ieee_rx_buf) != RF_CORE_RADIO_OP_STATUS_ACTIVE) {
@ -693,7 +702,7 @@ rx_off(void)
/* Continue nonetheless */ /* Continue nonetheless */
} }
while(rf_is_on()); LIMITED_BUSYWAIT(rf_is_on(), RF_TURN_OFF_WAIT_TIMEOUT);
if(RF_RADIO_OP_GET_STATUS(cmd_ieee_rx_buf) == IEEE_DONE_STOPPED || if(RF_RADIO_OP_GET_STATUS(cmd_ieee_rx_buf) == IEEE_DONE_STOPPED ||
RF_RADIO_OP_GET_STATUS(cmd_ieee_rx_buf) == IEEE_DONE_ABORT) { RF_RADIO_OP_GET_STATUS(cmd_ieee_rx_buf) == IEEE_DONE_ABORT) {
@ -744,8 +753,8 @@ soft_off(void)
return; return;
} }
while((cmd->status & RF_CORE_RADIO_OP_MASKED_STATUS) == LIMITED_BUSYWAIT((cmd->status & RF_CORE_RADIO_OP_MASKED_STATUS) ==
RF_CORE_RADIO_OP_MASKED_STATUS_RUNNING); RF_CORE_RADIO_OP_MASKED_STATUS_RUNNING, RF_TURN_OFF_WAIT_TIMEOUT);
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
static uint8_t static uint8_t
@ -764,20 +773,25 @@ static const rf_core_primary_mode_t mode_ieee = {
soft_on, soft_on,
}; };
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
static void static uint8_t
check_rat_overflow(bool first_time) check_rat_overflow(bool first_time)
{ {
static uint32_t last_value; static uint32_t last_value;
uint32_t current_value; uint32_t current_value;
uint8_t interrupts_disabled; uint8_t interrupts_disabled;
/* Bail out if the RF is not on */
if(!rf_is_on()) {
return 0;
}
interrupts_disabled = ti_lib_int_master_disable(); interrupts_disabled = ti_lib_int_master_disable();
if(first_time) { if(first_time) {
last_value = HWREG(RFC_RAT_BASE + RATCNT); last_value = HWREG(RFC_RAT_BASE + RATCNT);
} else { } else {
current_value = HWREG(RFC_RAT_BASE + RATCNT); current_value = HWREG(RFC_RAT_BASE + RATCNT);
if(current_value + RAT_RANGE / 4 < last_value) { if(current_value + RAT_RANGE / 4 < last_value) {
/* overflow detected */ /* Overflow detected */
last_rat_overflow = RTIMER_NOW(); last_rat_overflow = RTIMER_NOW();
rat_overflow_counter++; rat_overflow_counter++;
} }
@ -786,31 +800,40 @@ check_rat_overflow(bool first_time)
if(!interrupts_disabled) { if(!interrupts_disabled) {
ti_lib_int_master_enable(); ti_lib_int_master_enable();
} }
return 1;
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
static void static void
handle_rat_overflow(void *unused) handle_rat_overflow(void *unused)
{ {
uint8_t success;
uint8_t was_off = 0; uint8_t was_off = 0;
if(!rf_is_on()) { if(!rf_is_on()) {
was_off = 1; was_off = 1;
if(on() != RF_CORE_CMD_OK) { if(on() != RF_CORE_CMD_OK) {
PRINTF("overflow: on() failed\n"); PRINTF("overflow: on() failed\n");
ctimer_set(&rat_overflow_timer, RAT_OVERFLOW_PERIOD_SECONDS * CLOCK_SECOND / 2, ctimer_set(&rat_overflow_timer, CLOCK_SECOND,
handle_rat_overflow, NULL); handle_rat_overflow, NULL);
return; return;
} }
} }
check_rat_overflow(false); success = check_rat_overflow(false);
if(was_off) { if(was_off) {
off(); off();
} }
ctimer_set(&rat_overflow_timer, RAT_OVERFLOW_PERIOD_SECONDS * CLOCK_SECOND / 2, if(success) {
handle_rat_overflow, NULL); /* Retry after half of the interval */
ctimer_set(&rat_overflow_timer, RAT_OVERFLOW_PERIOD_SECONDS * CLOCK_SECOND / 2,
handle_rat_overflow, NULL);
} else {
/* Retry sooner */
ctimer_set(&rat_overflow_timer, CLOCK_SECOND,
handle_rat_overflow, NULL);
}
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
static int static int
@ -1000,7 +1023,22 @@ static uint32_t
calc_last_packet_timestamp(uint32_t rat_timestamp) calc_last_packet_timestamp(uint32_t rat_timestamp)
{ {
uint64_t rat_timestamp64; uint64_t rat_timestamp64;
uint32_t adjusted_overflow_counter = rat_overflow_counter; uint32_t adjusted_overflow_counter;
uint8_t was_off = 0;
if(!rf_is_on()) {
was_off = 1;
on();
}
if(rf_is_on()) {
check_rat_overflow(false);
if(was_off) {
off();
}
}
adjusted_overflow_counter = rat_overflow_counter;
/* if the timestamp is large and the last oveflow was recently, /* if the timestamp is large and the last oveflow was recently,
assume that the timestamp refers to the time before the overflow */ assume that the timestamp refers to the time before the overflow */
@ -1028,10 +1066,6 @@ read_frame(void *buf, unsigned short buf_len)
rfc_dataEntryGeneral_t *entry = (rfc_dataEntryGeneral_t *)rx_read_entry; rfc_dataEntryGeneral_t *entry = (rfc_dataEntryGeneral_t *)rx_read_entry;
uint32_t rat_timestamp; uint32_t rat_timestamp;
if(rf_is_on()) {
check_rat_overflow(false);
}
/* wait for entry to become finished */ /* wait for entry to become finished */
rtimer_clock_t t0 = RTIMER_NOW(); rtimer_clock_t t0 = RTIMER_NOW();
while(entry->status == DATA_ENTRY_STATUS_BUSY while(entry->status == DATA_ENTRY_STATUS_BUSY
@ -1503,9 +1537,9 @@ set_value(radio_param_t param, radio_value_t value)
/* Restart the radio timer (RAT). /* Restart the radio timer (RAT).
This causes resynchronization between RAT and RTC: useful for TSCH. */ This causes resynchronization between RAT and RTC: useful for TSCH. */
rf_core_restart_rat(); if(rf_core_restart_rat() == RF_CORE_CMD_OK) {
check_rat_overflow(false);
check_rat_overflow(false); }
if(rx_on() != RF_CORE_CMD_OK) { if(rx_on() != RF_CORE_CMD_OK) {
PRINTF("set_value: rx_on() failed\n"); PRINTF("set_value: rx_on() failed\n");

View file

@ -419,8 +419,7 @@ rf_core_restart_rat(void)
{ {
if(rf_core_stop_rat() != RF_CORE_CMD_OK) { if(rf_core_stop_rat() != RF_CORE_CMD_OK) {
PRINTF("rf_core_restart_rat: rf_core_stop_rat() failed\n"); PRINTF("rf_core_restart_rat: rf_core_stop_rat() failed\n");
/* Don't bail out here, still try to start it */
return RF_CORE_CMD_ERROR;
} }
if(rf_core_start_rat() != RF_CORE_CMD_OK) { if(rf_core_start_rat() != RF_CORE_CMD_OK) {