开头就先说点实在的。
SECS/GEM这套协议在半导体工厂里永远是那个“看不见但离不开”的角色。前一篇我们讲了它是什么、能干什么,这篇直接往深处挖:从物理端口到SECS-II消息结构,从GEM状态机到GEM300的FDC数据采集,再加上EAP在和设备对话时到底在忙些什么。如果接下来要对接设备、写EAP侧逻辑、或者排查通讯故障,这篇应该能帮你把整个协议层的骨架搭起来。
我自己刚接触这块的时候,最大感受是:文档里全是缩写,每个缩写背后又套着一层协议,根本不知道从哪看起。后来啃协议、抓报文、被现场故障折腾过几轮,才算把“物理链路—消息封装—状态机—业务语义”这条线走通。这篇文章就按这条线来写,尽量用实际报文和典型场景说话,少堆概念。
1. 底层通讯:HSMS和SECS-I,数据怎么从设备到主机
1.1 先分清两条物理链路
协议层之下就是传输层。SECS/GEM最常见的有两种物理传输方式:
- SECS-I:基于RS-232串口,半双工,波特率通常在9600到38400之间,现在老设备或某些特殊场景还在用,调试麻烦,速度也慢。
- HSMS:基于TCP/IP,全双工,现代工厂绝对的主流。默认端口是5000和5001,一收一发,支持长连接,吞吐量和稳定性都远超串口。
在HSMS里,TCP连接建立之后,报文不是裸着发,而是套一个固定格式的消息头。这个消息头一共10个字节,结构如下:
- Session ID(2字节):逻辑会话编号,告诉对端消息属于哪条会话,通常设备ID就在这里面,高四位还要拼上控制标志位。
- Header Byte 2(1字节):包含Message Type和Session Type。比如Select.req消息类型是0x01,Data Message是0x09。
- PType(1字节):协议类型,SECS-II取值0。
- SType(1字节):会话类型,0表示SECS-II数据消息,非0表示控制消息。
- System Bytes(4字节):消息ID,用于把请求和响应配对,排查问题的时候特别关键。
这里有个点容易忽略:TCP只是保证了字节流,但SECS消息有明确的边界和长度字段。HSMS每个报文最前面是4个字节的Message Length,表示后面跟着多少字节的Header加Data。这个长度字段如果解析错了,整个数据流就全乱了,所以EAP侧解析器第一步一定是严格校验长度和Header里的细节,不能想当然。
1.2 为什么必须区分Select/Reject/Linktest
HSMS不是TCP一连上就直接传SECS-II数据的。连接建立后,先走一遍会话建立流程,基本是“选择—响应—确认”的节奏:
- 主动方发Select.req。
- 被动方回Select.rsp。
- 主动方再发一个Data消息或直接进入正常通讯。
这套流程本质是“握手”。虽然TCP也握手,但HSMS的握手是解释“你要用哪些Session ID来跑SECS-II”,相当于业务层确认。Select.rsp里会带一个状态码,0表示成功,其他值都是错误原因。
连接建立后还有个非常容易被忽视的机制:Linktest。链路不能光靠TCP的心跳,SECS标准里规定通常每45秒到2分钟要发一次Linktest.req,对方回Linktest.rsp。如果连续几次没收到响应,就判定链路断开,需要重新Select。做过现场的人应该懂,很多设备状态显示Online,但实际数据全断,八成就是Linktest超时后重连逻辑没处理好。
调试的时候我自己习惯抓三层包配合看:先看TCP层有没有重传,再看HSMS的SType和System Bytes能不能对上,最后才是SECS-II消息本身。如果系统里出现大量重发消息,先别怀疑应用逻辑,查链路和超时参数往往是更高效的路径。
1.3 端口选择的讲究
标准端口是TCP 5000和5001,但实际部署里不一定非得这两个。有些设备用任意的自定义端口,有些EAP只能配置单个IP加端口。这里常见的坑有两个:
- 设备只监听一个端口,主机侧却配置了双向连接,导致一组连接一直连不上。
- 防火墙只放行了5000,设备却改用了5001,结果Select一直不成功。
所以对接初期先把端口和连接方向确认清楚,再谈报文。端口这块我踩过不止一次,有一次是设备配置错误,端口被改成了6000,EAP这边按5000去连,抓包看了半天才发现是端口不通。单纯看日志只能看到“Connection Refused”,非常迷惑人。
2. SECS-II消息:Stream和Function怎么配合
2.1 Stream/Function就是“大类和具体指令”
SECS-II把消息按Stream(S)和Function(F)分类,写法就是SxFy。比如S1F1是“Are You There”,S1F2是“On Line Data”,S6F11是“Event Report”,S2F41是“Host Command”。Stream相当于类别,Function相当于这个类别里的具体动作。
每个Stream的含义基本固定:
- S1:设备状态、通讯控制。
- S2:设备控制和诊断。
- S5:报警。
- S6:数据上报。
- S7:配方管理。
- S10:终端显示。
- S12:晶圆地图。
- S15:配方管理扩展。
- S16:FDC数据采集。
S1F1这种消息不光要发STM,还要带System Bytes。S1F1发过去之后,设备必须回复S1F2,即使没有数据,也要回一个空LIST。
这里有一个容易混淆的点:SECS里和“指令”相近的词有Primary Message、Reply Message、Secondary Message。Primary Message是主动发起的,Reply Message是回应Primary的。一条Primary消息可以对应多条Reply。SxFy中的F,单数一般是Primary,双数一般是Reply,这个规律适用于绝大多数消息,但不是绝对。
2.2 消息结构拆解:Header后面的Data才是重点
SECS-II消息的Header是固定的10字节,Data部分用特定格式编码。这里拿一个真实场景举例:
设备在线后,EAP发起S1F1查询:
00 00 00 0B 00 01 00 00 00 00 00 00 01 01 01 01拆开看是这样:
00 00 00 0B:Message Length,表示后面有11字节。00 01:Session ID,这里是1。00:Header Byte 2,表示Stream=1、Function=1、W-bit=0。00:PType=0。00:SType=9,表示SECS-II Data Message。00 00 00 01:System Bytes,这条消息的ID为1。
后面的Data部分就是一个Item。Item的结构分为:Format Code、Length、Value。具体来说:
01:Format Code=1,表示LIST。01:Length=1,表示LIST里有一个元素。01:Format Code=1,但这一层是L/B空列表?不对,这里要小心,格式码1是LIST,格式码2是BINARY等。实际数据取决于设备。
严格说,S1F1不带Body时,Data部分就是一个空LIST,有些实现甚至Data长度为0,只发Header。标准要求S1F1的Body是LS,,我见过有些EAP对空Body处理不够健壮,S1F1发出去后如果设备回了带异常内容的S1F2,解析就会崩。所以在解析器层面一定要做“预期外数据容忍”处理,不能假设所有回复的LIST结构都和文档完全一致。
常见Format Code如下:
- 0:LIST,最常用。
- 1:BINARY,1字节无符号整数。
- 2:BOOLEAN。
- 3:ASCII字符串。
- 4:INT8。
- 5:INT16。
- 6:INT32。
- 7:INT64。
- 8:UINT8。
- 9:UINT16。
- 10:UINT32。
- 11:UINT64。
- 12:FLOAT4(32位浮点)。
- 13:FLOAT8(64位浮点)。
解析LIST时要注意嵌套层级和长度,很多解析bug就出在这里。比如以为某个字段是固定位置,结果前面多了一个可选Item,整个索引就全错位了。
2.3 W-bit的妙用
SECS-II Headers里有一个W-bit(Wait-bit),用来指示设备:收到这个Primary消息之后,是否需要回复。一般W-bit=1时,消息需要回复;W-bit=0时,不一定需要,但大多数情况还是回。
W-bit最有价值的应用场景是Host Command(S2F41)。比如EAP下发一个“Start Process”命令,可以把W-bit设成1,要求设备处理完以后用S2F42回复命令执行结果。这样EAP就能判断命令是被接受还是被拒绝,以及执行状态是否完成。如果不带W-bit,或者设备实现得不严谨,命令有没有执行成功完全靠猜,那后面产线就有得折腾了。
TT(T3/T5/T6)这些超时参数的关注点也在这里。发送S2F41之后,如果设备没有在期望时间内回S2F42,EAP侧要能识别并做超时处理。有些设备处理命令本身就慢,比如需要几秒钟才能完成的动作,超时时间设得太短会一直误报,设太长又会拖累异常发现速度。一般T6的推荐值是5秒,但实际要根据设备类型调整。
3. GEM标准:设备必须具备的“行为规范”
3.1 GEM不是新协议,而是“设备必须做到什么”
GEM(Generic Equipment Model)不是独立的协议,它是建立在SECS-I/II之上的功能标准,规定了半导体设备向主机暴露哪些能力。也就是说,SECS-II定义了消息格式,但设备什么时候发、怎么回、状态怎么变,是由GEM约束的。
核心要点包括:
- 状态模型:设备有Offline/Online状态,Online里又分Local和Remote。
- 事件报告:设备发生重要行为(如Process Start、Recipe Start/End、Alarm Set/Clear)时,要主动发S6F11事件报告。
- 变量采集:设备提供设备变量和状态变量,EAP通过S1F3/S1F4等消息查询或订阅。
- 报警管理:设备产生报警时,通过S5F1发报警消息,清除时发S5F2。
- 远程命令:EAP通过S2F41下发命令,设备执行后S2F42回报。
- 配方管理:GEM300中通过S7Fxx等消息进行配方处理。
状态模型里最经典的几个状态:
- Offline:设备在本地模式,不接受远程控制。
- Online-Local:在线但本地操作,可以上报数据,但不能远程控制。
- Online-Remote:完全远程控制,EAP可以直接下命令。
注意,有一种情况是Equipment本身处于Online,但控制状态还是Local。这种情况下,有些命令设备会拒绝,所以EAP必须先查询状态,再决定是否下发命令。有些设备实现里,ControlState的切换要通过S1F17/S1F18这类消息来设置,不能直接在SE里改。
我在现场遇到过一台设备,从设备面板切到Auto之后,EAP里状态迟迟不变。排查了老半天,结果不是EAP问题,也不是插件问题,而是设备只在某些条件下才上报On-Line状态。这就说明GEM事件模型里每个状态转换都不是必然上报的,EAP侧最好用周期性的S1F1/S1F3查询兜底,别完全依赖事件。
3.2 事件报告S6F11是怎么组织的
S6F11格式是:
S6F11 organized as: <L <DATAID> // 报告ID <L <DATAID2> // 比较ID <RPTID1> // 报告ID1 <L ...DVVAL...> // 变量值 > >实际解析时有点绕。第一个DATAID是给整条Event Report的唯一标识,第二个DATAID是这个event里第一个Report的比较ID,RPTID指向报告模板,后面的LIST是具体变量值。S6F11里可以带多个Report,所以嵌套层数很深,代码里处理递归List结构要特别小心。
举个例子,一个Process Start事件,报告里可能带:
- 设备时间戳。
- 当前Recipe ID。
- 当前Slot ID。
- Process腔体压力。
- 腔体温度。
这些变量的顺序和类型由设备的Report配置决定。EAP侧解析S6F11时,必须知道每个RPTID对应的变量排列,不然拿到一串值也看不懂。
3.3 变量查询S1F3/S1F4
S1F3用来查询设备变量或状态变量。发S1F3时,Body是一个LIST,里面可以混合设备变量(DVVAL)和状态变量(SV)。设备回S1F4,把每一个变量的ID和值都返回回来。
格式如下:
S1F3: <L <DVVAL1> <DVVAL2> <SV1> > S1F4: <L <L <DVVAL1> <value1> > <L <DVVAL2> <value2> > <L <SV1> <value1> > >这个查询看似简单,但在大产线上有个性能问题:一台设备几百个变量,频繁查询会占用大量链路带宽。所以GEM里定义了“数据收集”(Data Collection)机制,通过S2F33/S2F34等消息配置采集周期和采集组,设备按配置定时上报,EAP就省了查询开销。
4. GEM300扩展:FDC、APC和配方管理
4.1 FDC:数据采集是实时监控的关键
GEM300不是独立协议,是SEMI E5、E37、E39、E40、E87等标准的集合,主要面向300mm晶圆工厂的需求。它最大的特点是引入了面向晶圆的数据追踪能力。
FDC(Fault Detection and Classification)就是通过S2F41/S6F11等消息,把设备的腔体压力、温度、气体流量、RF功率等高频数据采集到主机侧,用于异常检测和分类。采集参数的关键项有:
- 采集范围:一个或多个腔体。
- 采集周期:毫秒级到秒级不等,取决于参数变化速度和检测要求。
- 采集触发:通常绑定到Process Start事件。
FDC采集的数据量非常大,一条Process可能持续几分钟,每秒采集多个参数,一个批次下来就是海量数据。EAP侧要能及时处理这些上报,不能阻塞,也不能丢失。一般建议用异步队列接收FDC上报,数据处理放到专用线程池,接口层只负责快速解析和入库。
4.2 APC:过程控制闭环
APC(Advanced Process Control)更多体现在主机侧逻辑,不是协议本身的强制内容。常见实现方式是:设备上报FDC数据后,APC模块通过分析模型计算下一步的工艺参数调整量,再通过S2F41下发调整后的Recipe或参数。
这个闭环要求通讯延迟非常低。从设备事件发生到APC计算结果回写到设备,整个链路通常在几秒内必须完成。如果中间任何一个环节阻塞,工艺就会跑偏。所以EAP侧不光要处理消息,还要关心消息通道的优先级。一般建议把S6F11这种事件消息和S2F41这种命令消息放在同一个连接,但要通过业务层的优先级排队机制保证命令不被海量FDC上报挤压。
这一块在生产上是最容易遇到性能瓶颈的。设备在Process中一秒上报几十条FDC数据,EAP如果每条都同步处理,CPU占用会很高。我自己的做法是:消息解析和业务处理彻底分离,解析完直接放入环形队列,业务线程批量消费,数据库插入走批量提交,实测能扛住每秒几百条消息的负载。
4.3 配方管理:R2D是重点
GEM300里配方管理通过S7系列消息实现,包括:
- S7F1:请求配方列表。
- S7F3:请求当前配方ID。
- S7F5:请求配方内容。
- S7F19:配方确认和校验。
- S7F21:配方删除。
- S7F23:配方存档和加载。
实际业务里,主机下发一个配方通常不是直接把整个文件丢给设备,而是先通过EAP把配方内容拆成标准格式的S7F5/S7F6消息逐条发送,最后再校验。配方文件的传输对协议解析的健壮性要求很高,一个字节错了,整个Recipe就要重传。
R2D(Recipe-to-Device)是面向300mm产线的配方分发模型,强调在配方下载前做完整性校验、下载中做分块传输、下载后做数据比对。EAP在R2D链路里既要当翻译器,还要当校验器。我见过有些项目里,R2D下载的Recipe大小有好几MB,远远超过单条SECS消息的承载能力,所以必须拆分成多条S7F5消息,还要维护会话状态,确保所有分片到达后设备才能组装出完整Recipe。
5. EAP的角色:它到底在协议层做了什么
5.1 EAP是“翻译官”加“调度员”
EAP(Equipment Automation Program)处于MES和设备之间。从协议层角度看,它做三件事:
- 和设备建立并维护HSMS连接,解析SECS-II消息。
- 把设备的SECS消息翻译成MES能理解的数据模型(如批次、晶圆、配方、工艺步骤)。
- 把MES下发的工单、工艺要求翻译成设备能执行的消息指令。
所以EAP本质上是个协议转换器,不只是透传。它要处理的细节非常多:
- 维护会话状态和消息重传。
- 处理设备主动上报的事件,更新内部状态。
- 管理配方和参数的缓存。
- 处理并发——多台设备同时上报,EAP不能被拖死。
- 日志记录必须要完整,尤其是消息二进制和解析后的结构化日志,最好都有,排查问题的时候能少抓瞎。
5.2 常见的通讯实现框架
成熟的EAP通讯层一般分层设计:
- 传输层:管理HSMS连接、心跳、重连。
- 编解码层:把二进制转为SECS-II对象模型。
- 业务层:根据SECS消息类型分配处理器。
- 应用层:对接MES、调度、质检、FDC等模块。
传输层最核心的挑战是重连机制。设备可能因为断电、重启、面板操作而断开连接,EAP侧要有自动重连和重新Select的流程。重连时不能简单地把旧连接关掉再建新的,有些设备对并发连接很敏感,必须先等旧Socket完全关闭,再发起新连接。
编解码层要注意字节序。不同设备的实现可能在U4/U8等字段上存在字节序差异,严格按标准来实现的同时,也要给某些特殊情况留一下扩展点。
5.3 消息处理和超时处理
消息处理流程大概是这样:
- 收到TCP数据,按HSMS长度字段切割出完整消息。
- 解析Header,判断是控制消息还是SECS-II数据消息。
- 如果是SECS-II,根据Stream/Function找到对应的处理器。
- 处理器里解析Data部分,更新业务状态。
- 如果需要回复,构造Reply消息,填充原始System Bytes,发送。
- 如果超时未收到对应Reply,触发重发或异常告警。
超时处理的参数建议做成可配置,不要硬编码。不同设备的处理能力差异很大,一台老设备处理S1F3查询可能就要几百毫秒,设3秒超时都未必够。但FDC文件传输的下载超时又不能设太长,否则悬死一个下载任务挂半天。
6. 报文示例:一次完整交互可以这样看
6.1 建立连接和Select
假设EAP作为主动方连接设备(IP: 192.168.1.100:5000),TCP连接建立后,EAP发Select.req:
00 00 00 0A 80 01 00 00 01 00 00 00 00 01 00 00 00 01解析一下:
00 00 00 0A:总长度为10字节。80 01:Session ID=0x8001,控制消息的标志位是0x8000,这个会话ID是控制会话。00:Header Byte2=0,因为Select是控制消息,没有Stream/Function。00:PType=0。01:SType=1,表示Select.req。00 00 00 01:System Bytes=1。
设备回Select.rsp:
00 00 00 0A 80 01 00 00 00 02 00 00 00 01 00 00 00 01关键差异是SType=2。如果Byte11(状态字节)是0,说明Select成功,否则是失败原因。
6.2 设备上报事件
假设设备发生“Process Start”事件,上报的S6F11大致如下(简化到只剩核心字段):
00 00 00 33 00 01 00 01 00 01 00 00 00 05 01 01 01 16 02 01 03 0B 45 76 65 6E 74 53 74 61 72 74 04 03 80 01 01 04 03 80 01 02虽然报文看起来乱,但按Item结构拆解后就能看到:
- LIST( DATAID=1, LIST ( REPORT-ID=5001, EVENT-NAME="EventStart", ... ) )
- 数据部分包含事件原因、时间戳、触发源等信息。
EAP收到后要快速解析出事件类型和关键数据,再映射到业务模型里。如果事件上报里带的数据不完整,EAP应该能识别并打告警,不能把空数据当正常事件处理。
6.3 命令下发
EAP下发“启动工艺”命令,用S2F41:
S2F41 W <L <L <ASCII "START_PROCESS"> <L <ASCII "PASS_1"> <ASCII "RCP001"> > > >设备执行后回S2F42,Header里带上这条消息的Message Type和System Bytes,确保上下文的关联。如果设备忙或者参数不合法,S2F42里会带HCK(Host Command Acknowledge)状态码,EAP要根据HCK码做后续处理。
7. 常见问题与排查技巧实录
7.1 连接反复断开
现象:EAP和设备之间的连接建立后,过几秒就断,日志里出现超时重连记录。
排查点:
- 检查防火墙是否只允许单向连接。
- 检查Select.rsp里状态字节是否成功。
- 确认设备是否配置了允许来自该主机IP的连接。
- 看TCP层是否有RST包,如果有,说明某一侧主动断了连接。
实际现场中,最常见的坑是设备面板或配置界面里启用了“双主机”模式,导致同一时间只能有一台主机连接,EAP连上后被另一台顶掉。这种情况日志里极难发现,只能通过抓包看RST方向和时机。
7.2 S6F11上报后EAP无响应
现象:设备持续上报,EAP没有回S6F12。
排查点:
- 看EAP侧是否实现了S6F11的处理,如果只处理了S6F13等消息,就没回复。
- 检查消息里的RPTID与配置的Report是否匹配,不匹配会导致业务层拒收。
- 确认解析器没有因为前面的异常消息卡住。
GEM规范要求设备上报之后,主机必须在T5时间内回复S6F12。但实践中有些设备即使没收到S6F12也能继续工作,而有些设备会一直等着。所以EAP侧务必保证S6F12的回复不出错。
7.3 变量值漂移或数据类型不对
现象:EAP解析出的温度、压力值明显不在合理范围,或者直接解析失败。
排查点:
- 检查Format Code是否匹配,设备可能把INT4当成了INT8。
- 确认变量在设备侧的单位和EAP侧是否一致。
- 检查滑动窗口重叠问题,比如消息顺序错乱导致后续报文解析错位。
这种问题只能在联调阶段通过抓报文和实际值对照来发现。建议在EAP侧加一个“协议字段级日志”,每个解析出的关键变量,都打出原始字节和解析结果,方便快速对比。
8. 协议对接中的经验补充
到这里想额外说几点经验,都是踩过坑换来的。
第一,联调阶段永远先确认设备侧版本。很多“怪异现象”其实是设备固件版本不一致导致的,有的版本S1F4返回的结构和文档描述的差一个Item,有的版本S6F11的DATAID类型从INT2变成了INT4。平台侧一定要在启动时做协议版本协商或配置化兼容方案,别把设备版本写死。
第二,日志做得好,排查快十倍。SECS通讯日志至少要有这几层:原始报文Hex、解析后的结构化消息、业务处理结果。三层缺一不可。原始报文Hel用于深入抓包分析,结构化消息能快速定位是协议层还是业务层的问题,业务处理结果能判断是不是MES侧逻辑出错。