RISC-V处理器上的RT-Thread Nano RTOS入门指南

原文链接:Getting Started with RT-Thread Nano RTOS on RISC-V Processors 由Jean-Luc Aufranc撰写。

CNXSoft:这是RT-Thread开源物联网操作系统的特邀帖子,以GD32V RISC-V MCU开发板作为示例解释了如何在其实时操作系统上创建你的第一个运行程序。

本文介绍了如何将RT-Thread Nano移植到RISC-V架构,使用Eclipse IDE、GCC工具链和Gigadevice GD32V103 MCU构成一个基本项目。

前言

RT-Thread是一个开源的嵌入式实时操作系统,它具有标准版本和Nano版本。标准版本包括内核层、组件和服务层以及IoT框架层,而Nano版本则具有非常小的占用空间和完善的硬实时内核,更适合于资源受限的MCU(微处理器单元)。

移植Nano的主要步骤如下:

  1. 准备一个基本的Eclipse项目并获取RT-Thread Nano源代码。
  2. 将RT-Thread Nano源代码添加到基础项目中,并添加相应的标头路径。
  3. 修改Nano,主要用于中断时钟、内存和应用程序,以实现移植。
  4. 最后,为你的应用程序配置Nano OS。Nano是可定制的,可以通过h文件针对系统进行定制

准备工作

下载RT-Thread Nano源代码


在Eclipse中创建一个基本的裸机项目,例如一个闪烁的LED示例代码。

准备一个基础项目

在我们移植RT-Thread Nano之前,我们需要创建一个可工作的裸机项目。作为示例,本文使用基于GD32V103的闪烁LED程序。该程序的主要例程如下:


在我们的程序中,主要完成了系统初始化和LED闪烁功能。在编译下载程序后,可以看到开发板上的LED闪烁。你可以使用所需的芯片来完成类似的裸机项目。

将RT-Thread Nano添加到项目

添加Nano源文件

在Eclipse项目下创建一个新的rtthread文件夹,并将以下文件夹和文件添加到该文件夹中:

  1. Nano源代码中的includelibcpusrc文件夹。请注意,libcpu仅保留与芯片架构相关的文件,例如示例中使用的bumblebeecommon
  2. rtthread-nano / bsp中的配置文件:crtconfig.h
GD32V-Blink示例
GD32V-Blink示例

重新打开Eclipse工作区,导入项目,并将rtthread文件夹加载到项目中:

RISC-V上的RT-Thread项目
RISC-V上的RT-Thread项目

RISC-V芯片内核代码:context_gcc.scpuport.c

内核文件包括:clock.c,components.c,device.c,idle.c,ipc.c,irq.c,kservice.c,mem.c,object.c,scheduler.c,thread.c,time.c

开发板配置代码和配置文件:board.crtconfig.h

添加头文件路径

右键单击项目,点击属性进入如下图所示界面,点击C / C ++ Build-> Settings,分别添加汇编程序和C头路径:将路径添加到rtconfig.h头文件的位置,将头文件路径添加到include文件夹下。然后点击C / C ++ General->路径和符号,添加相应的头文件,最后点击Apply按钮。

GD32V-Project-Eclipse
GD32V-Project-Eclipse

安装RT-Thread Nano

修改start.S

修改启动文件,使用启动函数rt_thread_startup()调用entry()函数从而实现引导RT-Thread的代码。启动文件start.S需要修改,以便在启动时跳转到entry()函数执行,而不是跳转到main(),从而启动RT-Thread。


修改start.S
修改start.S

中断和异常处理

在系统没有实现此功能时RT-Thread提供了一个中断管理接口,该物理中断与用户的中断服务程序相关联。中断管理接口用于管理中断,以便在发生中断时可以触发相应的中断并执行中断服务程序。

该例程中的GD32VF103芯片在启动文件中提供了一个中断向量,用户可以使用中断向量提供的功能直接能实现相应的IRQ(中断请求)。触发中断时,处理器直接确定触发了哪个中断源,然后直接跳转到适当的固定位置进行处理,从而就无需自己再实施中断管理。

系统时钟配置

