从0到1学习FreeRTOS:FreeRTOS 内核应用开发:(四)FreeRTOS 的启动流程

本文详细介绍了FreeRTOS内核在系统启动过程中的关键步骤,包括从复位函数到C库的main()函数,任务创建xTaskCreate(),调度器启动vTaskStartScheduler(),以及在main.c中的任务执行逻辑。FreeRTOS自动初始化堆内存,创建空闲任务和定时器任务,确保系统中始终有一个任务处于运行状态。
摘要由CSDN通过智能技术生成

从0到1学习FreeRTOS:FreeRTOS 内核应用开发:(四)FreeRTOS 的启动流程

1、未到主函数之前:

       我们知道,在系统上电的时候第一个执行的是启动文件里面由汇编编写的复位函数Reset_Handler,具体见下面的代码清单。复位函数的最后会调用 C 库函数__main__main 函数的主要工作是初始化系统的堆和栈最后调用 C 中的 main 函数,从而去到 C 的世界。

Reset_Handler PROC
EXPORT Reset_Handler [WEAK]
IMPORT __main
IMPORT SystemInit
LDR R0, =SystemInit
BLX R0
LDR R0, =__main
BX R0
ENDP

2、创建任务 xTaskCreate()函数:

        在 main()函数中,我们直接可以对 FreeRTOS 进行创建任务操作,因为 FreeRTOS 会自动帮我们做初始化的事情,比如初始化堆内存。
        这种简单的特点使得 FreeRTOS 在初学的时候变得很简单,我们自己在 main()函数中直接初始化我们的板级外设——BSP_Init()然后进行任务的创建即可——xTaskCreate()在任务创建中, FreeRTOS 会帮我们进行一系列的系统初始化,在创建任务的时候,会帮我们初始化堆内存,具体见下面的代码清单。

BaseType_t xTaskCreate( TaskFunction_t pxTaskCode,
const char * const pcName,
const uint16_t usStackDepth,
void * const pvParameters,
UBaseType_t uxPriority,
TaskHandle_t * const pxCreatedTask )
{
if ( pxStack != NULL ) {
/* 分配任务控制块内存 */
pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) ); 
if ( pxNewTCB != NULL ) {
/* 将堆栈位置存储在 TCB 中。 */
pxNewTCB->pxStack = pxStack;
}
}
/*
省略代码
......
*/
}
/* 分配内存函数 */
void *pvPortMalloc( size_t xWantedSize )
{
BlockLink_t *pxBlock, *pxPreviousBlock, *pxNewBlockLink;
void *pvReturn = NULL;
vTaskSuspendAll();
{
/*如果这是对 malloc 的第一次调用,那么堆将需要初始化来设置空闲块列表。 */
if ( pxEnd == NULL ) {
prvHeapInit(); 
} else {
mtCOVERAGE_TEST_MARKER();
}
/*
省略代码
......
*/
}
}

        在未初始化内存的时候一旦调用了xTaskCreate()函数, FreeRTOS 就会帮我们自动进行内存的初始化,内存的初始化具体见下面的代码清单。注意,此函数是 FreeRTOS 内部调用的,目前我们暂时不用管这个函数的实现,在后面我们会仔细讲解 FreeRTOS 的内存管理相关知识,现在我们知道 FreeRTOS 会帮我们初始话系统要用的东西即可。

static void prvHeapInit( void )
{
BlockLink_t *pxFirstFreeBlock;
uint8_t *pucAlignedHeap;
size_t uxAddress;
size_t xTotalHeapSize = configTOTAL_HEAP_SIZE;
uxAddress = ( size_t ) ucHeap;
/* 确保堆在正确对齐的边界上启动。 */
if ( ( uxAddress & portBYTE_ALIGNMENT_MASK ) != 0 ) {
uxAddress += ( portBYTE_ALIGNMENT - 1 );
uxAddress &= ~( ( size_t ) portBYTE_ALIGNMENT_MASK );
xTotalHeapSize -= uxAddress - ( size_t ) ucHeap;
}
pucAlignedHeap = ( uint8_t * ) uxAddress;
/* xStart 用于保存指向空闲块列表中第一个项目的指针。
void 用于防止编译器警告*/
xStart.pxNextFreeBlock = ( void * ) pucAlignedHeap;
xStart.xBlockSize = ( size_t ) 0;
/* pxEnd 用于标记空闲块列表的末尾,并插入堆空间的末尾。 */
uxAddress = ( ( size_t ) pucAlignedHeap ) + xTotalHeapSize;
uxAddress -= xHeapStructSize;
uxAddress &= ~( ( size_t ) portBYTE_ALIGNMENT_MASK );
pxEnd = ( void * ) uxAddress;
pxEnd->xBlockSize = 0;
pxEnd->pxNextFreeBlock = NULL;
/* 首先,有一个空闲块,其大小可以占用整个堆空间,减去 pxEnd 占用的空间。 */
pxFirstFreeBlock = ( void * ) pucAlignedHeap;
pxFirstFreeBlock->xBlockSize = uxAddress - ( size_t ) pxFirstFreeBlock;
pxFirstFreeBlock->pxNextFreeBlock = pxEnd;
/* 只存在一个块 - 它覆盖整个可用堆空间。 因为是刚初始化的堆内存*/
xMinimumEverFreeBytesRemaining = pxFirstFreeBlock->xBlockSize;
xFreeBytesRemaining = pxFirstFreeBlock->xBlockSize;
xBlockAllocatedBit = ( ( size_t ) 1 ) << ( ( sizeof( size_t 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值