rt_thread nano GD32F407移植

rt_thread nano GD32F407移植

1、简介

RT-Thread Nano 是一个极简版的硬实时内核,它是由 C 语言开发,采用面向对象的编程思维,具有良好的代码风格,是一款可裁剪的、抢占式实时多任务的 RTOS。其内存资源占用极小,功能包括任务处理、软件定时器、信号量、邮箱和实时调度等相对完整的实时操作系统特性。适用于家电、消费电子、医疗设备、工控等领域大量使用的 32 位 ARM 入门级 MCU 的场合。

架构

RT-Thread Nano版本与其他RTOS的区别在于新增加了一个可裁剪的FinSH控制台,主要是通过串口实现的类似linux命令行终端的功能。

2、RT-Thread Nano移植

移植目结构

rtthread-nano 源码中,与移植相关的文件位于下图中有颜色标记的路径下(黄色表示 libcpu 移植相关的文件,绿色部分表示板级移植相关的文件):

与移植相关的文件

移植步骤

添加文件

Cortex-M 芯片内核移植代码:

context_rvds.s
cpuport.c

Kernel 文件包括

clock.c
components.c
device.c
idle.c
ipc.c
irq.c
kservice.c
mem.c
mempool.c
object.c
scheduler.c
thread.c
timer.c

配置文件:

board.c
rtconfig.h

屏蔽中断与异常处理

RT-Thread 会接管异常处理函数 HardFault_Handler() 和悬挂处理函数 PendSV_Handler(),这两个函数已由 RT-Thread 实现,所以需要删除工程里中断服务例程文件中的这两个函数,避免在编译时产生重复定义。如果此时对工程进行编译,没有出现函数重复定义的错误,则不用做修改。

系统时钟配置

需要在 board.c 中实现 系统时钟配置(为 MCU、外设提供工作时钟)与 os tick 的配置 (为操作系统提供心跳 / 节拍)。

如下代码所示,用户需要在 board.c 文件中系统初始化和 OS Tick 的配置,用户需在 timer 定时器中断服务函数调用 rt_os_tick_callback function,cortex-m 架构使用 SysTick_Handler()

在这里插入图片描述

内存堆初始化

系统内存堆的初始化在 board.c 中的 rt_hw_board_init() 函数中完成,内存堆功能是否使用取决于宏 RT_USING_HEAP 是否开启,RT-Thread Nano 默认不开启内存堆功能,这样可以保持一个较小的体积,不用为内存堆开辟空间。

开启系统 heap 将可以使用动态内存功能,如使用 rt_malloc、rt_free 以及各种系统动态创建对象的 API。若需要使用系统内存堆功能,则打开 RT_USING_HEAP 宏定义即可,此时内存堆初始化函数 rt_system_heap_init() 将被调用,如下所示:

heap1

初始化内存堆需要堆的起始地址与结束地址这两个参数,系统中默认使用数组作为 heap,并获取了 heap 的起始地址与结束地址,该数组大小可手动更改,如下所示:

6-2


3、FinSH组件移植

kprintf()移植

void rt_hw_console_output(const char *str)  //实现该函数,才能使用rt_kprintf
{
	 /* 进入临界段 */
  rt_enter_critical();
	
	while(*str!='\0')
	{
		 /* 换行 */
    if (*str == '\n')//RT-Thread 系统中已有的打印均以 \n 结尾,而并非 \r\n,所以在字符输出时,需要在输出 \n 之前输出 \r,完成回车与换行,否则系统打印出来的信息将只有换行
    {
       usart_data_transmit(USART1, '\r');
	
	     while(usart_flag_get(USART1, USART_FLAG_TC)== RESET);
    }

		usart_data_transmit(USART1, *(str++));
	
	  while(usart_flag_get(USART1, USART_FLAG_TC)== RESET);
		
	}
	 /* 退出临界段 */
  rt_exit_critical();  //注意:使用进入临界段语句rt_enter_critical(); 一定要使用退出临界段语句 rt_exit_critical();否则调度器锁住,无法进行调度
	
}

