0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

OPENHW开源CORE-V-MCU移植RT-Thread

RTThread物联网操作系统 来源:RTThread物联网操作系统 2023-02-01 10:05 次阅读

项目背景

OpenHW Group 是一个以协作方式开发开源硬件和相关软件的非营利组织,致力于开发、验证和提供开源处理器内核。OpenHW Group的开源项目致力于开发和验证基于免费和开放的RISC-V指令集架构 (ISA) 系列内核,称为 CORE-V系列。CV32E40P 开源处理器 IP 内核,这是 OpenHW CORE-V 系列中第一个经过全面验证的内核。本文的对象就是基于CV32E40P实现的开源CORE-V-MCU移植RT-Thread

CORE-V-MCU目前是以软核的形式在FPGA上进行了实现,中科院 PLCT 实验室针对CV32E40P内核的CORE-V-MCU适配了QEMU,本文最终的验证在QEMU上进行。

前期准备

开发环境:ubuntu18.04

验证示例工程

本次实验验证的平台是PLCT提供的QEMU,在Linux下的QEMU可以使用上述的笔者编译好的,也可以使用自己尝试编译PLCT提供的源码。

OPENHW提供了基于FreeRTOS的示例工程,由于使用的是PLCT提供的QEMU,所以IDE中自带的工程并不能直接使用,为了避免不必要的麻烦,本文采用PLCT提供的示例工程。

下载好示例工程,进入到app目录,执行以下命令配置编译工程:

source ../env/core-v-mcu.sh

make RISCV=xxx //xxx为工具链的路径

编译完成后将生成的cli_test可执行文件拷到qemu的安装目录,运行下述命令验证工程;

./qemu-system-riscv32 -M core_v_mcu -bios none -kernel cli_test -nographic -monitor none -serial stdio

运行结果:

6910266e-a1d4-11ed-bfe3-dac502259ad0.png

出现上述结果,则表示示例工程运行正常,这样我们就有一个可移植的模板工程,后续移植基于该工程开展。

移植RT-Thread

CV32E40P内核是一个RISC-V架构的内核,移植RTOS不可避免的会涉及到汇编部分的修改,所以在移植前期学习一下RISC-V架构与汇编会产生事半功倍的效果,同样在一之前需要熟悉CV32E40P的内核资源

https://docs.openhwgroup.org/projects/core-v-mcu/doc-src/overview.html

cv32e40p继承自pulp开源的RI5CY内核,而RI5CY内核的对接代码在RT-Thread的仓库libcpu/riscv/rv32m1已经实现,所以以RI5CY中的代码为基础,移植cv32e40p的对接代码。

成功移植RT-Thread有如下几个关键的阶段:

  • 节拍定时器正常工作

  • 线程可以正常创建,调度(这步最难,需要前面好多工作来保证)

  • shell可以正常使用(从这开始就顺利多了)

RTOS的最小时间单位是系统节拍,系统正常工作需要节拍定时器的支持,因而以节拍定时器的移植为切入点展开移植。

core-v-mcu.c中放置的是系统初始化,中断处理相关代码。其中system_init函数完成了时钟初始化,串口,I2C等外设的初始化,以及中断函数的绑定。在文件的开头可以找到如下一个指针数组:

1void(*isr_table[32])(uint32_t);

该数组用于绑定中断入口函数。

1for(inti=0;i< 32;i++){
2isr_table[i]=undefined_handler;
3handler_count[i]=0;
4}
5isr_table[0x7]=timer_irq_handler;
6isr_table[0xb]=(void(*)(uint32_t))fc_soc_event_handlzer1;

system_init函数中我们可以找到上述代码,浏览该文件我们可以知道,timer_irq_handler即系统定时器的中断入口函数,

在原有FreeRTOS工程中该函数内容如下:

1voidtimer_irq_handler(uint32_tmcause)
2{
3#warningrequirescriticalsectionifinterruptnestingisused.
4if(xTaskIncrementTick()!=0){
5vTaskSwitchContext();
6}
7}

该函数实现系统节拍的产生,所以将这里的内容修改为RT-Thread的节拍产生的方式,修改如下:

1voidtimer_irq_handler(uint32_tmcause)
2{
3#warningrequirescriticalsectionifinterruptnestingisused.
4rt_interrupt_enter();
5rt_tick_increase();
6rt_interrupt_leaves();
7}

