- 在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协议栈增加新的诊断数据区
118 lines
3.5 KiB
C++
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);
|
|
}
|
|
}
|