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

news2024/9/24 13:18:48

@[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。

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

2.6.2 修改uart.c文件

有两部分需要进行修改
第一部分:添加FreeRTOSConfig.h头文件
默认添加的是UCOS的“includes.h”头文件,将其删除,添加为“FreeRTOSConfig.h”的头文件。

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

第二部分:修改USART1的中断服务函数
uart.c文件默认支持UCOS的,UCOS进出中断时需要添加OSIntEnter()和 OSIntExit(),使用 FreeRTOS 的话就不需要了,所以将这两行代码删除掉。
看了下,本工程的uart.c文件中,该代码用了条件编译。如下。

#if SYSTEM_SUPPORT_OS	 	//使用OS
	OSIntEnter();    
#endif

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

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

删除后的代码为

//串口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中重新声明一下。

#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中的这三个函数注释掉。
用条件编译注释掉,如下

#if (!SYSTEM_SUPPORT_OS)
void SVC_Handler(void)
{
}
#endif

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

完成后再点击编译。

2.8 小节

编译后没有错误。
但是还需要编写应用程序进行验证。
移植步骤大体就是这样。
看开发手册中,不同芯片还会有其他错误,等实际遇到时再去改吧。

2.9 验证移植是否成功

需要编写应用程序。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1944147.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

小程序多排数据横向滚动实现

如何实现多排数据滚动效果 swiper 外部容器 swiper-item 每一页的数据 因为现在有多排数据,现在在swiper-item 中需要循环一个数组 初版 <template><view><view class"container"><view class"swiper-box"><swiper class&qu…

ubuntu 22.04 安装部署gitlab详细过程

目录 gitlab介绍 gitlab安装 步骤1&#xff1a;更新系统 步骤2&#xff1a;添加 GitLab 的 GPG 密钥 gitlab企业版 gitlab社区版 步骤3&#xff1a;安装 GitLab 社区版 社区版 步骤4&#xff1a;初始化 GitLab 步骤5&#xff1a;访问 GitLab 步骤6&#xff1a;查看r…

mybatis中的缓存(一级缓存、二级缓存)

文章目录 前言一、MyBatis 缓存概述二、一级缓存1_初识一级缓存2_一级缓存命中原则1_StatementId相同2_查询参数相同3_分页参数相同4_sql 语句5_环境 3_一级缓存的生命周期1_缓存的产生2_缓存的销毁3_网传的一些谣言 4_一级缓存核心源码5_总结 三、二级缓存1_开启二级缓存2_二级…

# OpenCV 图像预处理—形态学:膨胀、腐蚀、开运算、闭运算 原理详解

文章目录 形态学概念膨胀使用膨胀操作来修复裂痕示例代码关键解析&#xff1a; 腐蚀使用腐蚀操作消除噪点示例代码&#xff1a; 开运算—先腐蚀后膨胀闭运算—先膨胀后腐蚀 形态学概念 首先看这两张图片 一张图周围有大大小小的噪音和彩点&#xff0c;另一张图片中字母有间隙&…

安宝特方案|解放双手,解决死角,AR带来质量监督新体验

AR质量监督 解放双手&#xff0c;解决死角 在当今制造业快速发展的背景下&#xff0c;质量监督成为确保产品高质量和完善的管理制度的关键环节。然而&#xff0c;传统的质量监督方式存在诸多挑战&#xff0c;如人工操作带来的效率低下、查岗不及时、摄像头死角等问题。 为了解…

el-upload照片墙自定义上传多张图片(手动一次性上传多张图片)包含图片回显,删除

需求&#xff1a;el-upload照片墙自定义上传多张图片&#xff08;手动一次性上传多张图片&#xff09;包含图片回显&#xff0c;删除&#xff0c;预览&#xff0c;在网上看了很多&#xff0c;都没有说怎么把数据转为file格式的&#xff0c;找了很久最终实现&#xff0c; 难点&a…

Java之数组应用-选择排序-插入排序

已经完全掌握了冒泡排序和二分查找的同学&#xff0c;可以自己尝试学习选择、插入排序。不要求今天全部掌握&#xff0c;最近2-3天掌握即可&#xff01; 1 选择排序 选择排序(Selection Sort)的原理有点类似插入排序&#xff0c;也分已排序区间和未排序区间。但是选择排序每次…

《峡谷小狐仙-多模态角色扮演游戏助手》复现流程

YongXie66/Honor-of-Kings_RolePlay: The Role Playing Project of Honor-of-Kings Based on LnternLM2。峡谷小狐仙--王者荣耀领域的角色扮演聊天机器人&#xff0c;结合多模态技术将英雄妲己的形象带入大模型中。 (github.com) https://github.com/chg0901/Honor_of_Kings…

盘点2024年大家都在使用的AI智能写作工具

在科技发达的现在社会&#xff0c;AI已经悄悄的渗入我们生活的各种角落。不知道你有没有尝试过用ai智能写作来完成一些文章创作呢&#xff1f;这次我介绍几个可以提升效率的ai智能写作工具给你试试吧。 1.笔&#xff5c;灵AI写作 CSDN 传送门&#xff1a;https://ibiling.cn…

Interesting bug caused by getattr

题意&#xff1a;由 getattr 引起的有趣的 bug 问题背景&#xff1a; I try to train 8 CNN models with the same structures simultaneously. After training a model on a batch, I need to synchronize the weights of the feature extraction layers in other 7 models. …

Vue3+Element Plus 实现table表格中input的验证

实现效果 html部分 <template><div class"table"><el-form ref"tableFormRef" :model"form"><el-table :data"form.detailList"><el-table-column type"selection" width"55" align&…

初识c++(string和模拟实现string)

一、标准库中的string类 string类的文档介绍&#xff1a;cplusplus.com/reference/string/string/?kwstring 1、auto和范围for auto&#xff1a; 在早期C/C中auto的含义是&#xff1a;使用auto修饰的变量&#xff0c;是具有自动存储器的局部变量&#xff0c;后来这个 不重…

【北航主办丨本届SPIE独立出版丨已确认ISSN号】第三届智能机械与人机交互技术学术会议(IHCIT 2024,7月27)

由北京航空航天大学指导&#xff0c;北京航空航天大学自动化科学与电气工程学院主办&#xff0c;AEIC学术交流中心承办的第三届智能机械与人机交互技术学术会议&#xff08;IHCIT 2024&#xff09;将定于2024年7月27日于中国杭州召开。 大会面向基础与前沿、学科与产业&#xf…

初识c++:string类 (1)

目录 # 初识c&#xff1a;string类 1.为什么学习string类 2.标准库中的string类 2.1 string类的了解 2.2 auto和范围for 2.3 string类的常用接口说明 2.3.1string类对象的常见构造 2.3.2string类对象的容量操作 2.3.3string类对象的访问及遍历操作 2.3.4string类对象…

DNS概述及DNS服务器的搭建(twelve day)

回顾 关闭防火墙 systemctl stop firewalld 永久停止防火墙 systemctl disable firewalld 关闭selinux setenforce 0 永久关闭selinux安全架构 vim /etc/selinux/config 修改静态IP地址 vim /etc/sysconfig/network-scripts/ifcfg-ens160 #修改uuid的目的是为了保证网络的唯一…

计算机的错误计算(四十)

摘要 计算机的错误计算&#xff08;三十九&#xff09;阐明有时计算机将0算成非0&#xff0c;非0算成0&#xff1b;并且前面介绍的这些错误计算相对来说均是由软件完成。本节讨论手持式计算器对这些算式的计算效果。 例1. 用手持式计算器计算 与 . 我们用同一个计算器计算…

机械学习—零基础学习日志(高数10——函数图形)

零基础为了学人工智能&#xff0c;真的开始复习高数 函数图像&#xff0c;开始新的学习&#xff01;本次就多做一做题目&#xff01; 第一题&#xff1a; 这个解法是有点不太懂的了。以后再多研究一下。再出一道题目。 张宇老师&#xff0c;比较多提示了大家&#xff0c;一定…

哪些工作可以年入几十万到2亿?

关注卢松松&#xff0c;会经常给你分享一些我的经验和观点。 从今年起&#xff0c; 每个月都会有年入几十万到2亿的新闻案例出来&#xff0c;而且很多都是官方媒体发的&#xff0c;你们看看&#xff1a; 7月19日35岁小伙扛楼一年多存了40万 7月4日老板娘一天卖出200斤知了日入…

Leetcode3217. 从链表中移除在数组中存在的节点

Every day a Leetcode 题目来源&#xff1a;3217. 从链表中移除在数组中存在的节点 解法1&#xff1a;集合 链表遍历 代码&#xff1a; /** lc appleetcode.cn id3217 langcpp** [3217] 从链表中移除在数组中存在的节点*/// lc codestart /*** Definition for singly-link…

docker--容器数据进行持久化存储的三种方式

文章目录 为什么Docker容器需要使用持久化存储1.什么是Docker容器&#xff1f;2.什么是持久化存储&#xff1f;3.为什么Docker容器需要持久化存储&#xff1f;4.Docker如何实现持久化存储&#xff1f;(1)、Docker卷(Volumes)简介适用环境:使用场景:使用案例: (2)、绑定挂载&…