分析一下原工程中使用FREERTOS的流程,在hal层运行系统freertos,hw层用任务链表+定时器,hal层生成.a库文件给上层hw调用
贴上部分源码分析
- 首先是计数型信号量的创建
//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,指向了队列结构体本身。
- 其次是互斥型信号量的创建
//创建互斥信号量的实现
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;
}
- 然后是计数信号量的其他处理
//根据架构在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)。