FreeRTOS queues may be more expensive, but they provide benefits your queue may not provide. FreeRTOS's queues can switch tasks upon Queue send and receive, and your tasks will be managed better and sleep as appropriate whereas your own version likely doesn't integrate well with FreeRTOS. FreeRTOS PSoC Examples: Using multiple tasks in FreeRTOS: FreeRTOS Queue Example: Using a queue to communicate between tasks: PSoC 6 FreeRTOS - The First Example: Booting FreeRTOS on PSoC 6: FreeRTOS Binary Semaphore: An first example of a binary semaphore: FreeRTOS Binary Semaphore (Part 2) Removing polling in the UART Task: FreeRTOS Counting Semaphore.
PermalinkJoin GitHub today
The UART event handler passed to nrfdrvuartinit uses a semaphore to notify the RX task that data has been received, and the RX task sets up another receive using nrfdrvuartrx, then the RX task waits on the semaphore again.
GitHub is home to over 40 million developers working together to host and review code, manage projects, and build software together.
Sign up Find file Copy path
gbmhunterFixed comments (see .c to .h).d3141d6Nov 7, 2012
1 contributor
//! |
//! @file UartComms.c |
//! @author Geoffrey Hunter <[email protected]> (www.cladlab.com) |
//! @date 12/09/2012 |
//! @brief See UartComms.h |
//! @details |
//! <b>Last Modified: </b> 07/11/2012 n |
//! <b>Version: </b> v1.0.2 n |
//! <b>Company: </b> CladLabs n |
//! <b>Project: </b> Free Code Modules n |
//! <b>Language: </b> C n |
//! <b>Compiler: </b> GCC n |
//! <b>uC Model: </b> PSoC5 n |
//! <b>Computer Architecture: </b> ARM n |
//! <b>Operating System: </b> FreeRTOS v7.2.0 n |
//! <b>Documentation Format: </b> Doxygen n |
//! <b>License: </b> GPLv3 n |
//! |
//! See the Doxygen documentation or UartComms.h for a detailed description on this module. |
//! |
//// |
// INCLUDES // |
//// |
// Standard PSoC includes |
#include<device.h> |
// FreeRTOS includes |
#include'FreeRTOS.h' |
#include'task.h' |
#include'queue.h' |
#include'semphr.h' |
// User includes |
#include'PublicDefinesAndTypeDefs.h' |
#include'Config.h' |
#include'UartComms.h' |
#include'UartDebug.h' |
//// |
// GUARDS // |
//// |
#ifdef __cplusplus |
extern'C' { |
#endif |
#ifndef configENABLE_TASK_UART_COMMS |
#error Please define the switch configENABLE_TASK_UART_COMMS |
#endif |
#ifndef configPRINT_DEBUG_UART_COMMS |
#error Please define the switch configPRINT_DEBUG_UART_COMMS |
#endif |
#ifndef configALLOW_SLEEP_UART_COMMS |
#error Please define the switch configALLOW_SLEEP_UART_COMMS |
#endif |
//// |
// PRIVATE DEFINES // |
//// |
#defineTX_QUEUE_SIZE (1) //!< Queue size is 1, messages are sent byte by byte across the queue. |
#defineRX_QUEUE_SIZE (1) //!< Queue size is 1, messages are sent byte by byte across the queue. |
#defineTX_QUEUE_MAX_WAIT_TIME_MS (1000) //!< Max time (in ms) to wait for putting character onto tx queue before error occurs |
//! Max time (in ms) to wait for another task to finish putting a string onto the tx queue |
//! Since only the DEBUG task is using this UART, the semaphore should never have to be |
//! waited on. |
#defineTX_SEMAPHORE_MAX_WAIT_TIME_MS (1000) |
//! Time to wait for another char to arrive on tx queue before the UART module is slept. |
#defineTIME_TO_WAIT_FOR_ANOTHER_CHAR_BEFORE_SLEEPING_MS (5) |
//// |
// PRIVATE TYPEDEF's // |
//// |
// none |
//// |
// PRIVATE VARIABLES/STRUCTURES // |
//// |
static xTaskHandle _txTaskHandle = 0; //!< Handle for the TX task |
static xSemaphoreHandle _xTxMutexSemaphore = 0; //!< Mutex semaphore for allowing only one task to write to the tx buffer at once |
static uint8 _uartDebugSleepLockCount = 0; //! Used by the functions UartComms_SleepLock() and UartComms_SleepUnlock() to keep track of how many time the uart has been locked from sleeping. |
//! RX queue. Uart interrupt places characters on this queue as soon as they are received. |
static xQueueHandle _xRxQueue; |
//! Tx queue. Place characters on here to send them to the DEBUG module. |
static xQueueHandle _xTxQueue; |
//! Variable is TRUE if uart is asleep, otherwise FALSE. |
staticbool_t _isAsleep = FALSE; |
//! Holds configurable UART parameters |
struct{ |
bool_t allowUartSleep; |
} _uartCommsParameters = |
{ |
.allowUartSleep = configALLOW_SLEEP_UART_COMMS |
}; |
//// |
// PRIVATE FUNCTION PROTOTYPES // |
//// |
// General functions |
voidUartComms_TxTask(void *pvParameters); |
// ISR's |
CY_ISR_PROTO(UartComms_UartRxIsr); |
//// |
// PUBLIC FUNCTIONS // |
//// |
voidUartComms_Start(uint32 txTaskStackSize, uint8 txTaskPriority) |
{ |
#if(configENABLE_TASK_UART_COMMS 1) |
// Create the tx task |
xTaskCreate( &vUartComms_TxTask, |
(signed portCHAR *) 'Comms Uart TX Task', |
txTaskStackSize, |
NULL, |
txTaskPriority, |
&_txTaskHandle); |
#endif |
// Create TX Queue |
_xTxQueue = xQueueCreate(configUART_COMMS_TX_QUEUE_LENGTH, TX_QUEUE_SIZE); |
// Create RX Queue |
_xRxQueue = xQueueCreate(configUART_COMMS_RX_QUEUE_LENGTH, RX_QUEUE_SIZE); |
// Create TX mutex semaphore |
_xTxMutexSemaphore = xSemaphoreCreateMutex(); |
// Start the debug UART. This is a Cpyress API call. |
UartCpComms_Start(); |
} |
xTaskHandle UartComms_ReturnTxTaskHandle(void) |
{ |
return _txTaskHandle; |
} |
bool_tUartComms_PutString(constchar* string) |
{ |
// Take semaphore to allow placing things on queue |
if(xSemaphoreTake(_xTxMutexSemaphore, TX_SEMAPHORE_MAX_WAIT_TIME_MS/portTICK_RATE_MS) pdFAIL) |
{ |
#if(configPRINT_DEBUG_UART_COMMS 1) |
staticchar *msgTimeoutWaitingForTxQueueSemaphore = 'UART_COMMS: Timeout waiting for tx queue semaphore.rn'; |
UartComms_PutString(msgTimeoutWaitingForTxQueueSemaphore); |
#endif |
returnFALSE; |
} |
//! @todo Add error handling |
// Put characters onto tx queue one-by-one |
while(*string != '0') |
{ |
// Put char on back of queue one-by-one |
xQueueSendToBack(_xTxQueue, string, TX_QUEUE_MAX_WAIT_TIME_MS/portTICK_RATE_MS); |
// Increment string |
string++; |
//! @todo Add error handling if queue fail |
} |
// Return semaphore |
xSemaphoreGive(_xTxMutexSemaphore); |
returnTRUE; |
} |
voidUartComms_GetChar(char* singleChar) |
{ |
xQueueReceive(_xRxQueue, singleChar, portMAX_DELAY); |
} |
bool_tUartComms_IsAsleep(void) |
{ |
if(_isAsleep TRUE) |
returnTRUE; |
else |
returnFALSE; |
} |
voidUartComms_SleepLock(void) |
{ |
// Stop context switch since UART_COMMS_Wakeup() is not thread-safe |
taskENTER_CRITICAL(); |
//vTaskSuspendAll(); |
// Wakeup UART if sleep lock was on 0 (a hence sleeping) as long as sleep is allowed |
if((_isAsleep TRUE) && (_uartCommsParameters.allowUartSleepTRUE)) |
{ |
// Set flag to false to prevent multiple wake-ups |
_isAsleep = FALSE; |
// Cypress APU call |
UartCpComms_Wakeup(); |
#if(configPRINT_DEBUG_UART_COMMS 1) |
staticchar *msgWakingUartComms = 'UART_COMMS: Woke up comms UART.rn'; |
UartComms_PutString(msgWakingUartComms); |
#endif |
} |
// Increment sleep lock count. If statement should never be false, but added just as a |
// precaution. |
if(_uartDebugSleepLockCount != 255) |
_uartDebugSleepLockCount++; |
// Allow context switch again |
//xTaskResumeAll(); |
taskEXIT_CRITICAL(); |
} |
voidUartComms_SleepUnlock(void) |
{ |
// Prevent contect switch since UART_COMMS_Sleep() is not thread-safe |
taskENTER_CRITICAL(); |
//vTaskSuspendAll(); |
// Decrement sleep lock count. If statement should never be false, but added just as a |
// precaution |
if(_uartDebugSleepLockCount != 0) |
_uartDebugSleepLockCount--; |
// Sleep UART if sleepLockCount has reached 0 |
if((_uartDebugSleepLockCount 0) && (_isAsleep FALSE)) |
{ |
if(_uartCommsParameters.allowUartSleepTRUE) |
{ |
/* |
#if(configPRINT_DEBUG_UART_COMMS 1) |
static char *msgSleepingUartComms = 'UART_COMMS: Sleeping UART DEBUG.rn'; |
UartComms_PutString(msgSleepingUartComms); |
// Wait for message to complete since sleeping itself |
while(!(UART_COMMS_ReadTxStatus() & UART_COMMS_TX_STS_COMPLETE)); |
#endif |
*/ |
// Sleep UART. Cypress API call. |
UartCpComms_Sleep(); |
// Set flag to true so UartComms_SleepLock() knows to wake up device |
_isAsleep = TRUE; |
} |
else |
{ |
/* @debug Repeatedly prints itself |
#if(configPRINT_DEBUG_UART_COMMS 1) |
static char *msgUartCommsSleepDisabled = 'UART_COMMS: UART DEBUG sleep disabled. Keeping awake.rn'; |
UartComms_PutString(msgUartCommsSleepDisabled); |
#endif |
*/ |
} |
} |
// Allow context switch again |
//xTaskResumeAll(); |
taskEXIT_CRITICAL(); |
} |
//// |
// PRIVATE FUNCTIONS // |
//// |
// TASK FUNCTIONS // |
//! @brief DEBUG UART TX task |
//! @param *pvParameters Void pointer (not used) |
//! @note Not thread-safe. Do not call from any task, this function is a task that |
//! is called by the FreeRTOS kernel |
//! @private |
voidUartComms_TxTask(void *pvParameters) |
{ |
#if(configPRINT_DEBUG_UART_COMMS 1) |
staticchar* msgUartCommsTxTaskStarted = 'UART_COMMS: Comms Uart TX task started.rn'; |
UartDebug_PutString(msgUartCommsTxTaskStarted); |
#endif |
// Start USART RX interrupt, store in vector table the function address of UartComms_UartRxISR() |
// This must be done in the task, since the interrupt calls xQueueSendToBackFromISR() which |
// must not be called before the scheduler starts (freeRTOS restriction). |
IsrCpUartCommsRx_StartEx(UartComms_UartRxIsr); |
typedefenum |
{ |
ST_INIT, //!< Initial state |
ST_IDLE, //!< Idle state. UART could be asleep in this state |
ST_SENDING //!< Sending state. UART is prevented from sleeping in this state until timeout |
}txTaskState_t; |
txTaskState_t txTaskState = ST_INIT; |
// Infinite task loop |
for(;;) |
{ |
//! Holds received character from the #xUartCommsTxQueue |
char singleChar; |
// State machine |
switch(txTaskState) |
{ |
case ST_INIT: |
{ |
// Allow UART to initially sleep if allowed to |
//UartComms_SleepLock(); |
UartComms_SleepUnlock(); |
// Go to idle state |
txTaskState = ST_IDLE; |
break; |
} |
case ST_IDLE: |
{ |
// Now UART is asleep, wait indefinetly for next char |
xQueueReceive(_xTxQueue, &singleChar, portMAX_DELAY); |
// Prevent UART from sleeping and wake-up if neccessary |
UartComms_SleepLock(); |
// Goto sending state |
txTaskState = ST_SENDING; |
break; |
} |
case ST_SENDING: |
{ |
// Send char using Cypress API. |
// This function will not return untill there is room to put character on buffer |
//! @todo Implement this in a blocking fashion? |
UartCpComms_PutChar(singleChar); |
if(xQueueReceive(_xTxQueue, &singleChar, TIME_TO_WAIT_FOR_ANOTHER_CHAR_BEFORE_SLEEPING_MS/portTICK_RATE_MS) pdFAIL) |
{ |
// Wait until UART has completely finished sending the message |
// (both the hardware buffer and the byte sent flag are set) |
//while(!(UART_COMMS_ReadTxStatus() & (UART_COMMS_TX_STS_FIFO_EMPTY | UART_COMMS_TX_STS_COMPLETE))); //(software wait) |
while(!(UartCpComms_ReadTxStatus() & UartCpComms_TX_STS_COMPLETE)); |
//CyDelay(95); |
// Now it is safe to unlock the UART to allow for sleeping |
UartComms_SleepUnlock(); |
// Go back to idle state |
txTaskState = ST_IDLE; |
} |
break; |
} |
} |
// Finished, now loop for next message |
} |
} |
//// |
// ISR's // |
//// |
//! @brief ISR called when UART rx buffer has new character |
//! @private |
CY_ISR(UartComms_UartRxIsr) |
{ |
// Check to see if we just slept, if so, wake up peripherals |
//! @todo Get rid of this |
//if(PowerMgmt_AreWeSleeping() TRUE) |
// PowerMgmt_WakeUp(); |
static portBASE_TYPE xHigherPriorityTaskWoken; |
// Set to false on interrupt entry |
xHigherPriorityTaskWoken = FALSE; |
// Get received byte (lower 8-bits) and error info from UART (higher 8-bits) (total 16-bits) |
do |
{ |
uint16_t byte = UartCpComms_GetByte(); |
// Mask error info |
uint8_t status = (byte >> 8); |
// Check for error |
if(status (UartCpComms_RX_STS_BREAK | UartCpComms_RX_STS_PAR_ERROR | UartCpComms_RX_STS_STOP_ERROR |
| UartCpComms_RX_STS_OVERRUN | UartCpComms_RX_STS_SOFT_BUFF_OVER)) |
{ |
// UART error has occured |
//Main_SetErrorLed(); |
#if(configPRINT_DEBUG_UartCpComms 1) |
if(status UartCpComms_RX_STS_MRKSPC) |
{ |
staticchar* msgErrorMarkOrSpaceWasReceivedInParityBit = 'DEBUG_RX_INT: Error: Mark or space was received in parity bit.rn'; |
UartDebug_PutString(msgErrorMarkOrSpaceWasReceivedInParityBit); |
} |
elseif(status UartCpComms_RX_STS_BREAK) |
{ |
staticchar* msgBreakWasDetected = 'DEBUG_RX_INT: Error: Break was detected.rn'; |
UartDebug_PutString(msgBreakWasDetected); |
} |
elseif(status UartCpComms_RX_STS_PAR_ERROR) |
{ |
staticchar* msgErorrParity = 'DEBUG_RX_INT: Error: Parity error was detected.rn'; |
UartDebug_PutString(msgErorrParity); |
} |
elseif(status UartCpComms_RX_STS_STOP_ERROR) |
{ |
staticchar* msgErorrStop = 'DEBUG_RX_INT: Error: Stop error was detected.rn'; |
UartDebug_PutString(msgErorrStop); |
} |
elseif(status UartCpComms_RX_STS_OVERRUN) |
{ |
staticchar* msgErrorFifoRxBufferOverrun = 'DEBUG_RX_INT: Error: FIFO RX buffer was overrun.rn'; |
UartDebug_PutString(msgErrorFifoRxBufferOverrun); |
} |
elseif(status UartCpComms_RX_STS_FIFO_NOTEMPTY) |
{ |
staticchar* msgErrorRxBufferNotEmpty = 'DEBUG_RX_INT: Error: RX buffer not empty.rn'; |
UartDebug_PutString(msgErrorRxBufferNotEmpty); |
} |
elseif(status UartCpComms_RX_STS_ADDR_MATCH) |
{ |
staticchar* msgErrorAddressMatch = 'DEBUG_RX_INT: Error: Address match.rn'; |
UartDebug_PutString(msgErrorAddressMatch); |
} |
elseif(status UartCpComms_RX_STS_SOFT_BUFF_OVER) |
{ |
staticchar* msgErrorSoftwareBufferOverflowed = 'DEBUG_RX_INT: Error: RX software buffer ovverflowed.rn'; |
UartDebug_PutString(msgErrorSoftwareBufferOverflowed); |
} |
#endif |
} |
else |
{ |
// Put byte in queue (ISR safe function) |
xQueueSendToBackFromISR(_xRxQueue, &byte, &xHigherPriorityTaskWoken); |
} |
} |
while((UartCpComms_ReadRxStatus() & UartCpComms_RX_STS_FIFO_NOTEMPTY) != 0x00); |
// Force a context swicth if interrupt unblocked a task with a higher or equal priority |
// to the currently running task |
portEND_SWITCHING_ISR(xHigherPriorityTaskWoken); |
} |
//// |
// GRAVEYARD // |
//// |
// none |
#ifdef __cplusplus |
} // extern 'C' { |
#endif |
// EOF |
Copy lines Copy permalink
Active5 months ago
I am working on STM32L152VB-A controller. I am using FreeRTOS.
I used CubeMX to generate the code and I configured USART1 with global interrupts.
The non interrupt RX and TX (HAL_UART_Receive and HAL_UART_Transmit) is working.
But I am trying to make it work with interrupts.
I used CubeMX to generate the code and I configured USART1 with global interrupts.
The non interrupt RX and TX (HAL_UART_Receive and HAL_UART_Transmit) is working.
But I am trying to make it work with interrupts.
Only after I called HAL_UART_Receive_IT, I am getting interrupt.
Since I couldn't know the receive data size, I am planning to receive characters one by one.
Since I couldn't know the receive data size, I am planning to receive characters one by one.
Since I use RTOS, I am confused about where to write HAL_UART_Receive_IT, as the message can come at any time. can anybody guide me??
PS: I tried calling the HAL_UART_Receive_IT inside ISR, but it is also not working.
HarikrishnanHarikrishnan2,1502 gold badges32 silver badges56 bronze badges
Freertos Uart Driver
1 Answer
Freertos Uart Queue Example
I think you're confusing HAL_UART_Receive_IT with a function which actually receives anything. This is not the case. This function merely enables the UART peripheral and its receive interrupt.
If you want to stick with the HAL library you need to pass a struct of type UART_HandleTypeDef as parameter to HAL_UART_Receive_IT which contains
- a uint8_t* pointer to a receive buffer
- a transfer counter for the number of elements you'd like to receive
As far as I know there is no way for receiving elements indefinitely with this framework because once the transfer counter reaches zero the receive interrupt gets disabled automatically. So if you need this you're probably better of writing the ISR yourself by overwriting the weak function defined by ST (most likely called 'UARTx_IRQHandler').
To finally integrate the receive interrupt in FreeRTOS you've got two options:
- Receive data inside the ISR into a raw (uint8_t*) buffer like HAL does and use a critical section which temporarily disables the receive interrupt when accessing it.
- Receive data inside the ISR into a FreeRTOS queue using the interrupt safe API. The official FreeRTOS book chapter 6 explains this very well.
VinciVinci