[efr32] revert uart.c to commit 4c06b47c34 (#4030)

Fixes NCP often entering a uninitialized:fault state during reset.
Readded otSysEventSignalPending to efr32mg12 uart.c
This commit is contained in:
Marven Gilhespie
2019-07-29 16:25:55 +01:00
committed by Jonathan Hui
parent 66cd36b638
commit e0fdc20f47
2 changed files with 73 additions and 333 deletions
+37 -169
View File
@@ -41,23 +41,17 @@
#include "em_core.h"
#include "uartdrv.h"
#include <assert.h>
#include <string.h>
#include "hal-config.h"
enum
{
kReceiveFifoSize = 128,
kDmaBlockSize = 64
};
#define USART_PORT USART0
#define USART_PORT_RX_IRQn USART0_RX_IRQn
#define USART_INIT \
{ \
USART_PORT, /* USART port */ \
USART0, /* USART port */ \
115200, /* Baud rate */ \
BSP_SERIAL_APP_TX_LOC, /* USART Tx pin location number */ \
BSP_SERIAL_APP_RX_LOC, /* USART Rx pin location number */ \
@@ -79,107 +73,39 @@ enum
DEFINE_BUF_QUEUE(EMDRV_UARTDRV_MAX_CONCURRENT_RX_BUFS, sUartRxQueue);
DEFINE_BUF_QUEUE(EMDRV_UARTDRV_MAX_CONCURRENT_TX_BUFS, sUartTxQueue);
static CORE_DECLARE_NVIC_MASK(sRxNvicMask);
static UARTDRV_HandleData_t sUartHandleData;
static UARTDRV_Handle_t sUartHandle = &sUartHandleData;
static const uint8_t * sTransmitBuffer;
static volatile uint16_t sTransmitLength;
static volatile bool sReceiveDeferred;
static uint8_t sReceiveBuffer[2];
static const uint8_t * sTransmitBuffer = NULL;
static volatile uint16_t sTransmitLength = 0;
// Using unwrapped indexes allows buffer full and buffer empty conditions to be easily distinguished.
// These values will eventually wrap themselves (due to an integer overflow). They should always be wrapped
// using %kReceiveFifoSize at the point of use, except if testing for a buffer empty condition (mReadEnd == mReadStart).
// kReceiveFifoSize must therefore also be specified to a length of a power of 2.
typedef struct ReceiveFifo_t
{
// The data buffer
uint8_t mBuffer[kReceiveFifoSize];
// The offset of the first item to be read from the list (unwrapped)
uint16_t mReadStart;
// The offset of the last item to be read plus one (unwrapped)
volatile uint16_t mReadEnd;
// The offset of first unused item (unwrapped)
volatile uint16_t mWrite;
// The offset of the first item written to the list.
volatile uint16_t mHead;
// The offset of the next item to be written to the list.
volatile uint16_t mTail;
} ReceiveFifo_t;
static ReceiveFifo_t sReceiveFifo;
static bool enqueueNextReceive(void);
static void updateReceiveProgress(uint8_t *aData, UARTDRV_Count_t aCount)
{
assert(aData != NULL);
const uint16_t blockStartWrapped = aData - sReceiveFifo.mBuffer;
const uint16_t readEndWrapped = sReceiveFifo.mReadEnd % kReceiveFifoSize;
// Check readEndWrapped is within range of the current block. Required when mReadEnd was set to the end of
// the buffer on a previous call and readEndWrapped now wraps to 0.
if (readEndWrapped >= blockStartWrapped && readEndWrapped < blockStartWrapped + kDmaBlockSize)
{
sReceiveFifo.mReadEnd += blockStartWrapped + aCount - readEndWrapped;
}
}
static void processReceive(void);
static void receiveDone(UARTDRV_Handle_t aHandle, Ecode_t aStatus, uint8_t *aData, UARTDRV_Count_t aCount)
{
updateReceiveProgress(aData, aCount);
if (!enqueueNextReceive())
// We can only write if incrementing mTail doesn't equal mHead
if (sReceiveFifo.mHead != (sReceiveFifo.mTail + 1) % kReceiveFifoSize)
{
// A failure to enqueue the next receive is due to no free blocks remaining in the buffer. Defer enqueueing
// the next receive operation to processReceive() (running in the main execution context) where the
// contents of the buffer shall firstly be emptied. In the mean time, flow control RTS will be deasserted.
assert(sReceiveDeferred == false);
sReceiveDeferred = true;
sReceiveFifo.mBuffer[sReceiveFifo.mTail] = aData[0];
sReceiveFifo.mTail = (sReceiveFifo.mTail + 1) % kReceiveFifoSize;
}
UARTDRV_Receive(aHandle, aData, 1, receiveDone);
otSysEventSignalPending();
}
static inline bool isBufferEmpty(uint16_t unwrappedReadStart, uint16_t unwrappedReadEnd)
{
return (unwrappedReadStart == unwrappedReadEnd);
}
static bool enqueueNextReceive(void)
{
bool result;
const uint16_t wrappedWrite = sReceiveFifo.mWrite % kReceiveFifoSize;
const uint16_t wrappedReadStart = sReceiveFifo.mReadStart % kReceiveFifoSize;
Ecode_t status;
if (isBufferEmpty(sReceiveFifo.mReadStart, sReceiveFifo.mReadEnd))
{
// Buffer is completely empty
result = true;
}
else if (wrappedReadStart == wrappedWrite)
{
// Buffer is completely full because it isn't empty and wrappedReadStart == wrappedWrite
result = false;
}
else if (wrappedReadStart > wrappedWrite)
{
// Read wrappedReadStart is ahead of wrappedWrite: the next block may or may not be fully vacant
result = (wrappedReadStart - wrappedWrite >= kDmaBlockSize);
}
else
{
// Read wrappedReadStart is behind wrappedWrite, so therefore there is at least one block free
result = true;
}
otEXPECT(result);
status = UARTDRV_Receive(sUartHandle, sReceiveFifo.mBuffer + wrappedWrite, kDmaBlockSize, receiveDone);
otEXPECT_ACTION(ECODE_OK == status, result = false);
sReceiveFifo.mWrite += kDmaBlockSize;
exit:
return result;
}
static void transmitDone(UARTDRV_Handle_t aHandle, Ecode_t aStatus, uint8_t *aData, UARTDRV_Count_t aCount)
{
sTransmitLength = 0;
@@ -188,69 +114,26 @@ static void transmitDone(UARTDRV_Handle_t aHandle, Ecode_t aStatus, uint8_t *aDa
static void processReceive(void)
{
uint16_t readEnd;
uint8_t * buffer;
UARTDRV_Count_t itemsReceived;
UARTDRV_Count_t itemsRemaining;
uint16_t wrappedReadStart;
uint16_t wrappedReadEnd;
uint16_t readLength;
CORE_DECLARE_NVIC_STATE;
// Copy tail to prevent multiple reads
uint16_t tail = sReceiveFifo.mTail;
CORE_ENTER_NVIC(&sRxNvicMask);
UARTDRV_GetReceiveStatus(sUartHandle, &buffer, &itemsReceived, &itemsRemaining);
if (buffer != NULL)
// If the data wraps around, process the first part
if (sReceiveFifo.mHead > tail)
{
// Only update the receive progress if a current receive is in progress (buffer not NULL)
updateReceiveProgress(buffer, itemsReceived);
otPlatUartReceived(sReceiveFifo.mBuffer + sReceiveFifo.mHead, kReceiveFifoSize - sReceiveFifo.mHead);
// Reset the buffer mHead back to zero.
sReceiveFifo.mHead = 0;
}
readEnd = sReceiveFifo.mReadEnd;
CORE_EXIT_NVIC();
wrappedReadStart = sReceiveFifo.mReadStart % kReceiveFifoSize;
wrappedReadEnd = readEnd % kReceiveFifoSize;
if (!isBufferEmpty(sReceiveFifo.mReadStart, readEnd))
// For any data remaining, process it
if (sReceiveFifo.mHead != tail)
{
if (wrappedReadStart >= wrappedReadEnd)
{
// The buffer isn't empty, and wrappedReadStart >= wrappedReadEnd. Firstly, data needs to be read
// from wrappedReadStart to the end of the buffer. Subsequently, data can then be read from the start
// of the buffer to wrappedReadEnd.
readLength = kReceiveFifoSize - wrappedReadStart;
otPlatUartReceived(sReceiveFifo.mBuffer + wrappedReadStart, readLength);
otPlatUartReceived(sReceiveFifo.mBuffer + sReceiveFifo.mHead, tail - sReceiveFifo.mHead);
// Move the read start index by the amount of data read
sReceiveFifo.mReadStart += readLength;
}
// mReadStart may have been modified above, so recalculate wrappedReadStart
wrappedReadStart = sReceiveFifo.mReadStart % kReceiveFifoSize;
if (!isBufferEmpty(sReceiveFifo.mReadStart, readEnd))
{
// There is still data in the buffer (i.e. wrappedReadStart < wrappedReadEnd)
readLength = wrappedReadEnd - wrappedReadStart;
otPlatUartReceived(sReceiveFifo.mBuffer + wrappedReadStart, readLength);
// All data has been read
sReceiveFifo.mReadStart = readEnd;
}
// Set mHead to the local tail we have cached
sReceiveFifo.mHead = tail;
}
CORE_ENTER_NVIC(&sRxNvicMask);
// The buffer has been emptied, but it may have since filled up again just before entering this critical section.
// Attempt to enqueue any receive operations that previously failed to enqueue due to a full buffer.
if (sReceiveDeferred)
{
sReceiveDeferred = !enqueueNextReceive();
}
CORE_EXIT_NVIC();
}
otError otPlatUartFlush(void)
@@ -269,33 +152,19 @@ static void processTransmit(void)
otError otPlatUartEnable(void)
{
otError error = OT_ERROR_NONE;
UARTDRV_Init_t uartInit = USART_INIT;
bool enqueuedReceive;
memset(&sRxNvicMask, 0, sizeof(sRxNvicMask));
CORE_NvicMaskSetIRQ(LDMA_IRQn, &sRxNvicMask);
CORE_NvicMaskSetIRQ(USART_PORT_RX_IRQn, &sRxNvicMask);
sReceiveFifo.mHead = 0;
sReceiveFifo.mTail = 0;
sReceiveFifo.mReadStart = 0;
sReceiveFifo.mReadEnd = 0;
sReceiveFifo.mWrite = 0;
sTransmitLength = 0;
sTransmitBuffer = NULL;
UARTDRV_Init(sUartHandle, &uartInit);
otEXPECT_ACTION(ECODE_OK == UARTDRV_Init(sUartHandle, &uartInit), error = OT_ERROR_FAILED);
for (uint8_t i = 0; i < sizeof(sReceiveBuffer); i++)
{
UARTDRV_Receive(sUartHandle, &sReceiveBuffer[i], sizeof(sReceiveBuffer[i]), receiveDone);
}
CORE_DECLARE_NVIC_STATE;
CORE_ENTER_NVIC(&sRxNvicMask);
enqueuedReceive = enqueueNextReceive();
CORE_EXIT_NVIC();
otEXPECT_ACTION(enqueuedReceive, error = OT_ERROR_FAILED);
exit:
return error;
return OT_ERROR_NONE;
}
otError otPlatUartDisable(void)
@@ -306,15 +175,14 @@ otError otPlatUartDisable(void)
otError otPlatUartSend(const uint8_t *aBuf, uint16_t aBufLength)
{
otError error = OT_ERROR_NONE;
Ecode_t status;
otEXPECT_ACTION(sTransmitBuffer == NULL, error = OT_ERROR_BUSY);
sTransmitBuffer = aBuf;
sTransmitLength = aBufLength;
status = UARTDRV_Transmit(sUartHandle, (uint8_t *)sTransmitBuffer, sTransmitLength, transmitDone);
otEXPECT_ACTION(ECODE_OK == status, error = OT_ERROR_FAILED);
UARTDRV_Transmit(sUartHandle, (uint8_t *)sTransmitBuffer, sTransmitLength, transmitDone);
exit:
return error;
}
+36 -164
View File
@@ -40,15 +40,12 @@
#include "em_core.h"
#include "uartdrv.h"
#include <assert.h>
#include <string.h>
#include "hal-config.h"
enum
{
kReceiveFifoSize = 128,
kDmaBlockSize = 64
};
#define USART_PORT USART0
@@ -79,103 +76,36 @@ enum
DEFINE_BUF_QUEUE(EMDRV_UARTDRV_MAX_CONCURRENT_RX_BUFS, sUartRxQueue);
DEFINE_BUF_QUEUE(EMDRV_UARTDRV_MAX_CONCURRENT_TX_BUFS, sUartTxQueue);
static CORE_DECLARE_NVIC_MASK(sRxNvicMask);
static UARTDRV_HandleData_t sUartHandleData;
static UARTDRV_Handle_t sUartHandle = &sUartHandleData;
static const uint8_t * sTransmitBuffer;
static volatile uint16_t sTransmitLength;
static volatile bool sReceiveDeferred;
static uint8_t sReceiveBuffer[2];
static const uint8_t * sTransmitBuffer = NULL;
static volatile uint16_t sTransmitLength = 0;
// Using unwrapped indexes allows buffer full and buffer empty conditions to be easily distinguished.
// These values will eventually wrap themselves (due to an integer overflow). They should always be wrapped
// using %kReceiveFifoSize at the point of use, except if testing for a buffer empty condition (mReadEnd == mReadStart).
// kReceiveFifoSize must therefore also be specified to a length of a power of 2.
typedef struct ReceiveFifo_t
{
// The data buffer
uint8_t mBuffer[kReceiveFifoSize];
// The offset of the first item to be read from the list (unwrapped)
uint16_t mReadStart;
// The offset of the last item to be read plus one (unwrapped)
volatile uint16_t mReadEnd;
// The offset of first unused item (unwrapped)
volatile uint16_t mWrite;
// The offset of the first item written to the list.
volatile uint16_t mHead;
// The offset of the next item to be written to the list.
volatile uint16_t mTail;
} ReceiveFifo_t;
static ReceiveFifo_t sReceiveFifo;
static bool enqueueNextReceive(void);
static void updateReceiveProgress(uint8_t *aData, UARTDRV_Count_t aCount)
{
assert(aData != NULL);
const uint16_t blockStartWrapped = aData - sReceiveFifo.mBuffer;
const uint16_t readEndWrapped = sReceiveFifo.mReadEnd % kReceiveFifoSize;
// Check readEndWrapped is within range of the current block. Required when mReadEnd was set to the end of
// the buffer on a previous call and readEndWrapped now wraps to 0.
if (readEndWrapped >= blockStartWrapped && readEndWrapped < blockStartWrapped + kDmaBlockSize)
{
sReceiveFifo.mReadEnd += blockStartWrapped + aCount - readEndWrapped;
}
}
static void processReceive(void);
static void receiveDone(UARTDRV_Handle_t aHandle, Ecode_t aStatus, uint8_t *aData, UARTDRV_Count_t aCount)
{
updateReceiveProgress(aData, aCount);
if (!enqueueNextReceive())
// We can only write if incrementing mTail doesn't equal mHead
if (sReceiveFifo.mHead != (sReceiveFifo.mTail + 1) % kReceiveFifoSize)
{
// A failure to enqueue the next receive is due to no free blocks remaining in the buffer. Defer enqueueing
// the next receive operation to processReceive() (running in the main execution context) where the
// contents of the buffer shall firstly be emptied. In the mean time, flow control RTS will be deasserted.
assert(sReceiveDeferred == false);
sReceiveDeferred = true;
}
}
static inline bool isBufferEmpty(uint16_t unwrappedReadStart, uint16_t unwrappedReadEnd)
{
return (unwrappedReadStart == unwrappedReadEnd);
}
static bool enqueueNextReceive(void)
{
bool result;
const uint16_t wrappedWrite = sReceiveFifo.mWrite % kReceiveFifoSize;
const uint16_t wrappedReadStart = sReceiveFifo.mReadStart % kReceiveFifoSize;
Ecode_t status;
if (isBufferEmpty(sReceiveFifo.mReadStart, sReceiveFifo.mReadEnd))
{
// Buffer is completely empty
result = true;
}
else if (wrappedReadStart == wrappedWrite)
{
// Buffer is completely full because it isn't empty and wrappedReadStart == wrappedWrite
result = false;
}
else if (wrappedReadStart > wrappedWrite)
{
// Read wrappedReadStart is ahead of wrappedWrite: the next block may or may not be fully vacant
result = (wrappedReadStart - wrappedWrite >= kDmaBlockSize);
}
else
{
// Read wrappedReadStart is behind wrappedWrite, so therefore there is at least one block free
result = true;
sReceiveFifo.mBuffer[sReceiveFifo.mTail] = aData[0];
sReceiveFifo.mTail = (sReceiveFifo.mTail + 1) % kReceiveFifoSize;
}
otEXPECT(result);
status = UARTDRV_Receive(sUartHandle, sReceiveFifo.mBuffer + wrappedWrite, kDmaBlockSize, receiveDone);
otEXPECT_ACTION(ECODE_OK == status, result = false);
sReceiveFifo.mWrite += kDmaBlockSize;
exit:
return result;
UARTDRV_Receive(aHandle, aData, 1, receiveDone);
}
static void transmitDone(UARTDRV_Handle_t aHandle, Ecode_t aStatus, uint8_t *aData, UARTDRV_Count_t aCount)
@@ -185,69 +115,26 @@ static void transmitDone(UARTDRV_Handle_t aHandle, Ecode_t aStatus, uint8_t *aDa
static void processReceive(void)
{
uint16_t readEnd;
uint8_t * buffer;
UARTDRV_Count_t itemsReceived;
UARTDRV_Count_t itemsRemaining;
uint16_t wrappedReadStart;
uint16_t wrappedReadEnd;
uint16_t readLength;
CORE_DECLARE_NVIC_STATE;
// Copy tail to prevent multiple reads
uint16_t tail = sReceiveFifo.mTail;
CORE_ENTER_NVIC(&sRxNvicMask);
UARTDRV_GetReceiveStatus(sUartHandle, &buffer, &itemsReceived, &itemsRemaining);
if (buffer != NULL)
// If the data wraps around, process the first part
if (sReceiveFifo.mHead > tail)
{
// Only update the receive progress if a current receive is in progress (buffer not NULL)
updateReceiveProgress(buffer, itemsReceived);
otPlatUartReceived(sReceiveFifo.mBuffer + sReceiveFifo.mHead, kReceiveFifoSize - sReceiveFifo.mHead);
// Reset the buffer mHead back to zero.
sReceiveFifo.mHead = 0;
}
readEnd = sReceiveFifo.mReadEnd;
CORE_EXIT_NVIC();
wrappedReadStart = sReceiveFifo.mReadStart % kReceiveFifoSize;
wrappedReadEnd = readEnd % kReceiveFifoSize;
if (!isBufferEmpty(sReceiveFifo.mReadStart, readEnd))
// For any data remaining, process it
if (sReceiveFifo.mHead != tail)
{
if (wrappedReadStart >= wrappedReadEnd)
{
// The buffer isn't empty, and wrappedReadStart >= wrappedReadEnd. Firstly, data needs to be read
// from wrappedReadStart to the end of the buffer. Subsequently, data can then be read from the start
// of the buffer to wrappedReadEnd.
readLength = kReceiveFifoSize - wrappedReadStart;
otPlatUartReceived(sReceiveFifo.mBuffer + wrappedReadStart, readLength);
otPlatUartReceived(sReceiveFifo.mBuffer + sReceiveFifo.mHead, tail - sReceiveFifo.mHead);
// Move the read start index by the amount of data read
sReceiveFifo.mReadStart += readLength;
}
// mReadStart may have been modified above, so recalculate wrappedReadStart
wrappedReadStart = sReceiveFifo.mReadStart % kReceiveFifoSize;
if (!isBufferEmpty(sReceiveFifo.mReadStart, readEnd))
{
// There is still data in the buffer (i.e. wrappedReadStart < wrappedReadEnd)
readLength = wrappedReadEnd - wrappedReadStart;
otPlatUartReceived(sReceiveFifo.mBuffer + wrappedReadStart, readLength);
// All data has been read
sReceiveFifo.mReadStart = readEnd;
}
// Set mHead to the local tail we have cached
sReceiveFifo.mHead = tail;
}
CORE_ENTER_NVIC(&sRxNvicMask);
// The buffer has been emptied, but it may have since filled up again just before entering this critical section.
// Attempt to enqueue any receive operations that previously failed to enqueue due to a full buffer.
if (sReceiveDeferred)
{
sReceiveDeferred = !enqueueNextReceive();
}
CORE_EXIT_NVIC();
}
otError otPlatUartFlush(void)
@@ -266,33 +153,19 @@ static void processTransmit(void)
otError otPlatUartEnable(void)
{
otError error = OT_ERROR_NONE;
UARTDRV_Init_t uartInit = USART_INIT;
bool enqueuedReceive;
memset(&sRxNvicMask, 0, sizeof(sRxNvicMask));
CORE_NvicMaskSetIRQ(LDMA_IRQn, &sRxNvicMask);
CORE_NvicMaskSetIRQ(USART_PORT_RX_IRQn, &sRxNvicMask);
sReceiveFifo.mHead = 0;
sReceiveFifo.mTail = 0;
sReceiveFifo.mReadStart = 0;
sReceiveFifo.mReadEnd = 0;
sReceiveFifo.mWrite = 0;
sTransmitLength = 0;
sTransmitBuffer = NULL;
UARTDRV_Init(sUartHandle, &uartInit);
otEXPECT_ACTION(ECODE_OK == UARTDRV_Init(sUartHandle, &uartInit), error = OT_ERROR_FAILED);
for (uint8_t i = 0; i < sizeof(sReceiveBuffer); i++)
{
UARTDRV_Receive(sUartHandle, &sReceiveBuffer[i], sizeof(sReceiveBuffer[i]), receiveDone);
}
CORE_DECLARE_NVIC_STATE;
CORE_ENTER_NVIC(&sRxNvicMask);
enqueuedReceive = enqueueNextReceive();
CORE_EXIT_NVIC();
otEXPECT_ACTION(enqueuedReceive, error = OT_ERROR_FAILED);
exit:
return error;
return OT_ERROR_NONE;
}
otError otPlatUartDisable(void)
@@ -303,15 +176,14 @@ otError otPlatUartDisable(void)
otError otPlatUartSend(const uint8_t *aBuf, uint16_t aBufLength)
{
otError error = OT_ERROR_NONE;
Ecode_t status;
otEXPECT_ACTION(sTransmitBuffer == NULL, error = OT_ERROR_BUSY);
sTransmitBuffer = aBuf;
sTransmitLength = aBufLength;
status = UARTDRV_Transmit(sUartHandle, (uint8_t *)sTransmitBuffer, sTransmitLength, transmitDone);
otEXPECT_ACTION(ECODE_OK == status, error = OT_ERROR_FAILED);
UARTDRV_Transmit(sUartHandle, (uint8_t *)sTransmitBuffer, sTransmitLength, transmitDone);
exit:
return error;
}