2026-05-10 17:28:14 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* @file systick.cpp
|
|
|
|
|
|
* @brief SysTick 时基模块实现。
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#include "main.h"
|
|
|
|
|
|
#include "sys/systick.h"
|
|
|
|
|
|
|
|
|
|
|
|
volatile uint32_t SysTickTimer::s_ms = 0U;
|
|
|
|
|
|
|
2026-05-10 21:27:51 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* @brief SysTick 中断处理入口。
|
|
|
|
|
|
* @param[in] 无。
|
|
|
|
|
|
* @param[out] 无。
|
|
|
|
|
|
* @retval 无返回值。
|
|
|
|
|
|
* @note 每次 SysTick 中断到来时,将毫秒计数器自增 1。
|
|
|
|
|
|
*/
|
2026-05-10 17:28:14 +08:00
|
|
|
|
void SysTickTimer::onInterrupt()
|
|
|
|
|
|
{
|
|
|
|
|
|
s_ms++;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-10 21:27:51 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* @brief 执行毫秒级阻塞延时。
|
|
|
|
|
|
* @param[in] ms 需要延时的毫秒数。
|
|
|
|
|
|
* @param[out] 无。
|
|
|
|
|
|
* @retval 无返回值。
|
|
|
|
|
|
* @note 基于 SysTick 维护的毫秒计数器忙等,适用于短时初始化等待。
|
|
|
|
|
|
*/
|
2026-05-10 17:28:14 +08:00
|
|
|
|
void SysTickTimer::delayMs(uint32_t ms)
|
|
|
|
|
|
{
|
|
|
|
|
|
uint32_t start = s_ms;
|
|
|
|
|
|
while((s_ms - start) < ms) { }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-10 21:27:51 +08:00
|
|
|
|
/**
|
2026-09-02 02:38:35 +08:00
|
|
|
|
* @brief SysTick 失效时的致命停机:裸寄存器 USART0(PA9) 输出 FATAL 后挂死。
|
2026-05-10 21:27:51 +08:00
|
|
|
|
* @param[in] 无。
|
|
|
|
|
|
* @param[out] 无。
|
2026-09-02 02:38:35 +08:00
|
|
|
|
* @retval 无返回值(不返回)。
|
|
|
|
|
|
* @note 此时 USART0 驱动尚未初始化,只能裸写寄存器;
|
|
|
|
|
|
* 时钟树已是 180MHz(SystemInit 完成),BAUD=60 对应 3M(与工程 printf 一致)。
|
|
|
|
|
|
* 注意 system_gd32e50x.c 的 HXTAL FAIL 段有寄存器 bug(CTL0 写到 STAT0 偏移、
|
|
|
|
|
|
* 漏开 USART0EN),本段使用修正后的地址:APB2EN bit14=USART0EN、CTL0 @ +0x0C。
|
2026-05-10 21:27:51 +08:00
|
|
|
|
*/
|
2026-09-02 02:38:35 +08:00
|
|
|
|
static void fatalSystickHalt()
|
|
|
|
|
|
{
|
|
|
|
|
|
*((volatile uint32_t *)0x40021018U) |= (1U << 14) | (1U << 2) | (1U << 0); /* USART0EN|PAEN|AFEN */
|
|
|
|
|
|
{ volatile uint32_t _ctl = *((volatile uint32_t *)0x40010804U); /* PA9 → AF_PP */
|
|
|
|
|
|
_ctl &= ~(0xFU << 4); _ctl |= (0xBU << 4);
|
|
|
|
|
|
*((volatile uint32_t *)0x40010804U) = _ctl; }
|
|
|
|
|
|
*((volatile uint32_t *)0x40013808U) = 60U; /* BAUD: 180MHz/3M */
|
|
|
|
|
|
*((volatile uint32_t *)0x4001380CU) = (1U << 3) | (1U << 13); /* CTL0: TEN | UEN */
|
|
|
|
|
|
{ const char *_msg = "[APP] init: FATAL systick\r\n";
|
|
|
|
|
|
for(int i=0; _msg[i]; i++){
|
|
|
|
|
|
*((volatile uint32_t *)0x40013804U) = _msg[i]; /* DATA */
|
|
|
|
|
|
while((*((volatile uint32_t *)0x40013800U) & (1U << 7)) == 0U) {} } } /* STAT0.TBE */
|
|
|
|
|
|
while(1){ }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @brief 初始化 1ms SysTick 时基并验证中断真实触发。
|
|
|
|
|
|
* @param[in] 无。
|
|
|
|
|
|
* @param[out] 无。
|
|
|
|
|
|
* @retval bool true=节拍已前进;false=配置失败(不返回,直接 FATAL 停机)。
|
|
|
|
|
|
* @note 先更新 `SystemCoreClock`,再按 1kHz 频率配置 SysTick。
|
|
|
|
|
|
* 节拍验证失败时系统失去一切超时/延时基础,继续运行等于盲跑,
|
|
|
|
|
|
* 按致命错误处理(裸串口报告 + 挂死,与 HXTAL FAIL 同级)。
|
|
|
|
|
|
*/
|
|
|
|
|
|
bool SysTickTimer::initMs()
|
2026-05-10 17:28:14 +08:00
|
|
|
|
{
|
|
|
|
|
|
SystemCoreClockUpdate();
|
2026-09-02 02:38:35 +08:00
|
|
|
|
if (SysTick_Config(SystemCoreClock / 1000U) != 0U) {
|
|
|
|
|
|
fatalSystickHalt();
|
|
|
|
|
|
}
|
|
|
|
|
|
/* 有界等待节拍前进:guard 预算约 50ms+,覆盖 1ms 节拍;
|
|
|
|
|
|
* 若无界等待,中断未触发时此处即死循环且无任何诊断。 */
|
|
|
|
|
|
const uint32_t start = s_ms;
|
|
|
|
|
|
volatile uint32_t guard = 2000000U;
|
|
|
|
|
|
while (s_ms == start) {
|
|
|
|
|
|
if (--guard == 0U) {
|
|
|
|
|
|
fatalSystickHalt();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return true;
|
2026-05-10 17:28:14 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ----- 中断入口 C 包装 ---------------------------------------------- */
|
2026-05-10 21:27:51 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* @brief SysTick 中断向量入口。
|
|
|
|
|
|
* @param[in] 无。
|
|
|
|
|
|
* @param[out] 无。
|
|
|
|
|
|
* @retval 无返回值。
|
|
|
|
|
|
* @note C 向量包装函数,内部转调 `SysTickTimer::onInterrupt()`。
|
|
|
|
|
|
*/
|
2026-05-30 00:24:31 +08:00
|
|
|
|
extern "C" void SysTick_Handler(void) { SysTickTimer::onInterrupt(); }
|