4. J-Link脚本语言与流程控制
在自动化测试工程中,J-Link Command File(以下简称 JCF)是连接测试主机与目标芯片之间的“可编程桥梁”。它把原本需要人工在 J-Link Commander 中逐条敲入的命令,固化成可重复执行的脚本。对于测试准备与恢复流程而言,脚本的价值不在于“能执行”,而在于“能判断、能分支、能复用、能容错”。本节围绕变量、条件、循环、子程序和错误处理五个要素,说明如何构建一套可复用的测试准备与恢复流程。
一、JCF 的执行模型与变量
JCF 由 J-Link Commander 通过 -CommandFile 参数加载,按行顺序解释执行。脚本中的变量以 $ 开头,分为两类:一类是 J-Link 内置变量,如 $DEVICE、$SPEED,由连接参数决定;另一类是用户自定义变量,通过 SetVar 或 Var 声明。变量在脚本内是全局可见的,因此命名应带前缀以避免冲突,例如 $TEST_RETRY、$PREP_OK。
SetVar TEST_RETRY = 3
SetVar PREP_OK = 0
SetVar TARGET_ADDR = 0x08000000
SetVar EXPECT_ID = 0x1BA01477
变量可以参与算术与比较运算,J-Link 支持 + - * / & | ^ ~ 等运算符,比较结果以 0/1 表示。这一点是后续条件判断的基础。需要注意的是,JCF 的变量本质是整数,字符串比较需借助 strcmp 类命令或直接比较数值编码。
二、条件判断:让脚本具备“决策”能力
测试准备流程中最常见的判断是“目标是否已连接、ID 是否正确、是否处于调试状态”。JCF 提供 If ... Else ... EndIf 结构,条件表达式通常由比较运算构成。例如读取 CPU ID 后与期望值比对,只有匹配才继续执行擦除或下载,否则进入恢复分支。
If $CPU_ID == $EXPECT_ID
Print "ID matched, continue preparation"
SetVar PREP_OK = 1
Else
Print "ID mismatch, enter recovery"
SetVar PREP_OK = 0
EndIf
条件可以嵌套,但建议嵌套不超过两层,否则脚本可读性急剧下降。对于多分支场景,可用连续的 If/ElseIf 或提前用变量记录状态码,再统一判断。判断依据应来自真实可观测的量,例如 ReadAP 返回值、Mem 读取结果、Connect 的返回状态,而不是主观假设。
三、循环:批量操作与重试机制
JCF 支持 While ... EndWhile 循环,配合变量自增/自减实现计数控制。循环在测试准备中有两类典型用途:一是批量擦除多个扇区或写入多段数据;二是连接重试,当目标上电时序不稳定时,允许有限次重连。
SetVar RETRY = 0
While $RETRY < $TEST_RETRY
Connect
If $CONNECT_STATUS == 1
Break
EndIf
SetVar RETRY = $RETRY + 1
Sleep 200
EndWhile
循环必须设置明确的退出条件,避免死循环。上例中 $TEST_RETRY 是上限,Break 用于提前跳出。若循环体内部有耗时操作,应加入 Sleep 让目标电源与复位信号稳定,否则重试可能连续失败。循环结束后应检查 $RETRY 是否达到上限,以此判断准备流程是否成功。
四、子程序:把准备与恢复拆成可复用单元
JCF 通过 GoSub 与 Return 实现子程序调用,配合标签 Label 定义入口。子程序的最大价值是把“准备”和“恢复”两个方向的操作分别封装,主流程只负责编排顺序与判断结果。例如 PrepareTarget 负责复位、连接、校验 ID、擦除;RecoverTarget 负责复位、断开、重新上电、恢复默认时钟。
GoSub PrepareTarget
If $PREP_OK == 0
GoSub RecoverTarget
EndIf
...
PrepareTarget:
Reset
Connect
...
Return
子程序应遵循“单一职责”:一个子程序只完成一类操作,并通过全局变量或约定寄存器返回状态。调用前应确保相关变量已初始化,调用后应立即检查返回状态,避免错误被后续步骤掩盖。对于需要在多个测试用例间共享的准备逻辑,可把子程序集中放在一个 common.jcf 中,由各用例脚本通过 GoSub 引用。
五、错误处理:从“能跑”到“可控”
JCF 没有现代语言的异常机制,错误处理依赖“状态检查 + 分支 + 恢复子程序”的组合。常见错误包括:连接失败、ID 不匹配、擦除超时、写入校验失败、目标掉电。处理策略分三层:第一层是就地重试,适用于瞬时故障;第二层是回退到恢复子程序,把目标拉回已知状态;第三层是记录错误码并终止脚本,避免污染后续测试。
If $ERASE_STATUS != 0
Print "Erase failed, code=", $ERASE_STATUS
GoSub RecoverTarget
SetVar PREP_OK = 0
Exit
EndIf
错误码应统一规划,例如 0 表示成功,1 表示连接失败,2 表示 ID 不匹配,3 表示擦除失败,4 表示校验失败。这样上位机解析日志时可以直接按码判断,而不必解析文本。所有 Print 输出建议带固定前缀,如 [PREP]、[RECOVER],便于日志过滤。
六、把五要素组合成可复用的准备与恢复流程
将上述要素组合,可以得到一个稳定的测试准备骨架:主流程先初始化变量,调用 PrepareTarget;子程序内部用循环处理连接重试,用条件校验 ID,用变量记录 $PREP_OK;主流程根据 $PREP_OK 决定进入测试还是调用 RecoverTarget;恢复子程序同样以子程序形式封装,确保无论测试用例如何变化,目标都能回到已知状态。这样,脚本不再是“一次性命令堆叠”,而是具备判断、重试、回退和状态记录能力的可复用资产。
common.jcf 中,各测试用例脚本只保留差异化的准备参数与测试步骤,通过 GoSub 复用。这样修改一处即可影响全部用例,显著降低维护成本。While 可能长时间占用调试通道。务必在循环内设置最大重试次数,并在每次重试之间加入 Sleep,同时在上位机侧设置脚本执行超时。最后需要强调:JCF 的流程控制能力有限,它更适合做“确定性的准备与恢复”,而不是复杂业务逻辑。把判断条件限定在可观测的硬件状态上,把恢复动作做成幂等子程序,把错误码固定下来,才能让自动化测试在长时间运行中保持稳定与可追溯。