Files
DCU_APP/GD32E508_DCU_APP/comm/ethercat_pdo.h
T
cbb 9f1c2d25dd feat!: 1.6.0 DWT 剖分探针 + 1.6.1 输入 PDO 瘦身 640→496(待重烧验收)
1.6.0 剖分探针(上一轮真机已验证, 随本轮一并入库):
- ecatappl.c: 0x2000 sub5..12 DWT 周期累加器(PDI_Isr/输入映射/640B 写细分)
- ethercat_pdo.cpp: 输出按需全量读(12B 探针判 seq 沿, 省每周期 ~190µs 全量读)
- 段5 诊断区(负载率+seq)随 PDO 上报, 主站 /api/app/load 轮询

1.6.1 输入 PDO 瘦身 640→496(62×64bit; 0..359 与 1.5.61 逐字节兼容):
- 依据: DWT 实测 640B 写恒 296µs/拍且与 SYNC0 相位无关(主站 dc_bench 五形态
  对拍极差 0.04%), PRAM ≈0.463µs/B 线性; 真机 6086 帧 DLC 仅 24/32
- 批量接收条目 8B 头+64B 数据 → 8B+32B(DLC 真值保留, 截断打 flags bit1,
  环形队列仍存全量 64B); 段5 诊断区 632→484
- 预期写侧 −67µs/拍(→~230µs, 占空 29.7%→23%); LRW 帧 1024→880B
- 五处一致: ethercat_pdo_size.h(真源) / dc_app.c(62 条目+映射初始化器) /
  gen_eeprom.py(PD_IN_SIZE, nEntry 自动推导) / DCU_ESI.xml(SM3 496+62 条目) /
  bridge.h(kEcatRxBatchDataMax=32, 断言更新)
- 主站 tools/ecat decode_input 按 Ibytes 双布局自适应, 固件/EEPROM 与主站可
  任意先后升级; 混烧(只烧一侧)会被 SM 长度校验拦下(AL 0x001A)
- AC6 编译 0 警告; 真机验收待: 烧 axf + ecat.bat flash + 断电冷启动
  (流程与复验判据见 tools/ecat/MIGRATION.md 1.6.1 节)
2026-09-06 00:19:18 +08:00

