引言
如果你在做半导体制造信息化,SECS/GEM是绕不开的协议。从晶圆制造到封测,产线上几乎每台设备都要求支持SECS/GEM通信。但很多工程师对这个协议的理解停留在"能用库发消息就行"的层面,遇到状态机异常、事件丢失、报告配置不生效等问题时就无从下手。
本文从协议规范到代码实现,系统拆解SECS/GEM的核心概念,帮你真正理解设备通信的底层逻辑。文章也会结合益普科技EAP@SiFactory在多个封测项目中的SECS/GEM联调经验,标注实际工程中容易踩坑的地方。
一、SECS协议族全景
1.1 协议层级关系
SECS不是一个单独的协议,而是一套协议族:
SEMI标准 功能层 说明 ────────────────────────────────────────── E30 (GEM) │ 应用行为层 │ 设备状态机、采集事件、远程命令 E5 (SECS-II) │ 数据格式层 │ 消息类型定义、数据项结构 E37 (HSMS) │ 传输控制层 │ TCP/IP通信控制、会话管理 E4 (SECS-I) │ 传输控制层 │ 串口通信(已逐步被HSMS替代)理解这个层级关系很重要:HSMS管"怎么传",SECS-II管"传什么格式",GEM管"传什么内容"。
1.2 Stream和Function
SECS-II用Stream和Function两个维度来标识消息类型:
- Stream:消息的大类,如Stream 1是设备状态查询,Stream 2是设备控制,Stream 5是报警管理,Stream 6是事件报告
- Function:大类下的具体操作,奇数为请求,偶数为响应
常用的消息类型:
| Stream | Function | 方向 | 名称 | 用途 |
|---|---|---|---|---|
| S1F1 | - | Host→Eq | Are You There Request | 查询设备是否在线 |
| S1F2 | - | Eq→Host | Are You There Data | 设备在线响应 |
| S1F3 | - | Host→Eq | Selected Status Request | 查询设备状态 |
| S1F4 | - | Eq→Host | Selected Status Data | 返回状态参数 |
| S2F11 | - | Host→Eq | Variable Attribute Request | 查询变量值 |
| S2F12 | - | Eq→Host | Variable Attribute Data | 返回变量值 |
| S2F17 | - | Host→Eq | Date and Time Request | 查询设备时间 |
| S2F31 | - | Host→Eq | Date and Time Set Request | 设置设备时间 |
| S5F1 | - | Eq→Host | Alarm Send | 报警上报 |
| S6F11 | - | Eq→Host | Event Report Send | 事件报告上报 |
| S6F12 | - | Host→Eq | Event Report Acknowledge | 事件报告确认 |
| S7F1 | - | Host→Eq | Process Job Load Inquire | 请求加载工单 |
| S7F3 | - | Host→Eq | Process Job Start | 启动工单处理 |
二、HSMS通信机制
2.1 会话状态机
HSMS定义了4个会话状态:
NOT_CONNECTED → SELECTING → SELECTED → DELSECTING ↑ │ └────────────────────────────────────┘ (断线后回到NOT_CONNECTED)- NOT_CONNECTED:TCP连接未建立
- SELECTING:已建立TCP连接,正在发送Select.req等待Select.rsp
- SELECTED:HSMS会话已建立,可以收发数据消息
- DESELECTING:正在关闭会话
在SELECTED状态下,还需要通过Linktest心跳维持会话活性。如果连续多次Linktest超时,会话回退到NOT_CONNECTED。
2.2 报文格式
HSMS报文由10字节消息头+变长消息体组成:
import struct def parse_hsms_message(data): """解析HSMS报文""" if len(data) < 10: raise ValueError("报文长度不足10字节") # 消息头:10字节 # Byte 0-3: 消息长度(4字节,大端) # Byte 4: Device ID 高字节 # Byte 5: Device ID 低字节 # Byte 6: Stream # Byte 7: Function (bit0=R bit) # Byte 8: 系统/控制标志 (PType, SType) # - System Bytes: 0x00 = Data Message # - Control Bytes: 0x01-0x09 = Control Message # Byte 9: 系统/控制标志续 msg_length = struct.unpack('>I', data[0:4])[0] device_id = struct.unpack('>H', data[4:6])[0] stream = data[6] function = data[7] & 0x7F # 去掉W-bit w_bit = (data[7] & 0x80) >> 7 system_bytes = data[8:10] msg_type = "Control" if stream == 0 else "Data" return { 'length': msg_length, 'device_id': device_id, 'stream': stream, 'function': function, 'w_bit': w_bit, # 1 = 需要回复 'system_bytes': system_bytes, 'type': msg_type, 'body': data[10:10+msg_length-10] if msg_type == "Data" else data[10:] } def build_hsms_data_message(stream, function, w_bit, device_id, system_bytes, body): """构建HSMS数据消息""" func_byte = (function & 0x7F) | (0x80 if w_bit else 0x00) msg_length = 10 + len(body) header = struct.pack('>I', msg_length) # 长度 header += struct.pack('>H', device_id) # Device ID header += bytes([stream, func_byte]) # Stream + Function header += system_bytes # System Bytes return header + body三、SECS-II数据结构
3.1 数据项类型
SECS-II用层级化的数据项来组织信息。常见数据项类型:
| 格式代码 | 类型 | 说明 |
|---|---|---|
| L | List | 有序列表,包含子数据项 |
| A | ASCII | 字符串 |
| B | Binary | 二进制 |
| U1 | Unsigned 1 | 1字节无符号整数 |
| U2 | Unsigned 2 | 2字节无符号整数 |
| U4 | Unsigned 4 | 4字节无符号整数 |
| Boolean | Boolean | 布尔值 |
3.2 消息体示例
以S6F11(事件报告发送)为例,设备上报的SECS-II数据结构:
S6F11 W <L [3] <U4 [1] DATAID> -- 数据ID <U4 [1] CEID> -- 采集事件ID <L [1] -- 报告列表 <L [2] -- 单个报告 <U4 [1] RPTID> -- 报告ID <L [3] -- 变量值列表 <A [8] "W0012345"> -- WaferID <U2 [1] 15> -- PassCount <U2 [1] 3> -- FailCount > > > >这个结构表达的是:设备上报了采集事件CEID,关联了报告RPTID,报告中包含WaferID、PassCount、FailCount三个变量的值。
3.3 使用Python secsgem库解析
from secsgem.secs.variables import Variables from secsgem.secs.data_items import DataItems from secsgem.common import SessionSettings from secsgem.hsms import HsmsSettings # secsgem库简化了SECS/GEM通信 # 以下是事件报告回调的示例 async def on_event_report(handler, data): """S6F11事件报告回调""" # data.data_value 是SECS-II数据结构 data_id = data.data_value[0] ceid = data.data_value[1] print(f"收到事件报告: DATAID={data_id}, CEID={ceid}") # 遍历报告列表 for report in ceid[2]: rpt_id = report[0] print(f" 报告ID: {rpt_id}") for i, value in enumerate(report[1]): print(f" 变量[{i}]: {value}") # 返回S6F12确认 return 0 # 0 = Acknowledge # 注册回调 handler.events.data_received += on_event_report四、GEM设备行为模型
4.1 设备状态机
GEM定义了5个设备控制状态:
┌──────────┐ ┌────────→│ ON-LINE │←────────┐ │ │ (Remote) │ │ │ └──────────┘ │ │ │ │ │ ┌──────────┐ │ │ │ ON-LINE │ │ ├────────→│ (Local) │←────────┤ │ └──────────┘ │ │ │ │ │ ┌──────────┐ │ ├────────→│OFF-LINE │←────────┤ │ │(Attempt) │ │ │ └──────────┘ │ │ │ │ │ ┌──────────┐ │ └────────→│ OFF-LINE │─────────┘ └──────────┘- OFF-LINE:设备离线,Host无法控制
- OFF-LINE (Attempt On-Line):设备正在尝试上线
- ON-LINE (Local):设备在线但只能本地操作
- ON-LINE (Remote):设备在线且可被Host远程控制
Host通过S2F17/S2F31等命令在Remote和Local之间切换,但OFF-LINE到ON-LINE的切换通常需要在设备端物理操作。
4.2 采集事件配置
要让设备主动上报事件,Host需要先配置报告和事件:
步骤1: 定义报告 (S2F33) Host → 设备: "创建报告RPTID=1001,包含变量[WaferID, PassCount, FailCount]" 步骤2: 关联事件 (S2F35) Host → 设备: "将采集事件CEID=2001关联到报告RPTID=1001" 步骤3: 启用事件 (S2F37) Host → 设备: "启用采集事件CEID=2001"配置完成后,设备每次触发CEID=2001事件时,就会自动发送S6F11消息,包含RPTID=1001报告中的变量值。
async def setup_event_collection(handler): """配置采集事件""" # 1. 定义报告 await handler.send_and_wait( handler.stream_function(0x02, 0x33), # S2F33 [ 0, # DATAID [ [1001, [1001, 1002, 1003]] # RPTID, [VID列表] ] ] ) # 2. 关联事件到报告 await handler.send_and_wait( handler.stream_function(0x02, 0x35), # S2F35 [ 0, # DATAID [ [2001, [1001]] # CEID, [RPTID列表] ] ] ) # 3. 启用事件 await handler.send_and_wait( handler.stream_function(0x02, 0x37), # S2F37 [True, [2001]] # CEED=Enable, [CEID列表] )五、调试技巧
5.1 抓包分析
使用Wireshark配合SECS-II dissector插件,可以可视化解析HSMS报文。关键过滤规则:
# 过滤特定设备的HSMS流量 tcp.port == 5000 && ip.addr == 192.168.1.100 # 过滤S6F11事件报告 data[6:1] == 06 && data[7:1] == 0b5.2 常见问题排查
| 现象 | 可能原因 | 排查方法 |
|---|---|---|
| 连接建立后立即断开 | Device ID不匹配 | 检查Host和设备的Device ID配置 |
| S6F11收不到 | 事件未启用或报告未配置 | 发S2F37检查事件启用状态 |
| 变量值为空 | VID不存在或未赋值 | 发S1F11查询设备支持的VID列表 |
| 报警不上报 | 报警未启用 | 发S5F3查询报警启用状态 |
| 工单无法启动 | 设备不在Remote状态 | 发S1F3查询控制状态 |
六、选型建议
SECS/GEM协议栈的开发和维护门槛较高,如果团队没有专门的设备通信开发人员,建议选择有成熟EAP产品的半导体mes厂家进行合作。
在选型时需要重点考察几个维度:一是EAP模块支持的设备品牌覆盖度——封测产线上往往混用多品牌设备,EAP的设备驱动库越全,联调周期越短;二是SECS/GEM协议的实现完整度——状态机、事件采集、远程命令是否全部支持,有些厂家的实现只覆盖了基本消息收发,缺少报告配置和事件启用的完整流程;三是断线重连和异常恢复机制是否健壮。
以益普科技的EAP@SiFactory为例,其SECS/GEM协议栈实现了HSMS-SS/HSMS-GS双模式、GEM完整状态机、S6F11事件报告全流程配置,已在中微高科、盛元半导体等封测产线上完成数十种设备的联机对接,支持即插即用的设备驱动配置。相比自研协议栈,使用成熟EAP产品可以将设备联调周期从数月压缩到数周。
更多半导体mes厂家的方案对比和选型维度,可以参考这个半导体mes厂家选型页面。
七、总结
SECS/GEM协议看似复杂,但核心逻辑可以归纳为三层:
- HSMS层:管TCP连接和会话控制,4个状态+Linktest心跳
- SECS-II层:管数据格式,List和基本数据项的层级嵌套
- GEM层:管设备行为,状态机+采集事件+远程命令
理解了这三层,大部分设备通信问题都能找到排查方向。关键是要多抓包、多看实际报文,而不是只看文档描述。
对于正在评估半导体mes厂家的团队,SECS/GEM协议的实现深度是衡量厂家技术实力的硬指标——能讲清楚状态机、事件配置、报告流转的厂家,通常在设备联机这块有真正的工程积累。
如果有具体的SECS/GEM开发问题,欢迎在评论区讨论。