一、移植RT-Thread准备

  1. RT-Thread源码

    源码版本和下载方式,可以参考RT-Thread移植入门学习

  2. keil软件

  3. STM32工程项目模板

    因为每一厂家提供的库文件可能有一些区别,在移植时可能会出现各种不同的问题,对于刚了解RT-Thread的小伙伴不友好,所以我已经将之前创建好的项目模板放在百度网盘了,当然也可以参考STM32新建模板之库文件,百度的下载连接是:https://pan.baidu.com/s/1_H3l4Dy5aZHfZ_FirBjgtA ,提取码是:vbzt

  4. 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提供的工具进行移植

  1. 打开模板工程

  2. 通过keil下载RT-Thread内核接口

  3. 添加RT-Thread

  4. 添加完成后项目工程中会增加一个RTOS路径

  5. 编译,编译完成后会发现两个错误



    注意:这里主要的错误是在board.c文件中,声明了SystemCoreClockUpdate(void)方法和SystemCoreClock变量,但是没有对进进行定义导致的错误。

  6. 函数SystemCoreClockUpdate()



    这个函数主要是用于获取SystemCoreClock 定时器和处理器的频率,这一我们只是想测试一下移植的效果我们可以不用对其进行实现,我们会在下次笔记中进行分析。当然有在system_stm32fqox.c文件中已经实现了,这里就不会出现这样的错误,现在的解决办法比较简单,在文件最后定义一下这个函数即可。

  7. SystemCoreClock变量

    SystemCoreClock是当前系统时钟评率,并且是通过函数SystemCoreClockUpdate()中获取的,这里我们也不用过多了解,因为不同的库文件对系统时钟频率的命名是不一样的,比如我现在使用库文件的命名如下图所示:



    从图中可知,SystemFrequency的时钟频率是通过变量SYSCLK_FREQ_72MHz的赋值,所有我们只需要知道当前系统的频率赋值给SystemCoreClock变量即可。

  • 解决办法

    • 在board.c文件中引入头文件stm32f10x.h

    • 在函数rt_hw_board_init()中定义SystemCoreClock变量并赋值。

  1. 开启堆内存



    打开的方式比较简单,只需要在rtconfig.h文件中取消RT_USING_HEAP宏的注释即可

  2. 在次编译,这次编译即便会发现没有错误了,其中的警告我们先忽视。

  3. 编写主程序,在线程中进行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的闪烁试验了。

四、通过官方源码移植

  1. 在模板工程中创建RT_Thread、RT_Thread/kernel、board文件

  2. 将源码路径下的include和src文件拷贝到创建的RT_Thread/kernel文件中

  3. 将路径libcpu\arm中的cortex-m3文件拷贝到创建的RT_Thread文件中



    注意:这里拷贝的是项目架构文件,因为我这里使用的是M3的芯片,小伙们需要根据自己的芯片类型拷贝相应的文件

  4. 在board文件中创建board.c和rtconfig.h文件

  5. 添加源码到工程组文件

  6. 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)
{ }
  1. 拷贝rtconfig.h文件,同样是将上一流程中更改的内容拷贝过来
/* RT-Thread config file */

