NXP S32K146 FREERTOS信号量分析

分析一下原工程中使用FREERTOS的流程,在hal层运行系统freertos,hw层用任务链表+定时器,hal层生成.a库文件给上层hw调用
贴上部分源码分析

  1. 首先是计数型信号量的创建
//uart相关结构体
typedef struct
{  
//########略
    void* rb_tx_sem;                /* 消息发送信号量 */
} hal_uart_contex_t;
hal_uart_contex_t* ctx;

//Log函数之前分析了
#define FAIL_RETURN_GOTO(f, label) do { \
    if (!(f)) {\
        LOGW("failed(%s)", #f); \
        goto label; \
    } \
} while(0)

//hal_uart_open函数调用下边
 FAIL_RETURN_GOTO((ctx->rb_tx_sem = os_sem_create(0)) != NULL, __end);//返回一个句柄是否创建信号量成功,不成功goto label
 
 //封装了一下
 void* os_sem_create(INT8U init_value)
{
    return xSemaphoreCreateCounting(255, init_value);
}

//semphr.h声明
#define xSemaphoreCreateCounting( uxMaxCount, uxInitialCount ) 
xQueueCreateCountingSemaphore( ( uxMaxCount ), ( uxInitialCount )

//queue.c实现
//参数 uxMaxCount: 计数信号量最大计数值,当信号量值等于此值的时候释放信号量就会失败。
//参数 uxInitialCount: 计数信号量初始值。
	QueueHandle_t xQueueCreateCountingSemaphore( const \UBaseType_t uxMaxCount, 
	const UBaseType_t uxInitialCount )
	{
	QueueHandle_t xHandle;
	configASSERT( uxMaxCount != 0 );
	configASSERT( uxInitialCount <= uxMaxCount );
//创建了一个计数型信号量
	xHandle = xQueueGenericCreate( uxMaxCount, queueSEMAPHORE_QUEUE_ITEM_LENGTH, queueQUEUE_TYPE_COUNTING_SEMAPHORE);
//将计数信号量的初始值来设置uxMessagesWaiting
		if( xHandle != NULL )
		{
			( ( Queue_t * ) xHandle )->uxMessagesWaiting = uxInitialCount;
			traceCREATE_COUNTING_SEMAPHORE();
		}
		else
		{
			traceCREATE_COUNTING_SEMAPHORE_FAILED();
		}
		return xHandle;
	}
	
//通用队列创建函数
//参数uxQueueLength:队列项数目
//参数uxItemSize:每个队列项的大小
//参数ucQueueType:类型
	QueueHandle_t xQueueGenericCreate( const UBaseType_t uxQueueLength, \
	const UBaseType_t uxItemSize, const uint8_t ucQueueType )
	{
	Queue_t *pxNewQueue;
	size_t xQueueSizeInBytes;
	uint8_t *pucQueueStorage;
//断言判断一下队列长度是否大于0
		configASSERT( uxQueueLength > ( UBaseType_t ) 0 );
		if( uxItemSize == ( UBaseType_t ) 0 )
		{
		    //队列项为0即没有为队列项申请空间
			xQueueSizeInBytes = ( size_t ) 0;
		}
		else
		{
		    //为最大队列长度的队列项分配内存空间 长度*队列项
			xQueueSizeInBytes = ( size_t ) ( uxQueueLength * uxItemSize ); 
		}
       //分配队列结构体和队列项存储空间
		pxNewQueue = ( Queue_t * ) pvPortMalloc( sizeof( Queue_t ) + xQueueSizeInBytes );
		if( pxNewQueue != NULL )
		{
			/* 跳过队列结构,查找队列存储区域的位置. */
			pucQueueStorage = ( ( uint8_t * ) pxNewQueue ) + sizeof( Queue_t );
			#if( configSUPPORT_STATIC_ALLOCATION == 1 )
			{
				/* 队列既可以静态创建,也可以动态创建,因此请注意此任务是动态创建的,以防稍后删除。 . */
				pxNewQueue->ucStaticallyAllocated = pdFALSE;
			}
			#endif 
              //prvInitialiseNewQueue实现pcHead初始化uxLength/uxItemSize初始化
              //uxItemSize为0只需将phead设置为在内存映射中已知的一个良性值来指向队列  
			prvInitialiseNewQueue( uxQueueLength, uxItemSize, pucQueueStorage, ucQueueType, pxNewQueue );
		}
		else
		{
			traceQUEUE_CREATE_FAILED( ucQueueType );
		}
		return pxNewQueue;
	}
//到这我对于计数型信号量的理解就是,我创建一个队列但是不为队列项分配内存空间
//只为结构体分配内存空间,因为要用到Queue_t 结构体的成员uxMessagesWaiting作为计数,结构体的 phead也不能指向NULL因为互斥信号量要用到NULL,指向了队列结构体本身。
  1. 其次是互斥型信号量的创建
//创建互斥信号量的实现
	QueueHandle_t xQueueCreateMutex( const uint8_t ucQueueType )
	{
	//和计数型型号量的区别就是少了两句断言
	Queue_t *pxNewQueue;
	//区别在于互斥信号量的长度为1
	const UBaseType_t uxMutexLength = ( UBaseType_t ) 1, uxMutexSize = ( UBaseType_t ) 0;
		pxNewQueue = ( Queue_t * ) xQueueGenericCreate( uxMutexLength, uxMutexSize, ucQueueType );
		//区别在于这个函数实现用于入队操作
		prvInitialiseMutex( pxNewQueue );
		return pxNewQueue;
	}
  1. 然后是计数信号量的其他处理
//根据架构在HW层的调用的发送接口
BOOLEAN hal_uart_write(UART_CH_E ch, INT8U* pdata, INT16U len)
{
    INT32S left = len;
    hal_uart_contex_t* ctx;
    //tx_mutex上锁
    ASSERT(os_mutex_lock(ctx->tx_mutex, 10000) == TRUE);
    while (left > 0 )
    {
        //rb_tx_mutex上锁
        ASSERT(os_mutex_lock(ctx->rb_tx_mutex, 1000) == TRUE);
        if (!ringbuf_is_full(ctx->rb_tx))
        {
            //环形队列写入
            len = ringbuf_write(ctx->rb_tx, pdata, MIN(ringbuf_free_size(ctx->rb_tx), left));
            if (len > 0)
            {
                left -= len;
                pdata += len;
            }
            //解锁rb_tx_mutex
            os_mutex_unlock(ctx->rb_tx_mutex);
            os_sem_post(ctx->rb_tx_sem);
        }
        else
        {
            os_mutex_unlock(ctx->rb_tx_mutex);
            os_sem_post(ctx->rb_tx_sem);
            os_task_sleep(2);
        }
    }
    //tx_mutex解锁
    os_mutex_unlock(ctx->tx_mutex);
}

//hal层封装
BOOLEAN os_sem_post(void* hdl)
{
    ASSERT(hdl != NULL);
    return xSemaphoreGive(hdl) == pdFALSE ? FALSE : TRUE;
}

//声明宏定义
#define xSemaphoreGive( xSemaphore )		xQueueGenericSend( ( QueueHandle_t ) ( xSemaphore ), NULL, semGIVE_BLOCK_TIME, queueSEND_TO_BACK )

//xQueueGenericSend函数实现   
//这个函数用于入队操作,绝不可以用在中断服务程序中

BaseType_t xQueueGenericSend( QueueHandle_t xQueue, const void * const pvItemToQueue, TickType_t xTicksToWait, const BaseType_t xCopyPosition )
{
BaseType_t xEntryTimeSet = pdFALSE, xYieldRequired;
TimeOut_t xTimeOut;
Queue_t * const pxQueue = ( Queue_t * ) xQueue;
//三个断言根据函数封装来判断
	configASSERT( pxQueue );
	configASSERT( !( ( pvItemToQueue == NULL ) && ( pxQueue->uxItemSize != ( UBaseType_t ) 0U ) ) );
	configASSERT( !( ( xCopyPosition == queueOVERWRITE ) && ( pxQueue->uxLength != 1 ) ) );
	#if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) )
	{
		configASSERT( !( ( xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED ) && ( xTicksToWait != 0 ) ) );
	}
	#endif

	for( ;; )
	{
		taskENTER_CRITICAL();
		{
//队列还有空闲?正在运行的任务一定要比等待访问队列的任务优先级高.
//如果使用覆盖式入队,则不需要关注队列是否满
			if( ( pxQueue->uxMessagesWaiting < pxQueue->uxLength ) || ( xCopyPosition == queueOVERWRITE ) )
			{
				traceQUEUE_SEND( pxQueue );
///*完成数据拷贝工作,分为从队列尾入队,从队列首入队和覆盖式入队*/
				xYieldRequired = prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );
//注 prvCopyDataToQueue 实现
//第一种是队列项大小为0时(即队列结构体成员uxItemSize为0,
//比如二进制信号量和计数信号量),不进行数据拷贝工作,
//而是将队列项计数器加1(即队列结构体成员uxMessagesWaiting+=1)
				#if ( configUSE_QUEUE_SETS == 1 )
				{
					if( pxQueue->pxQueueSetContainer != NULL )
					{
						if( prvNotifyQueueSetContainer( pxQueue, xCopyPosition ) != pdFALSE )
						{
							queueYIELD_IF_USING_PREEMPTION();
						}
						else
						{
							mtCOVERAGE_TEST_MARKER();
						}
					}
					else
					{
/* 如果有任务在此等待队列数据到来,则将该任务解除阻塞*/
						if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
						{
/*有任务因等待出队而阻塞,则将任务从队列等待接收列表中删除,
然后加入到就绪列表*/
							if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
							{
/* 解除阻塞的任务有更高的优先级,则当前任务要让出CPU,因此触发一个上下文切换.又因为现在还在临界区,
要等退出临界区后,才会执行上下文切换.*/
								queueYIELD_IF_USING_PREEMPTION();
							}
							else
							{
								mtCOVERAGE_TEST_MARKER();
							}
						}
						else if( xYieldRequired != pdFALSE )
						{
							queueYIELD_IF_USING_PREEMPTION();
						}
						else
						{
							mtCOVERAGE_TEST_MARKER();
						}
					}
				}
				#else /* configUSE_QUEUE_SETS */
				{
					if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
					{
						if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
						{
							queueYIELD_IF_USING_PREEMPTION();
						}
						else
						{
							mtCOVERAGE_TEST_MARKER();
						}
					}
					else if( xYieldRequired != pdFALSE )
					{
						queueYIELD_IF_USING_PREEMPTION();
					}
					else
					{
						mtCOVERAGE_TEST_MARKER();
					}
				}
				#endif /* configUSE_QUEUE_SETS */

				taskEXIT_CRITICAL();
				return pdPASS;
			}
			else
			{
				if( xTicksToWait == ( TickType_t ) 0 )
				{
					taskEXIT_CRITICAL();
					traceQUEUE_SEND_FAILED( pxQueue );
					return errQUEUE_FULL;
				}
				else if( xEntryTimeSet == pdFALSE )
				{
					vTaskInternalSetTimeOutState( &xTimeOut );
					xEntryTimeSet = pdTRUE;
				}
				else
				{
					mtCOVERAGE_TEST_MARKER();
				}
			}
		}
		taskEXIT_CRITICAL();
		vTaskSuspendAll();
		prvLockQueue( pxQueue );
		if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
		{
			if( prvIsQueueFull( pxQueue ) != pdFALSE )
			{
				traceBLOCKING_ON_QUEUE_SEND( pxQueue );
				vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToSend ), xTicksToWait );
				prvUnlockQueue( pxQueue );
				if( xTaskResumeAll() == pdFALSE )
				{
					portYIELD_WITHIN_API();
				}
			}
			else
			{
				/* Try again. */
				prvUnlockQueue( pxQueue );
				( void ) xTaskResumeAll();
			}
		}
		else
		{
			/* The timeout has expired. */
			prvUnlockQueue( pxQueue );
			( void ) xTaskResumeAll();

			traceQUEUE_SEND_FAILED( pxQueue );
			return errQUEUE_FULL;
		}
	}
}