Finsh组件移植

char rt_hw_console_getchar(void)//使用Finsh组件三步骤:1.实现该函数及rt_hw_console_output函数;2.rtconfig.h中开启RT_USING_FINSH宏;3.添加Finsh组件(cmd.c、msh.c、shell.c),
{  //查询方式实现,记得将Usart1初始化中的中断接收配置相关代码注释掉
	   int ch = -1;
	   /*等待串口1输入数据*/
     if(usart_flag_get(USART1, USART_FLAG_RBNE) != RESET)
		 {
         ch = (int)usart_data_receive(USART1);
			   usart_flag_clear(USART1, USART_FLAG_RBNE);
		 }
		 else
		 {
			 
         if(usart_flag_get(USART1, USART_FLAG_ORERR) != RESET)
         {
             usart_flag_clear(USART1, USART_FLAG_ORERR);
         }
         rt_thread_mdelay(10);
			 
		 }

     return ch;
}

移植成功后打开串口输入help可以看见如下信息表示移植成功

在这里插入图片描述

4、FinSH调试技巧

1、函数初始化功能

rt_thread的初始化有两种方式

方法一:将函数放入rt_hw_board_init()函数

int rtthread_startup(void)
{
    rt_hw_interrupt_disable();

    /* board level initialization
     * 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();

#ifdef RT_USING_SIGNALS
    /* signal system initialization */
    rt_system_signal_init();
#endif

    /* 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;
}

方法二: 使用宏 INIT_BOARD_EXPORT() 进行自动初始化,不需要显式调用 (推荐使用)

/*rtdef.h*/

/* board init routines will be called in board_init() function */
#define INIT_BOARD_EXPORT(fn)           INIT_EXPORT(fn, "1")

/* pre/device/component/env/app init routines will be called in init_thread */
/* components pre-initialization (pure software initilization) */
#define INIT_PREV_EXPORT(fn)            INIT_EXPORT(fn, "2")
/* device initialization */
#define INIT_DEVICE_EXPORT(fn)          INIT_EXPORT(fn, "3")
/* components initialization (dfs, lwip, ...) */
#define INIT_COMPONENT_EXPORT(fn)       INIT_EXPORT(fn, "4")
/* environment initialization (mount disk, ...) */
#define INIT_ENV_EXPORT(fn)             INIT_EXPORT(fn, "5")
/* appliation initialization (rtgui application etc ...) */
#define INIT_APP_EXPORT(fn)             INIT_EXPORT(fn, "6")

推荐使用这个函数,可以有效的降低模块之间的耦合性

2、串口调试功能

添加自定义命令

除了 FinSH 自带的命令,FinSH 还也提供了多个宏接口来导出自定义命令,导出的命令可以直接在FinSH 中执行。

MSH_CMD_EXPORT(name, desc);//命令及其描述,用于添加自定义命令

如下添加两个控制led打开和关闭的finsh命令

void LedpOn(void)
{
	gpio_bit_set(GPIOF,GPIO_PIN_0);
}
MSH_CMD_EXPORT(LedpOn, Control Beep On);


void LedpOff(void)
{
	gpio_bit_reset(GPIOF,GPIO_PIN_0);
}

MSH_CMD_EXPORT(LedpOff, Control Beep Off);

打开终端就可以看见自己添加的命令了

d打开和关闭的finsh命令

void LedpOn(void)
{
	gpio_bit_set(GPIOF,GPIO_PIN_0);
}
MSH_CMD_EXPORT(LedpOn, Control Beep On);


void LedpOff(void)
{
	gpio_bit_reset(GPIOF,GPIO_PIN_0);
}

MSH_CMD_EXPORT(LedpOff, Control Beep Off);

打开终端就可以看见自己添加的命令了

在这里插入图片描述

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值