第 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 版权协议,转载请附上原文出处链接和本声明。