Files
DCU_APP/GD32E508_DCU_APP/sys/cpu_load.cpp
T
cbb 70daa4b0c6 feat(DCU_APP): 添加CPU负载监控和EtherCAT诊断功能
- 在DCU_APP项目中添加cpu_load.h和cpu_load.cpp模块用于CPU负载率监测
- 修改csolution配置将构建目标从Debug切换为Release
- 在EtherCAT PDO协议栈中新增段5诊断区(632-639字节),包含负载率和序列号
- 在所有关键中断服务程序中添加CpuLoad::isrEnter()/isrExit()钩子用于准确统计中断占用
- 增强EtherCAT同步中断处理,改进AL事件掩码守护机制,修复OP状态下PDI中断门控问题
- 解决SSC源码中指针地址对齐警告和打包成员访问警告问题
- 在主循环中集成CPU负载率采样tick()调用,实现1秒滚动窗口统计

BREAKING CHANGE: 构建配置从Debug改为Release,EtherCAT协议栈增加新的诊断数据区
2026-09-05 20:07:22 +08:00

118 lines
3.5 KiB
C++

/**
* @file cpu_load.cpp
* @brief CPU 负载率测量实现(1.5.61,度量定义与并发协议见 cpu_load.h)。
*
* 热路径(beginWork/endWork/isrEnter/isrExit/tick)放进 .ramfunc——它们会被包进
* EXTI0(Sync0, preempt=0) 等延迟敏感的 ISR 包装,与 EthercatSync::onSync0Exti
* 同款 section 属性,避免 flash 等待态给 Sync0 入口添抖动。1s 一次的窗口
* 结算(含 64 位除法)留在普通 flash 函数里。
*/
#include "sys/cpu_load.h"
#include "RTE_Components.h"
#include CMSIS_device_header
volatile uint32_t CpuLoad::s_depth = 0U;
volatile uint32_t CpuLoad::s_stamp = 0U;
volatile uint32_t CpuLoad::s_busy = 0U;
volatile uint32_t CpuLoad::s_winStart = 0U;
volatile uint16_t CpuLoad::s_loadPerm = 0U;
volatile uint32_t CpuLoad::s_seq = 0U;
/** @brief 区间并集的共享进入点。0→1 者负责盖时间戳;STREX 失败方重试时深度
* 已被抢占者修正,不会再重复盖戳。 */
__attribute__((always_inline)) static inline void cpuLoadEnter()
{
uint32_t d;
do {
d = __LDREXW(&CpuLoad::s_depth);
if (d == 0U) {
CpuLoad::s_stamp = DWT->CYCCNT;
__DMB();
}
} while (__STREXW(d + 1U, &CpuLoad::s_depth) != 0U);
__DMB();
}
/** @brief 区间并集的共享退出点。1→0 者把区间累进 s_busy(同样走独占访问,
* 防"ISR 恰好插在主循环退出的读-改-写之间"丢累加)。 */
__attribute__((always_inline)) static inline void cpuLoadLeave()
{
const uint32_t end = DWT->CYCCNT;
const uint32_t start = CpuLoad::s_stamp;
uint32_t d;
do {
d = __LDREXW(&CpuLoad::s_depth);
} while (__STREXW(d - 1U, &CpuLoad::s_depth) != 0U);
if (d == 1U) {
const uint32_t delta = end - start;
uint32_t b;
do {
b = __LDREXW(&CpuLoad::s_busy);
} while (__STREXW(b + delta, &CpuLoad::s_busy) != 0U);
}
}
void CpuLoad::init()
{
/* DWT 已由 EscLan9252::init 使能;这里幂等兜底(万一 EtherCAT 初始化被裁剪)。 */
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
s_depth = 0U;
s_busy = 0U;
s_winStart = DWT->CYCCNT;
s_loadPerm = 0U;
s_seq = 0U;
}
__attribute__((section(".ramfunc"), noinline)) void CpuLoad::beginWork()
{
cpuLoadEnter();
}
__attribute__((section(".ramfunc"), noinline)) void CpuLoad::isrEnter()
{
cpuLoadEnter();
}
__attribute__((section(".ramfunc"), noinline)) void CpuLoad::isrExit()
{
cpuLoadLeave();
}
/**
* @brief 窗口结算(普通 flash 函数,1s 才进一次)。
* @note s_busy 用独占访问换出:窗口边界上 ISR 的在途累加要么算进本窗口、
* 要么算进下窗口,不丢。
*/
static void cpuLoadRollWindow(uint32_t now)
{
const uint32_t elapsed = now - CpuLoad::s_winStart; /* 调用方已保证 >= 1s */
uint32_t busy;
do {
busy = __LDREXW(&CpuLoad::s_busy);
} while (__STREXW(0U, &CpuLoad::s_busy) != 0U);
CpuLoad::s_winStart = now;
uint32_t perm = (uint32_t)(((uint64_t)busy * 1000ULL) / (uint64_t)elapsed);
if (perm > 1000U) {
perm = 1000U;
}
CpuLoad::s_loadPerm = (uint16_t)perm;
CpuLoad::s_seq++;
}
__attribute__((section(".ramfunc"), noinline)) void CpuLoad::endWork()
{
cpuLoadLeave();
}
__attribute__((section(".ramfunc"), noinline)) void CpuLoad::tick()
{
const uint32_t now = DWT->CYCCNT;
if ((uint32_t)(now - s_winStart) >= SystemCoreClock) {
cpuLoadRollWindow(now);
}
}