FreeRTOS 中断使用信号量和任务同步失败

问题:在os的中断中使用信号量,和另外一个task进行同步,一段时间后会出现信号量获取失败,任务一直处于就绪状态但是无法继续运行。其他任务不受影响。

测试方法:使用调试器:在isr中全局变量int_count计数和task中的全局变量int_count1基数对比,发现int_count1在运行一段时间后会停止,isr中int_count计数还在继续。

ISR:

int32_t CAN_IRQnCallBack(uint32_t event, uint32_t wparam, uint32_t lparam)
{
			BaseType_t xHigherPriorityTaskWoken = pdFALSE;
	if (event & CAN_EVENT_RECVMSG)
	{
		
		if (CAN_IsMsgInReceiveBuf((CAN_Type*)lparam))
		{
					int_count++;		
					CAN_MessageRead((CAN_Type*)lparam, &g_recvCANMsgInfo);
					Sdk_CAN_CopyData(&g_recvCANMsgBuff, g_recvCANMsgInfo, lparam);//¸´ÖÆÊý¾Ý
					Com_CAN_QInsertMsg(&g_recvedCANMsgQ, g_recvCANMsgBuff);//²åÈëÊý¾Ý
			/* The event has occurred, use the semaphore to unblock the task so the task
			can process the event. */
			xSemaphoreGiveFromISR( xSemaphore_can, &xHigherPriorityTaskWoken );
			/* Clear the interrupt here. */
			/* Now the task has been unblocked a context switch should be performed if
			xHigherPriorityTaskWoken is equal to pdTRUE. NOTE: The syntax required to perform
			a context switch from an ISR varies from port to port, and from compiler to
			compiler. Check the web documentation and examples for the port being used to
			find the syntax required for your application. */
			portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
		}
	}
	
	return 1;
}

TASK:

/*CAN receive task */
void vTask_CheckCANData(void *pParams)
{
	
	for( ; ;)
	{

					/* Wait for the next event. */
			if( xSemaphoreTake( xSemaphore_can, portMAX_DELAY ) == pdTRUE )
			{
					int_count1++;
			/* The event has occurred, process it here. */
				Com_CAN_QDeleteMsg(&g_recvedCANMsgQ, &g_recvedCANDataBuf);
			/* Processing is complete, return to wait for the next event. */
			}
	}
}

原因分析:

首先打开freert os,一开始没有打开,导致分析方法不明。打开了configASSERT会发现程序会卡死在一个地方configASSERT( ucCurrentPriority >= ucMaxSysCallPriority );。

/* Definition assert() function. */
#define configASSERT(x)                          if((x)==0) { taskDISABLE_INTERRUPTS(); for( ;; ); }

FreeRTOS 中断使用信号量和任务同步失败_第1张图片

当前中断的优先级大于等于ucMaxSysCallPriority的优先级。ucMaxSysCallPriority在"FreeRTOSConfig.h"

 #define configMAX_SYSCALL_INTERRUPT_PRIORITY     95//191 /* equivalent to 0xb0, or priority 11. */

查找freert os的用户手册有如下说明:

FreeRTOS 中断使用信号量和任务同步失败_第2张图片

一开始没有打开configASSERT也可以分析,freert os的任务调度原理可一查找手册:

FreeRTOS 中断使用信号量和任务同步失败_第3张图片

说明从原理是程序写的是没问题的,所以可以猜测还是中断处理的问题,可能中断嵌套?

那么为什么在不受os管理的中断中使用信号量失败的原因又是什么呢?

分析一下,当这个高优先级的中断产生的时候,释放一个信号量,并调用任务调度,阻塞的任务获取到信号量。但是在信号量的释放和获取的过程需要taskENTER_CRITICAL();进行中断屏蔽,不允许重入,保证os的正常逻辑。

但是如果中断不受taskENTER_CRITICAL(); 屏蔽,自然会在运行一段时间后引发信号量操作失败。

解决办法:

初始化阶段设置CAN1中断优先级要小于configMAX_SYSCALL_INTERRUPT_PRIORITY     否则,高于configMAX_SYSCALL_INTERRUPT_PRIORITY     的中断是不可以使用os的接口的,因为这些中断是

优先于os的,不受管理的。

NVIC_SetPriority(CAN1_IRQn, 12);

该问题解决主要参考google文章:https://www.freertos.org/FreeRTOS_Support_Forum_Archive/January_2014/freertos_FreeRTOS_Sempahore_from_ISR_not_working_4594f7ddj.html

感谢!

你可能感兴趣的:(内核设计,操作系统)