简介:这份PDF文档面向半导体设备自动化领域的工程师与集成人员,系统讲解SECS/GEM设备接口协议及其落地实现,帮助读者理解设备与主机系统之间的标准化通信机制。内容以广州金南瓜科技的SECS/GEM方案为主线,涵盖通讯状态模型、控制状态模型与设备处理状态,并逐项展开主机发起场景、事件通知、在线识别、动态事件报告配置、变量与跟踪数据采集、报警管理、远程控制、设备常数及过程程序管理等设备能力,同时涉及TCP/IP通讯超时等协议细节,目录结构完整,便于按模块查阅与对照实施。资源包共1个PDF文件,约1006KB,轻量便携,适合随时翻阅。目前已有741人学习下载,可作为半导体产线自动化改造、设备联网调试与协议学习的实用参考。
1. 一份能直接对着写代码的 SECS/GEM 规格书,到底长什么样
手上拿到一份设备通信规格书,翻两页发现全是「错误!未定义书签。」,这种场面做过半导体设备对接的人大概都不陌生。这次拆的是一份 SECS/GEM 规格说明书,来自某半导体解决方案厂商 2020 年的版本,正文覆盖通讯状态模型、控制状态模型、GEM 能力清单、SECS-II 消息子集、SML 语法以及十几组典型交互场景。它不是协议科普,而是一份「主机侧程序员拿着就能对着写消息解析」的实施文档。适合三类人:正在给设备加 GEM 接口的嵌入式工程师、要写 Host 端 EAP/MES 对接层的上位机开发者、以及需要判断某台设备 GEM 合规性到什么程度的产线自动化从业者。下面按「文档怎么读 → 状态机怎么落 → 消息怎么发 → 坑在哪」的顺序拆。
2. 先读状态模型:通讯与控制两张图决定了你 80% 的异常处理逻辑
很多人拿到 SECS/GEM 文档直接翻到消息格式那一章,结果联调时设备一直回 S9F5 或者干脆不回,又回头找原因。血泪经验是:先把两张状态模型图吃透,后面所有超时、重连、Sx,F0 的处理都能对上号。这份文档用的是 Harel 记法画状态图,读法和普通状态机略有区别,先把这个门槛过了。
2.1 通讯状态模型:DISABLED / ENABLED 与四个子状态
文档把通讯状态拆成两层。顶层是 DISABLED 和 ENABLED,DISABLED 下 SECS-II 通信完全停止,操作员从 ENABLED 切到 DISABLED 时所有通信立即中断。ENABLED 下分 COMMUNICATING 和 NOT COMMUNICATING 两个子状态,而 NOT COMMUNICATING 又用 AND 关系同时挂着 HOST-INITIATED CONNECT 和 EQUIPMENT-INITIATED CONNECT 两条并行分支——这是 Harel 记法里容易看漏的地方,AND 状态意味着两条建链路径同时处于活动状态,谁先成功谁生效。
设备主动建链走 EQUIPMENT-INITIATED CONNECT,内部再分 WAIT CRA 和 WAIT DELAY。进入 NOT COMMUNICATING 时先到 WAIT CRA,把 CommDelay 定时器置为「已过期」,立刻发 S1,F13 等 S1,F14。如果连接事务失败,进 WAIT DELAY,初始化 CommDelay 定时器,把发送队列里的消息全部出队(必要时按生成顺序放进 spool 缓冲),等定时器到期再回 WAIT CRA 重发 S1,F13。主机主动建链走 HOST-INITIATED CONNECT,子状态 WAIT CR FROM HOST,就是干等主机发 S1,F13,收到后回 S1,F14 且 COMMACK=0,进入 COMMUNICATING。
这张图落到代码里,核心就是一个定时器加一个发送队列。下面是我一般会写的建链重试骨架,语言用 Python,逻辑和文档的状态迁移表一一对应:
import time COMM_DELAY = 10 # CommDelay 秒数,对应 ECID 建立通讯超时 MAX_RETRY = 0 # 0 表示无限重试,产线设备通常不设上限 class CommStateMachine: def __init__(self, send_s1f13, on_established): self.state = "WAIT_CRA" self.send_s1f13 = send_s1f13 # 发 S1,F13 的底层函数 self.on_established = on_established self.timer_start = time.time() self.retry = 0 def on_s1f14(self, commack): # 迁移 9:收到 S1,F14 且 COMMACK=0 才算建链成功 if commack == 0: self.state = "COMMUNICATING" self.on_established() else: self._to_wait_delay() # COMMACK 非 0 视为事务失败 def on_other_message(self): # 迁移 8:WAIT_DELAY 期间收到非 S1,F13 的消息,丢弃不回,立即重发 if self.state == "WAIT_DELAY": self.timer_start = time.time() - COMM_DELAY self._to_wait_cra() def tick(self): if self.state == "WAIT_DELAY" and time.time() - self.timer_start >= COMM_DELAY: self._to_wait_cra() def _to_wait_cra(self): self.state = "WAIT_CRA" self.send_s1f13() # 迁移 5/7:发 S1,F13 等 S1,F14 def _to_wait_delay(self): self.state = "WAIT_DELAY" self.timer_start = time.time() self.retry += 1 # 迁移 6:出队所有待发消息,按生成顺序进 spool 缓冲 self._flush_queue_to_spool()参数上最要紧的是 CommDelay,文档在「相关数据」里把它对应到 ECID 的 EstablishCommunicationsTimeout。这个值设太小,网络抖动时设备疯狂重发 S1,F13,主机侧日志被刷满;设太大,断链后恢复慢,产线会报通信超时。常见做法是 10 到 30 秒之间,具体看主机侧 EAP 的容忍窗口。另外注意迁移 8 的细节:WAIT DELAY 期间收到任何非 S1,F13 的消息,文档要求「丢弃、不回复、定时器置过期、立即发 S1,F13」,这个「不回」很关键,回了反而会让主机误判链路已通。
2.2 控制状态模型:OFF-LINE 下为什么还要回 S1,F13 和 S1,F17
控制状态模型定义主机和设备之间的协作级别。文档写得很明确:OFF-LINE 状态下,设备对主机发来的任何 primary message 都回 Sx,F0(表示该消息不被接受),但 S1,F13 和 S1,F17 例外,设备会正常处理和响应。S1,F17 是主机用来请求设备切到 ON-LINE 的消息。
这条规则踩过坑的人不少。有次联调,设备明明上电了,主机发 S1,F1 要在线识别,设备一直回 S1,F0,查了半天以为是消息格式错,最后发现设备停在 OFF-LINE,而 S1,F1 不在豁免列表里。所以主机侧的状态机要单独维护一个「设备是否 ON-LINE」的标志,在发任何业务消息前先确认,或者干脆先发 S1,F17 把设备拉上线。
控制状态迁移里还有一条容易忽略:设备从 ON-LINE 切回 OFF-LINE 有两种触发,操作员本地切换,或者主机发 S1,F15(Request OFF-LINE)。后者设备要回 S1,F16 确认。如果你的 Host 端在换产品、换配方时依赖 S1,F15 让设备下线,记得等 S1,F16 再继续,别发完就走,否则设备可能还在处理上一条消息,状态就乱了。
3. GEM 能力清单怎么用:从合规声明反推你要实现哪些消息
文档第 1.4 节的 GEM Adaptability 是一张勾选表,基本 GEM 要求和附加能力逐项标了 Yes/No。这张表的价值不在于「看它支不支持」,而在于它是你和设备厂商对齐范围的合同附件——主机侧要实现的每一条消息,都应该能在这张表里找到对应的 Yes。
3.1 基本要求与附加能力的边界
基本 GEM 要求里全部勾了 Yes:状态模型、设备处理状态、主机发起的 S1,F13/F14 场景、事件通知、在线识别、错误消息、文档、操作员发起的控制。附加能力里大部分也是 Yes,但有两项明确是 No:Material Movement(物料移动)和 Spooling(消息暂存)。这两项 No 直接决定了你的实现策略。
Material Movement 为 No,意味着设备不通过 SECS 消息报告载具或晶圆的位置移动,物料追踪得靠 MES 侧的其他手段补。Spooling 为 No 影响更大:通讯状态模型迁移 6 里提到「出队的消息如适当应放入 spool 缓冲」,但设备不支持 spooling,断链期间产生的事件就真的丢了。所以主机侧不能假设「断链恢复后能补收事件」,必须在 EAP 层做事件丢失告警,或者要求设备在关键事件上做本地缓存再重发。这一点在选型阶段就要问清楚,别等上线了发现数据有洞。
3.2 用能力表反查消息子集
文档第 6 章给了 SECS-II 消息子集,第 5 章列了实现的事件、变量、报警、常量和主机命令。正确的读法是拿 1.4 的表当索引:表里 Event Notification 是 Yes,就去第 5.1 节看实现了哪些 collection event;Variable Data Collection 是 Yes,就去 5.2 节看 data variable 清单;Alarm Management 是 Yes,就去 5.4 节对报警号。这样读不会漏,也不会把文档里没实现的功能当成有。
举个具体例子,动态事件报告配置(Dynamic Event Report Configuration)勾了 Yes,对应消息是 S2,F33(Define Report)和 S2,F35(Link Event Report)。主机侧的标准流程是:先 S1,F3 或 S1,F11 拿事件和变量名单,再 S2,F33 定义报告,再 S2,F35 把事件和报告关联,最后 S2,F37 开事件报告。这四步的顺序不能乱,S2,F35 引用的报告 ID 必须是 S2,F33 已经定义过的,否则设备回 S2,F34 带错误码。我一般会在 Host 端把「已定义报告 ID 集合」做成内存状态,每次 S2,F33 成功后更新,S2,F35 前校验,能省掉大量来回排查。
4. 消息格式与 SML:把文档里的 Data Item Dictionary 变成解析代码
第 6 章是整份文档最「可抄」的部分:6.1 是 SECS-II 消息子集,6.2 讲 SML 语言,6.2.1 是 Data Item Dictionary,6.2.2 是 Data Format。SML 是 SECS Message Language 的缩写,用文本形式描述一条 SECS-II 消息的结构,调试时比看十六进制报文直观得多。
4.1 SML 长什么样,怎么用它对照报文
一条典型的 S1,F13 在 SML 里大概是这样:
S1F13 W <L [2] <A [6] 'EQUIP1'> <A [4] '1.00'> >.S1F13是消息名,W 表示需要回复(Wait bit 置位),<L [2]是长度为 2 的列表,<A [6]是长度 6 的 ASCII 字符串。设备回 S1,F14 时结构类似,只是内容换成 COMMACK 等。联调时我习惯让设备侧或抓包工具把报文转成 SML 打印,和文档 6.2.2 的 Data Format 逐项对,比对着裸 hex 猜快十倍。
Data Item Dictionary 里定义了每种数据项的类型码和长度规则,常见的有 L(列表)、A(ASCII)、B(二进制)、BOOLEAN、U1/U2/U4(无符号整数)、I1/I2/I4(有符号整数)、F4/F8(浮点)。解析代码的核心就是按类型码递归下降。下面是一个最小可用的 SML 解析骨架,只处理 L 和 A,够你起步:
import re TOKEN = re.compile(r"<([A-Z][0-9]?)\s*\[(\d+)\]\s*(?:'([^']*)')?") def parse_sml(text): # 去掉消息头和结尾的 '.',只留 body body = text.split("\n", 1)[1].rstrip(".\n ") pos = 0 def parse_item(): nonlocal pos m = TOKEN.match(body, pos) if not m: raise ValueError(f"无法解析位置 {pos}: {body[pos:pos+20]}") typ, length, val = m.group(1), int(m.group(2)), m.group(3) pos = m.end() if typ == "L": items = [] for _ in range(length): items.append(parse_item()) return items if typ == "A": return val if val is not None else "" # 其他类型按需扩展:U4 转 int,B 转 bytes 等 return val return parse_item()逻辑说明:TOKEN匹配<类型 [长度] '值'>这种结构,parse_item遇到 L 就按长度递归解析子项,遇到 A 直接取值。参数上要注意两点:一是长度字段对 L 表示子项个数、对 A 表示字符数,别混用;二是 SML 里字符串可能含转义,实际解析前先确认设备侧用的是哪种转义约定,文档 6.2.2 的 Data Format 会写。这个骨架跑通后,把 U4、BOOLEAN 等类型补上,就能覆盖文档 6.2.1 里大部分数据项。
4.2 消息子集与场景章节的对应关系
第 6.1 节的 SECS-II 消息子集列了设备支持的所有消息,第 7 章 SECS Scenario 则按业务场景把这些消息串起来。读法建议是「以场景为纲、以子集为目」:先看 7.1 建立通讯,对应 S1,F13/F14;7.2 动态事件报告配置,对应 S2,F33/F34/F35/F36/F37/F38;7.3 变量和事件名单请求,对应 S1,F11/F12、S1,F3/F4;7.4 报警管理,对应 S5,F3/F4、S5,F5/F6;7.5 远程控制,对应 S2,F41/F42;7.6 设备常量,对应 S2,F15/F16、S2,F13/F14;7.7 处理程序管理,对应 S7 系列;7.8 终端服务,对应 S10,F3;7.9 时钟,对应 S2,F17/F18、S2,F31/F32;7.10 控制,对应 S1,F15/F16、S1,F17/F18。
这张对应表建议直接抄进你的接口设计文档,每个场景一节,每节写清楚「主机发什么、设备回什么、失败回什么、超时怎么办」。文档第 7 章每个场景都给了消息流,但没给超时值,超时得按 SEMI E37 的 T3/T5/T6/T7/T8 定时器自己定,常见做法是 T3 回复超时 45 秒、T5 连接分离超时 10 秒、T6 控制超时 5 秒、T7 未选中超时 10 秒、T8 网络字符超时 5 秒,具体以主机侧 EAP 配置为准。
5. 避坑与排查:联调现场最常翻车的五个点
5.1 现象:设备一直回 S9F5,主机侧日志显示消息格式错误
原因通常是主机发的消息里数据项类型和文档 6.2.1 的 Data Item Dictionary 对不上,比如文档要求 U4,主机发了 A。SECS-II 对类型是强校验的,类型错直接 S9F5(Unrecognized Data Item)。解决:把文档 6.2.2 的 Data Format 逐条抄成主机侧的 schema 校验表,发送前先本地校验类型和长度,别等设备回错再查。
5.2 现象:S2,F35 之后事件报告没上来
原因多半是 S2,F37 没发,或者 S2,F35 引用的报告 ID 在 S2,F33 里没定义成功。文档 7.2 的场景里这三步是连着的,但没强调依赖关系。解决:Host 端维护报告 ID 状态机,S2,F33 收到 S2,F34 且 ACKC6=0 才标记该 ID 可用,S2,F35 前校验,S2,F37 后再开一个「报告已使能」标志,事件上来时先查这个标志。
5.3 现象:断链恢复后主机侧事件数据有缺口
原因就是 1.4 节里 Spooling 勾了 No,设备断链期间的事件不缓存。解决:EAP 层对关键事件做丢失检测,比如按事件序号或时间戳连续性判断,发现缺口就触发补采(用 S1,F3 或 S6,F11 主动读变量),同时在设备选型阶段把 Spooling 列为加分项。
5.4 现象:设备停在 OFF-LINE,主机发业务消息全回 Sx,F0
原因见 2.2 节,OFF-LINE 下只有 S1,F13 和 S1,F17 被处理。解决:主机侧上线流程固定为「S1,F13 建链 → S1,F17 请求 ON-LINE → 等 S1,F18 确认 → 再发业务消息」,中间任何一步失败都回退重来,别跳步。
5.5 现象:CommDelay 到期后设备疯狂重发 S1,F13,主机日志被刷爆
原因是 CommDelay 设得太小,或者主机侧对 S1,F13 的回复延迟超过了 CommDelay。解决:CommDelay 按主机 EAP 的最坏回复延迟乘 2 到 3 倍来设,同时主机侧收到 S1,F13 要尽快回 S1,F14,别在回复前做耗时操作。另外检查是不是有多个设备实例共用同一个 CommDelay 配置,产线设备多的时候容易串。
6. 进阶:用文档第 5 章的变量清单做一套自检脚本
文档第 5 章列了实现的事件、数据变量、状态变量、报警、设备常量和主机命令,这些清单不只是给人看的,可以直接变成联调自检脚本的输入。我的习惯是把 5.1 到 5.6 的清单导成一张表,每行一个条目,字段包括类型(事件/变量/报警/常量/命令)、ID、名称、数据类型、是否已在主机侧实现。然后写一个脚本,按表逐项发对应的请求消息,比对设备返回值。
比如变量清单,用 S1,F11 请求 data variable namelist,拿回来的列表和文档 5.2 的清单做集合比对,多出来的说明设备固件版本比文档新,少了的说明文档没更新或者设备没实现。报警清单用 S5,F3 请求,比对报警号和文档 5.4。设备常量用 S2,F13 请求 namelist,比对 5.5。主机命令没法主动枚举,就按 5.6 的清单逐条发 S2,F41,看设备回 S2,F42 的 HCACK 是否为 0。
这套脚本跑一遍,基本能判断「设备实际实现」和「文档声明」的偏差有多大。偏差大的时候别急着改主机代码,先找设备厂商确认是文档滞后还是固件没刷。我一般会把自检结果存成 CSV,联调会议直接投屏,比口头对清单高效得多。
还有一个细节值得单独说:文档里大量章节标题后面跟着「错误!未定义书签。」,这是 Word 目录域没更新导致的,不影响正文内容,但说明这份文档在发布前没做最终排版检查。读的时候以正文标题为准,别被目录页码带偏。另外文档 2.2 节里「设备处理状态」的页码也是未定义书签,实际内容在 2.2 节正文里,翻的时候直接看正文。
从那以后我每次拿到这类规格书,第一件事是把 1.4 的能力表和 5.x 的清单导成结构化表格,第二件事是把 2.x 的状态迁移表逐条写成单元测试,两件事做完再动手写业务代码,返工率能降一大截。希望帮到你。
本文还有配套的精品资源,点击获取