手工向GD32F450移植RT-Thread内核

第一步 准备一个可编译成功的串口输出裸机工程

在裸机工程目录下创建文件夹rt_thread复制源码中这三个文件夹过来,然后再创建三个文件board.c board.h rtconfig.h(建议从已有同款芯片的工程中复制,这样就不用疯狂手敲了)

libcpu是已经移植好的cpu部分,找到自己同款芯片的文件,其他的删除
在这里插入图片描述

第二步 将准备好的文件添加到工程中,同时还有头文件路径配置

这是我的文件结构,不需要一样,源文件加进来就行

libcpu文件夹中有三个启动文件对应三种编译工具,添加时选择符合自己IDE的。
在这里插入图片描述

然后编译工程,会出现报错,这是rtconfig.h中部分声明造成的,现在需要暂时屏蔽不需要的组件,只留下内核部分
在这里插入图片描述
在这里插入图片描述

这时候编译,通常情况下会出现这样报错
在这里插入图片描述
这是因为操作系统内核接管了这两个中断函数 HardFault_Handler 和 PendSV_Handler ,我们需要将这两个函数从原本的裸机工程中移除。在此编译应该就没有报错了,此时操作系统内核已经编译,但是没有调用。

第三步 进入操作系统

将rtconfig中这些宏打开后进行编译,不出意外的话应该会报错提示没有rt_hw_board_init
在这里插入图片描述
在这里插入图片描述
具体原因可以去查书中关于操作系统启动过程的内容,这里直接在新建的borad.c文件中构建这个函数。
同时把原先在主函数中的硬件初始化过程剪切过来。
再次编译此时操作系统已经添加,不过没有添加启动时间调度,所以不能创建线程,也基本上没啥用。
目前可以先下载到开发板,如果没有错程序则可以跑到用户main函数中

在这里插入图片描述

可是通常情况下我们会发现,当前只是没有报错,但是程序不会执行用户main函数,通过调试发现程序会死在这里。
在这里插入图片描述
Debug中Call Stack + Locals窗口可以推出程序逻辑在re_application_init()中出问题。
在这里插入图片描述
在这里插入图片描述
因为rtconfig中配置中宏定义了RT_USING_HEAP,但是程序中还没有打开动态内存管理,所以解决问题的方法有两种:1关闭RT_USING_HEAP,采用静态方法创建主应用;2定义一块大内存,打开动态内存管理。

方法1:静态内存方法
直接在rtconfig文件中注释RT_USING_HEAP。然后在main中闪烁一个灯验证一下。下载完成后灯开始循环闪烁,证明main函数已经开始在跑了。
在这里插入图片描述

方法2:动态内存方法
首先定义一块大内存打开rtconfig中RT_USING_HEAP宏,然后调用rt_system_heap_init()完成动态内存初始化,重新下载验证可行性,同样可以进入main函数。
在这里插入图片描述
不过通常情况下,systerm_stack不会用定义的数组,而是利用编译剩下的全部内存,具体原理我也不太清楚,但是我知道通常可以从已有的工程中board.h找到这部分内容。
在这里插入图片描述
复制过来以后把动态内存的初始化参数对应修改,同样还要把刚才定义的数组注释掉。搞定后编译下载就ok了。
在这里插入图片描述

第四步 打开时间调度

这里需要使用一个定时中断回调函数周期性的调用rt_tick_increase,通常Cortex M的芯片会使用SysTick_Handler()来作为时间调度器的触发者。

首先在rt_hw_board_init()中配置滴答定时器
在这里插入图片描述
然后通过完成SysTick_Handler()实现时钟管理
在这里插入图片描述
完成后如何验证是否成功,rt_thread提供的延时函数都是依赖系统tick的,所以如果可以正常使用rt_thread_delay()和rt_thread_mdelay()就可以表示实现时钟管理成功。主函数改写如,下载后我的开发板开始一闪一闪:
在这里插入图片描述

第五步 实现控制台输出

控制台是我认为rt-thread最好用的地方,通过串口可以像PC端的终端一样打印好多信息。

Rt-thread提供rt_kprintf()和rt_hw_console_output()函数,用来输出调试信息。
rt_kprintf()的底层可以基于设备框架的字符设备,也可以通过rt_hw_console_output()函数输出,所以这里直接选择实现rt_hw_console_output()
在这里插入图片描述
编译下载,如果移植成功,通过串口调试会出现rt-thread的logo
在这里插入图片描述

第六步 实现动态内存管理完成动态线程创建

其实在上面第三步时已经实现了动态内存管理,可回翻再看下。现在直接创建两个线程验证rtt内核移植成功。这里主线程依旧是小灯闪烁,然后线程1和线程2分别在控制台打印不同字符串。

线程创建代码如下:

void thread1_entry(void *parameter)
{
	while(1)
	{
		rt_kprintf("this is thread1\n");
		rt_thread_mdelay(1000);
	}
}

void thread2_entry(void *parameter)
{
	while(1)
	{
		rt_kprintf("这是线程2\n");
		rt_thread_mdelay(1000);
	}
}

int main(void)
{
	rt_thread_t tid;
	
	tid = rt_thread_create("thread1", thread1_entry, RT_NULL, 512, RT_MAIN_THREAD_PRIORITY-1, 100);
	if(tid != RT_NULL)
	{
		rt_kprintf("thread1 create sucessful\n");
		rt_thread_startup(tid);
	}
	else
		rt_kprintf("thread1 create falled\n");
	
	tid = rt_thread_create("thread2", thread2_entry, RT_NULL, 512, RT_MAIN_THREAD_PRIORITY-1, 100);
	if(tid != RT_NULL)
	{
		rt_kprintf("thread2 create sucessful\n");
		rt_thread_startup(tid);
	}
	else
		rt_kprintf("thread2 create falled\n");
	
	while(1)
	{
		/* turn on LEDs */
		gd_eval_led_on(LED1);
		gd_eval_led_on(LED2);
		gd_eval_led_on(LED3);
		rt_thread_delay(1000);

		/* turn off LEDs */
		gd_eval_led_off(LED1);
		gd_eval_led_off(LED2);
		gd_eval_led_off(LED3);
		rt_thread_mdelay(1000);
	}
}

编译下载,串口调试结果符合,内核移植完成。
在这里插入图片描述

  • 3
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值