I have a UART Idle interrupt that is supposed to notify a task that activity on the UART has ended.
For this I am using a BinarySemaphore which in this case is just a Semaphore with max count of 1.
When I call the semaphore release function osSemaphoreRelease(semaphore_id_uart4_rx);
The application halts due to the following assert being triggered.
/* Normally a mutex would not be given from an interrupt, especially if
there is a mutex holder, as priority inheritance makes no sense for an
interrupts, only tasks. */
configASSERT( !( ( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX ) && ( pxQueue->pxMutexHolder != NULL ) ) );
The macro configASSERT
expands to
if ((!( ( pxQueue->pcHead == ((void *)0) ) && ( pxQueue->pcTail != ((void *)0) ) )) == 0) {vPortRaiseBASEPRI(); for( ;; );}
Now pxQueue->pcHead has a value of 0 and pxQueue->pcTail has a non 0 value. So the asseert is getting triggered.
The comment above this assert indicates that this is meant to catch use of MUTEXes from ISR. However, I am not using a MUTEX, I am using a BinarySemaphore ! FreeRTOS FAQ itself encourages you to use Semaphores or BinarySemaphores for syncronization between ISR and Task. Which is what I am doing. But still a Binary Semaphore is getting detected as a MUTEX which causes this problem. I even tried disabling MUTEXes from STM32CubeMX RTOS config, but it still detects it as a MUTEX and crashes.
Binary semaphores for FreeRTOS real time embedded software applications
Binary semaphores and mutexes are very similar but have some subtle differences: Mutexes include a priority inheritance mechanism, binary semaphores do not. This makes binary semaphores the better choice for implementing synchronisation (between tasks or between tasks and an interrupt), and mutexes the better choice for implementing simple mutual exclusion.
I am using NUCLEO-F429ZI board which has STM32F429ZIT6 on it, CubeMX version: 4.27.0, Firmware Package Name & Version: STM32Cube FW_F4 V1.21.0
Code:
Main Function:
int main(void)
{
/* USER CODE BEGIN 1 */
for(int i=0;i<360;i++) {
sine_wave_array[i]=sin(i/180.0 * 3.1416)*1900 + 1900 + 100;
if(sine_wave_array[i]<0) {
sine_wave_array[i]=0;
} else if(sine_wave_array[i]>=4096){
sine_wave_array[i]=4095;
}
}
//Initialize HMI struct
memset(&hmi,0,sizeof(hmi));
/* USER CODE END 1 */
/* MCU Configuration----------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_USART2_UART_Init();
MX_UART4_Init();
MX_UART5_Init();
MX_DAC_Init();
MX_TIM6_Init();
MX_SPI1_Init();
MX_I2C1_Init();
MX_ADC3_Init();
MX_USB_OTG_HS_PCD_Init();
MX_USART3_UART_Init();
MX_SPI4_Init();
MX_I2C2_Init();
MX_CAN1_Init();
MX_RTC_Init();
MX_TIM3_Init();
MX_TIM1_Init();
MX_TIM2_Init();
MX_TIM4_Init();
/* USER CODE BEGIN 2 */
HAL_ADC_Start_DMA(&hadc3,adcData,ADC_CHANNEL_COUNT);
__HAL_UART_ENABLE_IT(&huart4, UART_IT_IDLE);
// Setting IRQ priority for UART4
HAL_NVIC_SetPriority(UART4_IRQn, 15, 15);
HAL_NVIC_SetPriorityGrouping(0);
/* USER CODE END 2 */
/* USER CODE BEGIN RTOS_MUTEX */
/* add mutexes, ... */
/* USER CODE END RTOS_MUTEX */
/* USER CODE BEGIN RTOS_SEMAPHORES */
/* add semaphores, ... */
semaphore_id_uart4_rx = osSemaphoreCreate(osSemaphore(semaphore_uart4_rx), 1);
semaphore_id_uart5_rx = osSemaphoreCreate(osSemaphore(semaphore_uart5_rx), 1);
/* USER CODE END RTOS_SEMAPHORES */
/* USER CODE BEGIN RTOS_TIMERS */
/* start timers, add new ones, ... */
/* USER CODE END RTOS_TIMERS */
/* Create the thread(s) */
/* definition and creation of defaultTask */
osThreadDef(defaultTask, StartDefaultTask, osPriorityNormal, 0, 128);
defaultTaskHandle = osThreadCreate(osThread(defaultTask), NULL);
/* USER CODE BEGIN RTOS_THREADS */
/* add threads, ... */
osThreadDef(LWIPTask_, LWIPTask, osPriorityNormal, 0, 1024);
LWIPTaskHandle = osThreadCreate(osThread(LWIPTask_), NULL);
osThreadDef(USBTask_, USBTask, osPriorityNormal, 0, 512);
USBTaskHandle = osThreadCreate(osThread(USBTask_), NULL);
/* USER CODE END RTOS_THREADS */
/* USER CODE BEGIN RTOS_QUEUES */
/* add queues, ... */
/* USER CODE END RTOS_QUEUES */
/* Start scheduler */
osKernelStart();
/* We should never get here as control is now taken by the scheduler */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
ISR:
void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)
{
uint32_t isrflags = READ_REG(huart->Instance->SR);
uint32_t cr1its = READ_REG(huart->Instance->CR1);
uint32_t cr3its = READ_REG(huart->Instance->CR3);
uint32_t errorflags = 0x00U;
uint32_t dmarequest = 0x00U;
if ((isrflags & USART_SR_IDLE) != RESET) {
HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_SET);
volatile uint32_t tmp; /* Must be volatile to prevent optimizations */
tmp = huart->Instance->SR; /* Read status register */
tmp = huart->Instance->DR; /* Read data register */
HAL_UART_IdleCallback(huart);
}
/* If no error occurs */
errorflags = (isrflags & (uint32_t)(USART_SR_PE | USART_SR_FE | USART_SR_ORE | USART_SR_NE));
if(errorflags == RESET)
{
/* UART in mode Receiver -------------------------------------------------*/
if(((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))
{
UART_Receive_IT(huart);
return;
}
}
/* If some errors occur */
if((errorflags != RESET) && (((cr3its & USART_CR3_EIE) != RESET) || ((cr1its & (USART_CR1_RXNEIE | USART_CR1_PEIE)) != RESET)))
{
/* UART parity error interrupt occurred ----------------------------------*/
if(((isrflags & USART_SR_PE) != RESET) && ((cr1its & USART_CR1_PEIE) != RESET))
{
huart->ErrorCode |= HAL_UART_ERROR_PE;
}
/* UART noise error interrupt occurred -----------------------------------*/
if(((isrflags & USART_SR_NE) != RESET) && ((cr3its & USART_CR3_EIE) != RESET))
{
huart->ErrorCode |= HAL_UART_ERROR_NE;
}
/* UART frame error interrupt occurred -----------------------------------*/
if(((isrflags & USART_SR_FE) != RESET) && ((cr3its & USART_CR3_EIE) != RESET))
{
huart->ErrorCode |= HAL_UART_ERROR_FE;
}
/* UART Over-Run interrupt occurred --------------------------------------*/
if(((isrflags & USART_SR_ORE) != RESET) && ((cr3its & USART_CR3_EIE) != RESET))
{
huart->ErrorCode |= HAL_UART_ERROR_ORE;
}
/* Call UART Error Call back function if need be --------------------------*/
if(huart->ErrorCode != HAL_UART_ERROR_NONE)
{
/* UART in mode Receiver -----------------------------------------------*/
if(((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))
{
UART_Receive_IT(huart);
}
/* If Overrun error occurs, or if any error occurs in DMA mode reception,
consider error as blocking */
dmarequest = HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR);
if(((huart->ErrorCode & HAL_UART_ERROR_ORE) != RESET) || dmarequest)
{
/* Blocking error : transfer is aborted
Set the UART state ready to be able to start again the process,
Disable Rx Interrupts, and disable Rx DMA request, if ongoing */
UART_EndRxTransfer(huart);
/* Disable the UART DMA Rx request if enabled */
if(HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR))
{
CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR);
/* Abort the UART DMA Rx channel */
if(huart->hdmarx != NULL)
{
/* Set the UART DMA Abort callback :
will lead to call HAL_UART_ErrorCallback() at end of DMA abort procedure */
huart->hdmarx->XferAbortCallback = UART_DMAAbortOnError;
if(HAL_DMA_Abort_IT(huart->hdmarx) != HAL_OK)
{
/* Call Directly XferAbortCallback function in case of error */
huart->hdmarx->XferAbortCallback(huart->hdmarx);
}
}
else
{
/* Call user error callback */
HAL_UART_ErrorCallback(huart);
}
}
else
{
/* Call user error callback */
HAL_UART_ErrorCallback(huart);
}
}
else
{
/* Non Blocking error : transfer could go on.
Error is notified to user through user error callback */
HAL_UART_ErrorCallback(huart);
huart->ErrorCode = HAL_UART_ERROR_NONE;
}
}
return;
} /* End if some error occurs */
/* UART in mode Transmitter ------------------------------------------------*/
if(((isrflags & USART_SR_TXE) != RESET) && ((cr1its & USART_CR1_TXEIE) != RESET))
{
UART_Transmit_IT(huart);
return;
}
/* UART in mode Transmitter end --------------------------------------------*/
if(((isrflags & USART_SR_TC) != RESET) && ((cr1its & USART_CR1_TCIE) != RESET))
{
UART_EndTransmit_IT(huart);
return;
}
}
Functions called from ISR:
void HAL_UART_IdleCallback(UART_HandleTypeDef *huart) {
HAL_UART_RxGenericCallback(huart,3);
}
void HAL_UART_RxGenericCallback(UART_HandleTypeDef *huart,int type) {
if(type ==3) {
if(UART4 == huart->Instance) {
end4 = huart->RxXferSize - __HAL_DMA_GET_COUNTER(huart->hdmarx);
osSemaphoreRelease(semaphore_id_uart4_rx);
} else if (UART5 == huart->Instance) {
end5 = huart->RxXferSize - __HAL_DMA_GET_COUNTER(huart->hdmarx);
osSemaphoreRelease(semaphore_id_uart5_rx);
}
}
return;
}