From a221ea3dbf38b83e546e18a10b971f42eb632909 Mon Sep 17 00:00:00 2001 From: Francisco Molina Date: Fri, 25 Sep 2020 16:51:12 +0200 Subject: [PATCH] cpu/cc2538: add NETDEV_EVENTs and fix reception This commit adds NETDEV_EVENT_RX_COMPLETE, NETDEV_EVENT_TX_COMPLETE, NETDEV_EVENT_RX_START & NETDEV_EVENT_CRC_ERROR. In #13906 the crc lookahead had been moved because it would sometimes be inconsistent. The reason why is because since the reception is offloaded a new packet can be received before retrieving the first pkt from the FIFO. This PR fixes it by disabling reception while the frame is not processes i.e., `_recv` is not called. We also now flush at the end of a succesfull reception to know where in the fifo to probe. cc2538_off now does not flush the FIFO this the radio could be turned off after reception of a pkt but before this one is retrieved from the FIFO. --- cpu/cc2538/include/cc2538_rf.h | 26 +++++- cpu/cc2538/radio/cc2538_rf.c | 9 +- cpu/cc2538/radio/cc2538_rf_getset.c | 1 + cpu/cc2538/radio/cc2538_rf_netdev.c | 127 +++++++++++++++++++++------- 4 files changed, 128 insertions(+), 35 deletions(-) diff --git a/cpu/cc2538/include/cc2538_rf.h b/cpu/cc2538/include/cc2538_rf.h index 34808b6da855e..76cd09691ac25 100644 --- a/cpu/cc2538/include/cc2538_rf.h +++ b/cpu/cc2538/include/cc2538_rf.h @@ -23,6 +23,10 @@ #define CC2538_RF_H #include +#include +#include + +#include "cc2538_rfcore.h" #include "net/ieee802154.h" #include "net/netdev.h" @@ -206,6 +210,25 @@ enum { lna_pd = 0x2a, }; +/** + * @name CC2538 RF interrupts flags + * + * @{ + */ +#define CC2538_RF_SFD_TX (1 << 0) +#define CC2538_RF_SFD_RX (1 << 1) +#define CC2538_RF_TXDONE (1 << 2) +#define CC2538_RF_RXPKTDONE (1 << 3) +/** @} */ + +/** + * @name Internal device option flags + * @{ + */ +#define CC2538_OPT_PRELOADING (0x01) /**< preloading enabled */ + +/** @} */ + /** * @brief Device descriptor for CC2538 transceiver * @@ -214,7 +237,8 @@ enum { typedef struct { netdev_ieee802154_t netdev; /**< netdev parent struct */ uint8_t state; /**< current state of the radio */ - uint8_t flags; /**< Device specific flags */ + atomic_uint isr_flags; /**< interrupt flags */ + uint8_t flags; /**< device specific flags */ } cc2538_rf_t; /** diff --git a/cpu/cc2538/radio/cc2538_rf.c b/cpu/cc2538/radio/cc2538_rf.c index 58a9267df0a93..87705dad122c7 100644 --- a/cpu/cc2538/radio/cc2538_rf.c +++ b/cpu/cc2538/radio/cc2538_rf.c @@ -171,18 +171,17 @@ void cc2538_off(void) /* Wait for ongoing TX to complete (e.g. this could be an outgoing ACK) */ RFCORE_WAIT_UNTIL(RFCORE->XREG_FSMSTAT1bits.TX_ACTIVE == 0); - /* Flush RX FIFO */ - RFCORE_SFR_RFST = ISFLUSHRX; - /* Don't turn off if we are off as this will trigger a Strobe Error */ if (RFCORE_XREG_RXENABLE != 0) { RFCORE_SFR_RFST = ISRFOFF; + /* Clear FIFO IRQ */ + RFCORE_SFR_RFIRQF0 &= ~(RXPKTDONE | FIFOP | SFD); } } bool cc2538_on(void) { - /* Flush RX FIFO */ + /* Flush RX FIFO and reset demodulator */ RFCORE_SFR_RFST = ISFLUSHRX; /* Enable/calibrate RX */ @@ -221,7 +220,7 @@ void cc2538_tx_exec(cc2538_rf_t *dev) /* Transmission does not trigger an SFD interrupt, so we need to poll and wait fot the SFD bit to be set */ while (RFCORE->XREG_FSMSTAT1bits.TX_ACTIVE) { - if(RFCORE->XREG_FSMSTAT1bits.SFD) { + if (RFCORE->XREG_FSMSTAT1bits.SFD) { DEBUG_PUTS("[cc2538_rf] EVT - TX_STARTED"); netdev->event_callback(netdev, NETDEV_EVENT_TX_STARTED); break; diff --git a/cpu/cc2538/radio/cc2538_rf_getset.c b/cpu/cc2538/radio/cc2538_rf_getset.c index 08e9f68121967..b3e47b45f0313 100644 --- a/cpu/cc2538/radio/cc2538_rf_getset.c +++ b/cpu/cc2538/radio/cc2538_rf_getset.c @@ -174,6 +174,7 @@ void cc2538_set_monitor(bool mode) void cc2538_set_state(cc2538_rf_t *dev, netopt_state_t state) { switch (state) { + case NETOPT_STATE_STANDBY: case NETOPT_STATE_OFF: case NETOPT_STATE_SLEEP: cc2538_off(); diff --git a/cpu/cc2538/radio/cc2538_rf_netdev.c b/cpu/cc2538/radio/cc2538_rf_netdev.c index d2d349fead901..096a9e9879a5b 100644 --- a/cpu/cc2538/radio/cc2538_rf_netdev.c +++ b/cpu/cc2538/radio/cc2538_rf_netdev.c @@ -20,27 +20,21 @@ */ #include +#include #include "net/gnrc.h" #include "net/netdev.h" +#include "cpu.h" #include "cc2538_rf.h" #include "cc2538_rf_netdev.h" #include "cc2538_rf_internal.h" -#define ENABLE_DEBUG (0) +#define ENABLE_DEBUG 0 #include "debug.h" /* Reference pointer for the IRQ handler */ -static netdev_t *_dev; - -void cc2538_irq_handler(void) -{ - RFCORE_SFR_RFIRQF0 = 0; - RFCORE_SFR_RFIRQF1 = 0; - - netdev_trigger_event_isr(_dev); -} +static cc2538_rf_t *_dev; static int _get(netdev_t *netdev, netopt_t opt, void *value, size_t max_len) { @@ -309,6 +303,15 @@ static int _send(netdev_t *netdev, const iolist_t *iolist) return pkt_len; } +static void _recv_complete(netdev_t *netdev) +{ + (void) netdev; + /* flush the RX fifo*/ + RFCORE_SFR_RFST = ISFLUSHRX; + /* go back to receiving */ + RFCORE_SFR_RFST = ISRXON; +} + static int _recv(netdev_t *netdev, void *buf, size_t len, void *info) { (void) netdev; @@ -328,7 +331,7 @@ static int _recv(netdev_t *netdev, void *buf, size_t len, void *info) /* Make sure pkt_len is sane */ if (pkt_len > CC2538_RF_MAX_DATA_LEN) { DEBUG_PRINT("cc2538_rf: pkt_len > CC2538_RF_MAX_DATA_LEN\n"); - RFCORE_SFR_RFST = ISFLUSHRX; + _recv_complete(netdev); return -EOVERFLOW; } @@ -336,13 +339,13 @@ static int _recv(netdev_t *netdev, void *buf, size_t len, void *info) * There are at least 2 bytes (FCS). */ if (pkt_len < IEEE802154_FCS_LEN) { DEBUG_PRINT("cc2538_rf: pkt_len < IEEE802154_FCS_LEN\n"); - RFCORE_SFR_RFST = ISFLUSHRX; + _recv_complete(netdev); return -ENODATA; } if (len > 0) { /* GNRC wants us to drop the packet */ - RFCORE_SFR_RFST = ISFLUSHRX; + _recv_complete(netdev); } return pkt_len - IEEE802154_FCS_LEN; @@ -357,13 +360,6 @@ static int _recv(netdev_t *netdev, void *buf, size_t len, void *info) int8_t rssi_val = rfcore_read_byte() + CC2538_RSSI_OFFSET; uint8_t crc_corr_val = rfcore_read_byte(); - /* CRC check */ - if (!(crc_corr_val & CC2538_CRC_BIT_MASK)) { - /* CRC failed; discard packet */ - RFCORE_SFR_RFST = ISFLUSHRX; - return -ENODATA; - } - if (info != NULL) { netdev_ieee802154_rx_info_t *radio_info = info; @@ -386,26 +382,99 @@ static int _recv(netdev_t *netdev, void *buf, size_t len, void *info) (CC2538_CORR_VAL_MAX - CC2538_CORR_VAL_MIN); } - /* Check for overflow of the rx fifo */ - if (RFCORE->XREG_FSMSTAT1bits.FIFOP != 0 && - RFCORE->XREG_FSMSTAT1bits.FIFO == 0) - { - DEBUG_PRINT("cc2538_rf: RXFIFO Overflow\n"); - RFCORE_SFR_RFST = ISFLUSHRX; - } + /* always flush on completetion so we always know where the incoming + bytes are located, e.g.: when probing for the crc */ + _recv_complete(netdev); return pkt_len; } +void cc2538_irq_handler(void) +{ + /* read an clear the RF interrupt flags*/ + uint8_t irq_mask_0 = (uint8_t) RFCORE_SFR_RFIRQF0; + uint8_t irq_mask_1 = (uint8_t) RFCORE_SFR_RFIRQF1; + RFCORE_SFR_RFIRQF0 = 0; + RFCORE_SFR_RFIRQF1 = 0; + + DEBUG("[cc2538_rf_isr] RFIRQF0 %02x\n", irq_mask_0 ); + DEBUG("[cc2538_rf_isr] RFIRQF1 %02x\n", irq_mask_1 ); + + uint16_t new_flags = 0x0000; + uint16_t current_flags = atomic_load(&_dev->isr_flags); + + /* SFD ISR is triggered when an SFD has been received or transmitted */ + if (irq_mask_0 & SFD) { + if (RFCORE->XREG_FSMSTAT1bits.RX_ACTIVE) { + new_flags |= CC2538_RF_SFD_RX; + } + if (RFCORE->XREG_FSMSTAT1bits.TX_ACTIVE) { + new_flags |= CC2538_RF_SFD_TX; + } + } + + if (irq_mask_0 & (RXPKTDONE | FIFOP)) { + /* Disable future RX while the frame has not been processed */ + RFCORE_XREG_RXMASKCLR = 0xFF; + new_flags |= CC2538_RF_RXPKTDONE; + } + + if (irq_mask_1 & TXDONE) { + new_flags |= CC2538_RF_TXDONE; + } + + /* is ISR are serviced to slow then an event might be missed */ + if (IS_ACTIVE(ENABLE_DEBUG)) { + if (new_flags & current_flags) { + printf("[cc2538_rf]: ERROR lost IRQ events isr_flags: %02x\n", + new_flags & current_flags); + } + } + + atomic_store(&_dev->isr_flags, new_flags | current_flags); + + netdev_trigger_event_isr((netdev_t *) &_dev->netdev); +} + static void _isr(netdev_t *netdev) { - netdev->event_callback(netdev, NETDEV_EVENT_RX_COMPLETE); + unsigned state = irq_disable(); + uint16_t flags = atomic_load(&_dev->isr_flags); + atomic_store(&_dev->isr_flags, 0x0000); + irq_restore(state); + + if (flags & CC2538_RF_SFD_TX) { + DEBUG_PUTS("[cc2538_rf] EVT - TX_STARTED"); + netdev->event_callback(netdev, NETDEV_EVENT_TX_STARTED); + } + if (flags & CC2538_RF_TXDONE) { + DEBUG_PUTS("[cc2538_rf] EVT - TX_COMPLETE"); + netdev->event_callback(netdev, NETDEV_EVENT_TX_COMPLETE); + } + if (flags & CC2538_RF_SFD_RX) { + DEBUG_PUTS("[cc2538_rf] EVT - RX_STARTED"); + netdev->event_callback(netdev, NETDEV_EVENT_RX_STARTED); + } + if (flags & CC2538_RF_RXPKTDONE) { + /* CRC check */ + uint8_t pkt_len = rfcore_peek_rx_fifo(0); + if (rfcore_peek_rx_fifo(pkt_len) & CC2538_CRC_BIT_MASK) { + DEBUG_PUTS("[cc2538_rf] EVT - RX_COMPLETE"); + netdev->event_callback(netdev, NETDEV_EVENT_RX_COMPLETE); + } + else { + /* CRC failed, discard packet */ + DEBUG_PUTS("[cc2538_rf] EVT - CRC_ERROR\n"); + netdev->event_callback(netdev, NETDEV_EVENT_CRC_ERROR); + RFCORE_SFR_RFST = ISFLUSHRX; + } + } } static int _init(netdev_t *netdev) { cc2538_rf_t *dev = (cc2538_rf_t *) netdev; - _dev = netdev; + _dev = dev; uint16_t chan = cc2538_get_chan();