系统时钟配置(为MCU内核和外围设备提供工作时钟)和OS Tick配置(操作系统的心跳)在board.c文件中。

配置示例如下图所示,riscv_clock_init()配置系统时钟,和ostick_config()系统滴答。

RT-Thread系统时钟配置
RT-Thread系统时钟配置

riscv_clock_init() 配置系统时钟,如下所示:


OS Tick是使用硬件计时器实现的,需要用户在board.c中实现硬件计时器的中断服务例程eclic_mtip_handler(),并调用RT-Thread rt_tick_increase()。


由于eclic_mtip_handler()中断服务例程是由用户在board.c中重新实现的,并调用一个OS/系统tick,所以需要删除预定义的eclic_mtip_handler,以避免在编译时重复定义。如果项目成功编译且没有错误,则不需要进一步的修改。

内存堆初始化

系统内存堆的初始化是在board.c中的rt_hw_board_init() 函数中完成的是否使用内存堆功能取决于宏RT_USING_HEAP是否开启了,并且在默认情况下RT-Thread Nano不启用内存堆功能。这样可以保持较小的尺寸,而不会为内存堆打开空间。

启用系统堆时允许你使用动态内存功能,例如使用rt_malloc、rt_free和各种其他函数的API来动态创建对象。如果你需要使用系统内存堆功能,你可以打开RT_USING_HEAP的宏定义,其中内存堆初始化函数rt_system_heap_init()将被调用,如下所示:

RISC-V系统堆
RISC-V系统堆

初始化内存堆需要堆的开始和结束地址。数组的大小可以手动更改,如下所示:


注意打开堆动态内存功能时,堆默认值是很小的。使用时需要更改,否则可能会出现请求内存或创建线程失败的情况,修改方法如下:

你可以直接修改阵列中定义的RT_HEAP_SIZE大小,至少要超过每个动态请求的内存大小总和,但要小于总的芯片RAM的大小。

编写您的第一个应用程序

将RT-Thread Nano移植到RISC-V之后,你就可以开始编写第一个应用程序代码了。此时,main()函数已转换为RT-Thread操作系统中的线程了。并且经过一些修改后,板载闪烁的LED示例可以在RISC-V系统上运行:

  1. 首先,在文件顶部添加RT-Thread的相关头文件<rtthread.h>
  2. main()函数中(即在主线程中)实现闪烁LED代码,从而来初始化LED引脚并在一个钟循环打开/关闭LED。
  3. 将延迟函数替换为RT-Thread提供的延迟函数:rt_thread_mdelay()。此功能使系统安排并切换到另一个线程上来运行。


将编译后的代码下载到芯片后,你应该会看到基于RT-Thread的程序正在运行,并且LED再闪烁。注意:添加RT-Thread后,裸机中的main()函数将自动成为RT-Thread系统中主线程的入口函数。因为线程不应该总是独占着CPU,所以在main()中使用while(1)时,应在代码中添加  rt_thread_mdelay()函数,以便为其他线程腾出CPU时间。

与裸机闪烁LED示例代码的区别

  1. 延迟功能不同。RT-Thread提供了用于调度和延迟的rt_thread_mdelay()函数。在给定线程中调用该函数时,调度程序将切换到另一个线程。相反,裸机的延迟功能一直在CPU上运行。
  2. 系统时钟的初始化是不同的。将RT-Thread Nano移植到你的目标上(在我们的示例中为RISC-V)后,由于RT-Thread已经准备就绪,因此无需在main()中配置系统(例如HAL初始化、时钟初始化等)。在系统启动时配置系统时钟。上部分已经对“系统时钟配置”进行了说明。

配置RT-Thread Nano

你可以根据需要,配置相应的功能。如下所示打开或关闭rtconfig.h文件中的宏定义:


默认情况下,RT-Thread Nano不启用宏RT_USING_HEAP,因此仅支持静态创建任务和信号量。要动态创建对象,你则需要打开rtconfig.h文件中的RT_USING_HEAP宏定义。

分享这篇文章
订阅评论
提醒
0 评论
内联反馈
查看所有评论