Skip to content

Commit

Permalink
cpu/cc2538: add NETDEV_EVENTs and fix reception
Browse files Browse the repository at this point in the history
This commit adds NETDEV_EVENT_RX_COMPLETE, NETDEV_EVENT_TX_COMPLETE,
NETDEV_EVENT_RX_START & NETDEV_EVENT_CRC_ERROR.

In RIOT-OS#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.
  • Loading branch information
fjmolinas committed Sep 30, 2020
1 parent aa26166 commit a221ea3
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 35 deletions.
26 changes: 25 additions & 1 deletion cpu/cc2538/include/cc2538_rf.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@
#define CC2538_RF_H

#include <stdbool.h>
#include <stdio.h>
#include <stdatomic.h>

#include "cc2538_rfcore.h"

#include "net/ieee802154.h"
#include "net/netdev.h"
Expand Down Expand Up @@ -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
*
Expand All @@ -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;

/**
Expand Down
9 changes: 4 additions & 5 deletions cpu/cc2538/radio/cc2538_rf.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions cpu/cc2538/radio/cc2538_rf_getset.c
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
127 changes: 98 additions & 29 deletions cpu/cc2538/radio/cc2538_rf_netdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,27 +20,21 @@
*/

#include <errno.h>
#include <stdatomic.h>

#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)
{
Expand Down Expand Up @@ -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;
Expand All @@ -328,21 +331,21 @@ 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;
}

/* Make sure pkt_len is not too short.
* 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;
Expand All @@ -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;

Expand All @@ -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();

Expand Down

0 comments on commit a221ea3

Please sign in to comment.