涉及到中断,我们就得考虑系统的中断的实现方式,中断一般会分为向量中断与非向量中断。RISC-V常在启动后文件中进行中断模式的配置。从crt0.S文件可以找到如下代码:

1/*setvectortableaddress*/
2laa0,__vector_start
3ora0,a0,1/*enablevectoredmode(hardcodedanywayforCV32E40P)*/
4csrwmtvec,a0

RISC-V规范定义中断、异常的入口地址,以及模式使用mtvec寄存器配置,上述代码将系统的中断模式配置为了向量模式,向量模式下,每个函数均包含一个独立的入口函数用来处理中断。所以我们切换至写中断向量表的文件vector.S,我们可以很明显的看到一段代码,从名字就可以看出下面是一张向量表 :

 1vector_table:
 2jfreertos_risc_v_trap_handler//irq0
 3jfreertos_risc_v_trap_handler
 4jfreertos_risc_v_trap_handler
 5jfreertos_risc_v_trap_handler//irq3
 6jfreertos_risc_v_trap_handler
 7jfreertos_risc_v_trap_handler
 8jfreertos_risc_v_trap_handler
 9jfreertos_risc_v_trap_handler//ctxt_handler//irq7mtimeortimer
10jfreertos_risc_v_trap_handler
11jfreertos_risc_v_trap_handler
12jh7//freertos_risc_v_trap_handler
13jfreertos_risc_v_trap_handler//irq11Machine(eventFifo)
14jfreertos_risc_v_trap_handler
15jfreertos_risc_v_trap_handler
16jfreertos_risc_v_trap_handler
17jfreertos_risc_v_trap_handler
18jfreertos_risc_v_trap_handler//IRQ16
19jfreertos_risc_v_trap_handler//IRQ17
20jfreertos_risc_v_trap_handler//IRQ18
21jfreertos_risc_v_trap_handler//IRQ19
22jfreertos_risc_v_trap_handler//IRQ20
23jfreertos_risc_v_trap_handler//IRQ21
24jfreertos_risc_v_trap_handler//IRQ22
25jfreertos_risc_v_trap_handler//IRQ23
26jfreertos_risc_v_trap_handler//IRQ24
27jfreertos_risc_v_trap_handler//IRQ25
28jfreertos_risc_v_trap_handler//IRQ26
29jfreertos_risc_v_trap_handler//IRQ27
30jfreertos_risc_v_trap_handler//IRQ28
31jfreertos_risc_v_trap_handler//IRQ29
32jfreertos_risc_v_trap_handler//IRQ30
33jfreertos_risc_v_trap_handler//IRQ30

PS:上述向量表看的我懵了好久啊,相信对于刚接触底层不久的小伙伴也会有同样的感受吧,向量表不是一张多姿多彩的表吗,怎么感觉都一样啊???不急,我们在看一下core-v-mcu.c这个文件,又会发现一段非常显眼的代码:

1voidvSystemIrqHandler(uint32_tmcause)
2{
3uint32_tval=0;
4//externvoid(*isr_table[32])(uint32_t);
5isr_table[mcause&0x1f](mcause&0x1f);
6}

		

		
结合上文,思考一下大致可以明白这个函数的作用了:分发中断。即所有的异常与中断触发后均会执行这个函数,那我们全局搜索一下这个函数,
找一下是哪里调用了.全局搜索可以找到如下代码:
1CPPFLAGS+=-DportasmHANDLE_INTERRUPT=vSystemIrqHandler

			

			
继续搜索DportasmHANDLE_INTERRUPT可从portASM.S找到如下代码;
1load_xsp,xISRStackTop/*SwitchtoISRstackbeforefunctioncall.*/
2jalportasmHANDLE_INTERRUPT
3jprocessed_source

			

			

浏览代码可知,系统触发中断或异常后最终均会执行vSystemIrqHandler函数,该函数是在freertos_risc_v_trap_handler函数中被调用,至此我们大致可以明白整个过程了,当中断或者异常出发后,会查询向量表,执行freertos_risc_v_trap_handler函数,该函数会调用vSystemIrqHandler,经其分发后最终执行到系统初始化时绑定的中断入口函数。

