GD32F150实战RT-Thread Nano

--作者:燕十三(flyingcys)

-- blog:http://blog.csdn.net/flyingcys

--QQ:294102238

何为RT-Thread Nano?大家知道,Keil5以后采用pack形式管理芯片及各种相关组件的。RT-Thread Nano就是通过Keil pack方式发布,在保持原有RT-Thread基本功能的情况下,实现了极小的FlashRam占用。默认配置下,Flash可小至2.5KRam可以小至1K

目前pack包含有kernelshellmsh)、device drivers三部分功能,这3个功能可按实际使用情况按需加载。

本次使用的主芯片为GD32F150C8T6,资源为Flash:64KRam:8K

一、RT-Thread Nano Pack下载安装

1. Keil5主界面上点击“Pack Install”按钮,即可进入Pack Install界面

 

1Keil5主界面

2. Pack Install界面下,RT-Thread Pack在右边栏中。如未下载,可点击“Install”下载;如已安装,版本有更新,将提示“Update”可更新。

 

2RT-Thread Pack下载

3. 如在图2界面“Packs”栏中未发现“RT-Thread”,可先在菜单“Packs”下点击“Check for Updates”。Update完成后,将可看到RT-Thread Pack

 

3Pack Update

4. Pack下载完成后,Keil将自动弹出Pack安装界面,按步骤依次完成安装。

二、裸机最小系统工程建立

1. 本次工程使用的是芯片是GD32F150C8T664KFlash8KRamKeil5下开发须先在官网下载Keil Pack (GigaDevice.GD32F1x0_DFP.pack),并正确安装。

 

4GD32F150 Device选择

2. 先按照裸机Keil工程流程搭建工程,为 测试FlashRam大小,最小工程只包含必须的Libraries文件,main函数也未作任何多余处理。

 

5GD32F150C8T6最小工程

3. 编译完成后,默认配置Flash1112字节、Ram2144字节

4. 修改默认启动文件startup_gd32f1x0.s定义堆和栈大小:默认堆为0x400,栈为0x400。后续我们将采用RT-Thread管理内存堆,所有堆设置为0;栈可按照main函数应用需求调整为0x100或以上。


6:启动文件栈和堆修改

启动文件修改后,Ram大小为352字节

 

7:修改堆和栈后Flash和栈占用大小

三、kernel加载与应用

1. 加载RT-Thread Kernel:

在主界面点击Manage Run-Time Environment”按钮即可进入加载页。

8Manage Run-Time Environment

RTOS”一栏中选中“RT-Thread”,并在列表中选中“kernel”,当前版本为2.1.2

 

9RT-Thread kernel选择

2. 确定后,keil界面上会加载RT-Threadkernel文件,更根据当前选择芯片类型加入已移植完成的M3芯片内核代码、配置文件等。

 

10RT-Thread kernel文件

其中:

l 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

l Cortex-m3芯片内核移植代码:

cpuport.c
context_rvds.s

l 应用代码及配置文件:

board.c
rtconfig.h

3. 此时再次编译工程,编译器会提示有函数被重复定义了。需按照如下方式做一些修改:

a) 修改gd32f10x_it.c文件,删除如下函数:

void HardFault_Handler(void)
void PendSV_Handler(void)
void SysTick_Handler(void)

b) 按照board.c上的说明,依次完成如下操作:

 

11board.c修改流程说明

修改24行:#include “gd32f1x0.h”
修改48行:在rt_hw_board_init()函数内开启
SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND);
修改66行:void SysTick_Handler(void)

4. 修改main.c

加入#include <rtthread.h>
在while循环中加入rt_thread_dealy(100);

5. 再次编译顺利通过,下载至芯片运行可看到main函数中每1s可中断一次。RT-Thread任务调度器已经正常运行。

 

12RT-Thread正常运行

通过查看.map文件可获取当前各文件资源占用情况。在未开启任何优化的情况下,可以看到RT-Thread内核各文件资源占用情况。

 

13:资源占用表

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相关初始化、启动等代码到我们的工程里面,但实际情况是调度器已经正常运行了,这是怎么实现的呢?

1. 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 inside board 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():调度器启动

int rtthread_startup(void)
{
	rt_hw_interrupt_disable();

    /* board level initalization
     * NOTE: please initialize heap inside board 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;
}

2. 应用线程入口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()的。

 

14RT-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

 

15RT_USING_USER_MAIN选项

五、RT-Thread配置(rtconfig.h)

RT-Thread是一个高度可配置的嵌入式实时操作系统,配置通过rtconfig.h文件实现。Nano就是在rtconfig.h配置下实现了2.5KFlash1KRam的内核应用,但是由于Nano未开启RT_USING_HEAP选项,故只支持静态方式创建任务及信号量。下面分步开启rtconfig.h配置常用选项。

1. RT_USING_HEAP:开启heap

根据芯片型号在board.c37行,修改SARM_SIZE大小,默认为8GD32F150C8T6正好也为8K

 

图16SRAM_SIZE配置

开启RT_USING_HEAP选项后,在board.crt_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

 

图17HEAP_BEGIN定义

其中Image$$RW_IRAM1$$ZI$$Limit是链接器导出符号,表示ZI段的结束地址。

配置完成后,就可通过动态创建任务、信号量等方式开发软件了。

2. RT_USING_TIMER_SOFT:开启软件定时器

Nano默认配置未开启软件定时器功能。开启软件定时器功能后,可创建多个软件定时器,定时器精度为Systick触发精度。

 

图18:软件定时器开启


  • 4
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Introduction:GD32F10x标准固件库。适用于GD32F10x系列MCU,与Cortex-M微控制器软件接口标准(CMSIS)兼容。固件库包括程序、数据结构和宏定义,覆盖所有集成外设的特征,并包括了全部相关驱动和示例程序。 Introduction:GD32F1x0标准固件库。适用于GD32F1x0(130/150/170/190)系列MCU,与Cortex-M微控制器软件接口标准(CMSIS)兼容。固件库包括程序、数据结构和宏定义,覆盖所有集成外设的特征,并包括了全部相关驱动和示例程序 Introduction:GD32F10x系列IAR7.4、Keil MDK 4.74、Keil MDK 5.15 及更高版本支持安装文件。 Introduction:GD32F1x0 外设驱动库和通用例程 ,支持 GD32F130 / GD32F150 / GD32F170 / GD32F190 包含USB Device驱动库和例程 ,仅支持 GD32F150 提供 Keil 和 IAR 两种工程 ,分别在 Keil v4.7x/v5.18a , IAR v7.4 验证通过 Introduction:GD32F1x0 分散加载例程 ,支持 GD32F130 / GD32F150 / GD32F170 / GD32F190 例程演示了如何将代码分配到Flash指定区域,参考这个例程,客户可将非关键代码分配到Flash高地址空间。 Introduction:包含三个文件,具体说明如下: 1. GigaDevice.GD32F1x0_Addon.3.1.0.exe Keil4 环境补丁,支持 Keil v4.7x , 2. GigaDevice.GD32F1x0_DFP.3.1.0.pack Keil5 在线支持包, 支持 Keil v5.15 及以上版本; 3. IAR_GD32F1x0_ADDON.1.0.2.exe IAR 环境补丁,支持 IAR v7.4 以上版本. Introduction:Pdsc Installation of support files for Keil MDK 5.13 or later version
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值