[RISCV]为RISC-V移植FreeRTOS系列之三 -- 时基

本文介绍了在RISC-V架构上移植FreeRTOS时,时基初始化的重要性和流程,主要涉及mtime及mtimecmp寄存器的配置,并详细解析了初始化函数vPortSetupTimerInterrupt()的实现。通过对这两个寄存器的设置,确保了FreeRTOS在RISC-V上的正常运行。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

书接上回,上回说到我们已经做好了准备,所谓万事具备,就差一场东风,而能吹动FreeRTOS这条大船的是什么呢?没错,聪明的你已经猜到了,是时基。

有过其他MCU移植经验的小伙伴应该知道,时基是操作系统的心跳,所有的操作,包括任务切换,抢占等等都是基于时基,在STM32中,我们一般用systick(滴答计时器)作为时基,而在riscv中,我们用mechine timer(以下简称mtime)作为时基。


作者:wangyijieonline
链接:https://blog.youkuaiyun.com/wangyijieonline/article/details/109721689
来源:优快云
著作权归作者所有。商业转载请联系作者获得授权,非商业转载必须注明出处。


本文部分参考官方Guide:Using FreeRTOS on RISC-V Microcontrollers
在其中有这么一段:

In summary, to build FreeRTOS for a RISC-V core you need to:
1, Include the core FreeRTOS source files and the FreeRTOS RISC-V port layer source files in your project.
2, Ensure the assembler’s include path includes the path to the header file that describes any chip specific implementation details.
3, Define either a constant in FreeRTOSConfig.h or a linker variable to specify the memory to use as the interrupt stack.
4, Define configMTIME_BASE_ADDRESS and configMTIMECMP_BASE_ADDRESS in FreeRTOSConfig.h.
5, For the assembler, #define portasmHANDLE_INTERRUPT to the name of the function provided by your chip or tools vendor for handling external interrupts.
6, Install the FreeRTOS trap handler.

翻译一下:

要为 RISC-V 内核构建 FreeRTOS,您需要:
1、在项目中包括核心 FreeRTOS 源文件和 FreeRTOS RISC-V 端口层源文件。
2、确保汇编器的包含路径包括描述任何芯片特定实现详细信息的标头文件的路径。
3、定义 FreeRTOSConfig.h 中的常量或链接器变量以指定要用作中断堆栈的内存。
4、在 freeRTOScong.h configMTIME_BASE_ADDRESS定义configMTIMECMP_BASE_ADDRESS和定义。
5、对于汇编#define portasmHANDLE_INTERRUPT,请使用芯片或工具供应商为处理外部中断而提供的功能的名称。
6、安装 FreeRTOS 陷阱处理程序。

可以看到,在第4条,特意提到了两个defination configMTIME_BASE_ADDRESSconfigMTIMECMP_BASE_ADDRESS,在之前,我们在FreeRTOSconfig.h中定义过如下的define,这就是我们这一节要展开讲的。
在这里插入图片描述

mtime的初始化

在使用时基之前要先定义,而这个初始化应该是在FreeRTOS的任务调度之前完成,而实际,这件事做的确实很晚,是在vTaskStartScheduler();函数里执行的,具体的调用路径:

vTaskStartScheduler();		//./FreeRTOS/Source/task.c
	|	xPortStartScheduler();		//./FreeRTOS/Source/portable/GCC/RISC-V/port.c
			|	vPortSetupTimerInterrupt();		//./FreeRTOS/Source/portable/GCC/RISC-V/port.c

#if( configMTIME_BASE_ADDRESS != 0 ) && ( configMTIMECMP_BASE_ADDRESS != 0 )

	void vPortSetupTimerInterrupt( void )
	{
	uint32_t ulCurrentTimeHigh, ulCurrentTimeLow;
	volatile uint32_t * const pulTimeHigh = ( volatile uint32_t * const ) ( ( configMTIME_BASE_ADDRESS ) + 4UL ); /* 8-byte typer so high 32-bit word is 4 bytes up. */
	volatile uint32_t * const pulTimeLow = ( volatile uint32_t * const ) ( configMTIME_BASE_ADDRESS );
	volatile uint32_t ulHartId;

		__asm volatile( "csrr %0, mhartid" : "=r"( ulHartId ) );
		pullMachineTimerCompareRegister  = ( volatile uint64_t * ) ( ullMachineTimerCompareRegisterBase + ( ulHartId * sizeof( uint64_t ) ) );

		do
		{
			ulCurrentTimeHigh = *pulTimeHigh;
			ulCurrentTimeLow = *pulTimeLow;
		} while( ulCurrentTimeHigh != *pulTimeHigh );

		ullNextTime = ( uint64_t ) ulCurrentTimeHigh;
		ullNextTime <<= 32ULL; /* High 4-byte word is 32-bits up. */
		ullNextTime |= ( uint64_t ) ulCurrentTimeLow;
		ullNextTime += ( uint64_t ) uxTimerIncrementsForOneTick;
		*pullMachineTimerCompareRegister = ullNextTime;

		/* Prepare the time to use after the next tick interrupt. */
		ullNextTime += ( uint64_t ) uxTimerIncrementsForOneTick;
	}

#endif /* ( configMTIME_BASE_ADDRESS != 0 ) && ( configMTIME_BASE_ADDRESS != 0 ) */

mtime是包在riscv的ISA里的,只要确定好两个寄存器地址,一个MTIME_BASE_ADDRESS,一个MTIMECMP_BASE_ADDRESS,那基本就没啥问题了。
下面附上mtime的reg mem map(一共就俩64位寄存器。。。):
在这里插入图片描述
在这里插入图片描述

总结

当时基跑起来以后,其他的就无关MCU架构了,又成了一种上层软件的东西,我们的目的,机制与策略分离,再一次完美地实现。

好的,打完收工,下回说说上面的第5和第6条。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

山猫Show

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值