在RT-Thread 中由interrupt_gcc.S中的函数实现vSystemIrqHandler函数的调用,所以我们修改中断向量表的内容如下:

 1vector_table:
 2jIRQ_Handler//irq0
 3jIRQ_Handler
 4jIRQ_Handler
 5jIRQ_Handler//irq3
 6jIRQ_Handler
 7jIRQ_Handler
 8jIRQ_Handler
 9jIRQ_Handler//ctxt_handler//irq7mtimeortimer
10jIRQ_Handler
11jIRQ_Handler
12jIRQ_Handler//IRQ_Handler
13jIRQ_Handler//irq11Machine(eventFifo)
14jIRQ_Handler
15jIRQ_Handler
16jIRQ_Handler
17jIRQ_Handler
18jIRQ_Handler//IRQ16
19jIRQ_Handler//IRQ17
20jIRQ_Handler//IRQ18
21jIRQ_Handler//IRQ19
22jIRQ_Handler//IRQ20
23jIRQ_Handler//IRQ21
24jIRQ_Handler//IRQ22
25jIRQ_Handler//IRQ23
26jIRQ_Handler//IRQ24
27jIRQ_Handler//IRQ25
28jIRQ_Handler//IRQ26
29jIRQ_Handler//IRQ27
30jIRQ_Handler//IRQ28
31jIRQ_Handler//IRQ29
32jIRQ_Handler//IzRQ30
33jIRQ_Handler//IRQ30

			

浏览IRQ_Handler可知,触发中断或异常均会执行该代码,该函数的主要的功能就是实现了软件保存上下文。根据RISC-V规范可知,RISC-V架构定义不支持硬件压栈,所以需要软件实现这部分,这样做的出发点大概是为了简化RISC-V架构的内核的设计吧!!!

libcpu/riscv/rv32m1中的IRQ_Handler函数存在如下内容

1/*switchtointerruptstack*/
2lasp,__stack//移植时需修改
3/*interrupthandle*/
4callrt_interrupt_enter
5csrra0,mcause
6csrra1,mepc
7mva2,sp
8callSystemIrqHandler//移植时需修改
9callrt_interrupt_leave

这部分的作用是,加载中断栈的栈顶地址与执行保存上文之后的工作,这里是调用SystemIrqHandler函数进行中断分发,修改如下:

1/*switchtointerruptstack*/
2lasp,__freertos_irq_stack_top//栈顶地址位于链接脚本中
3/*interrupthandle*/
4callrt_interrupt_enter
5csrra0,mcause
6csrra1,mepc
7mva2,sp
8callvSystemIrqHandler//调用vSystemIrqHandler函数
9callrt_interrupt_leave

board.crt_hw_board_init函数中,添加如下代码:

1vPortSetupTimerInterrupt();//初始化定时器
2volatileuint32_tmtvec=0;
3__asmvolatile("csrr%0,mtvec":"=r"(mtvec));//声明仅有一张向量表
4__asmvolatile("csrsmie,%0"::"r"(0x880));//使能定时器中断与外部中断

至此,基本的移植工作已经完成,可以采用静态创建任务的方式,实现多任务的创建与调度。

动态内存

在board.c添加下述代码:

 1#ifdefined(RT_USING_USER_MAIN)&&defined(RT_USING_HEAP)
 2#defineRT_HEAP_SIZE(64*1024)
 3staticrt_uint8_trt_heap[RT_HEAP_SIZE];
 4void*rt_heap_begin_get(void)
 5{
 6returnrt_heap;
 7}
 8void*rt_heap_end_get(void)
 9{
10returnrt_heap+RT_HEAP_SIZE;
11}
12#endif

rt_hw_board_init添加下述代码:

1#ifdefined(RT_USING_USER_MAIN)&&defined(RT_USING_HEAP)
2rt_system_heap_init(rt_heap_begin_get(),rt_heap_end_get());
3#endif

完成上述工作便可使用RT-Thread的动态内存相关接口,同样可以种动态创建线程的函数。

shell

在链接脚本的.text段添加如下内容

 1/*sectioninformationforfinshshell*/
 2.=ALIGN(4);
 3__fsymtab_start=.;
 4KEEP(*(FSymTab))
 5__fsymtab_end=.;
 6.=ALIGN(4);
 7__vsymtab_start=.;
 8KEEP(*(VSymTab))
 9__vsymtab_end=.;
10.=ALIGN(4);

实现以下函数:

1charrt_hw_console_getchar(void)
2{
3returnudma_uart_getchar(0);
4}

