108 lines
2.7 KiB
C
108 lines
2.7 KiB
C
/*
|
||
* 模块名称:System Timer
|
||
* 模块功能:DWT CYCCNT 实现 64-bit 微秒级时间戳
|
||
* 在 SysTick 中断中检测 CYCCNT 溢出以扩展至 64-bit
|
||
* 适用平台:STM32F407ZGTx (168MHz)
|
||
* 作者:王建锋
|
||
* 创建日期:2026-07-19
|
||
*
|
||
* 限定条件:
|
||
* - CPU 主频 168MHz(若更改须同步 SYS_TIME_CYCLE_PER_US 宏)
|
||
* - 须在 FreeRTOS 启动前调用 sys_time_init()
|
||
* - sys_time_systick_hook() 须在 SysTick 中断中调用
|
||
*
|
||
* 修改记录:
|
||
* v1.0 2026-07-19 王建锋 创建初始版本
|
||
*/
|
||
|
||
#include "sys_time.h"
|
||
#include "app_cfg.h"
|
||
#include "stm32f4xx.h"
|
||
|
||
/*
|
||
* 每微秒 CPU 周期数(168MHz → 168 cycles/µs)
|
||
*/
|
||
#define SYS_TIME_CYCLE_PER_US 168UL
|
||
|
||
/*
|
||
* CYCCNT 每溢出一次代表的微秒数(2^32 / 168 ≈ 25,564,904 µs ≈ 25.56s)
|
||
*/
|
||
#define SYS_TIME_OVERFLOW_US (uint64_t)(((uint64_t)1 << 32) / SYS_TIME_CYCLE_PER_US)
|
||
|
||
static volatile uint32_t s_overflow_cnt;
|
||
|
||
/*
|
||
* 函数功能:初始化 DWT CYCCNT
|
||
* 入口参数:无
|
||
* 返 回 值:0 - 成功
|
||
* 限定条件:须在 FreeRTOS 启动前调用
|
||
* 函数说明:启用 DWT 和 CYCCNT 计数器,计数器从 0 开始
|
||
*/
|
||
int sys_time_init(void)
|
||
{
|
||
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
|
||
DWT->CYCCNT = 0;
|
||
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
|
||
|
||
s_overflow_cnt = 0;
|
||
|
||
return 0;
|
||
}
|
||
|
||
/*
|
||
* 函数功能:获取微秒级时间戳
|
||
* 入口参数:无
|
||
* 返 回 值:64 位微秒时间戳
|
||
* 函数说明:由当前 CYCCNT 值与溢出计数合成 64-bit 周期数再转换
|
||
*/
|
||
uint64_t sys_time_us(void)
|
||
{
|
||
uint32_t cyccnt = 0;
|
||
uint64_t ticks = 0;
|
||
uint32_t ov = 0;
|
||
uint32_t ov2 = 0;
|
||
|
||
/*
|
||
* 原子读取溢出计数与 CYCCNT,处理潜在的读取竞争
|
||
* 若两次读取溢出计数不一致则重读 CYCCNT
|
||
*/
|
||
do {
|
||
ov = s_overflow_cnt;
|
||
cyccnt = DWT->CYCCNT;
|
||
ov2 = s_overflow_cnt;
|
||
} while (ov != ov2);
|
||
|
||
ticks = ((uint64_t)ov << 32) | cyccnt;
|
||
return ticks / SYS_TIME_CYCLE_PER_US;
|
||
}
|
||
|
||
/*
|
||
* 函数功能:获取毫秒级时间戳
|
||
* 入口参数:无
|
||
* 返 回 值:64 位毫秒时间戳
|
||
* 限定条件:sys_time_init() 已成功调用
|
||
* 函数说明:通过对 sys_time_us() 取整实现
|
||
*/
|
||
uint64_t sys_time_ms(void)
|
||
{
|
||
return sys_time_us() / 1000;
|
||
}
|
||
|
||
/*
|
||
* 函数功能:SysTick 中断钩子,检测 CYCCNT 溢出
|
||
* 入口参数:无
|
||
* 返 回 值:无
|
||
* 函数说明:必须在 SysTick_Handler() 中调用
|
||
* 每 1ms 检查一次 CYCCNT 是否已回绕
|
||
*/
|
||
void sys_time_systick_hook(void)
|
||
{
|
||
static uint32_t s_last_cyccnt = 0;
|
||
uint32_t cyccnt = DWT->CYCCNT;
|
||
|
||
if (cyccnt < s_last_cyccnt) {
|
||
s_overflow_cnt++;
|
||
}
|
||
s_last_cyccnt = cyccnt;
|
||
}
|