一、获取FreeRTOS源码
进入FreeRTOS官网:https://www.freertos.org/a00104.html
点击Download下载源码文件。我下载的是“FreeRTOSv10.2.1_191129.exe”,其它版本也可以。
解压后:
先不用看Labs和Plus两个文件夹(后面熟悉了之后再看)。直接进入到FreeRTOS目录:
Demo:一些演示工程。
License:许可。
Source:源码目录。我们所需要的文件都在这里面。
进入到Source目录:
如图所示,就是FreeRTOS的源代码了。将其移植到我们的系统中即可。
二、移植FreeRTOS
在我们的系统工程中创建一个目录用于存放FreeRTOS源码。
我创建目录结构:OS\FreeRTOSv10.2.1\Source。
将以下文件都从刚下载的源码包中拷贝过来。
Source\*.c (源码c文件)
Source\include\*.h (源码头文件)
Source\portable\GCC\ARM_CM4F\port.c (这里与硬件相关,请根据自己的硬件平台选择。我使用的STM32L4VGT6平台,编译器用的ARM GCC,所以选择了GCC目录下CM4)
Source\portable\GCC\ARM_CM4F\protmacro.h
Source\portable\MemMang\heap_3.c (具体选用哪个可参考https://www.freertos.org/a00111.html)
特别注意:在选择port.c时,一定要选择与硬件对应的目录,否则即使编译通过了,也可能会跑不起来。
文件移植完成后,可以尝试编译看看,不过编译过程中可能会报一些错误。
常用错误是启动文件中的中断响应函数需要做一些修改。
三、修改启动文件
启动文件中会用到port.c中的三个中断函数。
vPortSVCHandler
xPortPendSVHandler
xPortSysTickHandler
这里为了保持启动文件的一致性,我们不修改启动文件,来修改port.c中的函数名:
vPortSVCHandler 修改为:SVC_Handler
xPortPendSVHandler 修改为:PendSV_Handler
xPortSysTickHandler 修改为:SysTick_Handler
这个函数在stm32l4xx_it.c也有定义,所以需要将其注释掉。
四、修改系统时钟频率
根据实际情况修改系统时钟频率:configCPU_CLOCK_HZ。
我的系统中使用SystemCoreClock定义的系统频率。
在FreeRTOSConfig.h中修改如下:
#if 1//def __ICCARM__
#include <stdint.h>
extern uint32_t SystemCoreClock;
#endif
#define configUSE_PREEMPTION 1
#define configUSE_IDLE_HOOK 0
#define configUSE_TICK_HOOK 0
#define configCPU_CLOCK_HZ ( SystemCoreClock )
#define configTICK_RATE_HZ ( ( TickType_t ) 1000 )
我这里通过前面这些步骤的修改,代码已经顺利编译通过。若还有遇到编译问题,可逐一排除(不清楚的可百度解决^_^)。
五、写测试代码
本例测试GPIOB6以1秒的频率闪烁。
#include "main.h"
// FreeRTOS head file, add here.
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "list.h"
#include "portable.h"
#include "FreeRTOSConfig.h"
void taskMain(void *pvParameters)
{
GPIO_InitTypeDef GPIO_InitStruct;
pvParameters = pvParameters;
//初始化硬件
HAL_Init();
//打开GPIOB的时钟
__HAL_RCC_GPIOB_CLK_ENABLE();
//初始化GPIOB6为输出
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Pin = GPIO_PIN_6;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
while(1)
{
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_6);
vTaskDelay(1000/portTICK_RATE_MS);
}
}
int main(void)
{
//创建任务taskMain
xTaskCreate( taskMain, "taskMain", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY+2, NULL );
// 启动任务调度
vTaskStartScheduler();
return 0;
}
比较幸运……
编译后直接跑起来了……