1voidrt_hw_console_output(constchar*str)
2{
3writeraw(0,strlen(str),(uint8_t*)str);
4}

注:writeraw函数来自udma_uart_writeraw,去掉了其中涉及FreeRTOS的API.

完成上述部分便可以使用RT-Thread的shell。

自动初始化

在链接脚本的.text段添加如下内容:

1/*sectioninformationforinitial.*/
2.=ALIGN(4);
3__rt_init_start=.;
4KEEP(*(SORT(.rti_fn*)))
5__rt_init_end=.;
6.=ALIGN(4);

添加上述代码后便可使用RT-Thread的自动初始化接口。

结果验证

在生成的目标文件的目录下,输入运行命令,示例命令:

1/home/wangshun/bin/qemu-riscv/bin/qemu-system-riscv32-Mcore_v_mcu-biosnone-kernelrtthread.elf-nographic-monitornone-serialstdio

使用时,/home/wangshun/bin/qemu-riscv/bin/修改为用户的qemu的路径。

运行结果如下:

 1|/
 2-RT-ThreadOperatingSystem
 3/|5.0.0buildDec16202211:25:07
 42006-2022CopyrightbyRT-Threadteam
 5HelloRT-Thread
 6msh>help
 7RT-Threadshellcommands:
 8finshToCLI-SwitchtoCLI:CLIcomponentofCore-V-MCU
 9pin-pin[option]
10clear-cleartheterminalscreen
11version-showRT-Threadversioninformation
12list-listobjects
13help-RT-Threadshellhelp.
14ps-Listthreadsinthesystem.
15free-Showthememoryusageinthesystem.
16msh>ps
17threadpristatusspstacksizemaxusedlefttickerror
18---------------------------------------------------------
19tshell20running0x000001600x0000100022%0x00000009OK
20tidle031ready0x000000f00x0000010098%0x1c05e62dOK
21timer4suspend0x000000e00x0000020043%0x00000008OK
22msh>

至此,移植RT-Thread至OPENHW开源的基于CV32E40P内核的CORE-V-MCU便移植完成。

CORE-V-MCU bsp

core-v-mcu的bsp已经合并至RT-Thread的主仓库,并配有详细的使用说明

小结

在为RISC-V移植RTOS时,笔者认为要具备RISC-V架构规范与编程规范的基本的了解,磨刀不误砍柴工嘛,虽然在写本文时洋洋洒洒写的很自在,但是在移植的过程中每遇到一个坑就会卡好久,不过也不要妄自菲薄,经过这么一个过程就好很多了,此时不禁让人感慨“两岸猿声啼不住,轻舟已过万重山”。

审核编辑 :李倩


声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 开源
    +关注

    关注

    3

    文章

    3231

    浏览量

    42346
  • RT-Thread
    +关注

    关注

    31

    文章

    1266

    浏览量

    39864
  • RISC-V
    +关注

    关注

    44

    文章

    2216

    浏览量

    45969

原文标题:OPENHW开源CORE-V-MCU移植RT-Thread

