RT-Thread移植到stm32
一、移植RT-Thread准备
-
RT-Thread源码
源码版本和下载方式,可以参考RT-Thread移植入门学习。 -
keil软件
-
STM32工程项目模板
因为每一厂家提供的库文件可能有一些区别,在移植时可能会出现各种不同的问题,对于刚了解RT-Thread的小伙伴不友好,所以我已经将之前创建好的项目模板放在百度网盘了,当然也可以参考STM32新建模板之库文件,百度的下载连接是:https://pan.baidu.com/s/1_H3l4Dy5aZHfZ_FirBjgtA ,提取码是:vbzt -
STM32F103C8T6开发版
想要购买通关开发版的我也提供了卖家的连接,需要的小伙伴可以参考STM32零基础入门教程
二、RT-Thread 帮助文档
这里我移植的是标准版,当然需要移植的组件也是很多的,我们从内核开始移植,然后在进行外设的移植。学习RT-Thread 过程中有什么不明白的可以参考官方提供的帮助文档。
RT-Thread标准版文档:https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/basic/basic?id=rt-thread-内核配置示例
移植RT-Thread的内核有两种方法,一种是通过keil提供的插件进行一起,一种是通过下载官方的源码进行移植,这里主要是了解通过源码的方式进行移植,这样在后面进行外设的移植时比较方便。
三、使用keil提供的工具进行移植
-
打开模板工程
-
通过keil下载RT-Thread内核接口
-
添加RT-Thread
-
添加完成后项目工程中会增加一个RTOS路径
-
编译,编译完成后会发现两个错误
注意:这里主要的错误是在board.c文件中,声明了SystemCoreClockUpdate(void)方法和SystemCoreClock变量,但是没有对进进行定义导致的错误。 -
函数SystemCoreClockUpdate()
这个函数主要是用于获取SystemCoreClock 定时器和处理器的频率,这一我们只是想测试一下移植的效果我们可以不用对其进行实现,我们会在下次笔记中进行分析。当然有在system_stm32fqox.c文件中已经实现了,这里就不会出现这样的错误,现在的解决办法比较简单,在文件最后定义一下这个函数即可。
-
SystemCoreClock变量
SystemCoreClock是当前系统时钟评率,并且是通过函数SystemCoreClockUpdate()中获取的,这里我们也不用过多了解,因为不同的库文件对系统时钟频率的命名是不一样的,比如我现在使用库文件的命名如下图所示:
从图中可知,SystemFrequency的时钟频率是通过变量SYSCLK_FREQ_72MHz的赋值,所有我们只需要知道当前系统的频率赋值给SystemCoreClock变量即可。
- 解决办法
- 在board.c文件中引入头文件stm32f10x.h
- 在函数rt_hw_board_init()中定义SystemCoreClock变量并赋值。
- 在board.c文件中引入头文件stm32f10x.h
-
开启堆内存
打开的方式比较简单,只需要在rtconfig.h文件中取消RT_USING_HEAP宏的注释即可
-
在次编译,这次编译即便会发现没有错误了,其中的警告我们先忽视。
-
编写主程序,在线程中进行led灯闪烁,main.c文件如下所示
#include "stm32f10x.h" #include "led.h" #include <rtthread.h> int main(void) { LED_GPIO_Config(); while (1) { GPIO_ResetBits(GPIOB,GPIO_Pin_12); rt_thread_delay(1000); // 延时1000 ms GPIO_SetBits(GPIOB, GPIO_Pin_12 ); rt_thread_delay(1000); // 延时1000 ms } }
到这里我们便可以简单的使用RT-Thread的延时函数进行led的闪烁试验了。
四、通过官方源码移植
-
在模板工程中创建RT_Thread、RT_Thread/kernel、board文件
-
将源码路径下的include和src文件拷贝到创建的RT_Thread/kernel文件中
-
将路径libcpu\arm中的cortex-m3文件拷贝到创建的RT_Thread文件中
注意:这里拷贝的是项目架构文件,因为我这里使用的是M3的芯片,小伙们需要根据自己的芯片类型拷贝相应的文件 -
在board文件中创建board.c和rtconfig.h文件
-
添加源码到工程组文件
-
board.c文件,相信这个文件已经不陌生了,没错我们将上一流程更改的内容拷贝过来
/* * Copyright (c) 2006-2019, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2017-07-24 Tanek the first version * 2018-11-12 Ernest Chen modify copyright */ #include <stdint.h> #include <rthw.h> #include <rtthread.h> #include "stm32f10x.h" #define _SCB_BASE (0xE000E010UL) #define _SYSTICK_CTRL (*(rt_uint32_t *)(_SCB_BASE + 0x0)) #define _SYSTICK_LOAD (*(rt_uint32_t *)(_SCB_BASE + 0x4)) #define _SYSTICK_VAL (*(rt_uint32_t *)(_SCB_BASE + 0x8)) #define _SYSTICK_CALIB (*(rt_uint32_t *)(_SCB_BASE + 0xC)) #define _SYSTICK_PRI (*(rt_uint8_t *)(0xE000ED23UL)) // Updates the variable SystemCoreClock and must be called // whenever the core clock is changed during program execution. extern void SystemCoreClockUpdate(void); // Holds the system core clock, which is the system clock // frequency supplied to the SysTick timer and the processor // core clock. extern uint32_t SystemCoreClock; static uint32_t _SysTick_Config(rt_uint32_t ticks) { if ((ticks - 1) > 0xFFFFFF) { return 1; } _SYSTICK_LOAD = ticks - 1; _SYSTICK_PRI = 0xFF; _SYSTICK_VAL = 0; _SYSTICK_CTRL = 0x07; return 0; } #if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP) #define RT_HEAP_SIZE 1024 static uint32_t rt_heap[RT_HEAP_SIZE]; // heap default size: 4K(1024 * 4) RT_WEAK void *rt_heap_begin_get(void) { return rt_heap; } RT_WEAK void *rt_heap_end_get(void) { return rt_heap + RT_HEAP_SIZE; } #endif /** * This function will initial your board. */ void rt_hw_board_init() { uint32_t SystemCoreClock = 72000000; /* System Clock Update */ SystemCoreClockUpdate(); /* System Tick Configuration */ _SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND); /* Call components board initial (use INIT_BOARD_EXPORT()) */ #ifdef RT_USING_COMPONENTS_INIT rt_components_board_init(); #endif #if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP) rt_system_heap_init(rt_heap_begin_get(), rt_heap_end_get()); #endif } void SysTick_Handler(void) { /* enter interrupt */ rt_interrupt_enter(); rt_tick_increase(); /* leave interrupt */ rt_interrupt_leave(); } void SystemCoreClockUpdate(void) { }
- 拷贝rtconfig.h文件,同样是将上一流程中更改的内容拷贝过来
/* RT-Thread config file */ #ifndef __RTTHREAD_CFG_H__ #define __RTTHREAD_CFG_H__ #if defined(__CC_ARM) || defined(__CLANG_ARM) #if defined(RTE_USING_FINSH) #define RT_USING_FINSH #endif //RTE_USING_FINSH #endif //(__CC_ARM) || (__CLANG_ARM) /** * RT-Thread 内核部分 */ /* 表示内核对象的名称的最大长度,若代码中对象名称的最大长度大于宏定义的长度, * 多余的部分将被截掉。*/ #define RT_NAME_MAX 8 /* 字节对齐时设定对齐的字节个数。常使用 ALIGN(RT_ALIGN_SIZE) 进行字节对齐。*/ #define RT_ALIGN_SIZE 4 /* 定义系统线程优先级数;通常用 RT_THREAD_PRIORITY_MAX-1 定义空闲线程的优先级 */ #define RT_THREAD_PRIORITY_MAX 32 /* 定义时钟节拍,为 100 时表示 100 个 tick 每秒,一个 tick 为 10ms */ #define RT_TICK_PER_SECOND 1000 /* 检查栈是否溢出,未定义则关闭 */ #define RT_USING_OVERFLOW_CHECK /* 定义该宏开启 debug 模式,未定义则关闭 */ #define RT_DEBUG /* 开启 debug 模式时:该宏定义为 0 时表示关闭打印组件初始化信息,定义为 1 时表示启用 */ #define RT_DEBUG_INIT 1 /* 开启 debug 模式时:该宏定义为 0 时表示关闭打印线程切换信息,定义为 1 时表示启用 */ #define RT_DEBUG_THREAD 0 /* 定义该宏表示开启钩子函数的使用,未定义则关闭 */ #define RT_USING_HOOK /* 定义了空闲线程的栈大小 */ #define IDLE_THREAD_STACK_SIZE 256 /** * 线程间同步与通信部分,该部分会使用到的对象有信号量、互斥量、事件、邮箱、消息队列、信号等。 */ /* 定义该宏可开启信号量的使用,未定义则关闭 */ #define RT_USING_SEMAPHORE /* 定义该宏可开启互斥量的使用,未定义则关闭 */ //#define RT_USING_MUTEX /* 定义该宏可开启事件集的使用,未定义则关闭 */ //#define RT_USING_EVENT /* 定义该宏可开启邮箱的使用,未定义则关闭 */ #define RT_USING_MAILBOX /* 定义该宏可开启消息队列的使用,未定义则关闭 */ //#define RT_USING_MESSAGEQUEUE /* 定义该宏可开启信号的使用,未定义则关闭 */ //#define RT_USING_SIGNALS /** * 内存管理部分 */ /* 开启静态内存池的使用 */ // RT_USING_MEMPOOL /* 定义该宏可开启两个或以上内存堆拼接的使用,未定义则关闭 */ //#define RT_USING_MEMHEAP /* 开启小内存管理算法 */ #define RT_USING_SMALL_MEM /* 关闭 SLAB 内存管理算法 */ //#define RT_USING_SLAB /* 开启堆的使用 */ #define RT_USING_HEAP /** * 内核设备对象 */ /* 表示开启了系统设备的使用 */ //#define RT_USING_DEVICE /* 定义该宏可开启系统控制台设备的使用,未定义则关闭 */ #define RT_USING_CONSOLE /* 定义控制台设备的缓冲区大小 */ #define RT_CONSOLEBUF_SIZE 128 /* 控制台设备的名称 */ //#define RT_CONSOLE_DEVICE_NAME "uart1" /** * 自动初始化方式 */ /* 定义该宏开启自动初始化机制,未定义则关闭 */ #define RT_USING_COMPONENTS_INIT /* 定义该宏开启设置应用入口为 main 函数 */ #define RT_USING_USER_MAIN /* 定义 main 线程的栈大小 */ #define RT_MAIN_THREAD_STACK_SIZE 2048 /** * FinSH */ /* 定义该宏可开启系统 FinSH 调试工具的使用,未定义则关闭 */ //#define RT_USING_FINSH /* 开启系统 FinSH 时:将该线程名称定义为 tshell */ //#define FINSH_THREAD_NAME "tshell" /* 开启系统 FinSH 时:使用历史命令 */ //#define FINSH_USING_HISTORY /* 开启系统 FinSH 时:对历史命令行数的定义 */ //#define FINSH_HISTORY_LINES 5 /* 开启系统 FinSH 时:定义该宏开启使用 Tab 键,未定义则关闭 */ //#define FINSH_USING_SYMTAB /* 开启描述功能 */ //#define FINSH_USING_DESCRIPTION /* 开启系统 FinSH 时:定义该线程的优先级 */ //#define FINSH_THREAD_PRIORITY 20 /* 开启系统 FinSH 时:定义该线程的栈大小 */ //#define FINSH_THREAD_STACK_SIZE 4096 /* 开启系统 FinSH 时:定义命令字符长度 */ //#define FINSH_CMD_SIZE 80 /* 开启系统 FinSH 时:定义该宏开启 MSH 功能 */ //#define FINSH_USING_MSH /* 开启系统 FinSH 时:开启 MSH 功能时,定义该宏默认使用 MSH 功能 */ //#define FINSH_USING_MSH_DEFAULT /* 开启系统 FinSH 时:定义该宏,仅使用 MSH 功能 */ //#define FINSH_USING_MSH_ONLY /** * 关于 MCU */ /* 定义该工程使用的 MCU 为 STM32F103ZE;系统通过对芯片类型的定义,来定义芯片的管脚 */ //#define STM32F103ZE /* 定义时钟源频率 */ //#define RT_HSE_VALUE 8000000 /* 定义该宏开启 UART1 的使用 */ //#define RT_USING_UART1 #endif
-
编译,这是会发现找不到RTE_Components.h文件
因为这个是之前keil软件中的头文件,编译的时候会自动生成,这里我们不需要,直接删除这个引用即可。
-
main.c文件
#include "stm32f10x.h" #include "led.h" #include <rtthread.h> int main(void) { LED_GPIO_Config(); while (1) { GPIO_ResetBits(GPIOB,GPIO_Pin_12); rt_thread_delay(1000); // 延时1000 ms GPIO_SetBits(GPIOB, GPIO_Pin_12 ); rt_thread_delay(1000); // 延时1000 ms } }
五、文件保护
防止在开发中不小心更改到内核文件,导致新的错误产生,所以我们需要进行文件保护。
处理办法也比较简单,在项目文件中把需要保护的文件改为只读即可
设置为只读模式后,在项目文件上就可以看到一把钥匙的存在,这样就可以避免在更改程序时,意外改动导致新的错误产生,如下图所示:
到此移植RT-Thread的内核也算基本完成了,当然还存在一些问题,接下来只需要哦边学习边修改即可,感兴趣的小伙伴可以看我之后的文章,哪里写得不好望小伙本们指出。
六、常见问题
- HardFault_Handler、PendSV_Handler、SysTick_Handler三个函数重复定义
- 解决办法,这个问题是因为在工程中导入了stm32f10x_it.c文件,而这个文件主要是提供了一些模板,这里我们不需要,所以解决方法有两种,
- 方式一: 直接将stm32f10x_it.c文件重项目中删除即可。
- 方式二: 在stm32f10x_it.c文件中将重复定义的函数屏蔽即可。
参考文献
stm32 移植 rt-thread:https://blog.csdn.net/qq_36958104/article/details/111604665
本文来自博客园,作者:浇筑菜鸟,转载请注明原文链接:https://www.cnblogs.com/jzcn/p/15827153.html
如本博客的内容侵犯了你的权益,请与以下地址联系,本人获知后,马上删除。同时本人深表歉意,并致以崇高的谢意! cn_jiaozhu@qq.com
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了