rt_thread_nano移植

本文最后更新于:2022年10月26日 凌晨

本文主要记录使用STM32cube创建的工程移植rt-thread-nano的过程,与官网不同,是直接导入文件的方式。

1. 对基础工程导入文件

1.1 基础工程

此工程由stm32cube生成,使用STM32F103ZE,功能为LED闪烁。

1.2 rt-thread-nano目录介绍

在官网有如下图,原文链接:

  • bsp就是些示例工程文件,不用管,我们要使用自己的工程
  • components是操作系统的上层组件,我们仅要移植最基本系统,也不管
  • docs文档,也不是目标
  • include存放头文件,目标之一
  • libcpu移植CPU相关,目标之一
  • src操作系统的源码,目标之一

1.3 将操作系统文件引入到基础工程中

  • 点击manage project items,然后新建组Kernel和cpu
  • 将操作系统src文件夹中的所以文件引入,如下图
  • 根据芯片不同引入不同的libcpu文件,如我使用的是STM32F103ZE,keil工程,所以引入rtthread-nano\rt-thread\libcpu\arm\cortex-m3目标下的相关文件,如下图:
  • 将操作系统中的include头文件目录添加到工程中

1.4 新建文件

  • 新建文件rtconfig.h,该文件存放操作系统的配置宏
  • 新建文件board.c,该文件主要实现时钟和板级初始化,下午将详细说明

1.5 此时的工程目录

2. 移植

首先移除stm32f1xx_it.c中的HardFault_Handler()和PendSV_Handler()函数,这两个函数已经被操作系统实现,会出现重复定义错误。

2.1 板级初始化与时钟初始化

在board.c中新建函数void rt_hw_board_init(),该函数将在rtthread_startup()函数中被调用,主要就是进行板级初始化和时钟初始化。

  • 首先调用原本在main函数中执行的HAL库初始化函数HAL_Init(),当然移植到此处原本位置就应该删除。在board中需要添加头文件stm32f1xx_hal.h

  • 然后将原本在main中实现的void SystemClock_Config(void)函数,移植到board中,在rt_hw_board_init函数中执行。

  • 然后配置操作系统时钟,使用滴答定时器来作为系统时钟,SystemClock_Config(void),函数实现如下,其中RT_TICK_PER_SECOND则是需要定义在rtconfig.h中,表示每多少次系统节拍等于一分钟。

    1
    2
    3
    4
    5
    6
    void rt_hw_systick_init(void)
    {
    HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq() / RT_TICK_PER_SECOND);
    HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
    NVIC_SetPriority(SysTick_IRQn, 0xFF);
    }
  • 还需要添加系统节拍中断服务程序SysTick_Handler(),该函数实际上就是在累加,然后删除生成文件中重复定义的此函数

1
2
3
4
5
6
7
8
9
10
11
void SysTick_Handler(void)
{
/* enter interrupt */
rt_interrupt_enter();

HAL_IncTick();
rt_tick_increase();

/* leave interrupt */
rt_interrupt_leave();
}
  • 最后添加对操作系统组件的初始化

    1
    2
    3
    #ifdef RT_USING_COMPONENTS_INIT
    rt_components_board_init();
    #endif
  • 此时的borad.c文件内容就如下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    #include <rthw.h>
    #include <stdint.h>
    #include <rtthread.h>
    #include "stm32f1xx_hal.h"

    void SystemClock_Config(void)
    {
    RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

    /** Initializes the RCC Oscillators according to the specified parameters
    * in the RCC_OscInitTypeDef structure.
    */
    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
    RCC_OscInitStruct.HSEState = RCC_HSE_ON;
    RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
    RCC_OscInitStruct.HSIState = RCC_HSI_ON;
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
    RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
    if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
    {
    //Error_Handler();
    }
    /** Initializes the CPU, AHB and APB buses clocks
    */
    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
    |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

    if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
    {
    //Error_Handler();
    }
    }

    void rt_hw_systick_init(void)
    {
    HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq() / RT_TICK_PER_SECOND);
    HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
    NVIC_SetPriority(SysTick_IRQn, 0xFF);
    }

    void rt_hw_board_init()
    {
    HAL_Init();
    SystemClock_Config();
    rt_hw_systick_init();
    #ifdef RT_USING_COMPONENTS_INIT
    rt_components_board_init();
    #endif
    }

    void SysTick_Handler(void)
    {
    /* enter interrupt */
    rt_interrupt_enter();

    HAL_IncTick();
    rt_tick_increase();

    /* leave interrupt */
    rt_interrupt_leave();
    }