#ifndef __RTTHREAD_CFG_H__
#define __RTTHREAD_CFG_H__ #if defined(__CC_ARM) || defined(__CLANG_ARM)
#include "RTE_Components.h" #if defined(RTE_USING_FINSH)
#define RT_USING_FINSH
#endif //RTE_USING_FINSH #endif //(__CC_ARM) || (__CLANG_ARM) // <<< Use Configuration Wizard in Context Menu >>>
// <h>Basic Configuration
// <o>Maximal level of thread priority <8-256>
// <i>Default: 32
#define RT_THREAD_PRIORITY_MAX 8
// <o>OS tick per second
// <i>Default: 1000 (1ms)
#define RT_TICK_PER_SECOND 1000
// <o>Alignment size for CPU architecture data access
// <i>Default: 4
#define RT_ALIGN_SIZE 4
// <o>the max length of object name<2-16>
// <i>Default: 8
#define RT_NAME_MAX 8
// <c1>Using RT-Thread components initialization
// <i>Using RT-Thread components initialization
#define RT_USING_COMPONENTS_INIT
// </c> #define RT_USING_USER_MAIN // <o>the stack size of main thread<1-4086>
// <i>Default: 512
#define RT_MAIN_THREAD_STACK_SIZE 256 // </h> // <h>Debug Configuration
// <c1>enable kernel debug configuration
// <i>Default: enable kernel debug configuration
//#define RT_DEBUG
// </c>
// <o>enable components initialization debug configuration<0-1>
// <i>Default: 0
#define RT_DEBUG_INIT 0
// <c1>thread stack over flow detect
// <i> Diable Thread stack over flow detect
//#define RT_USING_OVERFLOW_CHECK
// </c>
// </h> // <h>Hook Configuration
// <c1>using hook
// <i>using hook
//#define RT_USING_HOOK
// </c>
// <c1>using idle hook
// <i>using idle hook
//#define RT_USING_IDLE_HOOK
// </c>
// </h> // <e>Software timers Configuration
// <i> Enables user timers
#define RT_USING_TIMER_SOFT 0
#if RT_USING_TIMER_SOFT == 0
#undef RT_USING_TIMER_SOFT
#endif
// <o>The priority level of timer thread <0-31>
// <i>Default: 4
#define RT_TIMER_THREAD_PRIO 4
// <o>The stack size of timer thread <0-8192>
// <i>Default: 512
#define RT_TIMER_THREAD_STACK_SIZE 512
// </e> // <h>IPC(Inter-process communication) Configuration
// <c1>Using Semaphore
// <i>Using Semaphore
#define RT_USING_SEMAPHORE
// </c>
// <c1>Using Mutex
// <i>Using Mutex
//#define RT_USING_MUTEX
// </c>
// <c1>Using Event
// <i>Using Event
//#define RT_USING_EVENT
// </c>
// <c1>Using MailBox
// <i>Using MailBox
#define RT_USING_MAILBOX
// </c>
// <c1>Using Message Queue
// <i>Using Message Queue
//#define RT_USING_MESSAGEQUEUE
// </c>
// </h> // <h>Memory Management Configuration
// <c1>Dynamic Heap Management
// <i>Dynamic Heap Management
#define RT_USING_HEAP
// </c>
// <c1>using small memory
// <i>using small memory
#define RT_USING_SMALL_MEM
// </c>
// <c1>using tiny size of memory
// <i>using tiny size of memory
//#define RT_USING_TINY_SIZE
// </c>
// </h> // <h>Console Configuration
// <c1>Using console
// <i>Using console
#define RT_USING_CONSOLE
// </c>
// <o>the buffer size of console <1-1024>
// <i>the buffer size of console
// <i>Default: 128 (128Byte)
#define RT_CONSOLEBUF_SIZE 128
// </h> #if defined(RT_USING_FINSH)
#define FINSH_USING_MSH
#define FINSH_USING_MSH_ONLY
// <h>Finsh Configuration
// <o>the priority of finsh thread <1-7>
// <i>the priority of finsh thread
// <i>Default: 6
#define __FINSH_THREAD_PRIORITY 5
#define FINSH_THREAD_PRIORITY (RT_THREAD_PRIORITY_MAX / 8 * __FINSH_THREAD_PRIORITY + 1)
// <o>the stack of finsh thread <1-4096>
// <i>the stack of finsh thread
// <i>Default: 4096 (4096Byte)
#define FINSH_THREAD_STACK_SIZE 512
// <o>the history lines of finsh thread <1-32>
// <i>the history lines of finsh thread
// <i>Default: 5
#define FINSH_HISTORY_LINES 1 #define FINSH_USING_SYMTAB
// </h>
#endif // <<< end of configuration section >>> #endif
  1. 编译,这是会发现找不到RTE_Components.h文件



    因为这个是之前keil软件中的头文件,编译的时候会自动生成,这里我们不需要,直接删除这个引用即可。

  2. 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的内核也算基本完成了,当然还存在一些问题,接下来只需要哦边学习边修改即可,感兴趣的小伙伴可以看我之后的文章,哪里写得不好望小伙本们指出。

六、常见问题

  1. 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

