从安装到使用,RT-Thread Nano最全教程看完不信你还不会使用

小编 说自rt-thread nano发布以来,小编收到不少开发者询问rt-thread nano的配套教程实例,官方发布过一篇:从裸机开始,创建一个rt-thread nano系统工程,但对广大开发者来说还是远远不够,幸得rt-thread开发者燕十三大作一篇讲解实战 rt-thread nano ,算是手把手教学了。嗯,连我这个不懂技术的小白看了也会了。欢迎给rt-thread投稿,获赠rt-thread t恤一件。 征稿 | 你写不写,福利就在这里~~
何为rt-thread nano?大家知道,keil5以后采用pack形式管理芯片及各种相关组件的。rt-thread nano就是通过keil pack方式发布,在保持原有rt-thread基本功能的情况下,实现了极小的flash和ram占用。默认配置下,flash可小至2.5k, ram可以小至1k。
目前pack包含有kernel、shell(msh)、device drivers三部分功能,这3个功能可按实际使用情况按需加载。本次使用的主芯片为gd32f150c8t6,资源为flash:64k,ram:8k。
一、rt-thread nano pack下载安装
1.在keil5主界面上点击“pack install”按钮,即可进入pack install界面
图1:keil5主界面
2.在pack install界面下,rt-thread pack在右边栏中。如未下载,可点击“install”下载;如已安装,版本有更新,将提示“update”可更新。
图2:rt-threadpack下载
3.如在图2界面“packs”栏中未发现“rt-thread”,可先在菜单“packs”下点击“check for updates”。update完成后,将可看到rt-thread pack。
图3:pack update
4.pack下载完成后,keil将自动弹出pack安装界面,按步骤依次完成安装。
二、裸机最小系统工程建立
1.本次工程使用的是芯片是gd32f150c8t6,64kflash、8kram。keil5下开发须先在官网下载keil pack (gigadevice.gd32f1x0_dfp.pack),并正确安装。
2.先按照裸机keil工程流程搭建工程,为测试flash及ram大小,最小工程只包含必须的libraries文件,main函数也未作任何多余处理。
图4:gd32f150c8t6最小工程
3.编译完成后,默认配置flash:1112字节、ram:2144字节
4.修改默认启动文件startup_gd32f1x0.s定义堆和栈大小:默认堆为0x400,栈为0x400。后续我们将采用rt-thread管理内存堆,所有堆设置为0;栈可按照main函数应用需求调整为0x100或以上。
图5:启动文件栈和堆修改
启动文件修改后,ram大小为352字节
图6:修改堆和栈后flash和栈占用大小
三、kernel加载与应用
1.加载rt-thread kernel:在主界面点击“managerun-time environment”按钮即可进入加载页。
图7:managerun-time environment
在“rtos”一栏中选中“rt-thread”,并在列表中选中“kernel”,当前版本为2.1.2。
图8:rt-thread kernel选择
2.确定后,keil界面上会加载rt-thread的kernel文件,更根据当前选择芯片类型加入已移植完成的m3芯片内核代码、配置文件等。
图9:rt-thread kernel文件
其中:
kernel文件包括:
clock.c
components.c
device.c
idle.c
ipc.c
irq.c
kservice.c
mem.c
object.c
scheduler.c
thread.c
timer.c
cortex-m3芯片内核移植代码:
cpuport.c
context_rvds.s
应用代码及配置文件:
board.c
rtconfig.h
3.此时再次编译工程,编译器会提示有函数被重复定义了。需按照如下方式做一些修改:
a) 修改gd32f10x_it.c文件,删除如下函数:
void hardfault_handler(void)
void pendsv_handler(void)
void systick_handler(void)
b) 按照board.c上的说明,依次完成如下操作:
图10:board.c修改流程说明
修改24行:#include “gd32f1x0.h”
修改48行:在rt_hw_board_init()函数内开启systick_config(systemcoreclock / rt_tick_per_second);
修改66行:voidsystick_handler(void)
4.修改main.c:
加入#include
在while循环中加入rt_thread_dealy(100);
5.再次编译顺利通过,下载至芯片运行可看到main函数中每1s可中断一次。rt-thread任务调度器已经正常运行。
图11:rt-thread正常运行
通过查看.map文件可获取当前各文件资源占用情况。在未开启任何优化的情况下,可以看到rt-thread内核各文件资源占用情况。
图12:资源占用表
6.可在main函数内添加rt-thread支持的任务、定时器、信号量等功能。nano默认rtconfig.h配置只支持静态任务、信号量创建。在静态模式下,不能使用rt_thread_create/rt_thread_delete/rt_sem_create/rt_sem_delete/rt_malloc/rt_free与动态创建、删除有关的接口。如需动态创建,需开启rt_using_heap项,详见本篇第五部分:《rt-thread配置》
四、rt-thrad启动流程分析
这次创建的keil工程虽然应用了rt-thread嵌入式操作系统,但开发流程无不带os开发几乎没有差别。都是将main作为入口,完成硬件初始化、应用代码添加,而且可以直接应用rt-thread的各种功能完成产品开发。但是我们没有添加rt-thread相关初始化、启动等代码到我们的工程里面,但实际情况是调度器已经正常运行了,这是怎么实现的呢?
01
rt-thread入口 我们可以在components.c文件的140行看到#ifdef rt_using_user_main宏定义判断,这个宏是定义在rtconfig.h文件内的,而且处于开启状态。同时我们可以在146行看到#if defined (__cc_arm)的宏定义判断,__cc_arm就是指keil的交叉编译器名称。
我们可以在这里看到定义了2个函数:$$sub$$main()和$$super$$main()函数;这里通过$$sub$$main()函数在程序就如主程序之前插入一个例程,实现在不改变源代码的情况下扩展函数功能。链接器通过调用$$sub$$main()函数取代main(),然后通过$$super$$main再次回到main()
#if defined (__cc_arm)
extern int $super$$main(void);
/* re-define main function */
int $sub$$main(void)
{
rt_hw_interrupt_disable();
rtthread_startup();
return 0;
}
在$$sub$$main函数内调用了rt_hw_interrutp_disable()和rtthread_startup()两个函数。熟悉rt-thread开发流程的,一看就知道这是标准的rt-thread的启动入口。
其中:
rt_hw_interrupt_disable():关中断操作,
rtthread_startup():完成systick配置、timer初始化/启动、idle任务创建、应用线程初始化、调度器启动等工作。
int rtthread_startup(void)
{
rt_hw_interrupt_disable();
/* board level initalization
* note: please initialize heap insideboard initialization.
*/
rt_hw_board_init();
/* show rt-thread version */
rt_show_version();
/* timer system initialization */
rt_system_timer_init();
/* scheduler system initialization */
rt_system_scheduler_init();
/* create init_thread */
rt_application_init();
/* timer thread initialization */
rt_system_timer_thread_init();
/* idle thread initialization */
rt_thread_idle_init();
/* start scheduler */
rt_system_scheduler_start();
/* never reach here */
return 0;
}
rt_hw_board_init():该函数定义在board.c文件内,需要修改systick配置
rt_system_timer_init()/rt_system_timer_thread_init():timer初始化/启动
rt_thread_idle_init():idle任务创建
rt_application_init():应用线程初始化
rt_system_scheduler_start():调度器启动
02
应用线程入口 rt_application_init() void rt_application_init(void)
{
rt_thread_t tid;
#ifdef rt_using_heap
tid = rt_thread_create(main,main_thread_entry, rt_null,
rt_main_thread_stack_size,rt_thread_priority_max / 3, 20);
rt_assert(tid != rt_null);
#else
rt_err_t result;
tid = &main_thread;
result = rt_thread_init(tid,main, main_thread_entry, rt_null,main_stack, sizeof(main_stack),rt_thread_priority_max / 3, 20);
rt_assert(result == rt_eok);
#endif
rt_thread_startup(tid);
}
在这里,我们可以看到应用线程创建了一个名为main_thread_entry的任务,并且已经启动了该任务。我们再次来看一下man_thread_entry任务。
/* the system main thread */
void main_thread_entry(void*parameter)
{
extern int main(void);
extern int $super$$main(void);
/* rt-thread components initialization */
rt_components_init();
/* invoke system main function */
#if defined (__cc_arm)
$super$$main(); /* for armcc. */
#elif defined(__iccarm__) ||defined(__gnuc__)
main();
#endif
}
man_thread_entry任务完成了2个工作:调用rt_components_init()、进入应用代码真正的main函数。
在这里我们看到了$$super$$main()的调用,在前面我们讲了调用该函数可用来回到main()的。
图13:rt-thread初始化及启动流程
从以上分析可以,正是由于在rtconfig.h内开启了rt_using_user_main选项,编译器在main之前插入了$$sub$$main(),完成了rt-thread初始化及调度器启动工作。并且通过创建main_thread_entry任务,并通过$$super$$main()回到main()函数。这样看来main()函数其实只是rt-thread的一个任务,该任务的优先级为 rt_thread_priority_max / 3,任务栈为rt_main_thread_stack_size。
图14:rt_using_user_main选项
五、rt-thread配置(rtconfig.h)
rt-thread是一个高度可配置的嵌入式实时操作系统,配置通过rtconfig.h文件实现。nano就是在rtconfig.h配置下实现了2.5kflash,1kram的内核应用,但是由于nano未开启rt_using_heap选项,故只支持静态方式创建任务及信号量。下面分步开启rtconfig.h配置常用选项。
01
rt_using_heap:开启heap 根据芯片型号在board.c第37行,修改sarm_size大小,默认为8,gd32f150c8t6正好也为8k。
图15:sram_size配置
开启rt_using_heap选项后,在board.c的rt_hw_board_init()内将调用rt_system_heap_init()
#if defined(rt_using_user_main)&& defined(rt_using_heap)
rt_system_heap_init((void*)heap_begin,(void*)sram_end);
#endif
其中:
sram_end:根据宏定义为0x20000000 +sram_size * 1024
heap_begin:
图16:heap_begin定义
其中image$$rw_iram1$$zi$$limit是链接器导出符号,表示zi段的结束地址。
配置完成后,就可通过动态创建任务、信号量等方式开发软件了。
02
rt_using_timer_soft:开启软件定时器
nano默认配置未开启软件定时器功能。开启软件定时器功能后,可创建多个软件定时器,定时器精度为systick触发精度。
图17:软件定时器开启
- end -

MAX9665, MAX9666, MAX9667 6/8/
U盘及微硬盘的存储介质
滴滴CEO程维:成立战略事业部和智慧交通事业部
构建更智能的电网
“牙刷尾巴”智能牙刷解决方案浅析
从安装到使用,RT-Thread Nano最全教程看完不信你还不会使用
反超华为,小米AI专利数量跃居全球11位!
!销售/收购/维修HP8751A网络分析仪HP8751A 小
看门狗定时器允许进入测试模式
小米MIX 4或将于9月底推出,首款搭载三星全新光学传感器
延长电动车蓄电池使用寿命的心得体会,Using experience of lead-acid batteries
浅谈电力售电模式优化研究与应用
媲美人类水平的人工智能有望五年后问世
美国正式打造出第一个量子互联网的第一站
堡盟CX系列加持显微镜数字化升级
新专利介绍--无线远传燃气表唤醒装置及唤醒方法
华为VR策略浮出水面:先要为VR提高网速
太阳能控制器的作用是什么?
2016-2020年中国燃料电池汽车行业相关政策一览表
中兴微电子选定Arteris的Ncore Cache Coherent一致性IP和FlexNoC 互联IP用于多种SoC