## 描述
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联系作者,谢谢!!期待您的参与!!!
离线
感谢分享,如果晕哥可以把makedown支持下发帖就方便了
离线
补充一下内容:-DportasmHANDLE_INTERRUPT=vApplicationHandleTrap还需要定义这个portasmHANDLE_INTERRUPT宏为vApplicationHandleTrap
离线
楼主大哥优秀,有移植好的代码包吗?
离线
FreeRTOS和SiFive有提供现成的移植范例,在哪里忘了,反正我之前就稀里糊涂的跑起来了,挺easy的
离线
楼主大哥优秀,有移植好的代码包吗?
需要做的都在帖子里了哦,移植跟平台关联性很大,所以还是要自己做下适配的哦
离线
楼主大哥优秀,有移植好的代码包吗?
离线
流氓兔 说:楼主大哥优秀,有移植好的代码包吗?
虚拟机也顺便发布了,传送门:https://whycan.com/t_5844.html#p58010
最近编辑记录 xiaohui (2021-01-11 17:57:32)
离线
20210306更新:https://whycan.com/t_5844.html#p60439
离线
离线
xiaohui -
i'm trying to get a bare-metal port of newest FreeRTOS working. I have a bootloader that will load my code, i've got everything compiling and console output BEFORE vTaskStartScheduler(), console output from the beginning of the first task (only task besides idle).
all programming/compiling on Windows with the C-Sky Development Suite.
my problem is that my tick interrupt isn't working. i haven't been able to figure the 32 physical address for the MTIME and MTIMECMP
#define configMTIME_BASE_ADDRESS ( ? )
#define configMTIMECMP_BASE_ADDRESS ( ? )
i've read through D1/F133 manuals and C906 manual and can't quite get the proper address. i think i've got to use the CLINT base + some offsets.
any guidance or suggestions would be very much appreciated.
-Ed
离线
solution found. much searching and R&D.
#define configMTIMECMP_BASE_ADDRESS ( 0x14004000ul )
this is the base address and for a multicore you would have to offset by 8 * HART.
there is NO MTIME memory-map IO (MMIO). you must use the csr time register. for D1/F133 it will read out a 64 bit value. however the CLINT's MMIO is NOT 64 bit friendly. you cannot read a 64 bit value atomically. you must read two 32 bit values and concatenate in firmware.
all of the above require (IMHO) a unique port.c and portASM.s and i have made the necessary changes. all ticks and scheduler interrupts working now.
when a little more ready for prime time i will publish my results, including the bare-metal SPL if people are interested.
-Ed
离线
离线