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

前言

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

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


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


本文部分参考官方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位寄存器。。。):
[RISCV]为RISC-V移植FreeRTOS系列之三 -- 时基_第1张图片
[RISCV]为RISC-V移植FreeRTOS系列之三 -- 时基_第2张图片

总结

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

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

你可能感兴趣的:(RISCV,risc-v,freertos)