mirror of
https://github.com/espressif/openthread.git
synced 2026-09-03 15:50:06 +00:00
[cc2538] interrupt driven radio driver (#4137)
- Add a configuration flag that enables the reception of 802.15.4 radio frames by way of a hardware interrupt so that frames are not missed whilst the CPU is busy processing something else. - Move otPlatRadioGetPromiscuous into separate function. The only place `readFrame` uses `aInstance` is when calling `otPlatRadioGetPromiscuous`, which then ignores `aInstance` anyway. So make a private function that reads the hardware register which `readFrame` and `otPlatRadioGetPromiscuous` can call. - Use cc2538RadioGetPromiscuous in readFrame. This allows us to drop the problematic `aInstance` pointer. Whilst we're here, make the function `static` since nothing else outside of `radio.c` calls it. - Call readFrame on incoming data. If the interrupt fires, call `readFrame` to pull that data in. When polling, also check (with the interrupts disabled) just in case. - Enable correct NVIC interrupt. `startup-gcc.c` enables alternate interrupt mappings, which places the radio receive interrupt at number 26; which is in the very first register. - Avoid debug logs in receiveFrame. If we call this method from an interrupt handler, we want to avoid calling `snprintf` and similar functions as these are generally not interrupt-safe. Instead, use an extra byte of RAM to store the number of bytes dropped so we can log it from a safe context. This is only needed when both interrupts _and_ platform logging are enabled.
This commit is contained in:
committed by
Jonathan Hui
parent
992ca4fdda
commit
ebf665eb6a
@@ -108,6 +108,20 @@
|
||||
*/
|
||||
#define OPENTHREAD_CONFIG_NCP_UART_ENABLE 1
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_CC2538_USE_RADIO_RX_INTERRUPT
|
||||
*
|
||||
* Enable support for using interrupt-driven radio reception. This allows
|
||||
* for a single frame to be received whilst the CPU is busy processing some
|
||||
* other code.
|
||||
*
|
||||
* To disable interrupts and just rely on polling, set this to 0.
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_CC2538_USE_RADIO_RX_INTERRUPT
|
||||
#define OPENTHREAD_CONFIG_CC2538_USE_RADIO_RX_INTERRUPT 1
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_CC2538_WITH_CC2592
|
||||
*
|
||||
|
||||
@@ -41,8 +41,6 @@
|
||||
#include "common/logging.hpp"
|
||||
#include "utils/code_utils.h"
|
||||
|
||||
#define RFCORE_RXTX_INT (141)
|
||||
|
||||
#define RFCORE_XREG_RFIRQM0 0x4008868C // RF interrupt masks
|
||||
#define RFCORE_XREG_RFIRQM1 0x40088690 // RF interrupt masks
|
||||
#define RFCORE_XREG_RFERRM 0x40088694 // RF error interrupt mask
|
||||
@@ -173,6 +171,13 @@ static int8_t sTxPower = 0;
|
||||
static otRadioState sState = OT_RADIO_STATE_DISABLED;
|
||||
static bool sIsReceiverEnabled = false;
|
||||
|
||||
#if OPENTHREAD_CONFIG_LOG_PLATFORM && OPENTHREAD_CONFIG_CC2538_USE_RADIO_RX_INTERRUPT
|
||||
// Debugging _and_ logging are enabled, so if there's a dropped frame
|
||||
// we'll need to store the length here as using snprintf from an interrupt
|
||||
// handler is not a good idea.
|
||||
static uint8_t sDroppedFrameLength = 0;
|
||||
#endif
|
||||
|
||||
void enableReceiver(void)
|
||||
{
|
||||
if (!sIsReceiverEnabled)
|
||||
@@ -327,10 +332,12 @@ void cc2538RadioInit(void)
|
||||
sReceiveFrame.mLength = 0;
|
||||
sReceiveFrame.mPsdu = sReceivePsdu;
|
||||
|
||||
// Enable interrupts for RX/TX, interrupt 141.
|
||||
// That's NVIC index 5 bit 13.
|
||||
HWREG(NVIC_EN0 + (5 * 4)) = (1 << 13);
|
||||
#if OPENTHREAD_CONFIG_CC2538_USE_RADIO_RX_INTERRUPT
|
||||
// Enable interrupts for RX/TX, interrupt 26.
|
||||
// That's NVIC index 0 (26 >> 5) bit 26 (26 & 0x1f).
|
||||
HWREG(NVIC_EN0 + (0 * 4)) = (1 << 26);
|
||||
HWREG(RFCORE_XREG_RFIRQM0) |= RFCORE_XREG_RFIRQM0_RXPKTDONE;
|
||||
#endif
|
||||
|
||||
// enable clock
|
||||
HWREG(SYS_CTRL_RCGCRFC) = SYS_CTRL_RCGCRFC_RFC0;
|
||||
@@ -610,11 +617,16 @@ otRadioCaps otPlatRadioGetCaps(otInstance *aInstance)
|
||||
return OT_RADIO_CAPS_NONE;
|
||||
}
|
||||
|
||||
static bool cc2538RadioGetPromiscuous(void)
|
||||
{
|
||||
return (HWREG(RFCORE_XREG_FRMFILT0) & RFCORE_XREG_FRMFILT0_FRAME_FILTER_EN) == 0;
|
||||
}
|
||||
|
||||
bool otPlatRadioGetPromiscuous(otInstance *aInstance)
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aInstance);
|
||||
|
||||
return (HWREG(RFCORE_XREG_FRMFILT0) & RFCORE_XREG_FRMFILT0_FRAME_FILTER_EN) == 0;
|
||||
return cc2538RadioGetPromiscuous();
|
||||
}
|
||||
|
||||
static int8_t cc2538RadioGetRssiOffset(void)
|
||||
@@ -649,12 +661,18 @@ void otPlatRadioSetPromiscuous(otInstance *aInstance, bool aEnable)
|
||||
}
|
||||
}
|
||||
|
||||
void readFrame(otInstance *aInstance)
|
||||
static void readFrame(void)
|
||||
{
|
||||
uint8_t length;
|
||||
uint8_t crcCorr;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* There is already a frame present in the buffer, return early so
|
||||
* we do not overwrite it (hopefully we'll catch it on the next run).
|
||||
*/
|
||||
otEXPECT(sReceiveFrame.mLength == 0);
|
||||
|
||||
otEXPECT(sState == OT_RADIO_STATE_RECEIVE || sState == OT_RADIO_STATE_TRANSMIT);
|
||||
otEXPECT((HWREG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_FIFOP) != 0);
|
||||
|
||||
@@ -666,7 +684,7 @@ void readFrame(otInstance *aInstance)
|
||||
#error Time sync requires the timestamp of SFD rather than that of rx done!
|
||||
#else
|
||||
// Timestamp
|
||||
if (otPlatRadioGetPromiscuous(aInstance))
|
||||
if (cc2538RadioGetPromiscuous())
|
||||
#endif
|
||||
{
|
||||
// The current driver only supports milliseconds resolution.
|
||||
@@ -692,8 +710,14 @@ void readFrame(otInstance *aInstance)
|
||||
// resets rxfifo
|
||||
HWREG(RFCORE_SFR_RFST) = RFCORE_SFR_RFST_INSTR_FLUSHRX;
|
||||
HWREG(RFCORE_SFR_RFST) = RFCORE_SFR_RFST_INSTR_FLUSHRX;
|
||||
|
||||
#if OPENTHREAD_CONFIG_LOG_PLATFORM && OPENTHREAD_CONFIG_CC2538_USE_RADIO_RX_INTERRUPT
|
||||
// Debugging _and_ logging are enabled, it may not be safe to do
|
||||
// logging if we're in the interrupt context, so just stash the
|
||||
// length and do the logging later.
|
||||
sDroppedFrameLength = length;
|
||||
#else
|
||||
otLogDebgPlat("Dropping %d received bytes (Invalid CRC)", length);
|
||||
#endif
|
||||
}
|
||||
|
||||
// check for rxfifo overflow
|
||||
@@ -710,7 +734,21 @@ exit:
|
||||
|
||||
void cc2538RadioProcess(otInstance *aInstance)
|
||||
{
|
||||
readFrame(aInstance);
|
||||
#if OPENTHREAD_CONFIG_CC2538_USE_RADIO_RX_INTERRUPT
|
||||
// Disable the receive interrupt so that sReceiveFrame doesn't get
|
||||
// blatted by the interrupt handler while we're polling.
|
||||
HWREG(RFCORE_XREG_RFIRQM0) &= ~RFCORE_XREG_RFIRQM0_RXPKTDONE;
|
||||
#endif
|
||||
|
||||
readFrame();
|
||||
|
||||
#if OPENTHREAD_CONFIG_LOG_PLATFORM && OPENTHREAD_CONFIG_CC2538_USE_RADIO_RX_INTERRUPT
|
||||
if (sDroppedFrameLength != 0)
|
||||
{
|
||||
otLogDebgPlat("Dropping %d received bytes (Invalid CRC)", sDroppedFrameLength);
|
||||
sDroppedFrameLength = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((sState == OT_RADIO_STATE_RECEIVE && sReceiveFrame.mLength > 0) ||
|
||||
(sState == OT_RADIO_STATE_TRANSMIT && sReceiveFrame.mLength > IEEE802154_ACK_LENGTH))
|
||||
@@ -772,10 +810,30 @@ void cc2538RadioProcess(otInstance *aInstance)
|
||||
}
|
||||
|
||||
sReceiveFrame.mLength = 0;
|
||||
|
||||
#if OPENTHREAD_CONFIG_CC2538_USE_RADIO_RX_INTERRUPT
|
||||
// Turn the receive interrupt handler back on now the buffer is clear.
|
||||
HWREG(RFCORE_XREG_RFIRQM0) |= RFCORE_XREG_RFIRQM0_RXPKTDONE;
|
||||
#endif
|
||||
}
|
||||
|
||||
void RFCoreRxTxIntHandler(void)
|
||||
{
|
||||
#if OPENTHREAD_CONFIG_CC2538_USE_RADIO_RX_INTERRUPT
|
||||
if (HWREG(RFCORE_SFR_RFIRQF0) & RFCORE_SFR_RFIRQF0_RXPKTDONE)
|
||||
{
|
||||
readFrame();
|
||||
|
||||
if (sReceiveFrame.mLength > 0)
|
||||
{
|
||||
// A frame has been received, disable the interrupt handler
|
||||
// until the main loop has dealt with this previous frame,
|
||||
// otherwise we might overwrite it whilst it is being read.
|
||||
HWREG(RFCORE_XREG_RFIRQM0) &= ~RFCORE_XREG_RFIRQM0_RXPKTDONE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
HWREG(RFCORE_SFR_RFIRQF0) = 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user