给risc-v标准内核适配freertos-kernel

描述

PS:自从freertos被亚马逊收购后添加了大量的云服务的支持,所以下面称呼为freertos-kernel.特指项目地址:https://github.com/FreeRTOS/FreeRTOS-Kernel

说点肺话

为什么不叫移植freertos-kernel呢?因为从下面freertos-kernel的发布历史可以看到,freertos内核从FreeRTOS V10.1.1 and FreeRTOS V10.2.0开始就支持risc-v了,但是这个版本对于64bit的risc-v的支持好像还有点小问题。一直到FreeRTOS V10.2.1 and FreeRTOS V10.2.0 的发布支持了32位和64位的risc-v。如果要使用建议从这个版本开始进行适配工作。

Changes between FreeRTOS V10.2.1 and FreeRTOS V10.2.0 released May 13
2019:

  • Added ARM Cortex-M23 port layer to complement the pre-existing ARM
    Cortex-M33 port layer. + The RISC-V port now automatically
    switches between 32-bit and 64-bit cores.

Changes between FreeRTOS V10.2.1 and FreeRTOS V10.2.0 released May 13
2019:

  • The RISC-V port now automatically switches between 32-bit and 64-bit cores.

Changes between FreeRTOS V10.1.1 and FreeRTOS V10.2.0 released
February 25 2019:

  • Added GCC RISC-V MCU port with three separate demo applications.

做下准备

下面我们整理下适配一个比较规范的risc-v内核需要进行哪些工作和需要risc-v内核支持哪些外设才可以让freertos-kernel正常运行.

我们都知道,最简单的rtos运行只需要一个时钟为他提供一个基准时钟用于任务时间分片的计算,触发上下文切换和任务间通信的超时等操作。在freertos里还需要一片空间用户存放任务的栈。
在freertos适配risc-v的时候我们通常还会使用risc-v里的机器时钟mtime,他是一个只有计时用途的简易计数器,可以为freertos提供一个基准时钟。也可以使用一个硬件定时器代替。
freertos默认还会使用ecall指令,用于出让cpu控制权。通过修改也可以使用其他指令(如果是自己设计的核,你用着开心就好)。

应该准备好了,开始

好了,到现在我们已经准备好了freertos需要的运行条件。

  1. 设置栈顶
    我们需要指定__freertos_irq_stack_top这个符号,告诉freertos任务的栈需要存放到哪里。

  2. 设置mtime寄存器信息
    在FreeRTOSConfig.h文件里设置mtime寄存器信息

    #define configMTIME_BASE_ADDRESS 	( pdev_mtime_mtime_addr )
    #define configMTIMECMP_BASE_ADDRESS( pdev_mtime_mtimecmp_addr )
    
  3. 确认HOOK配置

    #define configUSE_IDLE_HOOK				0
    #define configUSE_TICK_HOOK				1
    
  4. 设置cpu频率和Tick中断的频率

    #define configCPU_CLOCK_HZ				( 1000 )
    #define configTICK_RATE_HZ				( ( TickType_t ) 1 )
    
  5. 设置最小栈大小限制和堆的总大小

    #define configMINIMAL_STACK_SIZE		( ( unsigned short ) 105 )
    #define configTOTAL_HEAP_SIZE			( ( size_t ) 14500 )
    
  6. 设置任务名称最大的长度(如无特殊,保持默认即可)

    #define configMAX_TASK_NAME_LEN			( 16 )
    
  7. 通过宏定义 __riscv_xlen 指定指令长度
    如果是64bit的risc-v平台可以参考下面编译参数

    CFLAGS      += -D__riscv_xlen=64 -D__riscv64
    

    如果是32bit的risc-v平台可以参考下面编译参数

    CFLAGS      += -D__riscv_xlen=32
    
  8. 第7点声明的__riscv64宏定义主要作用

    #ifdef __riscv64
    	#define portBYTE_ALIGNMENT			8
    #else
    	#define portBYTE_ALIGNMENT			16
    #endif
    

    从上面的代码可以看出主要是用于设置字节对齐大小

到这里freertos的基本设置已经完成!!下面需要编写平台初始化的代码,然后初始化freertos,创建任务,调用调度函数即可。

平台初始化

下面附上简单的平台初始化代码
start.S

    #include "rv_mtvec_map.h"
    .macro init;
    .endm
    .section .init;
    .option norvc
    .option nopic
    .align  6;
    .weak reset_vector;
    .globl _start;
    .type _start,@function
    
_start:
    la sp, __stack_end                                    
    /* reset vector */
    addi s2, x0, 'a';
    li  t1, pdev_uart0_write_addr;
    sb s2,0(t1);

    addi s2, x0, 'b';
    li  t1, pdev_uart0_write_addr;
    sb s2,0(t1);

    addi s2, x0, '\n';
    li  t1, pdev_uart0_write_addr;
    sb s2,0(t1);
    
    j reset_vector
    .align  4;                                             
reset_vector:
    addi s2, x0, 'r';
    li  t1, pdev_uart0_write_addr;
    sb s2,0(t1);

    addi s2, x0, '\n';
    li  t1, pdev_uart0_write_addr;
    sb s2,0(t1);
    
    la a0,e_vertor;

2:
	/* Clear bss section */
	la a0, __bss_start;
	la a1, __bss_end;
	bgeu a0, a1, 2f;
1:
	# sw zero, (a0);
	addi a0, a0, 4;
	bltu a0, a1, 1b;
2:

    call main;
    unimp

main.c

void main(void){
    // *(uint64_t *)(pdev_mtime_mtimecmp_addr+1) = 300;
    uint64_t i;
    puts("main\n");
    extern void main_blinky( void );
    main_blinky();
    puts("main_blinky\n");
    while(1){
        i = 1000;
        while(i--);
        puts("wait for cb\n");
    }
}

freertos的适配到此为止,感谢观看!!发现有疑问或者错误的地方欢迎发邮件到juicemail@163.com联系作者,谢谢!!期待您的参与!!!


版权声明:本文为xunxiaohui原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
THE END
< <上一篇
下一篇>>