3.1 FreeRTOS详细移植步骤(自己的实操)

@[TOC](3.1 FreeRTOS详细移植步骤(自己的实操))

自己使用阿波罗F767的内存管理实验和定时器实验,进行复刻。

FreeRTOS源码版本是FreeRTOS 202212.01。官网和Github都有下载。

按照STM32F767FreeRTOS开发手册V1.1进行移植复刻。

注:这个开发手册不是开发指南。跟视频里用的教程(开发手册)有出入。

新建FreeRTOS的工程方法可以分为:

1、CubeMX生成带FreeRTOS的HAL库工程。(CSDN有一篇文章介绍,简单)

2、已有HAL库的基础工程,将FreeRTOS移植进该工程。(步骤复杂)

3、已有标准固件库的基础工程,将FreeRTOS移植进该工程。(步骤复杂)

本文记录"已有HAL库的基础工程,将FreeRTOS移植进该工程"的方法。

计划完成FreeRTOS基础工程移植后

再完成"任务创建与恢复"实验,看看代码的含义。

完成后续视频中的实验。

由于没有开发板,实验只编程,没有报错即可,不看实验现象。

(虽然是一种不好的学习方法)

1 准备

1 阿波罗F767的内存管理实验

作为基础工程

2 阿波罗F767的定时器实验

用到里面的设备驱动代码

3 FreeRTOS源码

官网或github下载。2.24.5.24,下载的是V202212.01版本。

4(可选) 正点原子的"FreeRTOS移植实验",这个是移植完成的工程,可当作参考。

没找到HAL的FreeRTOS工程。只有固件库的FreeRTOS工程,可按照教程修改,使之支持HAL

库。

2 移植

2.1 STM32F7xx_DFP

keil5编辑STM32F系列的工程时,需要添加STM32F7xx_DFP的pack,CSDN上已记录添加步骤。

2.2 建立基础工程

使用内存管理实验作为基础工程。

将内存管理实验复制一份,并命名为"FreeRTOS_Demo"。

修改名字(非必须),并编译。

会发现0error0warning。

2.3 FreeRTOS源码文件处理

2.3.1 源码文件解压

2.3.2 源码文件简化

源码解压后的文件夹是FreeRTOSv202212.01,找到其中的Source文件夹是各源码文件,有一些文件用不到,所以就删了。

有以上绿色下划线的五个文件,FreeRTOS就可以用起来了。

不用其他功能,对应的.c文件,可不添加。

这里就全部保留了。

再将portable文件夹中的文件进行删除。

只留下下面三个文件夹(用其他编辑器或MCU,根据实际情况选择留下的文件夹)

2.4 添加FreeRTOS源码文件

将FreeRTOS源码文件添加至工程。过程简单,不再展示图片。

第一步:在基础工程中新建一个名为 FreeRTOS 的文件夹。

第二步:将Source文件夹下的所有源码文件,复制进第一步新建的文件夹中。

第三步:在keil中新建两个"分组",分别是 FreeRTOS_COREFreeRTOS_PORTABLE

新建分组,不等于新建文件夹。

第四步:在keil中为 FreeRTOS_CORE添加c文件

添加完成后

第五步:在keil中为FreeRTOS_PORTABLE添加c文件

这个分组中添加两个文件,port.cheap_4.c
port.c与所用的芯片有关,这个选用了STM32F767,所以要选择RVDS文件夹下的ARM_CM7中的port.c文件。
heap_4.c是内存管理算法,选择MemMang文件夹下的heap_4.c文件。

添加完成后如下图。

第六步:添加头文件路径

在上两步中添加了c文件,还要添加FreeRTOS的头文件路径,要不keil找不到头文件会报错。

完成以上六步后,点击编译,会报错,提示没有"FreeRTOSConfig.h"配置文件。

所以进行2.5小节。

2.5 添加FreeRTOS配置文件

FreeRTOSConfig.h是一个配置文件,在这个文件中,通过宏定义完成对系统功能的配置和裁剪。共有三个方法。推荐第三种。

方法一:自己创建并编写。

方法二:从官方demo中移植。

在官方demo中找到针对F7的KEIL工程。

上面的文件夹中,即可找到FreeRTOSConfig.h配置文件。

Cortex就是ARM公司一个系列处理器的名称。

比如英特尔旗下处理器有酷睿,奔腾,赛扬。

ARM在最初的处理器型号都用数字命名,最后一个是ARM11系列,在应用ARMv7架构后,推出了Cortex这一系列,老式的则命名为Classic系列。

其中:"A"系列面向尖端的基于虚拟内存的操作系统和用户应用;"R"系列针对实时系统;"M"系列对微控制器。

方法三:从"FreeRTOS移植实验"中获取(推荐)

从正点原子的"FreeRTOS移植实验"中获取带注释 的配置文件,更方便学习。

在扩展例程中找到该实验。

