SECS/GEM协议入门:从HSMS到半导体设备自动化通信全解析

发布时间:2026/10/3 15:37:56
SECS/GEM协议入门:从HSMS到半导体设备自动化通信全解析 早几年我第一次进FAB做设备联机对着满屏的S1F13、S6F11和T3 Timeout差点崩溃。那时候我连SECS/GEM到底是单一协议还是一套标准都没搞清楚只隐约知道它是半导体设备接入产线的“门槛”。后来在几个项目里把SECS-I、SECS-II、HSMS、GEM四个层面的东西逐个啃完才敢说自己真正入了门。这篇文章就是想把这些年学SECS/GEM协议踩过的坑和整理出来的路线完整写下来适合刚接触设备自动化、需要对接设备商或准备自己实现通信模块的人。读完之后你至少能看懂设备日志、会用模拟器连上一台虚拟设备并知道自己下一步该学什么。1. SECS/GEM到底解决什么问题1.1 从一条产线的联机场景说起半导体制造和泛半导体制造光伏、面板、LED、锂电池等有一个共同特点产线上有成百上千台设备有光刻机、刻蚀机、沉积设备、清洗机、测试机各家设备来自不同厂商每台设备都要和上位的MES或EAP系统通信。MES要下发批次信息和工艺配方EAP要收集设备的实时状态和工艺参数设备发生报警时要第一时间上报并做出响应。如果每家设备厂商都用自己的私有协议集成商就得为每台设备单独开发一套对接程序工程量巨大而且设备换一个型号整套对接就要推翻重来。SECS/GEM就是为了解决这个混乱局面出现的。它把设备与上位机之间的通信方式、消息格式、业务流程统一起来让设备只要实现了这套标准就能以标准化的方式接入产线自动化系统。这也是为什么很多设备招标文件里会明确写“支持SECS/GEM”或者“必须支持GEM功能”。1.2 SECS/GEM不是一个协议而是一组协议我最早犯的认知错误就是把SECS/GEM当成一个独立的协议去查资料结果越查越乱。实际上它是由SEMI国际半导体产业协会发布的一整套标准组合核心包含四份规范标准编号名称作用SEMI E4SECS-I定义基于RS-232串口的物理通信协议SEMI E5SECS-II定义设备消息的格式、内容和数据类型SEMI E30GEM定义设备自动化相关的行为规范和状态模型SEMI E37HSMS定义基于TCP/IP的高速通信协议打个比方SECS-I/HSMS是“快递运输方式”决定消息怎么送到对方手里SECS-II是“信封和语法规则”决定信里写什么、用什么格式写GEM是“聊天礼仪和业务流程”决定双方什么时候能说话、说什么话才算合规。三层配合才构成完整的设备通信能力。只学SECS-II不学HSMS你发不出报文只学HSMS不学GEM你签了协议也不知道该做什么业务。1.3 哪些人在学、学到什么程度算会跟这个协议打交道的人主要是三类设备厂商的软件工程师要为自己的设备实现SECS/GEM通信模块通常用C、C或C#工厂自动化集成商和EAP开发工程师要编写上位机程序去连接设备、解析消息、处理事件和报警测试和现场服务人员要使用模拟器调试设备通信分析联机问题。“学到什么程度算会”这个问题我的标准很简单拿到一台新设备你能在半天内完成TCP连接、Select握手、S1F13建联、获取设备状态并能收发一条S6F11事件报告就算入门了。能基于一份SML文件SECS消息描述文件实现消息解析和生成、能处理GEM状态模型、能排查T3超时和消息不匹配的问题可以算中级。能在项目里设计一套完整的上位机通信框架支持多设备并发、断线重连、消息事务管理这是高级。大多数人卡在入门到中级之间原因是资料太散缺少一条连贯的学习路径。2. 核心协议分层把SECS/GEM拆成四层看2.1 传输层的两个分支SECS-I 和 HSMSSECS-I是这个协议族里最早出现的传输方式底层走RS-232串口半双工通信传得慢最大速度也就9600到19200波特率在旧时代够用但现在产线数据量上了个台阶串口早已跟不上。现在新设备除非是十多年前的老机型基本都支持HSMS也就是通过TCP/IP传输。HSMS以TCP连接为基础主机和设备之间建立一条长连接消息以帧为单位传输。典型实现中设备配置为被动端在一个固定端口上监听通常是5000、5001、5055、21000这些端口主机作为主动端发起TCP连接。也有的设备支持主动端模式由设备主动去连主机具体看配置。两者对比如下对比项SECS-IHSMS底层介质RS-232串口TCP/IP以太网通信模式半双工全双工典型速率9600/19200bps百兆/千兆网典型场景老旧设备当前绝大多数设备连接建立物理链路连接Select.req/Select.rsp握手现在学SECS/GEM重点放在HSMS上。串口的SECS-I可以只了解原理不用深究。原因很简单你找遍新设备也很难遇到需要写SECS-I的地方而HSMS的抓包、调试、模拟器支持都要完善得多。2.2 消息层SECS-IIStream、Function、W-bit和System BytesSECS-II定义了消息的语法。每条数据消息都由“Stream Function”共同标识写法是SxFy。Stream表示消息大类Function表示该大类下的具体功能。平时最常见的S1F1就是“Are You There?”主机问一句“设备你在吗”设备回S1F2告诉主机自己的状态和基础信息。S1F13是“建立通信请求”相当于双方正式说“我们开始干活吧”设备回S1F14。S5F1是报警上报S6F11是事件报告S7F3是工艺程序请求S2F41是主机命令下发。消息还分Primary和Secondary。Primary是主动发起的一方发出的消息Secondary是对方回应的消息。比如S1F1是PrimaryS1F2就是Secondary。Primary消息上会带一个W位W-bit也叫Request Reply位。W位置1表示要求对方必须回复W位为0表示不需要回复。还有一个容易被忽略但是非常核心的概念叫System Bytes也叫事务ID。每次发送Primary消息时发送方生成一个唯一的编号放进消息头里对方的Secondary回复必须带上相同的编号。这样通信双方才能把请求和回复对应起来。我在实际调试中见过不少新人在自己写的上位机里每次都把System Bytes写死为0结果设备回了几条消息后完全分不清哪条对应哪条这是很典型的问题。SECS-II的消息内容使用一种类似嵌套列表的结构描述最底层是各种数据类型。常见的SECS-II数据类型包括B二进制、AASCII字符串、BOOLEAN布尔、U1/U2/U4/U8无符号整数、I1/I2/I4/I8有符号整数、F4/F8浮点数、L列表。一个消息体就是一个L列表里面可以套L列表相当于树形结构。SML文件里看起来大概是这样S1F1 W . S1F2 L A SECS/GEM A TestDevice A V1.0.0 .同样一个消息在字节流层面会编码成一串二进制数据包含格式字节、长度字节、数据内容。刚开始不建议直接啃字节级编解码先能在SML层面看懂消息结构理解“谁发的、发给谁、Stream和Function是多少、携带什么参数”就够了。2.3 应用层GEM设备自动化的“业务逻辑”SECS-II管的是“消息怎么写”GEM管的是“设备该有什么行为”。一台只实现了SECS-II、不实现GEM的设备就像一个人会说英语但不知道怎么完成工作流程你问他一句他能答一句但你没法让他配合你完成复杂的自动化任务。GEM规范定义了设备必须具备的几类能力通信状态管理设备开机后要能建立TCP连接、完成Select握手、进入通信状态。控制状态管理设备有OFF-LINE、ON-LINE等控制状态主机只有在设备处于ON-LINE状态时才能下发远程指令。设备处理状态包括DISABLED、NOT_READY、READY、IDLE、EXECUTING等状态描述设备是否空闲、是否在加工。事件上报设备发生特定事件比如加工完成、开始加工、载具到达通过S6F11消息主动上报给主机。报警管理设备报警时用S5F1上报主机可以用S5F3/S5F4启用或停用报警。数据变量包括状态变量SV、数据变量DV、设备常数EC主机可以通过消息查询或设定这些变量。远程命令主机下发S2F41让设备执行一些动作比如开始加工、停止加工。配方管理通过S7系列消息完成工艺配方的上传、下载、选择、校验。GEM最有价值的地方在于状态模型。它把设备的通信状态、控制状态、加工状态拆成几个独立模型并以状态转移图明确规定什么情况下能从A状态跳到B状态、跳转时要发什么消息。很多联机问题本质上是状态机没对上主机以为设备还在READY实际设备已经因为某个报警掉到NOT_READY了主机直接发远程指令却忘了先检查设备是否ON-LINE。读完E30的状态图再回头看这些问题会清楚很多。3. 学习环境搭建用模拟器完成第一次对话3.1 工具准备学SECS/GEM最忌讳只读规范不动手。我建议看完上一章的分层概念后立刻搭一个最小实验环境。需要准备的东西不复杂一台电脑就够了装两个程序一个模拟设备端一个模拟主机端。设备端模拟器可以选带有GEM功能的SECS/GEM Simulator很多半导体设备厂商内部用的也是类似工具主机端可以用同一套模拟器里的Host模式也可以用专门的主机模拟程序。如果你愿意折腾后面自己写Python脚本也能当主机用。再配合Wireshark抓包就能把每一条消息的字节级结构看得清清楚楚。还需要准备一份SML文件或者设备消息手册。没有真实设备的时候可以从模拟器自带的示例SML文件入手里面定义了设备支持的消息集合、事件列表、变量定义。SML文件相当于是设备的“接口文档”学会读SML后面看真实设备手册会顺利很多。3.2 建立连接的完整过程拿最常见的HSMS连接来演示。假设设备端监听的IP是127.0.0.1端口5000Device ID配置为0。主机作为主动端连接过程分几步主机发起TCP连接到设备端口。主机发送HSMS Select.req控制消息请求建立HSMS会话。设备回复Select.rsp文本区第一个字节如果是0x00表示连接建立成功非0值表示失败。会话建立后双方可以定时发送Linktest.req和Linktest.rsp来检测链路是否还活着。接着主机发送S1F13 W请求建立SECS通信。设备回复S1F14携带设备型号、软件版本等基础信息。主机再发S1F1 W设备回复S1F2完成第一次状态查询。其中Select.req和Select.rsp是HSMS层的东西不属于SECS-II数据消息所以它们的Stream和Function都是0通过消息头里的SType字段区分。SType为1表示Select.req2表示Select.rsp5和6分别表示Linktest.req和Linktest.rsp0才是正常的数据消息。搞清楚这个分层关系是看懂抓包文件的关键。3.3 用Wireshark抓包看一次握手启动Wireshark过滤条件直接写tcp.port 5000就能看到完整的交互过程。你会看到TCP三次握手之后紧跟一个HSMS消息。展开这条消息可以看到Message Length字段、Session ID、Stream、Function、SType、System Bytes这些信息。我第一次看到Wireshark解析出的HSMS报文时最大的感受是原来看规范时觉得抽象的“消息头10字节”在抓包里这么直观。比如Message Length是29你会看到TCP负载里确实是29字节的HSMS内容其中10字节是消息头剩下19字节是文本区。以后你写代码解析报文反复对着抓包验证出错率会大幅下降。这里有个实用经验用自己的主机脚本和模拟器通信时建议同时开Wireshark抓包每条消息从自己代码里打日志看一遍、从抓包里再看一遍。两边对得上说明你的编码和解码逻辑基本没问题对不上就是排查的最好时机。4. 手写最小HSMS/SECS-II通信模块4.1 HSMS消息封装看完抓包再动手写代码理解就完全不一样了。这里用Python做一个最小实现只做两件事构造HSMS消息、建立连接并完成Select和S1F13握手。HSMS消息结构是4字节Message Length大端 10字节消息头 文本区。消息头里包括Session ID2字节、Stream1字节、Function1字节、PType/W位组合字节、SType、System Bytes4字节。注意Message Length算的是消息头和文本区的总长度不包括它自己这4字节。我第一次实现时这里搞错过消息发出去设备直接丢弃。import socket import struct import time def build_hsms_message(session_id, stream, function, system_bytes, textb, wbitFalse, stype0): # PType字节bit7是W位 ptype 0x80 if wbit else 0x00 # 10字节消息头 header struct.pack(HBBBB, session_id, stream, function, ptype, stype) header struct.pack(I, system_bytes) payload header text # 4字节Message Length header长度 文本长度 length len(payload) return struct.pack(I, length) payload def parse_message(data): # 取出Message Length然后解析消息头 length struct.unpack(I, data[:4])[0] header data[4:14] session_id struct.unpack(H, header[0:2])[0] stream header[2] function header[3] ptype_byte header[4] stype header[5] system_bytes struct.unpack(I, header[6:10])[0] text data[14:4 length] return { length: length, session_id: session_id, stream: stream, function: function, wbit: (ptype_byte 0x80) ! 0, stype: stype, system_bytes: system_bytes, text: text, }这段代码是纯手工拼字节没有依赖第三方库目的是让你理解消息结构。真正项目里可以用更完善的收发框架但核心就是这两件事打包和拆包。4.2 建立会话并完成S1F13/S1F1消息封装好后连接流程就顺理成章了。拆成几个小函数每个函数对应一个操作Select、Linktest、S1F13、S1F1。def select(sock, session_id0): # Select.reqSType 1 req build_hsms_message(session_id, 0, 0, system_bytes1, textb, wbitFalse, stype1) sock.send(req) resp recv_hsms(sock) if resp[stype] ! 2: raise Exception(不是Select.rspSType %d % resp[stype]) if resp[text][0] ! 0x00: raise Exception(Select失败原因码 0x%02X % resp[text][0]) print(Select成功) def send_s1f13(sock, device_id, system_bytes): # S1F13 W建立通信请求 req build_hsms_message(device_id, 1, 13, system_bytes, textb, wbitTrue, stype0) sock.send(req) resp recv_hsms(sock) if resp[stream] 1 and resp[function] 14: print(收到S1F14通信建立成功) return resp def send_s1f1(sock, device_id, system_bytes): # S1F1 W查询设备状态 req build_hsms_message(device_id, 1, 1, system_bytes, textb, wbitTrue, stype0) sock.send(req) resp recv_hsms(sock) if resp[stream] 1 and resp[function] 2: print(收到S1F2设备在线) return resp注意Select.req的Session ID一般填0而数据消息的Session ID要填设备配置的Device ID。这里System Bytes每次发送都要递增保证全局唯一。你可以用一个全局计数器维护它。握手成功后连接就算建立了这时才能发S1F13、S1F1这些SECS-II数据消息。4.3 理解事务与W-bit写过一遍收发逻辑对事务和W-bit的理解会更深刻。W位为1的消息对方必须回复所以你在代码里send之后立刻阻塞等回复W位为0的消息你发出去了就不该等回复如果傻等就会超时。System Bytes的作用此时也体现出来了多消息并发时你把System Bytes和请求内容存在一个字典里收到回复后根据System Bytes拿到对应的回调逻辑这就是一个简化版的事务管理器。很多开源SECS/GEM库之所以要抽象出一层Transaction本质就是在管理W位和System Bytes的配对。你完全可以在实际项目中先不用库而是自己维护一个{system_bytes: 请求信息}的字典配合一个接收线程不断解析消息、查找字典并分发结果。把这个机制跑通后再去用开源库你会秒懂它内部的设计思路。5. 学习中的高频问题和排查思路5.1 连接建立不了、Select失败最常见的现象是TCP能连上但Select.req发出去之后设备不回复或者回复的Select.rsp里原因码不是0。先检查设备日志确认设备端是否开启了SECS服务、监听端口是否正确、设备是否处于允许外部连接的模式。排查步骤我一般按照从底到顶来先确认网络能ping通、端口能通再确认设备配置的Device ID和Host侧配置一致接着抓包看Select.req发出后有没有TCP层RST最后看设备回复的Select.rsp原因码。如果设备回复的原因码是1通常表示“连接不合法”常见原因是Host配置的Device ID与设备不匹配原因码2表示“另一个Host已经连接”看看是不是有别的上位机占用了连接。5.2 消息发出去了对方没反应TCP正常、Select成功但发S1F13或S1F1后设备就是不回。这时候先看自己消息头构造得对不对尤其是Message Length和System Bytes。Message Length少算或多算1字节设备解析崩溃或者直接丢弃消息表现就是“对方没反应”。另外一定要检查W位。如果发了不带W位的Primary消息设备确实可能不回。还有一个常见低级错误把SType填成了0以外的值或者把Select.req当数据消息发了出去设备端会认为根本不是一个正常消息。这类问题用Wireshark抓包最直观先看自己的包是否正常发出再看设备是否回了TCP ACK但没回HSMS消息。只要确认自己发出的消息在抓包里解析正常就要去设备端查日志了。5.3 SECS-II解码总是报错消息收发都正常但解析S6F11事件报告时莫名其妙报错。我踩过最多的是长度字段和数据类型不匹配。比如设备发了一个U4类型的变量你按I4去解析设备发了一个长度100的ASCII字符串你只分配了10字节的缓冲区再比如L列表的子元素个数和定义对不上解析器的状态就会乱掉。最稳妥的解决办法是始终基于SML文件来写解析器。SML里定义了消息的参数树包括每个位置的类型和长度。解析时先根据SML定义拿到结构再去消息体里逐个匹配。遇到数据对不上的情况优先怀疑设备固件版本和SML版本不一致找设备厂商要最新的SML文件对比。5.4 状态机、事件总是对不上很多设备已经实现了SECS/GEM主机也能连上但业务场景跑不通原因多半出在GEM状态模型上。典型情况主机想远程启动设备直接发S2F41命令但设备当前处于NOT_READY状态甚至还没有进入ON-LINE状态命令自然不会执行。我建议在学习阶段就专门整理一份设备支持的事件列表和报警列表配合设备的状态模型图核对。设备在什么状态下会上报哪个事件、报警后要发什么指令才能恢复这些信息通常都在设备的用户手册或通信手册里。调试时不要凭感觉发消息先查状态再发命令。5.5 问题排查速查表现象可能原因排查方法TCP能连通Select无响应设备端未启动SECS服务、端口配置错检查设备配置和监听状态Select.rsp原因码非0Device ID不匹配、连接被占用核对Device ID检查是否已有Host连接数据消息发出无回复Message Length错误、W位没置1、System Bytes重复抓包看消息是否能被正确解析SECS-II解析报错数据类型/长度与SML定义不一致对照SML逐字段解析向设备商要最新SMLS2F41指令不执行设备未ON-LINE、状态机不匹配先查控制状态按状态机要求先切换状态事件上报缺失事件未启用、数据报告未配置使用S5F3/S6F?相关消息启用事件和报告断线后重连不上上一连接未正常释放设置Separate流程或等待设备端连接超时释放6. 学习路径建议和实战心得6.1 从通信到自动化的路线如果你完全零基础我建议的路径是这样的先把本文前面几章过一遍重点理解分层结构和消息模型然后利用模拟器完成一次完整的连接、建联、事件上报流程接着手写一遍最小HSMS消息封装让Socket层收发跑通再往前一步去读一份真实的SML文件把常见消息S1F13、S1F14、S5F1、S6F11、S2F41都在代码里实现一遍编解码最后回到E30规范精读状态模型和各类服务描述。这条路线最忌讳的是“先啃规范再动手”。规范比较枯燥没有上下文直接读会很痛苦。反过来先让设备“说出第一句话”再看规范会忽然明白很多概念。6.2 几个容易被忽略的原则不要试图把SECS/GEM学成“背协议号”。Stream和Function非常多靠背是背不完的也容易忘。真正有用的是知道去规范里哪里查、SML里怎么定义、设备手册里怎么说明遇到没见过消息时知道如何分析字段。不要以为开源库万能。开源库确实能封装大部分细节但实际设备不像教科书那么规矩。有的设备Device ID配置得很奇怪有的设备的S6F11格式和标准有细微出入有的设备对很多消息根本不回复数据区。所以就算用库也要保留抓包和手工解析的能力。不要把GEM等同于EAP。SECS/GEM只是设备和主机之间的通信和自动化接口EAP的逻辑通常要考虑工艺调度、配方管理、数据存储、报警联动远远超出协议本身。学协议的时候也要学一些制造执行系统的基础概念否则很难理解设备的业务行为背后到底在做什么。6.3 最后分享一个调试小习惯每次接到一台新设备我习惯先发S1F13获取设备信息和软件版本然后拉一遍设备的事件列表、报警列表、状态变量清单整理成一张EXCEL表再和手册逐项对照。这个过程看起来慢但做完之后后续调试效率会提升很多。不要一上来就急着测S6F11、S2F41先摸清设备“支持什么”“默认状态是什么”“事件ID和变量ID怎么定义”后面踩的坑至少少一半。如果你正打算走这条技术路线记住最核心的一句话不要只盯着报文先把设备和主机之间的关系想清楚再回到报文里找对应。SECS/GEM不难难的是没人给你把散落的知识串成一条线。希望这篇文章能帮你把那个线头找到。