PolarFire® SoC FreeRTOS RISC-V 'systick' 定时器 mtime
PolarFire® SoC 尝试移植 FreeRTOS - 所长 - 博客园
PolarFire SoC MSS Technical Reference Manual

mtime是一个64位读写寄存器,用于对rtc_toggle信号的周期进行计数。当mtime的值大于或等于mtimecmp寄存器中的值时,将产生待处理的定时器中断。该定时器中断会反映在《机器中断待处理寄存器(mip)》所述的mip寄存器mtip位中。复位时,mtime被清零,但mtimecmp寄存器保持原值不变。
mtime寄存器每1微秒(1MHz)递增一次,这与RTC时钟的输入频率保持一致。关于rtc_toggle信号的具体应用,请参阅GitHub页面driver-examples/mss/mss-rtc目录下的示例项目。
看这意思, mtime 的增长 是 根据 RTC 输入时钟确定的? PolarFire SoC MSS Configurator User Guide
RTC/MAC SGMII reference clock input source ,, You can select the NW PLL ports or I/Os from Bank 5.
Bank 5 可是 125Mhz; 编写 以下代码, 将 RTC 时钟源 改为 1Mhz; 这样 mtime 时钟源 也固定了!
/mpfs-mmuart-interrupt/src/boards/icicle-kit/fpga_design_config/clocks/hw_mss_clks.h
#define LIBERO_SETTING_MSS_EXT_SGMII_REF_CLK 125000000
#define LIBERO_SETTING_MSS_RTC_TOGGLE_CLK 1000000
SYSREG->RTC_CLOCK_CR &= ~BIT_SET;
SYSREG->RTC_CLOCK_CR = LIBERO_SETTING_MSS_EXT_SGMII_REF_CLK / LIBERO_SETTING_MSS_RTC_TOGGLE_CLK;
SYSREG->RTC_CLOCK_CR |= BIT_SET;

寄存器地址;

FreeRTOSConfig.h 配置文件中 mtime 地址配置
#define configMTIME_BASE_ADDRESS ( CLINT_CTRL_ADDR + 0xBFF8UL )
#define configMTIMECMP_BASE_ADDRESS ( CLINT_CTRL_ADDR + 0x4000UL )
mtime 如何使用,怎么产生中断的?
咨询 deepseek
RISC-V 架构通过 mtime 和 mtimecmp 寄存器来实现定时器功能,下面是详细的使用方法:
RISC-V 定时器架构
核心寄存器:
-
mtime- 机器模式时间计数器(64位,只读) -
mtimecmp- 机器模式时间比较寄存器(64位,读写) -
mtime不断递增,当mtime>=mtimecmp时产生定时器中断
MTIME 中断号在 polarfire soc 中 是 7, 下面表格:

代码编写 产生 MTIME 中断,以 FreeRTOS 为例子:
1、FreeRTOSConfig.h 文件中
#define configMTIME_BASE_ADDRESS ( CLINT_CTRL_ADDR + 0xBFF8UL )
#define configMTIMECMP_BASE_ADDRESS ( CLINT_CTRL_ADDR + 0x4000UL )
2、FreeRTOS port.c 文件中
UBaseType_t const ullMachineTimerCompareRegisterBase = configMTIMECMP_BASE_ADDRESS;
这个函数里 ,会自动 读取 当前 hart id , 根据 hart id 自动 计算 mtimecmp 寄存器的 地址, 好高级!!!
void vPortSetupTimerInterrupt( void ) { uint32_t ulCurrentTimeHigh, ulCurrentTimeLow; volatile uint32_t * const pulTimeHigh = ( volatile uint32_t * const ) ( ( configMTIME_BASE_ADDRESS ) + 4UL ); /* 8-byte type 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; }
3、 使能 MTIME 的 中断
/* If there is a CLINT then it is ok to use the default implementation * in this file, otherwise vPortSetupTimerInterrupt() must be implemented to * configure whichever clock is to be used to generate the tick interrupt. */ vPortSetupTimerInterrupt(); #if ( ( configMTIME_BASE_ADDRESS != 0 ) && ( configMTIMECMP_BASE_ADDRESS != 0 ) ) { /* Enable mtime and external interrupts. 1<<7 for timer interrupt, * 1<<11 for external interrupt. _RB_ What happens here when mtime is * not present as with pulpino? */ __asm volatile ( "csrs mie, %0" ::"r" ( 0x880 ) ); } #endif /* ( configMTIME_BASE_ADDRESS != 0 ) && ( configMTIMECMP_BASE_ADDRESS != 0 ) */

汇编指令 :
__asm volatile ( "csrs mie, %0" ::"r" ( 0x880 ) );
使用的汇编指令是 csrs (Control and Status Register set),它的作用是:读取 mie 寄存器的当前值,或(OR) 上操作数 %0(即 0x880)的值,然后将结果写回 mie 寄存器。
这样 是开启 M 状态下总中断 , 以及 mtime 的中断 , 而且 还不影响 其他 中断;
deepseek 真他妈好用!
在 RISC-V 中,控制和状态寄存器(CSR)的写入操作有以下几种类型,用于避免常见的“读-修改-写”竞态条件:
-
csrs(CSR Set):-
功能: 将 CSR 中指定的比特位置 1。
-
操作:
t = CSRs[csr]; t = t | x; CSRs[csr] = t -
您的代码:
csrs mie, %0等价于mie = mie | 0x880; -
效果: 只会开启
0x880所对应的中断位,而其他所有位(例如MEIE,MTIE,MSIE等)保持原来的状态不变。这是一种安全的设置方式。
-
-
csrc(CSR Clear):-
功能: 将 CSR 中指定的比特位置 0。
-
操作:
t = CSRs[csr]; t = t & ~x; CSRs[csr] = t -
例如:
csrc mie, %0会关闭0x880对应的中断位。
-
-
csrw(CSR Write):-
功能: 直接将值写入 CSR。
-
操作:
CSRs[csr] = x -
如果您这样写:
__asm volatile ( "csrw mie, %0" ::"r" ( 0x880 ) ); -
效果: 这会用
0x880直接覆盖整个mie寄存器的值。所有其他之前被设置的位(比如机器定时器中断MTIE)都会被清零,这很可能导致系统异常或中断丢失。这是一种危险的操作,除非你确知要清除所有其他位。
-
关于 0x880:
这个值是两个中断使能位的掩码组合:
-
0x800(第 11 位):机器外部中断使能 (MEIE) -
0x080(第 7 位):机器定时器中断使能 (MTIE)
所以,您的这行代码的目的是同时启用机器模式下的定时器中断和外部中断。
浙公网安备 33010602011771号