找到后将文件复制,粘贴到移植工程中FreeRTOS文件夹下的Include中(放在USER下也行,灵活点),这样就不需要再添加"头文件路径"了。

此时再编译工程,仍会报错。

按照下面的步骤继续进行修改,逐渐的消除错误信息,完成移植。

2.6 修改system文件

修改其中的sys.h,delay.c,uart.c三个文件。

这三个文件大部分是针对UCOS的,所以要进行修改。

使之支持FreeRTOS。

2.6.1 修改sys.h文件

打开sys.h文件

使用了FreeRTOS,所以将SYSTEM_SUPPORT_OS修改为1。

c 复制代码
//0,不支持os
//1,支持os
#define SYSTEM_SUPPORT_OS		1		//定义系统文件夹是否支持OS

2.6.2 修改uart.c文件

有两部分需要进行修改

第一部分:添加FreeRTOSConfig.h头文件

默认添加的是UCOS的"includes.h"头文件,将其删除,添加为"FreeRTOSConfig.h"的头文件。

c 复制代码
//如果使用os,则包括下面的头文件即可.
#if SYSTEM_SUPPORT_OS
//#include "includes.h"					//UCOS 使用	 
#include "FreeRTOSConfig.h"  //FreeRTOS使用
#endif

第二部分:修改USART1的中断服务函数

uart.c文件默认支持UCOS的,UCOS进出中断时需要添加OSIntEnter()和 OSIntExit(),使用 FreeRTOS 的话就不需要了,所以将这两行代码删除掉。

看了下,本工程的uart.c文件中,该代码用了条件编译。如下。

c 复制代码
#if SYSTEM_SUPPORT_OS	 	//使用OS
	OSIntEnter();    
#endif

所以直接删除也行,宏前面加个叹号也行。

这里直接删除。

重新学习一下宏定义,看看#if和#ifdef的区别是什么?

删除后的代码为

c 复制代码
//串口1中断服务程序  FreeRTOS
void USART1_IRQHandler(void)                	
{ 
	u32 timeout=0;
    u32 maxDelay=0x1FFFF;

	
	HAL_UART_IRQHandler(&UART1_Handler);	//调用HAL库中断处理公用函数
	
	timeout=0;
    while (HAL_UART_GetState(&UART1_Handler)!=HAL_UART_STATE_READY)//等待就绪
	{
        timeout++;超时处理
        if(timeout>maxDelay) break;		
	}
     
	timeout=0;
	while(HAL_UART_Receive_IT(&UART1_Handler,(u8 *)aRxBuffer, RXBUFFERSIZE)!=HAL_OK)//一次处理完成之后,重新开启中断并设置RxXferCount为1
	{
        timeout++; //超时处理
        if(timeout>maxDelay) break;	
	}

} 

注意,在我这里用的这个例程中,USART1的中断服务函数是针对UCOS的,即使删除了OSIntEnter()和 OSIntExit()也可能 不对。

但在下方有一个被注释的USART1中断服务函数,这个是针对FreeRTOS的。就是上面删除后的代码。(这段代码也是跟指南中的代码一致的)

所以一定要跟上面的代码对应。

还可以将上面的代码复制,对"USART1的中断服务函数"进行替换。

2.6.3 修改delay.c文件

同理,delay.c文件中的程序是支持UCOS的,经过对比,发现不适合将程序修改后适配FreeRTOS,所以将delay.c文件的代码全部删除,然后将固件库的"FreeRTOS移植实验"delay.c文件代码复制过来。复制过来之后,再稍作修改,使之支持HAL库。

因为delay.c文件涉及到 FreeRTOS 的系统时钟,所以修改比较大。

delay.c文件中有5个函数,将所以的代码复制,经过修改后,支持HAL的FreeRTOS中的delay.c代码如下。

以后使用时,直接将下面的代码复制到delay.c中即可。

注意,倒数第二个函数void delay_ms(u32 nms),形参改变了,需要在.h中重新声明一下。

c 复制代码
#include "delay.h"
#include "sys.h"
// 	 
//如果使用OS,则包括下面的头文件即可
#if SYSTEM_SUPPORT_OS
#include "FreeRTOS.h"					//FreeRTOS使用		  
#include "task.h"
#endif
//  
//使用SysTick的普通计数模式对延迟进行管理(支持OS)
//包括delay_us,delay_ms
//********************************************************************************

static u8  fac_us=0;							//us延时倍乘数			   
static u16 fac_ms=0;							//ms延时倍乘数,在os下,代表每个节拍的ms数

 
extern void xPortSysTickHandler(void);
 
//systick中断服务函数,使用OS时用到
void SysTick_Handler(void)
{	
    if(xTaskGetSchedulerState()!=taskSCHEDULER_NOT_STARTED)//系统已经运行
    {
        xPortSysTickHandler();	
    }
		HAL_IncTick();
}
			   
