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 位