- 前言
笔者最近需要封装一些时间戳相关的API,对于RISC-V架构的CPU定时器相关配置方式基本忘光光了,所以简单复习了一下相关内容。需要深入了解的话可以阅读RISC-V架构手册的卷二第三章。
因为蜂鸟e203MCU仅支持RISC-V架构的机器模式(Machine Mode),本文仅讨论机器模式下的CPU定时器管理。
2.RISC-V架构的CPU 定时器
首先看CPU定时器中断的开启与关闭。
对于机器模式下全局中断的开关,可以通过mstatus寄存器的MIE字段进行控制。
MIE字段对应机器模式下的全局中断开关控制,SIE字段对应的是监督模式下的全局中断开关控制。
RSIC-V架构将中断分为外部中断,定时器中断,软件中断和调试中断四种类型。机器模式下,每种类型的中断发生的时候mcause寄存器会填入对应类型中断的编号,其编号值为:
相应的,每种类型的中断其开关控制可以在CSR寄存器MIE中进行配置。
MIE寄存器的字段格式为:
相关字段可以解释为:
字段 | 功能 |
MEIE | 机器模式下外部中断的中断使能控制 |
MTIE | 机器模式下定时器中断的中断使能控制 |
MSIE | 机器模式下软件中断的中断使能控制 |
如果我们要开启定时器中断,需要保证MTIE字段的置位。
然后看CPU定时器的配置。
机器模式下,CPU定时器的具体配置主要依靠两个内存地址映射的寄存器mtime和mtimecmp来进行。作为非CSR寄存器,其内容的读写通过地址访问进行,不同硬件系统的设计可能将这两个寄存器映射到完全不同的物理地址,但是其功能应保持一致。
mtime寄存器以恒定的频率进行计数增长,一旦大于等于mtimecmp寄存器中的值,即产生一个定时器中断。
3.蜂鸟E203MCU的相关软件实现
第二节提到的各种硬件设计,在E203的SDK中作为NMSIS的一部分被实现,其内容可以总结为:
编号 | 功能 | 文件 |
1 | 定时器使能控制 | hbird-sdk/NMSIS/Core/Include/core_feature_base.h |
2 | 定时器触发频率控制 | hbird-sdk/NMSIS/Core/Include/core_feature_timer.h |
首先看定时器的使能控制,对于全局使能控制,相关API可以归纳为:
编号 | API | 功能 |
1 | __enable_irq | 使能全局中断 |
2 | __disable_irq | 关闭全局中断 |
其实现方式第二节已经讨论过了,就是配置mstatus寄存器的MIE字段,比如:
配置定时器中断的使能状态,相关API可以归纳为:
编号 | API | 功能 |
1 | __enable_timer_irq | 使能定时器中断 |
2 | __disable_timer_irq | 关闭定时器中断 |
实现方式就是配置MIE寄存器的MTIE字段,比如:
然后我们看触发频率的配置。
core_feature_timer.h头文件中定义了mtime和mtimecmp寄存器的物理地址,并用一个结构体指针直接指向物理地址用于API实现中的字段配置:
相关API可以归纳为:
编号 | API | 功能 |
1 | SysTimer_GetLoadValue | 获取mtime寄存器值 |
2 | SysTimer_SetLoadValue | 配置mtime寄存器值 |
3 | SysTimer_GetCompareValue | 获取mtimecmp寄存器值 |
4 | SysTimer_SetCompareValue | 配置mtimecmp寄存器值 |
配置方式是直接使用前面定义的结构体指针SysTimer,比如:
4.蜂鸟e203的mtime增长频率是多少?
SDK中的delay_1ms函数的实现可以回答这个问题。该函数定义在hbird-sdk/SoC/hbirdv2/Common/Source/hbirdv2_common.c中。
其实现为:
可以看到SOC_TIMER_FREQ就是我们要找的数值,其定义为:
所以,答案是32768。
5.定时器Demo
下面以SDK中的demo_timer程序说明定时器的软件使用方式。
首先,注册中断handler并使能中断。
然后初始化mtime和mtimecmp的数值:
按照截图中的配置,半秒后会触发第一次定时器中断。
接下来定义好定时器中断handler函数:
可以看到,这里仅仅打印一下触发信息,然后继续配置下一次的触发时间,在半秒之后。
6.总结
蜂鸟e203MCU作为一款面向教学的开源MCU,其软硬件设计都非常容易理解,因此造就了很高得可玩性。同时,因为软硬件同时开源的特性,对于帮助开发者加深软硬件协同的理解或者说计算机底层机制的实现原理很有帮助。其定时器的设计与实现正是这一点的具体体现。