//初始化延迟函数
//当使用FreeRTOS时,此函数会初始化FreeRTOS的时钟节拍。
//SYSTICK的时钟固定为AHB时钟,基础例程里面SYSTICK时钟频率为AHB/8
//这里为了兼容FreeRTOS,所以将SYSTICK的时钟频率改为AHB的频率!
//SYSCLK:系统时钟频率
void delay_init(u8 SYSCLK)
{
	u32 reload;
	//SysTick 频率为 HCLK
	HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
	fac_us=SYSCLK;							//不论是否使用OS,fac_us都需要使用
	reload=SYSCLK;							//每秒钟的计数次数 单位为M	   
	reload*=1000000/configTICK_RATE_HZ;		//根据configTICK_RATE_HZ设定溢出时间
											//reload为24位寄存器,最大值:16777216,在168M下,约合0.0998s左右	
	fac_ms=1000/configTICK_RATE_HZ;			//代表OS可以延时的最少单位	   
	SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk;//开启SYSTICK中断
	SysTick->LOAD=reload; 					//每1/configTICK_RATE_HZ断一次	
	SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk; //开启SYSTICK     
}								    

//延时nus
//nus:要延时的us数.	
//nus:0~204522252(最大值即2^32/fac_us@fac_us=168)	    								   
void delay_us(u32 nus)
{		
	u32 ticks;
	u32 told,tnow,tcnt=0;
	u32 reload=SysTick->LOAD;				//LOAD的值	    	 
	ticks=nus*fac_us; 						//需要的节拍数 
	told=SysTick->VAL;        				//刚进入时的计数器值
	while(1)
	{
		tnow=SysTick->VAL;	
		if(tnow!=told)
		{	    
			if(tnow<told)tcnt+=told-tnow;	//这里注意一下SYSTICK是一个递减的计数器就可以了.
			else tcnt+=reload-tnow+told;	    
			told=tnow;
			if(tcnt>=ticks)break;			//时间超过/等于要延迟的时间,则退出.
		}  
	};										    
}  
//延时nms 会引起任务调度
//nms:要延时的ms数
//nms:0~65535
void delay_ms(u32 nms)
{	
	if(xTaskGetSchedulerState()!=taskSCHEDULER_NOT_STARTED)//系统已经运行
	{		
		if(nms>=fac_ms)						//延时的时间大于OS的最少时间周期 
		{ 
   			vTaskDelay(nms/fac_ms);	 		//FreeRTOS延时
		}
		nms%=fac_ms;						//OS已经无法提供这么小的延时了,采用普通方式延时    
	}
	delay_us((u32)(nms*1000));				//普通方式延时
}

//延时nms,不会引起任务调度
//nms:要延时的ms数
void delay_xms(u32 nms)
{
	u32 i;
	for(i=0;i<nms;i++) delay_us(1000);
}

修改完成后,点击编译。

2.7 修改中断相关文件

编译后会报错

这三个函数,在port.c和stm32f7xx_it.c中被多次定义了。

所以选在将stm32f7xx_it.c中的这三个函数注释掉。

用条件编译注释掉,如下

c 复制代码
#if (!SYSTEM_SUPPORT_OS)
void SVC_Handler(void)
{
}
#endif

注意,SYSTEM_SUPPORT_OS这个宏在sys.h中,所以要在stm32f7xx_it.c包含这个头文件。

完成后再点击编译。

2.8 小节

编译后没有错误。

但是还需要编写应用程序进行验证。

移植步骤大体就是这样。

看开发手册中,不同芯片还会有其他错误,等实际遇到时再去改吧。

2.9 验证移植是否成功

需要编写应用程序。

相关推荐
Rorsion44 分钟前
各种电机原理介绍
单片机·嵌入式硬件
善 .4 小时前
单片机的内存是指RAM还是ROM
单片机·嵌入式硬件
超级码农ProMax4 小时前
STM32——“SPI Flash”
stm32·单片机·嵌入式硬件
Asa3194 小时前
stm32点灯Hal库
stm32·单片机·嵌入式硬件
end_SJ6 小时前
初学stm32 --- 外部中断
stm32·单片机·嵌入式硬件
gantengsheng7 小时前
基于51单片机和OLED12864的小游戏《贪吃蛇》
单片机·嵌入式硬件·游戏·51单片机
嵌入式小强工作室8 小时前
stm32 查找进硬件错误方法
stm32·单片机·嵌入式硬件
委员8 小时前
基于NodeMCU的物联网窗帘控制系统设计
单片机·mcu·物联网·智能家居·iot
wenchm8 小时前
细说STM32F407单片机DMA方式读写SPI FLASH W25Q16BV
stm32·单片机·嵌入式硬件
南城花随雪。8 小时前
单片机:实现自动关机电路(附带源码)
单片机·嵌入式硬件