feat(boot): 1.1.0.22 CoE 跳回 APP + 连续崩溃门 + warm jump 根治
变更点: 1. CoE 0x2503「GD32 jump to app」 - 主站写 1 → requestJumpToApp:向量/CRC 校验后置 CHECK/AVAL/EN,process() 在 SDO 响应后跳 - 与 APP 0x2502 对称;crash_gate 只禁自动跳,人工跳仍允许 2. 连续 FWDGT 崩溃门(配置页 word9) - 复位 crash_count+1;达 OTA_LAYOUT_CRASH_STAY_MAX(3) 后关闭全部自动跳 APP - APP 喂狗稳定后再清 0(不在 init 立刻清) 3. warm jump 卡死 - bootEcatDeinit 去掉 LAN9252 writeReg32(INT_EN/IRQ_CFG):HBI 不返回会锁死 AHB - 跳转前有界等 USART TC,避免 handoff 半截 + APP 乱码 4. EtherCAT 邮箱空闲限速 5ms;delayMs 改 WFI,BOOT 驻留不空转烧 CPU 5. ota_layout.h vendored 进仓库(GD32E50X_BOOT/shared/),include 改 ../shared/ 6. .gitignore:firmware_keep/、评审 HTML、IDE 过程目录
This commit is contained in:
@@ -20,6 +20,7 @@
|
||||
* 所以主站**只能靠 0x1008 的 "GD32E508 DCU BOOT" 字符串**辨认这是引导程序。
|
||||
* 0x2500 会话控制(REC of UINT32)
|
||||
* 0x2501 数据通道(ARR of UINT8,BitSize = 4096*8,写回调落 flash)
|
||||
* 0x2503 跳回 APP(VAR UINT32,写 1 触发;与 0x2502 对称,方向相反)
|
||||
*/
|
||||
|
||||
#include "ecat_def.h"
|
||||
@@ -118,6 +119,23 @@ OBJCONST TSDOINFOENTRYDESC OBJMEM asDlChunkEntryDesc[] = {
|
||||
};
|
||||
static OBJCONST UCHAR aName0x2501[] = "GD32 firmware image chunk";
|
||||
|
||||
/*============================================================================
|
||||
* 0x2503 跳回 APP(主站 → BOOT:「让你跳回应用」)
|
||||
*
|
||||
* 与 APP 的 0x2502 对称:写 1 只置 pending,真正跳转由 process() 在
|
||||
* SDO 响应发出之后做,不会把 SM1 半包留在总线上。
|
||||
* VAR 对象只能写 :00;条目必须 ACCESS_READWRITE 才过 objdef 写权限门。
|
||||
*==========================================================================*/
|
||||
|
||||
static UINT32 s_jumpAppReq = 0U;
|
||||
|
||||
OBJCONST TSDOINFOENTRYDESC OBJMEM sEntryDesc0x2503[] = {
|
||||
{DEFTYPE_UNSIGNED32, 0x20, ACCESS_READWRITE},
|
||||
};
|
||||
static OBJCONST UCHAR aName0x2503[] = "GD32 jump to app";
|
||||
|
||||
/* 回调实现在 dlLoadU32 之后(见下方 ObjJumpAppWrite)。 */
|
||||
|
||||
/*============================================================================
|
||||
* SDO 回调
|
||||
*==========================================================================*/
|
||||
@@ -177,6 +195,27 @@ static inline UINT32 dlLoadU32(const UINT16 MBXMEM *p)
|
||||
return v;
|
||||
}
|
||||
|
||||
/** @brief 0x2503 写 1 = 请求跳回 APP(挂 pending_app_jump,process() 排空)。 */
|
||||
static UINT8 ObjJumpAppWrite(UINT16 index, UINT8 subindex, UINT32 dataSize,
|
||||
UINT16 MBXMEM *pData, UINT8 bCompleteAccess)
|
||||
{
|
||||
(void)index;
|
||||
(void)dataSize;
|
||||
(void)bCompleteAccess;
|
||||
|
||||
if (subindex != 0U) {
|
||||
return ABORTIDX_SUBINDEX_NOT_EXISTING;
|
||||
}
|
||||
if (dlLoadU32(pData) != 1U) {
|
||||
return ABORTIDX_GENERAL_ERROR;
|
||||
}
|
||||
if (!ota.requestJumpToApp()) {
|
||||
return ABORTIDX_GENERAL_ERROR;
|
||||
}
|
||||
s_jumpAppReq = 1U;
|
||||
return 0U;
|
||||
}
|
||||
|
||||
/** @brief 0x2500 写入:sub1 = 命令,sub2 = 镜像总长;sub3/sub4 只读。 */
|
||||
static UINT8 ObjFoeDlCtlWrite(UINT16 index, UINT8 subindex, UINT32 dataSize,
|
||||
UINT16 MBXMEM *pData, UINT8 bCompleteAccess)
|
||||
@@ -283,6 +322,10 @@ TOBJECT OBJMEM ApplicationObjDicList[] = {
|
||||
asDlChunkEntryDesc, aName0x2501, &s_dlChunk,
|
||||
NULL, ObjFoeDlWrite, 0x0000},
|
||||
|
||||
{NULL, NULL, 0x2503, {DEFTYPE_UNSIGNED32, 0 | (OBJCODE_VAR << 8)},
|
||||
sEntryDesc0x2503, aName0x2503, &s_jumpAppReq,
|
||||
NULL, ObjJumpAppWrite, 0x0000},
|
||||
|
||||
/* 终止条目 */
|
||||
{NULL, NULL, 0xFFFF, {0, 0}, NULL, NULL, NULL, NULL, NULL, 0x000}
|
||||
};
|
||||
@@ -363,7 +406,10 @@ static bool s_hwOk = false;
|
||||
namespace {
|
||||
/** @brief 与 main.cpp 的 1ms 主循环节拍对齐的时基判定(ECAT_TIMER_INT=0)。 */
|
||||
constexpr uint32_t kTickCycles = ECAT_TIMER_INC_P_MS; /* 180000 @180MHz = 1ms */
|
||||
uint32_t s_lastCheck = 0U;
|
||||
/** @brief 空闲时 MainLoop 最小间隔。FreeRun 每圈 csrRead 双读 = EXMC 20+ 线翻转,
|
||||
* 邮箱-only 在 5ms 节拍下仍够用;OTA/ECAT 会话期间不限速。 */
|
||||
constexpr uint32_t kEcatIdlePollMinMs = 5U;
|
||||
uint32_t s_lastPollCyc = 0U;
|
||||
}
|
||||
|
||||
/** @brief 上电调一次。硬件不通就整个 EtherCAT 栈不启,SPI OTA 照旧。 */
|
||||
@@ -383,19 +429,27 @@ extern "C" void ecatTaskStart(void)
|
||||
* APP 侧就是因为零调用者才让 s_alEventMask 影子停在 0xFFFF。 */
|
||||
(void)HW_Init();
|
||||
(void)MainInit();
|
||||
s_lastCheck = DWT->CYCCNT;
|
||||
s_lastPollCyc = DWT->CYCCNT;
|
||||
}
|
||||
|
||||
/** @brief 主循环每圈调。邮箱服务、AL 状态机、SDO 分段都在这条路上推进。 */
|
||||
/** @brief 主循环每圈调。邮箱服务、AL 状态机、SDO 分段都在这条路上推进。
|
||||
* 空闲时按 kEcatIdlePollMinMs 限速,降低 FreeRun 对 LAN9252 的 EXMC 翻转。 */
|
||||
extern "C" void ecatTaskPoll(void)
|
||||
{
|
||||
if (!s_started || !s_hwOk) {
|
||||
return;
|
||||
}
|
||||
|
||||
const bool busy = ota.isActive() || ota.ecatSessionActive();
|
||||
const uint32_t now = DWT->CYCCNT;
|
||||
if (!busy) {
|
||||
const uint32_t elapsed_ms = (now - s_lastPollCyc) / ECAT_TIMER_INC_P_MS;
|
||||
if (elapsed_ms < kEcatIdlePollMinMs) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
s_lastPollCyc = now;
|
||||
MainLoop();
|
||||
|
||||
/* ECAT_TIMER_INT=0:SSC 的超时计数靠 MainLoop 内部自己按 HW_GetTimerValue()
|
||||
* 判 1ms,这里不需要额外节拍。保留函数以便 Phase 2 挂进度上报。 */
|
||||
(void)kTickCycles;
|
||||
(void)s_lastCheck;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user