漫谈LiteOS之开发板-LiteOS硬中断移植(基于GD32450i-EVAL)
10 LiteOS硬中断移植
摘要:本文是承接漫谈LiteOS之开发板系列第8篇的延伸,前者使用非接管中断方式进行移植,本文是用接管中断方式进行移植,希望对你有所帮助。
1 为什么移植?
嵌入式设备的芯片型号和外设的差异较大,资源有限。而RTOS无法适配集成所有的驱动,因此会先适配部分开发板,然后通过移植使得适配更多的开发板。
可移植性是嵌入式操作系统与普通操作系统的显著区别之一,而所谓移植就是通过一定的代码修改使得该操作系统适配自己的开发板,以使得自己的开发板可以运行一些手头开发板没有配套的编译工程。
2 移植的分类
移植通常分为系统移植和驱动移植,驱动移植需要依赖具体的外设,本文主要介绍操作系统的移植。采用的主要方案是硬中断接管和不接管中断中的硬中断方式。
3 开发环境
软件环境:Windows系统、Keil5、J-Link对应驱动;
硬件环境:GD32450i-EVAL开发板、J-Link下载器、串口线、数据线;
注意:上述环境也可根据自己需求进行修改,如使用IAR、GCC等。
4 移植流程
4.1 准备工作
(1)下载LiteOS源码
在github上下载最新的LiteOS源码,地址:https://github.com/LiteOS/LiteOS,下载任意版本皆可,其源码核心一致,我这里使用的是dev-deserted,其工程目录详情如图1所示。
图1 LiteOS源码工程目录以及对应描述
(2)提取LiteOS核心移植文件
对LiteOS源码做一个简单的提取便于后续操作的简洁性,当然也可以不提取,新建文件夹命名为LiteOS,将 LiteOS源码中的arch文件、components/cmsis文件、kernel文件、以及targets文件中的示例工程中拷贝两个OS_CONFIG文件,其中一个为接管中断(如Standard_GD32F103C_START工程中的OS_CONFIG文件)一个为非接管中断(如Standard_STM32F103VC_TAIBI工程中的OS_CONFIG文件)。具体如下表1所示。
表1 LiteOS核心文件提取
一级目录 | 一级目录 | 一级目录 | 描述 |
arch | arm | arm-m | M 核中断、调度、tick相关代码 |
common | arm核公用的 cmsis core 接口 | ||
cmsis | LiteOS 提供的 cmsis os接口实现 | ||
kernel | base | core | LiteOS 基础内核代码文件,包括队列、 task 调度、软 timer、时间片等功能 |
OM | 与错误处理相关的文件 | ||
Include | LiteOS 内核内部使用的头文件 | ||
ipc | LiteOS 中 ipc 通讯相关的代码文件,包括事件、信号量、消息队列、互斥锁等 | ||
mem | LiteOS 中的内核内存管理的相关代码 | ||
misc | 内存对齐功能以及毫秒级休眠 sleep 功能 | ||
include | LiteOS 开源内核头文件 | ||
extended | tickless | 低功耗框架代码 | |
OS_CONFIG | 非接管中断 | ||
OS_CONFIG_Take | 接管中断 |
(3)创建裸机工程
使用前面的串口示例代码作为裸机工程,当然也可以使用keil自己创建裸机工程,自己创建的裸机工程一定要进行简单的功能测试。将步骤(2)中的LiteOS文件拷贝到裸机工程根目录下,具体如图2所示。
图2 LiteOS目录概图
4.2 添加内核源码
在裸机工程中,添加LiteOS相关文件夹,分别命名为LiteOS/cmsis、LiteOS/arch、LiteOS/kernel、LiteOS/config(可有可无,便于后期操作而已),并分别将cmsis os代码、kernel代码、arch代码、OS_CONFIG文件等添加到对应的文件夹,具体如图3所示。
图3 添加工程分组
其中需要添加的源码以及对应的文件所在位置具体如下表所示。添加后的文件目录详情,具体如图4所示。
图4 添加Lite OS源码
4.3 添加头文件
添加源码之后,需要添加对应应用的头文件,具体如图5所示。
图5 添加头文件
4.4 修改target.h文件
与非接管中断方式不同,需要对头文件和接管中断方式进行修改。其头文件如图6所示。第43行,需要修改为开发板相对应的系列头文件。
图6 target.h头文件修改
接管中断方式改为YES,第94行,如下所示
#define LOSCFG_PLATFORM_HWI YES
4.5 修改启动文件
由于LiteOS接管中断方式的中断向量表示系统管理的,因此启动文件需要进行修改。即将los_startup_keil.s文件添加到keil文件夹下,同时将裸机工程中的startup_gd32450.s文件删除,具体如图7所示。
图7 修改启动文件
4.6 分散加载文件修改
首先在编译后生成的文件(E:\GD32450i-EVAL\Project\GD32F450I_TakeOver\MDK-ARM\output) 文件夹下的GD32450I_EVAL.sct文件即为分散加载文件,此处需要根据开发板的RAM以及Flash大小进行一定的修改,二者大小具体如图8所示。
图8 查看开发板SRAM大小
sct文件默认下是keil自动生成的,需要使用LiteOS开发中的。sct文件。该文件在LiteOS源码中的targets中的例程中位于MDK_ARM文件夹下,可以拷贝过来之后根据flash以及RAM进行地址的调整。具体使用的设置如图9所示。
图9 配置sct文件路径
由于中断向量表示放在运行内存里的,为了避免影响分配内存,需要将代码分散加载到不同的区域中,因此需要对分散加载文件进行修改本文中附件会有该文件。具体修改如图10所示。
图10分散加载文件的修改
其中1(0x08000000):表示flash的起始地址。2(0x00100000):表示域大小(Flash大小)对于GD32450i-EVAL开发板其大小为1M。其中3(0x20000000):表示运行时域基地址。4(0x400)表示存储中断向量表的空间大小。其中5(0x20000400):大小为3+4。6(0x0002F800):表示存放数据段的空间大小。其中7(0x20000400):大小为5+6。
4.5 注释回调函数代码
由于PendSV_Handler以及SysTick_Handler(void)函数在LiteOS源码以及裸机工程中的gd32f4xx_it.c文件中都有定义,因此如果直接编译会出现重定义的错误,如图11所示。此时我们需要将对应gd32f4xx_it.c中代码注释掉或删除即可。
图11 运行错误详情
5 测试
上面已经将移植工作基本完成,后面只需要做一下测试即可,具体包括硬件测试以及LiteOS测试。
5.1 硬件启动测试
对于测试,首先需要将串口调试好,便于后续的调试,此处我以串口函数以及LED灯进行测试。在使用LiteOS系统之前首先需要将开发板启动起来,具体如下所示。但是需要注意的是初始化的时候不要调用delay函数,因为SysTick_Handler(void)函数被注释掉了,如果调用该函数会导致,程序卡死在delay处。测试的时候一定要注意main函数中要有while循环使其卡停在此处。
#include "gd32f4xx.h" #include "gd32f450i_eval.h" #include "systick.h" #include <stdio.h> void Hardware_Init(void); void led_init(void); int main() { Hardware_Init(); printf("\r\n USART printf example: please press the Tamper key \r\n"); while(1){ gd_eval_led_on(LED1); } } void Hardware_Init(void) { led_init(); systick_config(); gd_eval_com_init(EVAL_COM1); } void led_init(void) { gd_eval_led_init(LED1); } int fputc(int ch, FILE *f) { usart_data_transmit(EVAL_COM1, (uint8_t)ch); while(RESET == usart_flag_get(EVAL_COM1, USART_FLAG_TBE)); return ch; }
5.2 移植功能测试
接下来只需要对Lite OS移植进行测试,对主函数进行修改实现任务的创建于调用即可,主函数具体如下所示。
#include "gd32f4xx.h" #include "gd32f450i_eval.h" #include "systick.h" #include <stdio.h> #include "los_sys.h " #include "los_typedef.h" #include "los_task.ph" UINT32 g_TskHandle; void Hardware_Init(void); void led_init(void); UINT32 creat_task1(); UINT32 creat_task2(); int main(){ Hardware_Init(); printf("\r\n USART printf example: please press the Tamper key \r\n"); UINT32 uwRet = 0; uwRet = LOS_KernelInit(); if (uwRet != LOS_OK){ return LOS_NOK; } uwRet = creat_task1(); if (uwRet != LOS_OK){ return LOS_NOK; } uwRet = creat_task2(); if (uwRet != LOS_OK){ return LOS_NOK; } LOS_Start(); while(1){ gd_eval_led_on(LED1); } } void Hardware_Init(void){ led_init(); systick_config(); gd_eval_com_init(EVAL_COM1); } void led_init(void){ gd_eval_led_init(LED1); } int fputc(int ch, FILE *f){ usart_data_transmit(EVAL_COM1, (uint8_t)ch); while(RESET == usart_flag_get(EVAL_COM1, USART_FLAG_TBE)); return ch; } void task1(void){ int count = 1; while(1){ printf("This is task1, count is %d\r\n", count++); LOS_TaskDelay(1000); } } UINT32 creat_task1(){ UINT32 uwRet = LOS_OK; TSK_INIT_PARAM_S task_init_param; task_init_param.usTaskPrio = 0; task_init_param.pcName = "task1"; task_init_param.pfnTaskEntry = (TSK_ENTRY_FUNC)task1; task_init_param.uwStackSize = 0x200; uwRet = LOS_TaskCreate(&g_TskHandle, &task_init_param); if(LOS_OK != uwRet){ return uwRet; } return uwRet; } void task2(void){ int count = 1; while (1){ printf("This is task2,count is %d\r\n",count++); LOS_TaskDelay(2000); } } UINT32 creat_task2(){ UINT32 uwRet = LOS_OK; TSK_INIT_PARAM_S task_init_param; task_init_param.usTaskPrio = 1; task_init_param.pcName = "task2"; task_init_param.pfnTaskEntry = (TSK_ENTRY_FUNC)task2; task_init_param.uwStackSize = 0x200; uwRet = LOS_TaskCreate(&g_TskHandle, &task_init_param); if(LOS_OK != uwRet){ return uwRet; } return uwRet; }
运行结果如图12所示,可以看见两个任务在交替打印。移植完成,本例程使用的是非接管中断的方式,如果使用接管中断方式的,需要拷贝结果中断的OS_CONFIG文件,同时对于target.h文件需要额外的修改,同时修改.sct文件(在keil工程下的Objects文件夹下),而不是使用自动生成的.sct文件.
图12 Lite OS移植成功运行结果
主文博客链接:https://bbs.huaweicloud.cn/blogs/124244
- 点赞
- 收藏
- 关注作者
评论(0)