有关于xQueueGenericSend这个函数的具体分析请参考

//freertos创建的UART发送任务(部分)
 if (os_sem_wait(ctx->rb_tx_sem, HAL_UART_TX_WAIT_TIMEOUT))
 {
            ASSERT(os_mutex_lock(ctx->rb_tx_mutex, 1000) == TRUE);
            //略 发送处理!!!!
            os_mutex_unlock(ctx->rb_tx_mutex);
 }
//封装
BOOLEAN os_sem_wait(void* hdl, INT16U waitms)
{
    ASSERT(hdl != NULL);
    return xSemaphoreTake(hdl, waitms / portTICK_PERIOD_MS) == pdFALSE ? FALSE : TRUE;
}
//宏定义声明
#define xSemaphoreTake( xSemaphore, xBlockTime )		xQueueSemaphoreTake( ( xSemaphore ), ( xBlockTime ) )

//函数实现
//xQueueSemaphoreTake实现
BaseType_t xQueueSemaphoreTake( QueueHandle_t xQueue, TickType_t xTicksToWait )
{
BaseType_t xEntryTimeSet = pdFALSE;
TimeOut_t xTimeOut;
Queue_t * const pxQueue = ( Queue_t * ) xQueue;

#if( configUSE_MUTEXES == 1 )
	BaseType_t xInheritanceOccurred = pdFALSE;
#endif

	configASSERT( ( pxQueue ) );
	configASSERT( pxQueue->uxItemSize == 0 );
	#if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) )
	{
		configASSERT( !( ( xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED ) && ( xTicksToWait != 0 ) ) );
	}
	#endif
	for( ;; )
	{
		taskENTER_CRITICAL();
		{
		    //计数赋值
			const UBaseType_t uxSemaphoreCount = pxQueue->uxMessagesWaiting;
			//判断是否有计数
			if( uxSemaphoreCount > ( UBaseType_t ) 0 )
			{
				traceQUEUE_RECEIVE( pxQueue );
			//拿走减与上边计数器加1对应
				pxQueue->uxMessagesWaiting = uxSemaphoreCount - ( UBaseType_t ) 1;
				#if ( configUSE_MUTEXES == 1 )
				{
					if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )
					{
						pxQueue->pxMutexHolder = ( int8_t * ) pvTaskIncrementMutexHeldCount();
					}
					else
					{
						mtCOVERAGE_TEST_MARKER();
					}
				}
				#endif /* configUSE_MUTEXES */
				if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )
				{
					if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
					{
						queueYIELD_IF_USING_PREEMPTION();
					}
					else
					{
						mtCOVERAGE_TEST_MARKER();
					}
				}
				else
				{
					mtCOVERAGE_TEST_MARKER();
				}

				taskEXIT_CRITICAL();
				return pdPASS;
			}
			else//计数器没值判断是否有阻塞时间
			{
				if( xTicksToWait == ( TickType_t ) 0 )
				{
					#if( configUSE_MUTEXES == 1 )
					{
						configASSERT( xInheritanceOccurred == pdFALSE );
					}
					#endif /* configUSE_MUTEXES */
					taskEXIT_CRITICAL();
					traceQUEUE_RECEIVE_FAILED( pxQueue );
					return errQUEUE_EMPTY;
				}
				else if( xEntryTimeSet == pdFALSE )
				{
					vTaskInternalSetTimeOutState( &xTimeOut );
					xEntryTimeSet = pdTRUE;
				}
				else
				{
					/* Entry time was already set. */
					mtCOVERAGE_TEST_MARKER();
				}
			}
		}
		taskEXIT_CRITICAL();
		vTaskSuspendAll();
		prvLockQueue( pxQueue );

		/* Update the timeout state to see if it has expired yet. */
		if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
		{
			if( prvIsQueueEmpty( pxQueue ) != pdFALSE )
			{
				traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue );

				#if ( configUSE_MUTEXES == 1 )
				{
					if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )
					{
						taskENTER_CRITICAL();
						{
							xInheritanceOccurred = xTaskPriorityInherit( ( void * ) pxQueue->pxMutexHolder );
						}
						taskEXIT_CRITICAL();
					}
					else
					{
						mtCOVERAGE_TEST_MARKER();
					}
				}
				#endif

				vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );
				prvUnlockQueue( pxQueue );
				if( xTaskResumeAll() == pdFALSE )
				{
					portYIELD_WITHIN_API();
				}
				else
				{
					mtCOVERAGE_TEST_MARKER();
				}
			}
			else
			{
				prvUnlockQueue( pxQueue );
				( void ) xTaskResumeAll();
			}
		}
		else
		{
			/* Timed out. */
			prvUnlockQueue( pxQueue );
			( void ) xTaskResumeAll();
			if( prvIsQueueEmpty( pxQueue ) != pdFALSE )
			{
				#if ( configUSE_MUTEXES == 1 )
				{
					if( xInheritanceOccurred != pdFALSE )
					{
						taskENTER_CRITICAL();
						{
							UBaseType_t uxHighestWaitingPriority;
							uxHighestWaitingPriority = prvGetDisinheritPriorityAfterTimeout( pxQueue );
							vTaskPriorityDisinheritAfterTimeout( ( void * ) pxQueue->pxMutexHolder, uxHighestWaitingPriority );
						}
						taskEXIT_CRITICAL();
					}
				}
				#endif /* configUSE_MUTEXES */

				traceQUEUE_RECEIVE_FAILED( pxQueue );
				return errQUEUE_EMPTY;
			}
			else
			{
				mtCOVERAGE_TEST_MARKER();
			}
		}
	}
}

有关于xQueueSemaphoreTake这个函数的具体分析请参考
总结:
一、通过函数 xQueueCreateCountingSemaphore()建队列,uxMessagesWaiting =初始值。(先初始化计数信号量)
二、函数中通过函数 xQueueGenericSend()释放信号量,因此信号量(uxMessagesWaiting +=1)变为有效。
三、任务 Task 通过函数 xQueueSemaphoreTake()获取信号量,但是当计数信号量无效时(uxMessagesWaiting =0),任务 Task 进入阻塞态。当计数信号量有效时(uxMessagesWaiting >0),任务 Task 获取信号量成功,任务从阻塞态解除,开始执行相关的处理过程(即发送循环队列buf)。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值