2.2 配置文件rtconfig.h

直接从操作系统目录的bsp中复制过来作为基板。其实也没啥改的,使用默认即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
/* RT-Thread config file */

#ifndef __RTTHREAD_CFG_H__
#define __RTTHREAD_CFG_H__

//设置系统最大优先级,可设置范围 8256,默认值 8,可修改。
#define RT_THREAD_PRIORITY_MAX 8
//设置 RT-Thread 操作系统节拍,表示多少 tick 每秒
#define RT_TICK_PER_SECOND 1000
//字节对齐时设定对齐的字节个数,默认 4,常使用 ALIGN(RT_ALIGN_SIZE) 进行字节对齐。
#define RT_ALIGN_SIZE 4
//设置对象名称的最大长度,默认 8 个字符,一般无需修改
#define RT_NAME_MAX 8
//设置使用组件自动初始化功能,默认需要使用,开启该宏则可以使用自动初始化功能。
#define RT_USING_COMPONENTS_INIT
//开启宏,则打开 user_main 功能,默认需要开启,这样才能调用 RT-Thread 的启动代码;main 线程的栈大小默认为 256,可修改
#define RT_USING_USER_MAIN
#define RT_MAIN_THREAD_STACK_SIZE 256


//定义宏则开启 debug 模式,默认关闭。若开启系统调试,则可以打印系统 LOG 日志。
//#define RT_DEBUG
#define RT_DEBUG_INIT 0
//#define RT_USING_OVERFLOW_CHECK

//钩子函数配置
//是否 开启系统钩子功能
//#define RT_USING_HOOK
//是否 开启空闲线程钩子功能
//#define RT_USING_IDLE_HOOK

//软件定时器配置
//关闭软件定时器功能,为 1 则打开
#define RT_USING_TIMER_SOFT 0
#if RT_USING_TIMER_SOFT == 0
#undef RT_USING_TIMER_SOFT
#endif
//设置软件定时器线程的优先级,默认为 4
#define RT_TIMER_THREAD_PRIO 4
//设置软件定时器线程的栈大小,默认为 512 字节
#define RT_TIMER_THREAD_STACK_SIZE 512

//IPC 配置
// 设置是否使用 信号量
#define RT_USING_SEMAPHORE
// 设置是否使用 互斥量
//#define RT_USING_MUTEX
// 设置是否使用 事件集
//#define RT_USING_EVENT
// 设置是否使用 邮箱
#define RT_USING_MAILBOX
// 设置是否使用 消息队列
//#define RT_USING_MESSAGEQUEUE

//内存配置
// 是否使用 内存堆
//#define RT_USING_HEAP
// 是否使用 小内存管理
#define RT_USING_SMALL_MEM
是否使用 小体积的算法,牵扯到 rt_memset、rt_memcpy 所产生的体积
//#define RT_USING_TINY_SIZE

//FinSH 控制台配置
// <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(RTE_USING_FINSH)
#define 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

2.3 main.c的修改

main函数是作为操作系统自动启动的一个线程,所以可以直接用。只需要修改延时函数,改为操作系统的rt_thread_mdelay。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include "main.h"
#include "gpio.h"
#include "rtthread.h"

int main(void)
{
MX_GPIO_Init();
while (1)
{
/* USER CODE END WHILE */
HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_RESET);
//HAL_Delay(1000);
rt_thread_mdelay(1000);
HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_SET);
//HAL_Delay(1000);
rt_thread_mdelay(1000);
}
}

直接编译,无错误,然后下载,现象和之前的应该时相同。

2.4 堆

如果需要创建动态的组件,那么需要实现堆的初始化,仍然在board.c 中的 rt_hw_board_init() 函数中完成,是否启用的宏定义在rtconfig.h中定义,RT_USING_HEAP ,默认不开启,所以上面就可以直接使用了。
需要添加的话,在rt_hw_board_init函数的操作系统组件初始化完成后进行

1
2
3
#if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP)
rt_system_heap_init(rt_heap_begin_get(), rt_heap_end_get());
#endif

然后需要在board.c实现函数rt_heap_begin_get和rt_heap_end_get

1
2
3
4
5
6
7
8
9
10
11
12
13
#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

参考

RT-Thread Nano 移植原理
RT-Thread Nano 配置


rt_thread_nano移植
https://blog.kala.love/posts/da823a5a/
作者
Lissettecarlr
发布于
2021年4月6日
许可协议