116 lines
5.1 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.
/**
* @file ethercat_pdo.h
* @brief EtherCAT 过程数据(PDO)收发模块(1.5.54 由 dc_app.c 的散装 C 代码类化)。
*
* 一个 EtherCAT 周期在 SSC 里被拆成三个回调,本类按这三步各提供一个入口:
* 1. APPL_OutputMapping() → readOutputs() 从 ESC 取走主站下发的输出数据
* 2. APPL_Application() → process() 跑应用逻辑(当前是 PDO↔CAN 转发)
* 3. APPL_InputMapping() → writeInputs() 把输入数据交回 ESC(从站→主站)
*
* 缓冲区归本类所有,dc_app.c 只保留 SSC 对象字典(0x7000/0x6000 的 packed 结构体
* 是 SDO 存储,必须留在 C 侧)与三行 extern "C" 转发。这样"收发"这件事只有一个
* 归属:想加新的过程数据语义只改本类,不必再动 SSC 移植层。
*
* @note 1.5.55 起输出/输入**长度不再相等**(64B / 384B),为电机控制台腾出
* 状态窗口空间。长度常量统一由 ethercat_can_bridge.h 提供,避免三处各写
* 一个魔数后失配。
*
* @note 上下文:free-run 时三个回调都在主循环(ECAT_Main / ECAT_Application);
* 启用 DC 后 readOutputs/writeInputs 改由 Sync0_Isr(preempt=0) 调用,而
* process() 仍在主循环。因此 s_out/s_in 是跨上下文共享的——两者都只在
* 单一写者下被整块读写,且 CM4 上 memcpy 的撕裂最坏只会让某个周期读到
* 上/下半帧混合。对 seq 沿触发语义无害(seq 是单字节,要么旧要么新,
* 不会产生第三个值),故不加临界区,避免在 ISR 里关中断拖累抖动。
*/
#ifndef COMM_ETHERCAT_PDO_H
#define COMM_ETHERCAT_PDO_H
#include <cstdint>
#include "comm/ethercat_can_bridge.h"
/**
* @brief EtherCAT 过程数据收发。
* @note 全静态类,与 EthercatSlave / EthercatSync 同风格。
*/
class EthercatPdo {
public:
/** @brief 输出过程数据长度(主站→从站)。 */
static constexpr uint16_t kPdoOutBytes = kEcatPdoOutBytes;
/** @brief 输入过程数据长度(从站→主站)。 */
static constexpr uint16_t kPdoInBytes = kEcatPdoInBytes;
/**
* @brief 取走主站下发的输出过程数据(主站→从站)。
* @param[in] esc 指向 ESC 输出缓冲的 kPdoOutBytes 字节。
* @note 由 APPL_OutputMapping() 每周期调用;只做搬运不做业务,
* 业务在 process() 里跑,保证 ISR 上下文(DC 模式)足够短。
*/
static void readOutputs(const uint8_t *esc);
/**
* @brief 输出探针(1.6.0 输出按需全量读,配合 SSC PDO_OutputMapping)。
* @param[in] head 输出 PDO 头 12B(覆盖 SEQ@0 / WIN@8 / FLAGS@3)。
* @return true=需要全量读(seq 沿或清统计请求);false=本周期跳过全量读。
* @note 每周期由 PDI_Isr 在读 ESC 前调用:内部刷新桥的 s_winBase 并做 seq
* 基准 priming;s_lastSeq 的推进仍留在全量路径(processOutput)。
*/
static bool outputProbe(const uint8_t *head);
/**
* @brief 跑一个应用周期:消费输出、生成输入。
* @note 由 APPL_Application() 在主循环调用。
*/
static void process();
/**
* @brief 交回输入过程数据(从站→主站)。
* @param[out] esc 指向 ESC 输入缓冲的 kPdoInBytes 字节。
* @note 由 APPL_InputMapping() 每周期调用。
*/
static void writeInputs(uint8_t *esc);
/** @brief 累计取走输出的周期数(主站在发过程数据的证据)。 */
static uint32_t outputCycles() { return s_outputCycles; }
/** @brief 累计交回输入的周期数。 */
static uint32_t inputCycles() { return s_inputCycles; }
/** @brief 是否已开始过程数据交换(收到过至少一个输出周期)。 */
static bool isExchanging() { return s_outputCycles != 0U; }
/**
* @brief 拷出最近一份输出过程数据快照(诊断用)。
* @param[out] dst 至少 kPdoOutBytes 字节。
*/
static void snapshotOutput(uint8_t *dst);
private:
/**
* @brief 填充输入 PDO 段 5 设备诊断区(尾部 8 字节,1.5.61)。
* @param[out] in 全长输入过程数据缓冲。
* @note 布局常量 ECAT_DIAG_OFF_* 见 ethercat_can_bridge.h;当前携带
* CPU 负载率(0.1% 单位) + 窗口序号,取自 sys/cpu_load.h。
*/
static void fillDiagTail(uint8_t *in);
/** @brief 最近一份主站下发的输出数据。 */
static uint8_t s_out[kPdoOutBytes];
/** @brief 待交回主站的输入数据。 */
static uint8_t s_in[kPdoInBytes];
static volatile uint32_t s_outputCycles;
static volatile uint32_t s_inputCycles;
};
extern "C" {
/** @brief 供 dc_app.c(C 文件)调用:取走输出过程数据。 */
void EcatPdo_ReadOutputs(const uint8_t *esc);
/** @brief 供 dc_app.c 调用:跑一个应用周期。 */
void EcatPdo_Process(void);
/** @brief 供 dc_app.c 调用:交回输入过程数据。 */
void EcatPdo_WriteInputs(uint8_t *esc);
}
#endif /* COMM_ETHERCAT_PDO_H */