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、评审过程稿
This commit is contained in:
cbb
2026-09-20 22:58:09 +08:00
parent 63af85e7be
commit 5fd986299c
32 changed files with 2592 additions and 781 deletions
+77 -120
View File
@@ -11,94 +11,6 @@
This file contains the Process Data interface
\version 5.11
<br>Changes to version V5.10.1:<br>
V5.11 COE3: change 0x10F3.2 (Sync Error limit) from UINT32 to UINT16 (according to the ETG.1020)<br>
V5.11 ECAT1: update EEPROM access reset operation<br>
V5.11 ECAT10: change PROTO handling to prevent compiler errors<br>
V5.11 ECAT11: create application interface function pointer, add eeprom emulation interface functions<br>
V5.11 ECAT2: update EEPROM access retry cycle (add 10ms delay between two retry cycles)<br>
V5.11 ECAT3: handle bus cycle calculation for input/output only devices and create warning diag message only if calculation failed<br>
V5.11 ECAT4: enhance SM/Sync monitoring for input/output only slaves<br>
V5.11 ECAT6: add function to calculate bus cycle time<br>
V5.11 ECAT8: call PDO_InputMapping only once if DC is enabled and COE is not supported<br>
V5.11 EEPROM1: fix compiler error during pEEPROM pointer initialization<br>
V5.11 EEPROM2: write Station alias value to EEPROM data register on EEPROM reload command<br>
V5.11 EEPROM3: clear EEPROM error bits<br>
V5.11 EEPROM4: prevent the variable in the EEPROM busy loop to be removed by the compiler<br>
V5.11 ESM7: "add Sync define for 0x22 (""SYNCTYPE_SM2_SYNCHRON""), support value 0x22 for 0x1C33.1 (SM2 sync)"<br>
<br>Changes to version V5.01:<br>
V5.10 COE1: Define one entry description for all 0x1C3x objects and change data type of SI11,12,13 to UINT16 (according ETG.1020)<br>
V5.10 ECAT1: Correct calculation of blinking and flashing sequence<br>
V5.10 ECAT13: Update Synchronisation handling (FreeRun,SM Sync, Sync0, Sync1)<br>
Compare DC UINT configuration (by ESC Config data) vs. DC activation register settings<br>
Update 0x1C3x entries<br>
V5.10 ECAT2: Prevent EEPROM data null pointer access (if the pointer is null an command error is set)<br>
EEPROM emulation return command error if unknown command was received<br>
V5.10 ECAT4: Update alignment marco for 8 to 15 bit alignments (16 and 32 Bit controllers)<br>
Bugfix calculate LED blink frequency<br>
V5.10 ECAT7: Add "bInitFinished" to indicate if the initialization is complete<br>
V5.10 HW2: Change HW_GetTimer return value to UINT32<br>
<br>Changes to version V5.0:<br>
V5.01 APPL3: Include library demo application<br>
V5.01 ESC1: Change ESC access function (if EEPROM Emulation is active)<br>
V5.01 ESC2: Add missed value swapping<br>
<br>Changes to version V4.40:<br>
V5.0 TEST1: Add test application. See Application Note ET9300 for more details.<br>
V5.0 ECAT2: Application specific functions are moved to application files.<br>
V5.0 ECAT3: Global dummy variables used for dummy ESC operations.<br>
V5.0 ESC1: ESC 32Bit Access added.<br>
V5.0 ESC3: Add EEPROM emulation support.<br>
V5.0 ESM3: Handling pending ESM transitions.<br>
V5.0 ESC5: Enhance EEPROM access handling.<br>
V5.0 PDO1: AL Event flags are not rechecked in PDO_OutputMappping(). (Already checked before call function)<br>
V5.0 SYNC1: Add missed SM event indication (0x1C32/0x1C33 SI11).<br>
<br>Changes to version V4.30:<br>
V4.40 DIAG1: add diagnosis message support<br>
V4.40 PDO1: merge content of HW_InputMapping (spihw.c/mcihw.c) to PDO_InputMapping. merge content of HW_OutputMapping (spihw.c/mcihw.c) to PDO_OutputMapping.<br>
V4.40 PDO2: Generic process data length calculation<br>
V4.40 ECAT2: call cyclic CheckIfLocalError() to check the local flags<br>
V4.40 HW0: Generic hardware access functions. Add Function (PDI_Isr()), content merged from spihw.c and mcihw.c.<br>
V4.40 WD1: define (ESC_SM_WD_SUPPORTED) to choose ESC SyncManager watchdog or local watchdog<br>
V4.40 ESM2: Change state transition behaviour from SafeOP to OP<br>
V4.40 TIMER1: Change bus cycle time calculation and trigger of ECAT_CheckTimer() if ECAT_TIMER_INT is reset<br>
V4.40 HW1: Add support for fc1100 hardware<br>
<br>Changes to version V4.20:<br>
V4.30 EL9800: EL9800_x cyclic application is moved to el9800.c<br>
V4.30 OBJ 3: add object dictionary initialization<br>
V4.30 SYNC: add CalcSMCycleTime() (calculation of bus cycle time); change synchronisation control functions<br>
V4.30 PDO: include PDO specific functions (moved from coeappl.c).<br>
xxx_InputMapping(); xxx_OutputMapping(); xxx_ReadInputs(); xxx_ResetOutputs(); xxx_Application()<br>
V4.30 CiA402: Add CiA402_StateMachine() and CiA402_Application() call<br>
V4.20 DC 1: Add DC pending Statemachine handling<br>
V4.20 PIC24: Add EL9800_4 (PIC24) required source code<br>
V4.20 LED 1: Modified LED Handling<br>
V4.11 APPL 1: The checkWatchdog() function should not called in checkTimer() if this function is triggered by an Interrupt<br>
<br>Changes to version V4.08:<br>
V4.10 LED 1: The handling of the EtherCAT-Error-LED was added<br>
V4.10 AOE 3: The AoE fragment size has to be initialized during the state transition<br>
from INIT to PREOP<br>
<br>Changes to version V4.07:<br>
V4.08 LED 1: The handling of the EtherCAT-LED can be (de-)selected by the switch LEDS_SUPPORTED<br>
because the ET1100 and ET1200 have an output port which could be connected directly.<br>
<br>Changes to version V4.01:<br>
V4.02 ECAT 1: The watchdog timer variables shall be initialized.<br>
<br>Changes to version V4.00:<br>
V4.01 APPL 1: If the application is running in synchron mode and no SM event<br>
is received, the application should be called from the main loop<br>
V4.01 APPL 2: In FreeRun mode the output should only be copied if the slave is in OP<br>
<br>Changes to version V3.20:<br>
V4.00 APPL 1: The watchdog checking should be done by a microcontroller<br>
timer because the watchdog trigger of the ESC will be reset too<br>
if only a part of the sync manager data is written<br>
V4.00 APPL 2: The setting of EtherCAT state LEDs were included<br>
V4.00 APPL 3: The outputs should be reset to a safe state,<br>
when the state OP is left<br>
V4.00 APPL 4: An example for the EEPROM access through the ESC is shown in<br>
the function APPL_StartMailboxHandler<br>
V4.00 APPL 5: The inputs should be read once when the state transition<br>
from PREOP to SAFEOP is made<br>
V4.00 APPL 6: The main function was split in MainInit and MainLoop
*/
@@ -157,17 +69,22 @@ BOOL bCycleTimeMeasurementStarted; // indicates if the bus cycle measurement is
UINT16 aPdOutputData[(MAX_PD_OUTPUT_SIZE>>1)];
UINT16 aPdInputData[(MAX_PD_INPUT_SIZE>>1)];
/*ECAT_DBG_START(1.6.0 临时剖分埋点)*/
/* 1.6.0 负载归因埋点:DWT 周期累加器,经 0x2000 sub5..8 上报,主站 1s 差分出速率。
* 只为定位 free-run 模式下每周期 508µs 计入时间的真实去向;定位完成后整块移除。
/*ECAT_DBG_START(剖分埋点)*/
/* 负载归因埋点:DWT 周期累加器,经 0x2000 sub5..8 上报,主站 1s 差分出速率。
* EcatDbg_Dwt() 定义在 comm/ethercat_sync.cpp (extern "C")。 */
extern UINT32 EcatDbg_Dwt(void);
#define ecatdbg_dwt() EcatDbg_Dwt()
/* 1.6.0:输出探针(实现见 comm/ethercat_pdo.cpp,C 链接) */
/* CPU 负载挂钩(sys/cpu_load.cpp) */
extern void CpuLoad_Enter(void);
extern void CpuLoad_Leave(void);
/* 1ms 调度节拍(ethercat_sync.cpp extern "C") */
extern UINT32 EcatDbg_GetTick1ms(void);
/* 输出探针(实现见 comm/ethercat_pdo.cpp,C 链接) */
extern UINT8 EcatPdo_OutputProbe(UINT8 const *head);
/* 1.6.22:稀疏写 ESC 计划(密排 count 只写有效段; 实现见 ethercat_pdo.cpp) */
extern void EcatPdo_NoteOutputMapped(void);
/* 稀疏写 ESC 计划(密排 count 只写有效段; 实现见 ethercat_pdo.cpp) */
extern UINT8 EcatPdo_SparseEscPlan(UINT16 *off0, UINT16 *len0, UINT16 *off1, UINT16 *len1);
/* 1.6.25:差分写 ESC 多段计划(段头/段尾 + 3-buffer 冲刷; 实现见 ethercat_pdo.cpp) */
/* 差分写 ESC 多段计划(段头/段尾 + 3-buffer 冲刷; 实现见 ethercat_pdo.cpp) */
extern UINT8 EcatPdo_EscWritePlan(UINT16 *offs, UINT16 *lens, UINT8 maxSegs);
volatile UINT32 g_dbg_pdiCyc = 0; /* sub5: PDI_Isr 全函数累计周期 */
volatile UINT32 g_dbg_outCyc = 0; /* sub6: PDO_OutputMapping(输出探针/全量读) */
@@ -200,10 +117,10 @@ BOOL bInitFinished = FALSE; /** < \brief indicates if the initialization is fini
*////////////////////////////////////////////////////////////////////////////////////////
void PDO_InputMapping(void)
{
/*ECAT_DBG(1.6.0 剖分:输入映射全程 + 过程数据写细分)*/
/* 1.6.22 稀疏写:APPL 仍整填 aPdInputData(对齐 SDO 0x6000),但 HW_EscWriteIsr
/*ECAT_DBG(剖分:输入映射全程 + 过程数据写细分)*/
/* 稀疏写:APPL 仍整填 aPdInputData(对齐 SDO 0x6000),但 HW_EscWriteIsr
* 只写密排有效段+段3/5,跳过空槽区 —— 省的是 PRAM 字节时间,不是 RAM 拷贝。
* 1.6.25 差分写:在稀疏之上再跳过「与影子一致且 3-buffer 冲刷完成」的段。 */
* 差分写:在稀疏之上再跳过「与影子一致且 3-buffer 冲刷完成」的段。 */
const UINT32 dbgT0 = ecatdbg_dwt();
APPL_InputMapping((UINT16*)aPdInputData);
const UINT32 dbgT1 = ecatdbg_dwt();
@@ -228,32 +145,46 @@ void PDO_InputMapping(void)
to the hardware. This function is only called in case of an SM2
(output process data) event.
1.6.0 输出按需全量读(负载优化):每周期先读输出 PDO 头 12B 探针(覆盖 SEQ@0
输出按需全量读:每周期先读输出 PDO 头 12B 探针(覆盖 SEQ@0
与 WIN@8),经 EcatPdo_OutputProbe 判定——seq 无变化沿且无清统计请求时,
跳过 384B 全量读(只补读 SM2 末字完成事件应答),省掉每周期 ~190µs 的
PRAM 搬运(含 ESC 核仲裁等待)。主站滚动窗口扫槽依赖的 WIN 字节在探针内
每周期刷新,窗口扫描不受影响。SM2 应答语义不变:首字(探针内)+末字
(两分支各自覆盖)。
跳过全量读(只补读 SM2 末字完成事件应答)。主站滚动窗口扫槽依赖的
WIN 字节在探针内每周期刷新,窗口扫描不受影响。
SM2 应答语义不变:首字(探针内)+末字(两分支各自覆盖)。
*////////////////////////////////////////////////////////////////////////////////////////
void PDO_OutputMapping(void)
{
/*ECAT_DBG(1.6.0 剖分:输出映射全程)*/
/*ECAT_DBG(剖分:输出映射全程)*/
const UINT32 dbgT0 = ecatdbg_dwt();
/* 1.6.0:输出按需全量读——探针 12B 判定是否真的有新输出 */
/* 输出映射:12B 探针判定是否有新输出。
* 「每拍始终全量读 384B」会在 PDO 提速后把 PDI 成本抬高一个数量级
* (历史:探针版 4kHz load≈80%;全量+process 双读时 2kHz 即饱和)。
* 探针命中才全量读;否则只补读 SM2 末字。s_out 长期不更新由
* EthercatPdo::process() 按新鲜度门兜底全量读(不是每拍)。 */
UINT8 head[12];
HW_EscReadIsr(((MEM_ADDR *) head), nEscAddrOutputData, 12U );
if ( EcatPdo_OutputProbe(head) )
{
HW_EscReadIsr(((MEM_ADDR *)aPdOutputData), nEscAddrOutputData, nPdOutputSize );
/* 有新 seq 时不必每次拉满 384B:先读命令前缀(含批量 count@48)。
* 8kHz 主站每拍都递增 seq 时,若 count==0 仍全量读会每拍吃满 PRAM,
* 把 CAN 解析饿死(gseq/s 从 ~3750 掉到数百)。 */
const UINT16 prefix = (nPdOutputSize < 52U) ? nPdOutputSize : 52U;
HW_EscReadIsr(((MEM_ADDR *)aPdOutputData), nEscAddrOutputData, prefix);
const UINT8 batchCount = (prefix > 48U) ? ((const UINT8 *)aPdOutputData)[48] : 0U;
if (batchCount > 0U && nPdOutputSize > prefix) {
HW_EscReadIsr(((MEM_ADDR *)((UINT8 *)aPdOutputData + prefix)),
(UINT16)(nEscAddrOutputData + prefix),
(UINT16)(nPdOutputSize - prefix));
}
APPL_OutputMapping((UINT16*) aPdOutputData);
EcatPdo_NoteOutputMapped();
}
else
{
/* 无新输出:补读 SM2 末字完成事件应答(首字已随探针读过) */
HW_EscReadWordIsr(u16dummy,(nEscAddrOutputData+nPdOutputSize-2));
if (nPdOutputSize >= 2U) {
HW_EscReadWordIsr(u16dummy,(nEscAddrOutputData+nPdOutputSize-2));
}
}
g_dbg_outCyc += ecatdbg_dwt() - dbgT0;
}
@@ -342,7 +273,7 @@ void HandleBusCycleCalculation(void)
void PDI_Isr(void)
{
/*ECAT_DBG(1.6.0 剖分:ISR 全程)*/
/*ECAT_DBG(剖分:ISR 全程)*/
const UINT32 dbgT0 = ecatdbg_dwt();
if(bEscIntEnabled)
{
@@ -397,17 +328,30 @@ void PDI_Isr(void)
/*ECATCHANGE_END(V5.11) ECAT4*/
/*
Call ECAT_Application() in SM Sync mode
Call ECAT_Application() in SM Sync mode (non-DC only).
DC:应用节拍已由 Sync0_Isr 拥有(bDcSyncActive),PDI 再跑一次
会把 Process/buildInput 算两遍 load_perm。
非 DC:仍只在 SM/SM2 类型时在 PDI 内跑应用。
**不要**「凡有 AL 过程事件就跑」——8kHz 时 PDI 每拍都带事件,
Process+InputMapping 热路径会被放大,单拍超过 ~120µs 墙,
实测 6kHz 即掉出(曾可 8kHz)。
负载随 PDO 上升由 ISR 包装 + free-run 1ms 节流路径体现,
见 sys/cpu_load.h;输出侧保持 12B 探针,避免每拍全量读。
*/
if (sSyncManOutPar.u16SyncType == SYNCTYPE_SM_SYNCHRON)
if (!bDcSyncActive
&& (sSyncManOutPar.u16SyncType == SYNCTYPE_SM_SYNCHRON
|| sSyncManOutPar.u16SyncType == SYNCTYPE_SM2_SYNCHRON
|| sSyncManInPar.u16SyncType == SYNCTYPE_SM_SYNCHRON
|| sSyncManInPar.u16SyncType == SYNCTYPE_SM2_SYNCHRON))
{
/* The Application is synchronized to process data Sync Manager event*/
const UINT32 dbgTb = ecatdbg_dwt();
ECAT_Application();
g_dbg_appCyc += ecatdbg_dwt() - dbgTb;
}
if ( bEcatInputUpdateRunning
if ( bEcatInputUpdateRunning
/*ECATCHANGE_START(V5.11) ESM7*/
&& ((sSyncManInPar.u16SyncType == SYNCTYPE_SM_SYNCHRON) || (sSyncManInPar.u16SyncType == SYNCTYPE_SM2_SYNCHRON))
/*ECATCHANGE_END(V5.11) ESM7*/
@@ -438,7 +382,7 @@ void PDI_Isr(void)
HW_EscReadWordIsr(u16dummy,(nEscAddrOutputData+nPdOutputSize-2));
}
} //if(bEscIntEnabled)
/*ECAT_DBG(1.6.0 剖分:ISR 全程 收尾)*/
/*ECAT_DBG(剖分:ISR 全程 收尾)*/
g_dbg_pdiCyc += ecatdbg_dwt() - dbgT0;
g_dbg_pdiCnt++;
}
@@ -653,15 +597,28 @@ void MainLoop(void)
}
DISABLE_ESC_INT();
/*ECAT_DBG(1.6.0 剖分:free-run 应用+输入映射块)*/
/*ECAT_DBG(剖分:free-run 应用+输入映射块)*/
{
const UINT32 dbgT1 = ecatdbg_dwt();
ECAT_Application();
/*
* free-run 主循环:**严格 1ms 节流**再跑应用并计入 busy。
* 不要「AL 有过程事件就跑」——事件位可能连续置位,退化成
* 每圈 MainLoop 都 Process,热路径被抬爆(8kHz 掉到 6kHz)。
* SM 模式(bEscIntEnabled)本分支本就不进;PDO 高速走 PDI ISR,
* 负载由 EXTI1 挂钩计入。
*/
static UINT32 s_freeRunAppMs = 0xFFFFFFFFu;
const UINT32 nowMs = EcatDbg_GetTick1ms();
if (nowMs != s_freeRunAppMs) {
s_freeRunAppMs = nowMs;
CpuLoad_Enter();
ECAT_Application();
if ( bEcatInputUpdateRunning )
{
/* EtherCAT slave is at least in SAFE-OPERATIONAL, update inputs */
PDO_InputMapping();
if ( bEcatInputUpdateRunning )
{
PDO_InputMapping();
}
CpuLoad_Leave();
}
g_dbg_freerunCyc += ecatdbg_dwt() - dbgT1;
}
+5 -53
View File
@@ -67,48 +67,6 @@ When the repeated mailbox service was sent (call of MBX_MailboxReadInd), psReadM
and psStoreMbx will be sent (in MBX_CopyToSendMailbox) and stored in psReadMbx, psStoreMbx will be set to 0.
\version 5.11
<br>Changes to version V5.10:<br>
V5.11 ECAT10: change PROTO handling to prevent compiler errors<br>
V5.11 ECAT7: add missing big endian swapping<br>
V5.11 HW1: "move hardware independent functions ""HW_DisableSyncManChannel()"", ""HW_EnableSyncManChannel()"", ""HW_GetSyncMan()"", ""HW_ResetALEventMask()"", ""HW_SetALEventMask()"" to ecatalv.c"<br>
V5.11 MBX2: "check in IP if enough dynamic memory is available to handle mailbox communication, if it is not the case the mbx error ""no memory"" is returned on any mbx request"<br>
V5.11 MBX3: set application triggered emergency and EoE data to pending if no mailbox queue is supported and another mailbox request is currently handled, Handle only one mailbox request at a time (in case that MAILBPX_QUEUE is disabled)<br>
V5.11 TEST4: add new mailbox test behaviour (the master mailbox cnt shall be incremented by 1 and the slave mailbox cnt is alternating)<br>
<br>Changes to version V5.01:<br>
V5.10 EOE3: Change local send frame pending indication variable to a global variable (it need to be resetted if the mailbox is stopped and a frame is pending)<br>
V5.10 ESC6: Update SyncManager register size (only for 8Bit ESC access)<br>
V5.10 MBX2: Allocate only memory for current configured mailbox size (max supported size was allocated before)<br>
<br>Changes to version V5.0:<br>
V5.01 ESC2: Add missed value swapping<br>
V5.01 MBX2: Return an error if length specified in mailbnox header is too large.<br>
<br>Changes to version V4.40:<br>
V5.0 ECAT3: Global dummy variables used for dummy ESC operations.<br>
V5.0 ESC1: ESC 32Bit Access added.<br>
V5.0 MBX2: Prevent double swapping (MBX repeat service) of MBX length field.<br>
V5.0 MBX4: Unlock SM buffer based on SM state.<br>
<br>Changes to version V4.11:<br>
V4.40 MBX8: Handle pending mailbox data even if mailbox queue is enabled<br>
V4.40 MBX7: Reset SyncManger 1 Repeat Acknowledge bit if local variable is reset<br>
V4.40 EMCY2: Send queued emergency messages<br>
V4.40 BOOT2: Support only FoE in Bootstrap state<br>
V4.40 MBX5: Prevent multiple free buffer<br>
V4.40 MBX6: change return value if no mailbox buffer is available<br>
<br>Changes to version V4.08:<br>
V4.11 MBX 1: free some dynamic memory to avoid memory leaks in the mailbox queue<br>
<br>Changes to version V4.07:<br>
V4.10 MBX 1: check Mailbox message buffer and print emergency messages<br>
during state change Init -> PreOP<br>
<br>Changes to version V4.07:<br>
V4.08 MBX 1: The mailbox queue was added (switch MAILBOX_QUEUE), if the<br>
mailbox should be handled in the ESC-Interrupt Service Routine<br>
the defines ENTER_MBX_CRITICAL and LEAVE_MBX_CRITICAL could be used<br>
to disable the interrupts or change the priority<br>
V4.08 AOE 1: AoE was added<br>
<br>Changes to version V4.06:<br>
V4.07 ECAT 1: The sources for SPI and MCI were merged (in ecat_def.h<br>
set the switch MCI_HW to 1 when using the MCI,<br>
set the switch SPI_HW to 1 when using the SPI
*/
@@ -133,7 +91,7 @@ V4.07 ECAT 1: The sources for SPI and MCI were merged (in ecat_def.h<br>
#include "ecatcoe.h"
#include <stdio.h> /* printf: SM 几何交叉校验 WARN(1.5.59,见 MBX_StartMailboxHandler) */
#include <stdio.h> /* printf: SM 几何交叉校验 WARN(见 MBX_StartMailboxHandler) */
/*--------------------------------------------------------------------------------------
------
@@ -284,16 +242,10 @@ void MBX_Init(void)
UINT16 MBX_StartMailboxHandler(void)
{
UINT16 result = 0;
/* 1.5.59 根治"邮箱楔死"(响应帧头落在 SM1 start+4/+8、逐会话漂移,断电才清):
* 根因链 = INIT→PREOP 时经 GetSyncMan/CSR 单次间接读(EXMC HBI)把 SM0/SM1
* 几何缓存进 u16EscAddr* 与 u16*MbxSize 等变量;总线毛刺给出的"合法"错值
* (0x1204/0x1208 均为偶地址且在检查范围内)即被缓存,此后所有 SDO 响应写错址,
* 主站按协议从 0x1200 读永远错位,重枚举重读仍错 → 只有断电能解。本板邮箱
* 几何是 SII 固定值(gen_eeprom.py 的 MBX_RX/TX_OFFSET/SIZE,ESC 上电自行
* 加载,主站 config_init 也只是照抄),改为构建期常量(ecat_def.h:
* MBX_SM0/1_START/SIZE)直达缓存,CSR 读降级为交叉校验:失配打 WARN(说明
* ESC 寄存器被非常规改写,需查)但缓存仍取常量——CSR 错值从此没有进入
* 缓存的路径,楔死无建立点;运行期内存踩踏也会在每次 INIT→PREOP 被常量覆写。
/* 邮箱几何构建期常量(ecat_def.h:MBX_SM0/1_START/SIZE)直达缓存,
* 不信任 GetSyncMan/CSR 单次间接读——CSR 读降级为交叉校验:
* 失配打 WARN(说明 ESC 寄存器被非常规改写,需查)但缓存仍取常量。
* 运行期内存踩踏也会在每次 INIT→PREOP 被常量覆写。
* 注意:ESC 寄存器经 PDI/CSR 读出即主机序(与 GetSyncMan 既有路径一致,勿加
* SWAPWORD;PRAM 帧数据才是线上大端,那边交换是对的)。 */
/*ECATCHANGE_START(V5.11) HW1*/