简介:这份PDF文档面向半导体设备自动化领域的工程师与开发人员,系统讲解SECS/GEM(SEMI设备通信标准/通用设备模型)规范及其在设备与主机系统数据交互中的应用,帮助读者理解不同厂商设备如何实现互操作与标准化通信。文档以广州金南瓜科技的实施方案为蓝本,涵盖通讯状态模型、控制状态模型与设备处理状态,并逐项展开主机发起场景、事件通知、在线识别、动态事件报告配置、变量与跟踪数据采集、报警管理、远程控制、设备常数及过程程序管理等设备能力,同时涉及TCP/IP通讯超时与变量命令实现等细节。资源包仅含1个PDF文件,大小约1006KB,目录结构完整、章节划分清晰,便于按模块查阅与对照实施。目前已有746人学习,适合需要快速掌握SECS/GEM接口规范、搭建设备通信方案或进行二次开发的技术人员参考。
1. 通讯状态机:为什么设备上电后不是立刻就能收消息
很多人第一次接触 SECS/GEM,会默认「TCP 连上了就能发消息」。真到产线上跑一遍就会发现,网线插好、ping 通、端口也开着,主机发过去的 S1F1 却石沉大海。这不是玄学,而是 SECS/GEM 在 TCP 之上又叠了一层自己的状态机:链路通只是物理前提,通讯状态机没走到 COMMUNICATING,设备在协议层面就是「聋」的。
这份规格说明书把状态模型放在正文最前面(第 2 章),而不是先讲消息格式,本身就是一种态度:SECS/GEM 的难点不在报文长什么样,而在「什么时候允许发、发了对方认不认」。搞懂通讯状态模型和控制状态模型这两台状态机,你才能解释产线上大量「连上了但不通」「通了但不让控」的怪现象。下面从状态机的设计动机一路拆到 S1F13/F14 的握手细节。
2. 通讯状态模型:ENABLED 之下为什么还藏着两层子状态
2.1 DISABLED 与 ENABLED:一个被低估的开关
规格书对 DISABLED 的定义很硬:在此状态下,SECS-II 与主机不存在通信,操作员从 ENABLED 切到 DISABLED,所有 SECS-II 通信立即停止。注意「立即」两个字——它不是等当前事务做完再停,而是直接掐断。这个设计动机很实际:产线上设备要进入维护、要换配方、要做安全联锁时,工程师需要一个确定性的「协议静默」手段,而不是靠拔网线这种物理操作。
ENABLED 是系统默认值(规格书原文说 DISABLED 也是「可能的系统默认」,取决于设备厂商配置),它本身不直接通信,而是分出 COMMUNICATING 和 NOT COMMUNICATING 两个子状态。这里有个容易翻车的点:进入 ENABLED 后,设备并不会自动进入 COMMUNICATING,而是先落在 NOT COMMUNICATING,等正式建链完成才迁移。换句话说,ENABLED 只表示「允许通信」,不表示「已经通信」。
常见的实现思路是把这两个状态映射成设备内部的两个布尔量:commEnabled和commEstablished。前者由操作员或配置决定,后者由握手结果决定。主机侧如果只看 TCP 连接状态就判断设备在线,就会踩到「连接在、状态没到」的坑。
2.2 NOT COMMUNICATING 的两个 AND 子状态
规格书用 Harel 记法画状态图,NOT COMMUNICATING 下有两个 AND 子状态:HOST-INITIATED CONNECT 和 EQUIPMENT-INITIATED CONNECT,而且强调「当设备不通信时,这两个子状态都是有效的」。AND 状态意味着两者并行活跃,不是二选一。
这背后的机制是:SECS/GEM 允许双向发起建链。主机可以主动发 S1F13 来建链(HOST-INITIATED 分支,进入 WAIT CR FROM HOST),设备也可以主动发 S1F13(EQUIPMENT-INITIATED 分支,进入 WAIT CRA / WAIT DELAY 循环)。两条路径并行等待,谁先成功谁就把状态推到 COMMUNICATING。这种设计是为了兼容不同 fab 的运维习惯——有的厂主机侧统一调度建链,有的厂希望设备上电就自己喊话。
设备主动分支里有个定时器机制值得细看。规格书的状态迁移表写得很清楚:
| 迁移 | 当前状态 | 触发 | 新状态 | 动作 |
|---|---|---|---|---|
| 5 | 进入 EQUIPMENT-INITIATED CONNECT | 任何进入 NOT COMMUNICATING | WAIT CRA | 初始化通信、CommDelay 置「过期」、发 S1F13 |
| 6 | WAIT CRA | 连接事务失败 | WAIT DELAY | 启动 CommDelay 定时器、清空发送队列、必要时转入 spool 缓冲 |
| 7 | WAIT DELAY | CommDelay 超时 | WAIT CRA | 发 S1F13,等 S1F14 |
| 8 | WAIT DELAY | 收到非 S1F13 消息 | WAIT CRA | 丢弃消息、不回复、CommDelay 置过期、发 S1F13 |
| 9 | WAIT CRA | 收到 S1F14 且 COMMACK=0 | COMMUNICATING | 建链完成 |
这张表里藏着两个设计取舍。第一,失败后不是立刻重试,而是进 WAIT DELAY 等定时器,避免设备在主机没起来时疯狂刷 S1F13 把网络打爆。第二,迁移 8 特别有意思:在 WAIT DELAY 期间收到任何非 S1F13 的消息,设备会丢弃且不回复,然后立刻转回 WAIT CRA 重发 S1F13。这相当于把「收到杂音」当成「链路可能已通」的信号,主动抢一次建链机会。血泪经验是:如果你在调试时看到设备反复发 S1F13 而主机侧日志里有一堆被丢弃的消息,多半是主机在设备还没建链时就急着发业务消息了。
2.3 S1F13/F14 握手:COMMACK 才是通行证
建链的核心事务是 S1F13(Establish Communications Request)和 S1F14(Establish Communications Acknowledge)。规格书迁移 9 和迁移 15 都强调:只有收到 S1F14 且 COMMACK=0,才进入 COMMUNICATING。COMMACK 非 0 表示拒绝,设备要继续等。
这里有个源码级的细节值得说透。S1F13 的报文体通常携带 MDLN(设备型号)和 SOFTREV(软件版本),主机收到后据此判断是不是自己要管的设备。S1F14 的 COMMACK 是二进制值,0 表示接受。常见的实现思路是设备侧维护一个建链事务 ID,收到 S1F14 后先校验它是不是对本次 S1F13 的回复,再校验 COMMACK,两个都过才迁移状态。如果只校验 COMMACK 不校验事务对应关系,在重发场景下可能把上一轮的迟到回复当成这一轮的确认,状态机就乱了。
用伪代码表达设备侧 WAIT CRA 的处理逻辑,大致是这样:
# 设备侧 WAIT CRA 状态处理(示意) def on_message(msg, state): if state == "WAIT_CRA": if msg.stream == 1 and msg.function == 14: # 先校验是否对应当前建链事务,再校验 COMMACK if msg.system_bytes.transaction_id == current_s1f13_tid: if msg.body.COMMACK == 0: transition_to("COMMUNICATING") else: # 被拒绝,回到等待重试 start_comm_delay_timer() transition_to("WAIT_DELAY") elif msg.stream == 1 and msg.function == 13: # 双方同时发起建链,回 S1F14 接受 send_s1f14(commack=0, tid=msg.system_bytes.transaction_id) transition_to("COMMUNICATING")这段逻辑里current_s1f13_tid是设备每次发 S1F13 时记录的 System Bytes 事务号,SECS-II 消息头里的这个字段就是用来做请求-应答配对的。参数COMMACK是 S1F14 消息体里的一个二进制项,取值 0 接受、非 0 拒绝。很多自研实现省掉了事务号校验,单机测试看不出问题,一上多主机或网络抖动场景就开始出现「状态机跳变但业务不通」的怪象。
3. 控制状态模型:OFF-LINE 为什么还回消息
3.1 OFF-LINE 的「有限响应」策略
控制状态模型定义主机和设备之间的协作级别。规格书对 OFF-LINE 的描述是:设备对主机发来的任何 primary message 都回 Sx,F0,但 S1F13 和 S1F17 例外——这两个会正常处理和响应。
这个设计初看反直觉:既然离线了,为什么还理人?原因是 OFF-LINE 不等于 DISABLED。DISABLED 是协议层静默,OFF-LINE 是控制层「我不接受你的业务指令,但我还在线,还能建链、还能被请求上线」。S1F17 就是主机用来请求设备切到 ON-LINE 的消息。如果 OFF-LINE 时连 S1F17 都不理,主机就永远没法把设备拉回在线,只能靠人去现场按按钮,这在全自动产线上是不可接受的。
Sx,F0 是 SECS-II 里的「Abort Transaction」回复,表示「我收到了但我不处理」。设备回 Sx,F0 而不是沉默,是为了让主机侧的事务能正常结束、释放等待资源,避免主机侧超时堆积。这个细节体现的是协议设计里的「礼貌拒绝」原则:拒绝也要给回执。
3.2 ON-LINE 与 LOCAL/REMOTE 的叠加
控制状态模型在 ON-LINE 之下通常还叠加 LOCAL 和 REMOTE 两个子状态(规格书正文因目录错位未完整展开,但这是 GEM 标准 E30 的通用模型)。REMOTE 表示主机可以下发远程命令,LOCAL 表示操作员在设备面板上接管,主机只能读不能控。
常见的实现思路是把控制状态做成一个二维状态:online_state ∈ {OFFLINE, ONLINE}与control_mode ∈ {LOCAL, REMOTE}的组合。远程控制消息(比如 S2F41 Host Command Send)在 OFFLINE 或 LOCAL 下都应该被拒绝,但拒绝方式不同:OFFLINE 回 Sx,F0,LOCAL 通常回带错误码的 S2F42。这个区别在排查「主机发了命令设备没动」时非常关键——看回复是 F0 还是带 HCACK 的 F42,就能定位是控制层没上线还是本地模式没切远程。
3.3 状态迁移的时序约束
控制状态迁移不是瞬时的。规格书在场景章节(第 7 章)里给了 Host Sets ON-LINE、Host Sets OFF-LINE、Host Accepts ON-LINE 等场景,每个场景都是一次完整的消息往返。以 Host Sets ON-LINE 为例,主机发 S1F17,设备回 S1F18 带 ONLACK,ONLACK=0 表示接受。如果设备当前在 LOCAL 模式,ONLACK 可能返回非 0 表示拒绝,主机需要先协调操作员切模式。
这里有个时序约束容易被忽略:设备从 OFF-LINE 切 ON-LINE 的过程中,可能还有在途的 Sx,F0 回复没发完。合格的实现会在状态迁移前把待发队列处理干净,或者给迁移加一个短暂的静默窗口。我见过有实现直接改状态标志位,结果主机侧收到「ONLACK=0 之后又来一个 Sx,F0」,事务配对直接错乱。
4. 事件报告与数据采集:动态配置背后的三层结构
4.1 为什么报告要「动态」配置
GEM 的事件报告不是设备写死一堆消息往主机推,而是主机先定义「哪些变量、在什么事件发生时、打包成什么报告」推给设备,设备按这个配置来发。规格书第 3.4 节 Dynamic Event Report Configuration 和第 5 章变量实现就是讲这套机制。
设计动机很直接:同一条产线上,不同工序、不同产品对数据的需求不一样。刻蚀工序关心腔体压力和 RF 功率,薄膜工序关心气体流量和温度。如果设备固件把报告格式写死,换产品就得改固件,这在半导体厂是不可能的。动态配置把「采什么」的决定权交给主机侧,设备只负责执行。
这套机制在 SECS-II 里由三层结构支撑:报告(Report)、事件(Collection Event)、变量(Data Variable / Status Variable)。主机通过 S2F33 定义报告里包含哪些 VID(变量 ID),通过 S2F35 把报告挂到某个 CEID(事件 ID)上,通过 S2F37 使能/禁用事件。设备侧收到配置后,在对应事件触发时按报告定义打包数据,用 S6F11 推给主机。
4.2 S2F33/S2F35/S2F37 的配置语义
S2F33 Define Report 的报文体是一个列表,每项包含 RPTID 和一组 VID。这里有个语义细节:S2F33 是「全量定义」还是「增量定义」取决于实现,规格书通常要求设备支持全量替换语义——主机发一次 S2F33,设备侧的报告定义就完全以这次为准,之前没提到的报告作废。这个语义如果不明确,主机侧做增量更新时会出现「旧报告残留」的问题。
S2F35 Link Event Report 把 RPTID 和 CEID 关联起来,一个 CEID 可以挂多个 RPTID,设备在事件触发时把多个报告合并发送。S2F37 Enable/Disable Event Report 控制 CEID 的开关,带一个 CEED 列表。这三条消息的应答都是对应的 F34/F36/F38,带一个 ACKC6 或类似的状态码。
用表格把这三层的关系理一下:
| 消息 | 作用 | 关键参数 | 设备侧存储结构 |
|---|---|---|---|
| S2F33 | 定义报告内容 | RPTID、VID 列表 | report_def: RPTID -> [VID] |
| S2F35 | 报告挂到事件 | CEID、RPTID 列表 | event_link: CEID -> [RPTID] |
| S2F37 | 使能/禁用事件 | CEED、CEID 列表 | event_enabled: CEID -> bool |
设备侧收到 S6F11 触发时,先查event_link[CEID]拿到报告列表,再对每个 RPTID 查report_def拿到 VID 列表,逐个取值打包。这个查表过程在事件高频触发时是性能热点,常见的优化是把三层结构在配置变更时预编译成一张扁平化的「CEID -> [VID]」映射,事件触发时直接遍历。
4.3 Trace 与 Status 数据的区别
规格书把数据采集分成 Variable Data Collection、Trace Data Collection、Status Data Collection 三类。变量数据是事件驱动的,事件发生才采;Trace 数据是周期性的,主机通过 S2F23 设定采样周期和总次数,设备按周期用 S6F1 推送;状态数据是主机主动查询,用 S1F3/S1F4 拉取。
这个分类对应三种不同的产线需求:事件数据用于追溯「某一刻发生了什么」,Trace 数据用于工艺曲线分析(比如温度随时间变化),状态数据用于主机侧做设备健康监控。实现上,Trace 需要一个独立的定时器线程,和事件线程解耦,否则高频 Trace 会拖慢事件响应。踩过的坑是:把 Trace 采样放在事件循环里做,结果 Trace 周期设到 100ms 时,S6F11 事件推送延迟肉眼可见地涨。
5. 避坑与排查:SECS/GEM 联调中最常见的五个翻车点
5.1 现象:TCP 通、S1F1 无响应
原因:通讯状态机停在 NOT COMMUNICATING,设备在协议层不处理业务消息。TCP 连接只代表 HSMS 层通了,SECS-II 层的建链握手(S1F13/F14)没完成。
解决:抓包看有没有 S1F13 发出、有没有 S1F14 回来。如果设备侧一直发 S1F13 但主机不回,检查主机侧 HSMS 是否把 S1F13 当成业务消息路由到了错误的分发器;如果主机回了 S1F14 但 COMMACK 非 0,检查主机侧的设备白名单配置。
5.2 现象:S2F41 远程命令发了,设备回 S2F42 但 HCACK 非 0
原因:控制状态不在 REMOTE。设备可能在 LOCAL 模式,或者虽然 ON-LINE 但操作员在面板上切了本地。
解决:先发 S1F3 查状态变量里的控制模式,或者看 S2F42 的 HCACK 具体值。常见实现里 HCACK=1 表示命令不存在,HCACK=2 表示当前状态不能执行,HCACK=4 表示参数错误。对照规格书第 5.6 节主机命令实现里的命令清单,确认命令名拼写和参数个数。
5.3 现象:S6F11 事件推送了,但主机侧解析出的变量值全是默认值
原因:S2F33 定义报告时 VID 写错,或者设备侧 VID 表里没有这个 ID,设备按「未知变量返回默认值」处理。
解决:先发 S1F11(Data Variable Namelist Request)拉设备侧支持的 VID 清单,和主机配置比对。规格书第 7.3.1 节 Data Variable Namelist Request 场景就是干这个的。注意 S1F11 的应答 S1F12 里每个变量带单位、默认值、上下限,主机侧应该用这份清单做配置校验,而不是手写 VID。
5.4 现象:Trace 数据周期不准,越跑越慢
原因:Trace 采样和事件处理共用线程,或者采样定时器用了非单调时钟,系统时间调整时周期漂移。
解决:Trace 用独立线程加单调时钟(monotonic clock),采样周期从上次采样完成时刻算起而不是从固定时间点算。规格书第 3.6 节 Trace Data Collection 对采样语义有要求,实现时把 S2F23 的 TOTAL 计数和周期分开管理,TOTAL 到 0 自动停。
5.5 现象:报警发了 S5F1,主机侧没收到,但设备日志显示已发送
原因:报警使能状态没同步。GEM 的报警管理有 enable/disable 机制(S5F3/S5F4),设备侧如果默认全部禁用,S5F1 就不会真正推出去。
解决:主机侧启动时先发 S5F3 使能需要的 ALID,或者查 S5F5 确认当前使能状态。规格书第 7.4.1 节 Enable/Disable Alarms 场景给了完整流程。另一个可能是报警在 OFF-LINE 时触发,设备按控制状态模型回了 Sx,F0 而不是 S5F1,需要确认触发时刻的控制状态。
6. 设计取舍:为什么 SECS/GEM 把复杂度放在状态机而不是消息格式
回头看这份规格说明书的结构,第 2 章状态模型、第 3 章设备能力、第 4 章通讯协议、第 6 章消息类型、第 7 章场景,消息格式(第 6 章)反而排在状态模型后面。这个排序不是随意的,它反映了 SECS/GEM 的核心设计哲学:消息格式是死的,状态机是活的。
SECS-II 的消息格式本身很朴素——Stream/Function 编号加一个自描述的数据项树(L/A/B/BOOLEAN/I/F 等格式码),第 6.2.1 节的 Data Item Dictionary 把每种格式的长度编码规则写清楚就完了。真正让不同厂商设备能互操作的,是状态机对「什么时候允许发什么」的约束。通讯状态机保证双方对「链路是否可用」有共识,控制状态机保证双方对「谁有权控制」有共识,事件报告的三层结构保证双方对「采什么数据」有共识。这三层共识建立起来,消息格式的差异反而是最容易适配的。
这个取舍的代价是状态机的实现复杂度高。一个合格的 GEM 接口要实现通讯状态机的 15 条迁移、控制状态机的多组场景、事件报告的三层配置,还要处理各种超时和重试。规格书第 4.1 节 TCP/IP 通讯超时只给了一个 EstablishCommunicationsTimeout 的 ECID,实际实现里还需要 T3(回复超时)、T5(连接分离超时)、T6(控制事务超时)、T7(未选择超时)、T8(网络字符间超时)等一组定时器,这些在 SEMI E37 里有定义,规格书正文没展开但实现时绕不开。
我一般会这么理解:SECS/GEM 的复杂度不是设计缺陷,而是半导体制造对「确定性」的要求倒逼出来的。产线上设备停机一分钟的损失,远大于接口实现多写几千行状态机代码的成本。所以协议选择把复杂度前置到状态机,换取运行时的可预测性。
验证一套 GEM 实现是否合格,我的习惯是拿规格书第 7 章的场景清单逐条走:建立通讯的两个方向、动态事件报告配置、变量和事件清单请求、报警使能与上报、远程命令、设备常数读写、处理程序上下载、终端服务、时钟同步、控制状态切换。每条场景都要求抓包确认消息序列和状态迁移对得上,而不是只看「功能能用」。从那以后我每次接手新的 GEM 接口联调,都强制先把通讯状态机和控制状态机的迁移表打印出来贴在显示器边上,每收到一条消息先对状态再对格式。希望帮到你。
本文还有配套的精品资源,点击获取