Files
STM32F4-Base/App/sys_time.c
2026-07-19 15:27:49 +08:00

108 lines
2.7 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* 模块名称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;
}