我有一个 UART 空闲中断,它应该通知任务 UART 上的活动已经结束。
为此,我使用了 BinarySemaphore,在这种情况下,它只是一个最大计数为 1 的信号量。
当我调用信号量释放函数时osSemaphoreRelease(semaphore_id_uart4_rx);
由于触发了以下断言,应用程序暂停。
/* 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 ) ) );
宏configASSERT
扩展为
if ((!( ( pxQueue->pcHead == ((void *)0) ) && ( pxQueue->pcTail != ((void *)0) ) )) == 0) {vPortRaiseBASEPRI(); for( ;; );}
现在 pxQueue->pcHead 的值为 0,而 pxQueue->pcTail 的值为非 0。所以断言被触发了。
此断言上方的注释表明这是为了从 ISR 中捕获对 MUTEX 的使用。但是,我没有使用 MUTEX,我使用的是 BinarySemaphore !FreeRTOS FAQ 本身鼓励您使用 Semaphores 或 BinarySemaphores 在 ISR 和 Task 之间进行同步。这就是我正在做的事情。但是二进制信号量仍然被检测为导致此问题的 MUTEX。我什至尝试从 STM32CubeMX RTOS 配置中禁用 MUTEX,但它仍将其检测为 MUTEX 并崩溃。
二进制信号量和互斥量非常相似,但有一些细微的差别:互斥量包括优先级继承机制,而二进制信号量没有。这使得二进制信号量成为实现同步(任务之间或任务与中断之间)的更好选择,而互斥锁成为实现简单互斥的更好选择。
我正在使用 NUCLEO-F429ZI 板,上面有 STM32F429ZIT6,CubeMX 版本:4.27.0,固件包名称和版本:STM32Cube FW_F4 V1.21.0
代码:
主功能:
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 */
}
情监侦:
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;
}
}
从 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;
}