mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2025-01-17 05:32:45 +01:00
Merge pull request #16821 from jia200x/pr/cc2538/rx_busy
cc2538_rf: remove RX Busy detection in request_set_trx_state
This commit is contained in:
commit
3b002cc4c8
@ -298,6 +298,24 @@ typedef struct {
|
||||
*/
|
||||
void cc2538_rf_hal_setup(ieee802154_dev_t *hal);
|
||||
|
||||
/**
|
||||
* @brief Enable CC2538 RF IRQs.
|
||||
*/
|
||||
static inline void cc2538_rf_enable_irq(void)
|
||||
{
|
||||
RFCORE_XREG_RFIRQM1 = TXDONE | CSP_STOP | TXACKDONE;
|
||||
RFCORE_XREG_RFIRQM0 = RXPKTDONE | SFD;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disable CC2538 RF IRQs.
|
||||
*/
|
||||
static inline void cc2538_rf_disable_irq(void)
|
||||
{
|
||||
RFCORE_XREG_RFIRQM1 = 0;
|
||||
RFCORE_XREG_RFIRQM0 = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief IRQ handler for RF events
|
||||
*
|
||||
|
@ -134,8 +134,7 @@ void cc2538_init(void)
|
||||
RFCORE_XREG_FIFOPCTRL = CC2538_RF_MAX_DATA_LEN;
|
||||
|
||||
/* Set default IRQ */
|
||||
RFCORE_XREG_RFIRQM1 = TXDONE | CSP_STOP | TXACKDONE;
|
||||
RFCORE_XREG_RFIRQM0 = RXPKTDONE | FIFOP | SFD;
|
||||
cc2538_rf_enable_irq();
|
||||
|
||||
/* Enable all RF CORE error interrupts */
|
||||
RFCORE_XREG_RFERRM = STROBE_ERR | TXUNDERF | TXOVERF | \
|
||||
|
@ -30,21 +30,39 @@
|
||||
|
||||
#include "net/ieee802154/radio.h"
|
||||
|
||||
#define ENABLE_DEBUG 0
|
||||
#include "debug.h"
|
||||
|
||||
static const ieee802154_radio_ops_t cc2538_rf_ops;
|
||||
|
||||
static ieee802154_dev_t *cc2538_rf_hal;
|
||||
|
||||
static bool cc2538_tx_busy; /**< used to indicate TX chain is busy */
|
||||
static bool cc2538_rx_busy; /**< used to indicate RX chain is busy */
|
||||
typedef enum {
|
||||
CC2538_STATE_READY, /**< The radio is ready to receive requests */
|
||||
CC2538_STATE_TRX_TRANSITION, /**< There's a pending TRX state transition */
|
||||
CC2538_STATE_CONFIRM_TX, /**< Transmission finished and waiting for confirm */
|
||||
CC2538_STATE_TX_BUSY, /**< The radio is busy transmitting */
|
||||
CC2538_STATE_TX_ACK, /**< The radio is currently transmitting an ACK frame */
|
||||
CC2538_STATE_CCA, /**< The radio is doing CCA */
|
||||
CC2538_STATE_CONFIRM_CCA, /**< CCA finished and waiting for confirm */
|
||||
} cc2538_state_t;
|
||||
|
||||
static cc2538_state_t cc2538_state;
|
||||
static uint8_t cc2538_min_be = CONFIG_IEEE802154_DEFAULT_CSMA_CA_MIN_BE;
|
||||
static uint8_t cc2538_max_be = CONFIG_IEEE802154_DEFAULT_CSMA_CA_MAX_BE;
|
||||
static int cc2538_csma_ca_retries = CONFIG_IEEE802154_DEFAULT_CSMA_CA_RETRIES;
|
||||
|
||||
static bool cc2538_cca_status; /**< status of the last CCA request */
|
||||
static bool cc2538_cca; /**< used to check whether the last CCA result
|
||||
corresponds to a CCA request or send with
|
||||
CSMA-CA */
|
||||
|
||||
static void _enable_rx(void)
|
||||
{
|
||||
RFCORE_XREG_FRMCTRL0 &= ~CC2538_FRMCTRL0_RX_MODE_DIS;
|
||||
}
|
||||
|
||||
static void _disable_rx(void)
|
||||
{
|
||||
RFCORE_XREG_FRMCTRL0 |= CC2538_FRMCTRL0_RX_MODE_DIS;
|
||||
}
|
||||
|
||||
static int _write(ieee802154_dev_t *dev, const iolist_t *iolist)
|
||||
{
|
||||
@ -69,8 +87,10 @@ static int _confirm_transmit(ieee802154_dev_t *dev, ieee802154_tx_info_t *info)
|
||||
{
|
||||
(void) dev;
|
||||
|
||||
if (cc2538_tx_busy) {
|
||||
return -EAGAIN;
|
||||
cc2538_rf_disable_irq();
|
||||
int res = -EAGAIN;
|
||||
if (cc2538_state != CC2538_STATE_CONFIRM_TX) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (info) {
|
||||
@ -82,14 +102,22 @@ static int _confirm_transmit(ieee802154_dev_t *dev, ieee802154_tx_info_t *info)
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
cc2538_state = CC2538_STATE_READY;
|
||||
res = 0;
|
||||
|
||||
end:
|
||||
cc2538_rf_enable_irq();
|
||||
return res;
|
||||
}
|
||||
|
||||
static int _request_transmit(ieee802154_dev_t *dev)
|
||||
{
|
||||
(void) dev;
|
||||
|
||||
cc2538_tx_busy = true;
|
||||
cc2538_rf_disable_irq();
|
||||
assert(cc2538_state != CC2538_STATE_TX_BUSY);
|
||||
cc2538_state = CC2538_STATE_TX_BUSY;
|
||||
|
||||
if (cc2538_csma_ca_retries < 0) {
|
||||
RFCORE_SFR_RFST = ISTXON;
|
||||
/* The CPU Ctrl mask is used here to indicate whether the radio is being
|
||||
@ -101,10 +129,8 @@ static int _request_transmit(ieee802154_dev_t *dev)
|
||||
RFCORE_XREG_CSPCTRL |= CC2538_CSP_MCU_CTRL_MASK;
|
||||
}
|
||||
else {
|
||||
cc2538_cca = false;
|
||||
|
||||
/* Disable RX Chain for CCA (see CC2538 RM, Section 29.9.5.3) */
|
||||
RFCORE_XREG_FRMCTRL0 |= CC2538_FRMCTRL0_RX_MODE_DIS;
|
||||
_disable_rx();
|
||||
RFCORE_SFR_RFST = ISRXON;
|
||||
/* Clear last program */
|
||||
RFCORE_SFR_RFST = ISCLEAR;
|
||||
@ -162,6 +188,7 @@ static int _request_transmit(ieee802154_dev_t *dev)
|
||||
/* Execute the program */
|
||||
RFCORE_SFR_RFST = ISSTART;
|
||||
}
|
||||
cc2538_rf_enable_irq();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -226,8 +253,12 @@ static int _read(ieee802154_dev_t *dev, void *buf, size_t size, ieee802154_rx_in
|
||||
}
|
||||
|
||||
end:
|
||||
/* Enable RX Chain */
|
||||
RFCORE_XREG_FRMCTRL0 &= ~CC2538_FRMCTRL0_RX_MODE_DIS;
|
||||
/* Don't enable RX chain if the radio is currently doing CCA or during
|
||||
* transmission. */
|
||||
if (cc2538_state != CC2538_STATE_CCA
|
||||
&& cc2538_state != CC2538_STATE_TX_BUSY) {
|
||||
_enable_rx();
|
||||
}
|
||||
RFCORE_SFR_RFST = ISFLUSHRX;
|
||||
return res;
|
||||
}
|
||||
@ -236,22 +267,38 @@ static int _confirm_cca(ieee802154_dev_t *dev)
|
||||
{
|
||||
(void) dev;
|
||||
|
||||
RFCORE_XREG_RFIRQM0 |= RXPKTDONE;
|
||||
int res = -EAGAIN;
|
||||
cc2538_rf_disable_irq();
|
||||
assert(cc2538_state == CC2538_STATE_CCA || cc2538_state == CC2538_STATE_CONFIRM_CCA);
|
||||
|
||||
return cc2538_cca_status;
|
||||
if (cc2538_state != CC2538_STATE_CONFIRM_CCA) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
cc2538_state = CC2538_STATE_READY;
|
||||
_enable_rx();
|
||||
res = cc2538_cca_status;
|
||||
|
||||
end:
|
||||
cc2538_rf_enable_irq();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int _request_cca(ieee802154_dev_t *dev)
|
||||
{
|
||||
(void) dev;
|
||||
int res = -EINVAL;
|
||||
cc2538_rf_disable_irq();
|
||||
if (!RFCORE->XREG_FSMSTAT1bits.RX_ACTIVE) {
|
||||
return -EINVAL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Ignore baseband processing */
|
||||
RFCORE_XREG_RFIRQM0 &= ~RXPKTDONE;
|
||||
cc2538_state = CC2538_STATE_CCA;
|
||||
|
||||
/* Ignore baseband processing */
|
||||
_disable_rx();
|
||||
|
||||
cc2538_cca = true;
|
||||
RFCORE_SFR_RFST = ISCLEAR;
|
||||
RFCORE_SFR_RFST = STOP;
|
||||
RFCORE_XREG_CSPCTRL &= ~CC2538_CSP_MCU_CTRL_MASK;
|
||||
@ -259,7 +306,9 @@ static int _request_cca(ieee802154_dev_t *dev)
|
||||
/* Execute the last program */
|
||||
RFCORE_SFR_RFST = ISSTART;
|
||||
|
||||
return 0;
|
||||
end:
|
||||
cc2538_rf_enable_irq();
|
||||
return res;
|
||||
}
|
||||
|
||||
static int _set_cca_threshold(ieee802154_dev_t *dev, int8_t threshold)
|
||||
@ -295,9 +344,9 @@ static int _config_phy(ieee802154_dev_t *dev, const ieee802154_phy_conf_t *conf)
|
||||
static int _confirm_set_trx_state(ieee802154_dev_t *dev)
|
||||
{
|
||||
(void) dev;
|
||||
if (RFCORE->XREG_FSMSTAT0bits.FSM_FFCTRL_STATE == FSM_STATE_RX_CALIBRATION) {
|
||||
return -EAGAIN;
|
||||
}
|
||||
assert(cc2538_state == CC2538_STATE_TRX_TRANSITION);
|
||||
cc2538_state = CC2538_STATE_READY;
|
||||
cc2538_rf_enable_irq();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -305,33 +354,38 @@ static int _request_set_trx_state(ieee802154_dev_t *dev, ieee802154_trx_state_t
|
||||
{
|
||||
|
||||
(void) dev;
|
||||
int irq = irq_disable();
|
||||
if (cc2538_tx_busy || cc2538_rx_busy) {
|
||||
irq_restore(irq);
|
||||
return -EBUSY;
|
||||
cc2538_rf_disable_irq();
|
||||
int res = -EBUSY;
|
||||
if (cc2538_state != CC2538_STATE_READY) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
res = 0;
|
||||
cc2538_state = CC2538_STATE_TRX_TRANSITION;
|
||||
|
||||
switch (state) {
|
||||
case IEEE802154_TRX_STATE_TRX_OFF:
|
||||
case IEEE802154_TRX_STATE_TX_ON:
|
||||
if (RFCORE->XREG_FSMSTAT0bits.FSM_FFCTRL_STATE != FSM_STATE_IDLE) {
|
||||
RFCORE_SFR_RFST = ISRFOFF;
|
||||
}
|
||||
cc2538_rx_busy = false;
|
||||
break;
|
||||
case IEEE802154_TRX_STATE_RX_ON:
|
||||
RFCORE_XREG_RFIRQM0 |= RXPKTDONE;
|
||||
/* Enable RX Chain */
|
||||
RFCORE_XREG_FRMCTRL0 &= ~CC2538_FRMCTRL0_RX_MODE_DIS;
|
||||
_enable_rx();
|
||||
RFCORE_SFR_RFST = ISRXON;
|
||||
break;
|
||||
}
|
||||
|
||||
RFCORE_SFR_RFIRQF0 = 0;
|
||||
RFCORE_SFR_RFIRQF1 = 0;
|
||||
RFCORE_SFR_RFIRQF0 &= ~RXPKTDONE;
|
||||
RFCORE_SFR_RFIRQF0 &= ~SFD;
|
||||
|
||||
irq_restore(irq);
|
||||
return 0;
|
||||
end:
|
||||
if (res < 0) {
|
||||
cc2538_rf_enable_irq();
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void cc2538_irq_handler(void)
|
||||
@ -339,79 +393,108 @@ void cc2538_irq_handler(void)
|
||||
uint_fast8_t flags_f0 = RFCORE_SFR_RFIRQF0;
|
||||
uint_fast8_t flags_f1 = RFCORE_SFR_RFIRQF1;
|
||||
|
||||
RFCORE_SFR_RFIRQF0 = 0;
|
||||
RFCORE_SFR_RFIRQF1 = 0;
|
||||
uint8_t handled_f0 = 0;
|
||||
uint8_t handled_f1 = 0;
|
||||
|
||||
if ((flags_f0 & SFD)) {
|
||||
/* If the radio already transmitted, this SFD is the TX_START event */
|
||||
if (cc2538_tx_busy) {
|
||||
cc2538_rf_hal->cb(cc2538_rf_hal, IEEE802154_RADIO_INDICATION_TX_START);
|
||||
}
|
||||
/* If the RX chain was not busy, the detected SFD corresponds to a new
|
||||
* incoming frame. Note the automatic ACK frame also triggers this event.
|
||||
* Therefore, we use this variable to distinguish them. */
|
||||
else if (!cc2538_rx_busy){
|
||||
cc2538_rx_busy = true;
|
||||
cc2538_rf_hal->cb(cc2538_rf_hal, IEEE802154_RADIO_INDICATION_RX_START);
|
||||
}
|
||||
}
|
||||
assert(cc2538_state != CC2538_STATE_TRX_TRANSITION);
|
||||
|
||||
if (flags_f1 & TXDONE) {
|
||||
handled_f1 |= TXDONE;
|
||||
/* TXDONE marks the end of the TX chain. The radio is not busy anymore */
|
||||
cc2538_tx_busy = false;
|
||||
assert(cc2538_state == CC2538_STATE_TX_BUSY);
|
||||
cc2538_state = CC2538_STATE_CONFIRM_TX;
|
||||
cc2538_rf_hal->cb(cc2538_rf_hal, IEEE802154_RADIO_CONFIRM_TX_DONE);
|
||||
}
|
||||
|
||||
/* The RX chain is not busy anymore on TXACKDONE event */
|
||||
if (flags_f1 & TXACKDONE) {
|
||||
handled_f1 |= TXACKDONE;
|
||||
assert(cc2538_state == CC2538_STATE_TX_ACK);
|
||||
cc2538_state = CC2538_STATE_READY;
|
||||
}
|
||||
|
||||
if ((flags_f0 & SFD)) {
|
||||
handled_f0 |= SFD;
|
||||
switch(cc2538_state) {
|
||||
case CC2538_STATE_READY:
|
||||
cc2538_rf_hal->cb(cc2538_rf_hal, IEEE802154_RADIO_INDICATION_RX_START);
|
||||
break;
|
||||
case CC2538_STATE_TX_BUSY:
|
||||
/* If the radio already transmitted, this SFD is the TX_START event */
|
||||
cc2538_rf_hal->cb(cc2538_rf_hal, IEEE802154_RADIO_INDICATION_TX_START);
|
||||
break;
|
||||
case CC2538_STATE_TX_ACK:
|
||||
/* The detected SFD comes from the transmitted ACK frame. Simply
|
||||
* ignore it */
|
||||
break;
|
||||
default:
|
||||
/* This should never happen */
|
||||
DEBUG("ERROR: cc2538_state: %i\n", cc2538_state);
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (flags_f0 & RXPKTDONE) {
|
||||
handled_f0 |= RXPKTDONE;
|
||||
/* CRC check */
|
||||
uint8_t pkt_len = rfcore_peek_rx_fifo(0);
|
||||
if (rfcore_peek_rx_fifo(pkt_len) & CC2538_CRC_BIT_MASK) {
|
||||
/* Disable RX while the frame has not been processed */
|
||||
RFCORE_XREG_FRMCTRL0 |= CC2538_FRMCTRL0_RX_MODE_DIS;
|
||||
_disable_rx();
|
||||
/* If AUTOACK is disabled or the ACK request bit is not set */
|
||||
if (IS_ACTIVE(CONFIG_IEEE802154_AUTO_ACK_DISABLE) ||
|
||||
(!(rfcore_peek_rx_fifo(1) & IEEE802154_FCF_ACK_REQ))) {
|
||||
/* The radio won't send an ACK. Therefore the RX chain is not
|
||||
* busy anymore
|
||||
*/
|
||||
cc2538_rx_busy = false;
|
||||
cc2538_state = CC2538_STATE_READY;
|
||||
}
|
||||
else {
|
||||
cc2538_state = CC2538_STATE_TX_ACK;
|
||||
}
|
||||
cc2538_rf_hal->cb(cc2538_rf_hal, IEEE802154_RADIO_INDICATION_RX_DONE);
|
||||
}
|
||||
else {
|
||||
/* Disable RX while the frame has not been processed */
|
||||
/* CRC failed; discard packet. The RX chain is not busy anymore */
|
||||
cc2538_rx_busy = false;
|
||||
cc2538_state = CC2538_STATE_READY;
|
||||
cc2538_rf_hal->cb(cc2538_rf_hal, IEEE802154_RADIO_INDICATION_CRC_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
/* The RX chain is not busy anymore on TXACKDONE event */
|
||||
if (flags_f1 & TXACKDONE) {
|
||||
cc2538_rx_busy = false;
|
||||
}
|
||||
|
||||
/* Check if the interrupt was triggered because the CSP finished its routine
|
||||
* (CSMA-CA or CCA request)
|
||||
*/
|
||||
if (flags_f1 & CSP_STOP) {
|
||||
handled_f1 |= CSP_STOP;
|
||||
RFCORE_XREG_CSPCTRL |= CC2538_CSP_MCU_CTRL_MASK;
|
||||
if (!cc2538_cca) {
|
||||
switch (cc2538_state) {
|
||||
case CC2538_STATE_TX_BUSY:
|
||||
if (RFCORE_XREG_CSPZ > 0) {
|
||||
RFCORE_SFR_RFST = ISTXON;
|
||||
}
|
||||
else {
|
||||
/* In case of CCA failure the TX chain is not busy anymore */
|
||||
cc2538_tx_busy = false;
|
||||
cc2538_state = CC2538_STATE_CONFIRM_TX;
|
||||
cc2538_rf_hal->cb(cc2538_rf_hal, IEEE802154_RADIO_CONFIRM_TX_DONE);
|
||||
}
|
||||
}
|
||||
else {
|
||||
break;
|
||||
case CC2538_STATE_CCA:
|
||||
cc2538_cca_status = BOOLEAN(RFCORE->XREG_FSMSTAT1bits.CCA)
|
||||
&& RFCORE->XREG_RSSISTATbits.RSSI_VALID;
|
||||
cc2538_state = CC2538_STATE_CONFIRM_CCA;
|
||||
cc2538_rf_hal->cb(cc2538_rf_hal, IEEE802154_RADIO_CONFIRM_CCA);
|
||||
break;
|
||||
default:
|
||||
/* This should never happen */
|
||||
DEBUG("ERROR: cc2538_state: %i\n", cc2538_state);
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
RFCORE_SFR_RFIRQF0 &= ~handled_f0;
|
||||
RFCORE_SFR_RFIRQF1 &= ~handled_f1;
|
||||
}
|
||||
|
||||
static int _off(ieee802154_dev_t *dev)
|
||||
|
Loading…
Reference in New Issue
Block a user