文章出处:【微信号:RTThread,微信公众号:RTThread物联网操作系统】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    OPENHW开源CORE-V-MCU移植RT-Thread

    本次实验验证的平台是PLCT提供的QEMU,在Linux下的QEMU可以使用上述的笔者编译好的,也可以使用自己尝试编译PLCT提供的源码。
    的头像 发表于 10-13 14:58 1143次阅读
    <b class='flag-5'>OPENHW</b><b class='flag-5'>开源</b><b class='flag-5'>CORE-V-MCU</b><b class='flag-5'>移植</b><b class='flag-5'>RT-Thread</b>

    i.MX RT1170:VGLite移植RT-Thread Nano过程讲解(上)

    RT-Thread 是国人自主研发的开源实时操作系统(RTOS),RT-Thread Nano 是极简版的硬实时内核,内存占用小,移植简单。VGLite 是 NXP 提供的轻量级 2D
    的头像 发表于 11-09 11:20 2489次阅读
    i.MX <b class='flag-5'>RT</b>1170:VGLite<b class='flag-5'>移植</b><b class='flag-5'>RT-Thread</b> Nano过程讲解(上)

    OPENHW开源CORE-V-MCU移植RT-Thread的流程

    %0x00000008 OKmsh >至此,移植RT-ThreadOPENHW开源的基于CV32E40P内核的CORE-V-MCU便
    发表于 02-09 14:32

    移植RT-Thread的原理与方法

    大家好我是惊觉。是的,失踪人口回来了。最近参加了rt-thread的国产MCU移植活动,移植rt-thread到华大的HC32L196。rt
    的头像 发表于 09-17 09:41 7684次阅读

    【国产MCU移植】HC32F460基于Keil MDK 移植 RT-Thread Nano

    【国产MCU移植】HC32F460基于Keil MDK 移植 RT-Thread Nano
    发表于 11-18 18:51 65次下载
    【国产<b class='flag-5'>MCU</b><b class='flag-5'>移植</b>】HC32F460基于Keil MDK <b class='flag-5'>移植</b> <b class='flag-5'>RT-Thread</b> Nano

    【国产MCU系列】在 HK32F030 上移植 RT-Thread Nano

    如需下载相关开源资料请点击阅读原文这是一个航顺 HK32F030 的 RT-Thread Nano 移植示例,记录了在 Keil 裸机工程的基础上进行 RT-Thread Nano
    发表于 11-21 18:51 42次下载
    【国产<b class='flag-5'>MCU</b>系列】在 HK32F030 上<b class='flag-5'>移植</b> <b class='flag-5'>RT-Thread</b> Nano

    【国产MCU移植移植RT-Thread到国产芯片HC32F460PETB

    【国产MCU移植移植RT-Thread到国产芯片HC32F460PETB
    发表于 11-23 18:06 37次下载
    【国产<b class='flag-5'>MCU</b><b class='flag-5'>移植</b>】<b class='flag-5'>移植</b><b class='flag-5'>RT-Thread</b>到国产芯片HC32F460PETB

    【国产MCU移植移植RT-Thread到国产芯片FM33LC026

    【国产MCU移植移植RT-Thread到国产芯片FM33LC026
    发表于 11-30 16:51 22次下载
    【国产<b class='flag-5'>MCU</b><b class='flag-5'>移植</b>】<b class='flag-5'>移植</b><b class='flag-5'>RT-Thread</b>到国产芯片FM33LC026

    RT-Thread移植到GD32F150系列MCU

    RT-Thread移植到GD32F150系列MCU
    发表于 12-07 19:36 7次下载
    <b class='flag-5'>RT-Thread</b><b class='flag-5'>移植</b>到GD32F150系列<b class='flag-5'>MCU</b>

    RT-Thread系统移植到STM32f103

    RT-Thread系统移植到STM32f103
    发表于 12-09 12:51 26次下载
    <b class='flag-5'>RT-Thread</b>系统<b class='flag-5'>移植</b>到STM32f103

    基于 Keil MDK 移植 RT-Thread Nano

    本文介绍如何基于 Keil MDK 移植 RT-Thread Nano ,并以一个 stm32f103 的基础工程作为示例进行讲解。 RT-Thread Nano 已集成在 Keil MD...
    发表于 01-26 17:04 16次下载
    基于 Keil MDK <b class='flag-5'>移植</b> <b class='flag-5'>RT-Thread</b> Nano

    RT-Thread操作系统的FreeRTOS兼容层

    项目。已经于2022年9月由唐照洲(美国佐治亚理工学院,大四)顺利结项完成。FreeRTOS兼容层目前已经落地到RT-Thread对ESP32-IDF(唐照洲)和core-v-mcu(王顺)两款SDK
    的头像 发表于 01-14 00:55 1583次阅读

    RT-Thread文档_内核移植

    RT-Thread文档_内核移植
    发表于 02-22 18:31 3次下载
    <b class='flag-5'>RT-Thread</b>文档_内核<b class='flag-5'>移植</b>

    RT-Thread文档_RT-Thread SMP 介绍与移植

    RT-Thread文档_RT-Thread SMP 介绍与移植
    发表于 02-22 18:31 9次下载
    <b class='flag-5'>RT-Thread</b>文档_<b class='flag-5'>RT-Thread</b> SMP 介绍与<b class='flag-5'>移植</b>

    机智云设备移植RT-Thread

    开发环境:Keil版本:V5.30RT-Thread版本:3.1.5STM32cubeMX:V6.0.1开发板MCU:STM32F103机智云平台生成的应用代码是裸机版本的,而在实际应用过
    的头像 发表于 04-19 18:39 943次阅读
    机智云设备<b class='flag-5'>移植</b><b class='flag-5'>RT-Thread</b>