IgH EtherCAT主站中Device网卡、EEPROM(SII)和EoE模块如何介绍?
摘要:目录一、Device 模块概览Device 模块是什么?技术详情ec_device 结构体字段设备抽象层架构设备绑定解绑流程深入源码ec_device_init()ec_device_attach()ec_device_poll()ec_
目录一、Device 模块概览Device 模块是什么?技术详情ec_device 结构体字段设备抽象层架构设备绑定/解绑流程深入源码ec_device_init()ec_device_attach()ec_device_poll()ec_device_send()ec_device_tx_data()SKB 环形缓冲二、Ethernet (EoE) 模块概览EoE 是什么?技术详情ec_eoe 结构体关键字段EoE 状态机EoE 帧分片与重组EoE 帧类型深入源码ec_eoe_init()ec_eoe_run()EoE 状态函数详解ec_eoe_state_rx_start (Line 744)ec_eoe_state_rx_fetch_data (Line 839)ec_eoe_state_tx_start (Line 1021)ec_eoe_state_tx_sent (Line 1101)ec_eoe_request_t — EoE IP 参数请求三、EEPROM / SII 处理概览EEPROM (SII) 是什么?EEPROM 内存映射技术详情固定信息区 (0x0000–0x003F)Category 类型表EEPROM 读取流程深入源码SII FSM 状态机 (fsm_sii.c)SII FSM 状态函数详解ec_fsm_sii_state_start_reading (Line 266)ec_fsm_sii_state_read_check (Line 290)ec_fsm_sii_state_read_fetch (Line 329)ec_fsm_sii_state_start_writing (Line 439)ec_fsm_sii_state_write_check (Line 461) / write_check2 (Line 499)sii_firmware.c — SII 固件覆盖ec_sii_image_t — SII 完整镜像ESC EEPROM 控制寄存器 (N32H7x5EC)
一、Device 模块
3.8 — device.c / device.h — 设备抽象层
概览
Device 模块是什么?
Device 模块是 IgH 主站与物理网卡驱动之间的抽象层。每个 ec_device 封装了一个 Linux net_device,提供 EtherCAT 帧的发送和接收功能。主站最多支持两个设备(主设备 + 备设备),实现冗余拓扑。
核心功能
设备绑定: 将网卡驱动注册到主站(attach/detach)
帧发送: 构造 SKB 并通过网卡 DMA 发送
帧接收: 通过 Poll 函数获取接收到的帧数据
SKB 环形缓冲: 预分配 16 个 SKB 用于发送,避免运行时分配
统计: 帧收发计数、字节数、错误数
技术详情
ec_device 结构体字段
字段
类型
说明
master
ec_master_t *
所属主站
dev
struct net_device *
Linux 网络设备指针
poll
ec_pollfunc_t
网卡 Poll 函数指针(中断替代)
module
struct module *
网卡驱动模块指针
open
uint8_t
设备是否已打开
link_state
uint8_t
链路状态
tx_skb[EC_TX_RING_SIZE]
struct sk_buff **
发送 SKB 环形缓冲(16 个)
tx_ring_index
unsigned int
当前发送缓冲索引
jiffies_poll
unsigned long
最后一次 Poll 的时间
tx_count / rx_count
u64
收发帧计数
tx_bytes / rx_bytes
u64
收发字节计数
tx_errors
u64
发送错误计数
tx/rx_frame_rates[3]
s32
不同统计周期的帧速率
tx/rx_byte_rates[3]
s32
不同统计周期的字节速率
设备抽象层架构
flowchart TD
subgraph IgH 主站核心
M[ec_master]
D[ec_device]
end
subgraph 设备抽象层
D1[ec_device_attach]
D2[ec_device_poll]
D3[ec_device_send]
D4[ec_device_tx_data]
end
subgraph 网卡驱动层
N1[net_device]
N2[ndo_start_xmit]
N3[poll 函数]
N4[DMA 引擎]
end
M --> D
D --> D1
D --> D2
D --> D3
D --> D4
D1 -->|绑定| N1
D2 -->|调用| N3
D3 -->|调用| N2
D4 -->|返回 SKB data| N4
N4 -->|DMA| HW[物理网卡]
设备绑定/解绑流程
flowchart LR
subgraph 网卡驱动
A[ecdev_offer]
end
subgraph Master
B[ec_device_attach]
C[ec_device_open]
end
A -->|注册 poll+netdev| B
B -->|保存指针| C
C -->|调用 ndo_open| D[网卡就绪]
深入源码
ec_device_init()
位置: master/device.c:74–167
初始化设备:清零结构体,预分配 16 个 (EC_TX_RING_SIZE) 发送 SKB。每个 SKB 预留 ETH_HLEN + EC_MAX_DATA_SIZE 空间,确保发送时无需动态分配。
ec_device_attach()
位置: master/device.c:223–248
绑定网卡设备:保存 net_device 指针、poll 函数和 module 指针。这是网卡驱动通过 ecdev_offer() 将自身注册到 IgH 的入口。
ec_device_poll()
位置: master/device.c:563–578
调用网卡驱动的 poll 函数,模拟中断处理。在 EtherCAT 模式下,网卡中断被禁用,由主站线程主动调用 poll 获取接收数据。这是 IgH 实现确定性的关键——避免中断延迟的不确定性。
ec_device_send()
位置: master/device.c:415–453
发送以太网帧:
获取当前发送 SKB: tx_skb[tx_ring_index]
设置 SKB 长度: ETH_HLEN + size
通过 netdev_ops->ndo_start_xmit 或 hard_start_xmit 提交到网卡
递增 tx_ring_index (环形)
更新发送统计计数
ec_device_tx_data()
位置: master/device.c:396–406
返回当前发送 SKB 的数据指针 (跳过 ETH_HLEN = 14 字节以太网头)。主站使用此指针直接写入 EtherCAT 帧数据,避免额外拷贝。
SKB 环形缓冲
参数
值
说明
EC_TX_RING_SIZE
16 (0x10)
环形缓冲大小
每个 SKB 大小
ETH_HLEN + EC_MAX_DATA_SIZE
14 + 1486 = 1500 字节
分配时机
ec_device_init()
初始化时一次性分配
二、Ethernet (EoE) 模块
3.9 — ethernet.c / ethernet.h + eoe_request.h — Ethernet over EtherCAT
概览
EoE 是什么?
EoE (Ethernet over EtherCAT) 允许通过 EtherCAT 网络传输标准以太网帧,实现从站的网络隧道功能。IgH 为每个支持 EoE 的从站创建一个虚拟网络接口 (如 eoe0s0),应用程序可以像操作普通网卡一样配置 IP 地址、路由等。
典型应用场景
网络桥接: 将从站的 EoE 接口桥接到物理网络,实现远程管理
IP 配置: 通过 EoE 为从站设置 IP 地址、子网掩码、网关
Web 管理: 访问从站内置 Web 服务器进行参数配置
数据采集: 从站通过 EoE 上传诊断数据到上位机
技术详情
ec_eoe 结构体关键字段
分类
字段
类型
说明
基础
master
ec_master_t *
所属主站
slave
ec_slave_t *
关联从站
state
void (*)(ec_eoe_t *)
当前状态函数
虚拟网卡
dev
struct net_device *
虚拟网络设备
接收
rx_skb
struct sk_buff *
当前接收 SKB
rx_expected_fragment
uint8_t
期望的下一个分片号
rx_counter / rx_rate
uint32_t
接收字节计数/速率
rx_idle
unsigned int
接收空闲标志
发送
tx_ring
struct sk_buff **
发送帧环形缓冲
tx_ring_size
unsigned int
发送环形缓冲大小
tx_frame_number
uint8_t
当前发送帧号
tx_fragment_number
uint8_t
当前发送分片号
tx_offset
size_t
当前发送偏移
tx_counter / tx_rate
uint32_t
发送字节计数/速率
EoE 状态机
stateDiagram-v2
[*] --> rx_start: ec_eoe_init()
rx_start --> rx_check: 准备接收检查
rx_check --> rx_fetch: 邮箱有数据
rx_check --> tx_start: 无数据,转发送
rx_fetch --> rx_fetch_data: 请求读取邮箱
rx_fetch_data --> rx_start: 完整帧接收完成
rx_fetch_data --> rx_fetch_data: 继续接收分片
tx_start --> tx_sent: 有数据待发送
tx_start --> rx_start: 无数据待发送
tx_sent --> tx_start: 分片发送完成
tx_sent --> tx_sent: 继续发送下一分片
EoE 帧分片与重组
EoE 将标准以太网帧分片传输,每个分片通过邮箱发送:
参数
值
说明
分片载荷
邮箱大小 - 邮箱头 - EoE 头
取决于从站邮箱配置
帧号
tx_frame_number
标识一帧的所有分片
分片号
tx_fragment_number
从 0 递增
最后分片标志
EoE 头中设置
接收方用于判断帧是否完整
发送环形缓冲
tx_ring
默认 100 个 SKB 槽位
EoE 帧类型
类型
值
说明
EC_EOE_TYPE_FRAME_FRAG
0x00
EoE 帧分片(收发)
EC_EOE_TYPE_TIMESTAMP_RES
0x01
时间戳响应
EC_EOE_TYPE_INIT_REQ/RES
0x02/0x03
IP 参数设置请求/响应
EC_EOE_TYPE_MACFILTER_REQ/RES
0x04/0x05
MAC 地址过滤设置
深入源码
ec_eoe_init()
位置: master/ethernet.c:207
EoE 处理器初始化:
通过 alloc_netdev() 创建虚拟网络设备,命名格式 eoe<MASTER>[as]<SLAVE>
设置 MAC 地址(基于主站 NIC 地址或生成唯一地址)
分配发送环形缓冲 (默认 100 个 SKB 槽位)
初始化状态机为 ec_eoe_state_rx_start
调用 register_netdev() 注册网络设备到内核
ec_eoe_run()
由 EoE 线程周期性调用,执行 EoE 状态机的当前状态函数。每次调用处理一个状态转移(接收检查/发送分片)。
EoE 状态函数详解
ec_eoe_state_rx_start (Line 744)
初始化接收序列:准备检查从站发送邮箱状态。
ec_eoe_state_rx_fetch_data (Line 839)
处理接收到的 EoE 数据分片:
解析 EoE 帧号和分片号
如果是第一分片 (fragment_number == 0),分配新的 SKB
将分片数据拷贝到 SKB
如果是最后分片,将完整帧通过 netif_rx() 传递给内核网络栈
ec_eoe_state_tx_start (Line 1021)
开始发送流程:检查是否有待发送的以太网帧,若有则从 tx_ring 取出并开始分片发送。
ec_eoe_state_tx_sent (Line 1101)
检查上一分片是否发送成功,若成功则继续发送下一分片,否则重试。
ec_eoe_request_t — EoE IP 参数请求
用于通过 EoE 协议设置从站 IP 参数:
字段
说明
mac_address[6]
MAC 地址
ip_address
IP 地址
subnet_mask
子网掩码
gateway
默认网关
dns
DNS 服务器
name[32]
主机名
result
操作结果码
请求通过 slave->eoe_requests 队列传递到从站 FSM,由 fsm_eoe 处理发送。
三、EEPROM / SII 处理
3.10 — fsm_sii.c / sii_firmware.c — EEPROM 读写与解析
概览
EEPROM (SII) 是什么?
EEPROM (电可擦可编程只读存储器) 是 EtherCAT 从站中的非易失性存储器,存储从站的 SII (Slave Information Interface, 从站信息接口) 数据。SII 数据定义了从站的身份、通信参数、PDO 映射等关键信息,主站通过 ESC 的 EEPROM 访问寄存器 (0x0500–0x05FF) 读写这些数据。
SII 数据内容
固定信息: 厂商 ID、产品码、序列号、邮箱配置
Category 区: 字符串、通用信息、Sync Manager、PDO 映射、DC 参数等
用户数据: 厂商自定义数据区域
大小: 典型 4KB–16KB(IgH 限制最大 EC_MAX_SII_SIZE = 4096 words)
EEPROM 内存映射
图:EEPROM 内存布局 — 固定信息区 (0x0000–0x003F) + Category 变长区
技术详情
固定信息区 (0x0000–0x003F)
字偏移
大小 (words)
内容
源码常量
0x00–0x01
2
配置站地址/别名
EC_ALIAS_SII_OFFSET = 0x04
0x04–0x05
2
厂商 ID (Vendor ID)
EC_VENDOR_SII_OFFSET = 0x08
0x05–0x06
2
产品码 (Product Code)
EC_PRODUCT_SII_OFFSET = 0x0A
0x06–0x07
2
版本号 (Revision Number)
EC_REVISION_SII_OFFSET = 0x0C
0x07–0x08
2
序列号 (Serial Number)
EC_SERIAL_SII_OFFSET = 0x0E
0x0A–0x0B
2
Bootstrap 邮箱偏移/大小
—
0x0C–0x0D
2
Bootstrap 邮箱发送偏移/大小
—
0x0E–0x0F
2
标准邮箱接收偏移/大小
—
0x10–0x11
2
标准邮箱发送偏移/大小
—
0x12
1
邮箱协议位域
—
0x1F–0x20
2
EEPROM 大小
—
字节寻址 vs 字寻址
EEPROM 使用字 (word, 2字节) 寻址。表中偏移为字偏移,实际 ESC 寄存器访问使用字节地址(字偏移 × 2)。源码常量如 EC_VENDOR_SII_OFFSET = 0x08 为字节偏移。
Category 类型表
Type
名称
内容
解析函数
0x001A
Strings
文本字符串表(设备名称等)
ec_slave_fetch_sii_strings()
0x001B
General
设备通用信息
—
0x001C
FMMU 描述
FMMU 使用方式
—
0x001D
Sync Manager 描述
SM 配置参数
—
0x001E
General 类别
CoE 标志、物理层、功耗
ec_slave_fetch_sii_general()
0x0020
TxPDO
输入 PDO 映射
ec_slave_fetch_sii_pdos()
0x0021
RxPDO
输出 PDO 映射
ec_slave_fetch_sii_pdos()
0x0028
FMMU 使用
每个 FMMU 的使用描述
—
0x0029
Sync Manager
每个 SM 的配置
ec_slave_fetch_sii_syncs()
0x0032
TxPDO (扩展)
扩展输入 PDO
—
0x0033
RxPDO (扩展)
扩展输出 PDO
—
0x003C
DC 同步
分布式时钟同步参数
—
0xFFFF
结束标记
Category 链表终止
—
EEPROM 读取流程
flowchart TD
A[fsm_slave_scan 触发 SII 读取] --> B[fsm_sii: start_reading]
B --> C[写入 ESC EEPROM 控制寄存器 0x0502]
C --> D[read_check: 检查读取完成]
D --> E{EEPROM 忙?}
E -->|是| F[等待重试]
F --> D
E -->|否| G[read_fetch: 读取数据]
G --> H[从 ESC 读取 4 字节 0x0508/0x050C]
H --> I{还有更多数据?}
I -->|是| B
I -->|否| J[解析 Category 链]
J --> K[fetch_sii_strings]
J --> L[fetch_sii_general]
J --> M[fetch_sii_syncs]
J --> N[fetch_sii_pdos]
K --> O[SII 数据就绪]
深入源码
SII FSM 状态机 (fsm_sii.c)
stateDiagram-v2
[*] --> start_reading: 开始读操作
start_reading --> read_check: 发送读取请求
read_check --> read_fetch: EEPROM 就绪
read_check --> read_check: 忙,等待
read_fetch --> start_reading: 继续读下一个 word
read_fetch --> end: 读取完成
state read_check {
note1: 检查 0x0502 状态位
note2: bit0=busy, bit4=loaded
}
state read_fetch {
note3: 从 0x0508/0x050C 读 4 字节
}
[*] --> start_writing: 开始写操作
start_writing --> write_check: 发送写入请求
write_check --> write_check2: 写入完成
write_check2 --> start_writing: 继续写下一个 word
write_check2 --> end: 写入完成
write_check2 --> error: 写入失败
end --> [*]
error --> [*]
SII FSM 状态函数详解
ec_fsm_sii_state_start_reading (Line 266)
发起 EEPROM 读取请求:通过 FPWR 向 ESC 寄存器 0x0502 写入读取命令(设置地址 + 读使能)。
ec_fsm_sii_state_read_check (Line 290)
检查 EEPROM 读取状态:通过 FPRD 读取 0x0502 寄存器。
检查 busy 位 (bit 0):EEPROM 仍在读取中,等待下次执行
检查 loaded 位 (bit 4):数据已加载到寄存器
若超时 (EC_IO_TIMEOUT),重试
ec_fsm_sii_state_read_fetch (Line 329)
读取 EEPROM 数据:通过 FPRD 从 ESC 寄存器 0x0508 和 0x050C 读取 4 字节数据(每次读取 2 个 word)。将数据存储到 SII 缓冲区。
ec_fsm_sii_state_start_writing (Line 439)
发起 EEPROM 写入请求:通过 FPWR 向 ESC 寄存器 0x0508/0x50C 写入数据,然后向 0x0502 写入写入命令。
ec_fsm_sii_state_write_check (Line 461) / write_check2 (Line 499)
检查 EEPROM 写入完成状态:读取 0x0502 寄存器,等待 busy 位清除。
sii_firmware.c — SII 固件覆盖
该模块允许从文件系统加载自定义 SII 镜像,替代 EEPROM 内容:
查找路径: 从 EC_SII_DIR 目录查找 SII 文件
文件命名: 基于 vendor_id/product_code/revision_number 定位文件
加载机制: 通过 Linux 固件请求 API (request_firmware())
用途: 无需物理修改 EEPROM 即可更新从站配置,支持 SII 数据热更新
ec_sii_image_t — SII 完整镜像
字段
类型
说明
list
struct list_head
链表节点(master->sii_images)
words
uint16_t *
原始 SII 字数据
nwords
size_t
SII 内容大小(words)
sii
ec_sii_t
解析后的 SII 数据
ESC EEPROM 控制寄存器 (N32H7x5EC)
地址
名称
说明
0x0500
EEPROM 配置
EEPROM 访问配置寄存器
0x0502
EEPROM 控制/状态
读/写命令、busy/loaded 状态位
0x0504
EEPROM 地址
读/写起始地址
0x0508
EEPROM 数据 (低)
读/写数据低 16 位
0x050A
EEPROM 数据 (高)
读/写数据高 16 位
