如何使用RISC-V定时器生成精确频率中断
RISC-V mtimer精确固定频率中断解决方案
问题根源
你当前的实现错误是直接修改mtime寄存器:绝大多数RISC-V硬件实现中,mtime是由硬件自动递增的只读计数器,软件写入操作本身就不符合RISC-V规范,即使部分实现允许写入,从中断触发到执行mtime -= 50000的间隔会导致mtime被修改为偏小的值,最终引入固定的计时偏差,这是你中断频率偏低的核心原因。
原生RISC-V mtimer完全可以实现无偏差的精确固定频率中断,不需要额外硬件支持,按如下方案修改即可:
正确实现步骤
- 预设计数步长:根据你的50MHz时钟、1ms中断间隔的需求,定义固定步长
#define MTIMER_STEP 50000
- 初始化阶段:读取当前
mtime的值,设置初始的mtimecmp,开启机器模式定时器中断即可
mtimecmp = mtime + MTIMER_STEP;
- 中断处理函数内仅更新
mtimecmp寄存器,不要触碰mtime:
mtimecmp += MTIMER_STEP;
精度保证原理
mtime是硬件持续自主计数的,每次中断触发的条件是mtime >= mtimecmp,你每次给mtimecmp累加固定步长,本质是基于上一次触发中断的理论阈值向上叠加,不管中断响应延迟、寄存器更新操作消耗了多少个时钟周期,下一次中断的触发阈值永远是上一次理论触发点+固定步长,不存在累加偏差,最终的平均中断频率完全精确等于目标值。
注意事项
- 如果你的中断处理总耗时超过1ms,会出现中断合并的情况(即一次中断处理还没做完,下一次中断触发条件已经满足),此时不会丢失计数,只是两次中断会合并为一次触发,平均频率仍然准确,只要保证中断处理耗时小于步长对应的时间即可实现严格的1ms间隔触发。
- 32位RISC-V平台操作64位的
mtime、mtimecmp寄存器时,需要做原子操作保护:读mtime时需重复读取高32位直到两次读取值一致,再搭配低32位获取完整值;写mtimecmp时先写高32位为0xFFFFFFFF,再写低32位,最后写入正确的高32位,避免中途触发意外中断。
内容的提问来源于stack exchange,提问作者dsula
相关产品推荐
相关产品推荐

