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 节)
This commit is contained in:
@@ -119,19 +119,26 @@ void EthercatCanBridge::fillRxBatch(uint8_t *in)
|
||||
if (dlc > kEcatCanFdDataMax) {
|
||||
dlc = kEcatCanFdDataMax;
|
||||
}
|
||||
/* 1.6.1: PDO 内数据条目 32B 上限——DLC 字节填**真值**,超出部分截断并打
|
||||
* flags bit1;环形队列里仍是全量 64B,截断只发生在 PDO 快照这一步。
|
||||
* 主站按 "8 + min(dlc, kEcatRxBatchDataMax)" 推进游标。 */
|
||||
uint8_t dlcWire = dlc;
|
||||
if (dlcWire > kEcatRxBatchDataMax) {
|
||||
dlcWire = kEcatRxBatchDataMax;
|
||||
}
|
||||
/* 装不下就停,**且不推进 tail** —— 该帧留到下个周期,不丢。 */
|
||||
if ((uint16_t)(off + ECAT_FRM_HDR_SIZE + dlc) > kEcatPdoInBytes) {
|
||||
if ((uint16_t)(off + ECAT_FRM_HDR_SIZE + dlcWire) > kEcatPdoInBytes) {
|
||||
break;
|
||||
}
|
||||
|
||||
uint8_t *p = &in[off];
|
||||
p[ECAT_FRM_OFF_CH] = it.ch;
|
||||
p[ECAT_FRM_OFF_DLC] = dlc;
|
||||
p[ECAT_FRM_OFF_FLAGS] = 0x01U;
|
||||
p[ECAT_FRM_OFF_FLAGS] = (uint8_t)(0x01U | (dlc > kEcatRxBatchDataMax ? 0x02U : 0x00U));
|
||||
wr32le(&p[ECAT_FRM_OFF_ID], it.id);
|
||||
memcpy(&p[ECAT_FRM_HDR_SIZE], it.data, dlc);
|
||||
memcpy(&p[ECAT_FRM_HDR_SIZE], it.data, dlcWire);
|
||||
|
||||
off = (uint16_t)(off + ECAT_FRM_HDR_SIZE + dlc);
|
||||
off = (uint16_t)(off + ECAT_FRM_HDR_SIZE + dlcWire);
|
||||
tail = (uint8_t)((tail + 1U) % kEcatRxRingSlots);
|
||||
++count;
|
||||
}
|
||||
@@ -145,6 +152,33 @@ void EthercatCanBridge::fillRxBatch(uint8_t *in)
|
||||
s_rxRingLost = 0U; /* 回填后清零:lost 是"自上次回填以来"的增量 */
|
||||
}
|
||||
|
||||
bool EthercatCanBridge::peekOutput(const uint8_t *head)
|
||||
{
|
||||
if (head == nullptr) {
|
||||
return false;
|
||||
}
|
||||
const uint8_t seq = head[ECAT_CAN_TX_OFF_SEQ];
|
||||
|
||||
/* 窗口下标每周期都必须刷新(主站靠滚动 WIN 扫 27 槽),与 seq 沿无关。
|
||||
* 越界值钳到 0,避免读到槽数组外(与 processOutput 同款钳制)。 */
|
||||
const uint8_t win = head[ECAT_CAN_TX_OFF_WIN];
|
||||
s_winBase = (win < kMotorSlotCount) ? win : 0U;
|
||||
|
||||
/* 上电/重连后首帧只记基准(与 processOutput 的 priming 分支语义一致) */
|
||||
if (!s_seqPrimed) {
|
||||
s_seqPrimed = true;
|
||||
s_lastSeq = seq;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* seq 沿 → 全量读;FLAGS bit0(清统计请求)允许不带 seq 沿(同 processOutput)。
|
||||
* s_lastSeq 不在这里推进:全量路径上 processOutput 的沿处理只做一次。 */
|
||||
if (seq != s_lastSeq) {
|
||||
return true;
|
||||
}
|
||||
return (head[ECAT_CAN_TX_OFF_FLAGS] & 0x01U) != 0U;
|
||||
}
|
||||
|
||||
void EthercatCanBridge::processOutput(const uint8_t *out)
|
||||
{
|
||||
if (out == nullptr) {
|
||||
|
||||
Reference in New Issue
Block a user