循序渐进,学习开发一个RISC-V 上的操作系统

  • Post author:
  • Post category:其他


第 12 章 硬件定时器

RISC-V 定时器中断

RISC-V CLINT 介绍

软件中断和定时器中断都由芯片自带的设备CLINT控制触发。

CLINT编程接口-寄存器

mtimecmp需要手动设置初始值,上述代码初始化时,调用time_load()函数,并传入时间间隔参数TIMER_INTERVAL 来设置mtimecmp的初值。

当mtime >= mtimecmp时,CLINT会产生一个timer中断。如果要使能该中断需要保证全局中断打开mstatus.mIE = 1并且mie.MTIE标志位置1

当timer中断发生时,hart会设置mip.MTIP,程序可以在mtimecmp中写入新的值,清除mip.MTIP

当cause最高位为1且casue_code为7时,说明当前触发了定时器中断,调用timer_handler,首先hart自动进行设置,然后调用timer_load()函数,让mtimecmp += TIMER_INTERVAL 即再过TIMER_INTERVAL时间间隔会再次触发定时器中断,

实现了周期性定时器

CLINT总体框架流程:

硬件定时器的应用

时间管理

实现操作系统的时间管理。

时钟节拍(Tick)

  • 操作系统中最小的时间单位。
  • Tick 的单位(周期)由硬件定时器的周期决定 (通常为 1 ~ 100ms)。
  • Tick 周期越小,系统的精度越高,但开销越大。

系统时钟

  • 操作系统维护的一个整型计数值,记录着系统启动直到当前发生的 Tick 总数。
  • 可用于维护系统的墙上时间,所以也称为系统时钟。

代码运行

1、先手动设置对应hart下的MTIMECMP

2、分别打开machine模式下的定时器中断使能和全局中断使能

3、发生定时器中断时,进入timer_handler处理函数,打印当前tick值,并更新MTIMECMP,实现周期定时器。

/* load timer interval(in ticks) for next timer interrupt.*/
void timer_load(int interval)
{
	/* each CPU has a separate source of timer interrupts. */
	int id = r_mhartid();
	
	*(uint64_t*)CLINT_MTIMECMP(id) = *(uint64_t*)CLINT_MTIME + interval;
}

void timer_init()
{
	/*
	 * On reset, mtime is cleared to zero, but the mtimecmp registers 
	 * are not reset. So we have to init the mtimecmp manually.
	 */
	timer_load(TIMER_INTERVAL);

	/* enable machine-mode timer interrupts. */
	w_mie(r_mie() | MIE_MTIE);

	/* enable machine-mode global interrupts. */
	w_mstatus(r_mstatus() | MSTATUS_MIE);
}

void timer_handler() 
{
	_tick++;
	printf("%d\n", _tick);
	timer_load(TIMER_INTERVAL);
}

运行效果如下:



版权声明:本文为Lbrooon原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。