Files
DCU_APP/GD32E508_DCU_APP/sys/cpu_load.cpp
T
cbb 5fd986299c feat(comm): 1.6.51 CAN 空通道自动静默 + PDO 诊断 + OTA 布局共用头
变更点:
1. CAN-FD(device/CANFD.cpp、sys/config.h)
   - 发送统一 FD+BRS(DLC≤8 不再回退经典 CAN);OTA 期仍按通道压制 BRS
   - 空通道自动识别:连续 5 个 1Hz 窗口无有效帧且有错误 → 静默上报;有帧即恢复
   - 三路 CAN 默认全开;RX parse budget 48→64
2. EtherCAT 桥 / PDO
   - 段1 增 txtxid/rx00ff;版本应答 0x00FF 粘滞发布,避免被 CONFIG 冲掉
   - STATUS 禁止写入 xrx 快照;processSeq 新鲜度救援
3. OTA / 配置
   - sys/config.h include 仓库内 shared/ota_layout.h(与 BOOT 共用,不再依赖仓外路径)
   - ota_boot_request 对齐配置页 word 布局
4. docs/audit_ecat_spi_wifi_ota_compatibility.md:ECAT/SPI/WiFi/OTA 兼容性审计
5. .gitignore:忽略 .trae/、docs/traework-import、评审过程稿
2026-09-20 22:58:09 +08:00

123 lines
3.8 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);
}
}
/* C 侧挂钩:供 ecatappl.c / dc_app.c 计入 EtherCAT 过程数据路径。
* 与 beginWork/endWork 共用深度计数器,嵌套不重不漏。 */
extern "C" void CpuLoad_Enter(void) { CpuLoad::beginWork(); }
extern "C" void CpuLoad_Leave(void) { CpuLoad::endWork(); }