feat(app): 1.6.39 —— 1.6.29 起未上板业务改动入库,启动链与已提交基线对齐

主体为工作区累积的业务改动(CAN/PDO/桥/SSC/task_manager 等,详目见
config.h 版本注释链),新增 CoE 0x100A 真版本上报与 0x2502 APP→BOOT
总线交接。启动链(startup/SystemInit/initial/systick/hardfault)与
HEAD 逐字节一致;1.6.35~38 的跳转诊断实验(3M 化/BKP 面包屑/
haltWithWatchdog)未提交、已整体回退,补丁存 _revert_backup_20260916/。
真机实测(配对 BOOT 1.1.0.18):刷写 warm jump 与 reset cold jump 均可。
This commit is contained in:
cbb
2026-09-16 00:48:34 +08:00
parent 6136c2363f
commit 7d9d9c70a1
17 changed files with 399 additions and 95 deletions
+73 -5
View File
@@ -166,6 +166,10 @@ extern void EcatPdo_ReadOutputs(const UINT8 *esc);
extern void EcatPdo_Process(void);
extern void EcatPdo_WriteInputs(UINT8 *esc);
/* 0x2502 用:进 BOOT 的异步请求(sys/ota_boot_request.cpp 的 extern "C" shim)。
* 只置 pending 标志,真正的配置页写入 + 复位在主循环下一圈,见 ObjBootReqWrite 注。 */
extern void EcatEnterBootRequestAsync(void);
/*---------------------------------------------------------------------------
* PDO Assign 对象 (0x1C12 / 0x1C13)
*---------------------------------------------------------------------------*/
@@ -298,6 +302,57 @@ OBJCONST TSDOINFOENTRYDESC OBJMEM asSyncDiagEntryDesc[] = {
{DEFTYPE_UNSIGNED32, 0x20, ACCESS_READ}, /* sub23 : [DIFF-STATS] 比对自身 DWT 周期 */
};
/*---------------------------------------------------------------------------
* 0x2502 引导程序交接请求(主站 → APP:「让你回 BOOT」)
*
* 为什么要有它:EtherCAT 直灌的会话对象在 **BOOT** 里(0x2500/0x2501),APP 的字典
* 根本没有这两个对象 —— 实测对着 APP 写 0x2500 回 abort=0x06020000「对象不存在」。
* 所以一台正在跑 APP 的机器必须先交接,才能走总线刷写。量产那条交接只有
* SPI 0xB0 和 CAN 0x320+"OTA!",没有总线内的入口;常驻刷写必须补上。
*
* 语义:写 1 = 请求进 BOOT;写 0 是无操作(不做"取消",避免半路误清)。
* 动作复用现成的 OtaBootRequest 异步链:这里**只置 pending 标志**,配置页三字的
* Flash 写入 + NVIC_SystemReset 由主循环 OtaBootRequest::process() 下一圈执行
* (sys/initial.cpp 每圈调;与 SPI 0xB0 在 ISR 里只置标志同一个形状),
* 所以 SDO 响应先发出去、复位后到,不会把 SM1 半包留在总线上。
*
* 交接后板子会稳定停在 BOOT:APP 写的是 EN=NOT_AVAL,而 BOOT 的救砖门
* ecatArmed() = !(CHECK==AVAL && EN==AVAL) ⇒ 顺手就把 0x2500 直灌解锁了,
* 不需要 word8 令牌(也别依赖它:APP 的 otaConfigSet 只保全 8 个字,一擦页就没了)。
*---------------------------------------------------------------------------*/
OBJCONST TSDOINFOENTRYDESC OBJMEM sEntryDesc0x2502[] = {
/* VAR 只有 :00 一个条目,且必须带写权限位(SSC 的通用写权限门在 objdef.c:1325,
* 早于 1352 的回调分发 —— BOOT 的 0x2500 就是栽在只给 ACCESS_READ 上) */
{DEFTYPE_UNSIGNED32, 0x20, ACCESS_READWRITE},
};
static OBJCONST UCHAR aName0x2502[] = "GD32 boot request";
static UINT32 s_bootReq = 0U; /**< 最近一次写入值,读回用于主站自证 */
static UINT8 ObjBootReqWrite(UINT16 index, UINT8 subindex, UINT32 dataSize,
UINT16 MBXMEM *pData, UINT8 bCompleteAccess)
{
const UINT8 *p8 = (const UINT8 *)pData;
UINT32 v;
(void)index;
(void)bCompleteAccess;
if (subindex != 0U) {
return ABORTIDX_SUBINDEX_NOT_EXISTING;
}
if (pData == NULL || dataSize < 4U) {
return ABORTIDX_PARAM_LENGTH_TOO_SHORT;
}
v = (UINT32)p8[0] | ((UINT32)p8[1] << 8) | ((UINT32)p8[2] << 16) | ((UINT32)p8[3] << 24);
s_bootReq = v;
if (v == 1U) {
EcatEnterBootRequestAsync();
}
return 0U;
}
/*---------------------------------------------------------------------------
* Object Names
*---------------------------------------------------------------------------*/
@@ -343,6 +398,10 @@ TOBJECT OBJMEM ApplicationObjDicList[] = {
{NULL, NULL, 0x2000, {DEFTYPE_RECORD, 23 | (OBJCODE_REC << 8)},
asSyncDiagEntryDesc, aName0x2000, &s_syncDiag, NULL, NULL, 0x0000},
/* 0x2502: 引导程序交接请求(写 1 = 回 BOOT 等灌写;见 ObjBootReqWrite 注) */
{NULL, NULL, 0x2502, {DEFTYPE_UNSIGNED32, 0 | (OBJCODE_VAR << 8)},
sEntryDesc0x2502, aName0x2502, &s_bootReq, NULL, ObjBootReqWrite, 0x0000},
/* 终止条目 */
{NULL, NULL, 0xFFFF, {0, 0}, NULL, NULL, NULL, NULL, NULL, 0x000}
};
@@ -391,8 +450,17 @@ UINT16 APPL_StopInputHandler(void) { return 0; }
/*---------------------------------------------------------------------------
* Output Handler (SAFEOP→OP)
*---------------------------------------------------------------------------*/
UINT16 APPL_StartOutputHandler(void) { return 0; }
UINT16 APPL_StopOutputHandler(void) { return 0; }
UINT16 APPL_StartOutputHandler(void)
{
EcatCan_ResetSequenceState();
return 0;
}
UINT16 APPL_StopOutputHandler(void)
{
EcatCan_ResetSequenceState();
return 0;
}
/*---------------------------------------------------------------------------
* APPL_AckErrorInd
@@ -691,7 +759,7 @@ void EcatDbg_OpInputFreshness(void)
}
/* 强制刷新:先重开门/首输出标志(门关着时 PDI 永远不会回来),
* 再在关中断窗口内做一次输入映射 —— 此路径极低频,关中断可接受。 */
* 再在 EXMC 互斥窗口(仅屏蔽 EXTI0/1/2)内做一次输入映射,保证不关全局中断(Preempt 0 CAN RX 不受影响)。 */
{
UINT16 dummy = 0U;
const UINT16 evt = HW_GetALEventRegister();
@@ -703,9 +771,9 @@ void EcatDbg_OpInputFreshness(void)
HW_EscReadWord(dummy, nEscAddrOutputData);
HW_EscReadWord(dummy, (UINT16)(nEscAddrOutputData + nPdOutputSize - 2U));
}
__asm volatile ("cpsid i" ::: "memory");
const uint32_t prevMask = EscExmcBus_MaskEnter();
PDO_InputMapping();
__asm volatile ("cpsie i" ::: "memory");
EscExmcBus_MaskExit(prevMask);
++s_opFreshRescues;
s_inMapSeqSeen = s_inMapSeq;
s_inStaleBaseCyc = EcatDbg_Dwt();
+10
View File
@@ -12,6 +12,7 @@
#include "ecat_def.h"
#include "esc.h"
#include "ecatslv.h"
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
@@ -36,6 +37,15 @@ void APPL_Application(void);
void EcatDbg_OpInputFreshness(void);
UINT32 EcatDbg_OpFreshRescues(void);
/* 1.6.34: HBI/EXMC 事务互斥(仅屏蔽 EXTI0/1/2,不关全局中断) */
uint32_t EscExmcBus_MaskEnter(void);
void EscExmcBus_MaskExit(uint32_t prev);
uint32_t HW_EscExmcMaskEnter(void);
void HW_EscExmcMaskExit(uint32_t prev);
/* 1.6.34: 复位输出 sequence 状态机 */
void EcatCan_ResetSequenceState(void);
#ifdef __cplusplus
}
#endif
+3 -1
View File
@@ -666,8 +666,10 @@
#define DEVICE_SW_VERSION "1.0"
#endif
/* 0x100A 的位长。SSC 默认 3 字符只装得下占位 "1.0";这里抬到 16,真实值由
* sys/initial.cpp 起板时写进 acSoftwareversion(与 BOOT 侧同款改动)。 */
#ifndef DEVICE_SW_VERSION_LEN
#define DEVICE_SW_VERSION_LEN 0x3
#define DEVICE_SW_VERSION_LEN 0x10
#endif
/*-----------------------------------------------------------------------------------------