RT-Thread移植到stm32的更多相关文章

  1. Basic脚本解释器移植到STM32

    本文来自http://blog.csdn.net/hellogv/ .引用必须注明出处! 上次讲了LUA移植到STM32.这次讲讲Basic脚本解释器移植到STM32. 在STM32上跑Basic脚本 ...

  2. FreeRTOS移植到STM32上的移植过程

    所有的单片机都是顺序执行的,而对于多任务而言就显得力不从心了,虽然在一些小项目中可以通过定时器来实现,但这种实现方式没有实时性,一旦任务需要在规定时间内做出响应,那只能通过实时操作系统来完成了.在很多 ...

  3. 基于Linux的kfifo移植到STM32(支持os的互斥访问)

    基于Linux的kfifo移植到STM32(支持os的互斥访问) 关于kfifo kfifo是内核里面的一个First In First Out数据结构,它采用环形循环队列的数据结构来实现:它提供一个 ...

  4. RT Thread 通过ENV来配置SFUD,操作SPI Flash

    本实验基于正点原子stm32f4探索者板子 请移步我的RT Thread论坛帖子. https://www.rt-thread.org/qa/forum.php?mod=viewthread& ...

  5. HarmonyOS(LiteOs_m) 官方例程移植到STM32初体验

    HarmonyOS(LiteOs_m) 官方例程移植到STM32初体验 硬件平台 基于正点原子战舰V3开发板 MCU:STM32F103ZET6 片上SRAM大小:64KBytes 片上FLASH大小 ...

  6. STM32 + RT Thread OS 学习笔记[二]

    串口通讯例程 通过上面的练习,对STM32项目开发有了一个直观印象,接下来尝试对串口RS232进行操作. 1.   目标需求: 开机打开串口1,侦听上位机(使用电脑串口测试软件)发送的信息,然后原样输 ...

  7. STM32 + RT Thread OS 串口通讯

    1.   创建项目 a)   禁用Finsh和console b)   默认情况下,项目文件包含了finsh,它使用COM1来通讯,另外,console输出(rt_kprintf)也使用了COM1.因 ...

  8. STM32 + RT Thread OS 学习笔记[三]

    RTGUI 据说RTGUI是多线程的,因此与RT-Thread OS的耦合度较高,有可能要访问RT-Thread的线程控制块.如果要移植到其它OS,估计难度较大.目前还处于Alpha状态,最终将会包含 ...

  9. STM32 + RT Thread OS 学习笔记[四]

    1.  补注 a)      硬件,打通通讯通道 若学习者购买了学习板,通常可以在学习板提供的示例代码中找到LCD的相关驱动代码,基本上,这里的驱动的所有代码都可以从里面找到. 从上面的示意图可见,M ...

随机推荐

  1. Spring工具类 非spring管理环境中获取bean及环境配置

    SpringUtils.java import org.springframework.beans.BeansException; import org.springframework.beans.f ...

  2. Linux执行脚本报错:-bash: ./xx.sh: /bin/bash^M: bad interpreter: No such file or directory

    1.用vim打开文本 输入 : set ff 这里要先按":"号 显示文件为dos格式 2.强制装换格式为unix 先按冒号":" set ff=unix 然后 ...

  3. Linux(centos)下修改mysql的sql_mode模式

    进入MySQL的配置文件 默认是/etc/my.cnf vim my.cnf 在最后一行加入 sql-mode="NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITU ...

  4. 【LeetCode】1135. Connecting Cities With Minimum Cost 解题报告 (C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 Kruskal算法 日期 题目地址:https://l ...

  5. 【LeetCode】633. Sum of Square Numbers 解题报告(python & Java & C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 双指针 列表生成式 循环 日期 题目地址:https ...

  6. Sky Code(poj3904)

    Sky Code Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 2085   Accepted: 665 Descripti ...

  7. 用户线程&&守护线程

         守护线程是为用户线程服务的,当一个程序中的所有用户线程都执行完成之后程序就会结束运行,程序结束运行时不会管守护线程是否正在运行,由此我们可以看出守护线程在 Java 体系中权重是比较低的.当 ...

  8. DAG-GNN: DAG Structure Learning with Graph Neural Networks

    目录 概 主要内容 代码 Yu Y., Chen J., Gao T. and Yu M. DAG-GNN: DAG structure learning with graph neural netw ...

  9. Chapter 15 Outcome Regression and Propensity Scores

    目录 15.1 Outcome regression 15.2 Propensity scores 15.3 Propensity stratification and standardization ...

  10. Least Angle Regression

    目录 引 一些基本的假设 LARS算法 算法 与别的方法结合 LARS与LASSO的关系 LARS 与 Stagewise 代码 Efron B, Hastie T, Johnstone I M, e ...