新闻详情

新闻详情

首页 / 资讯中心 / 详情

QNX开发之ECAT专用网卡驱动ecpkt · 05-接收

发布时间:2026/10/1 8:26:35来源:尧图网络
QNX开发之ECAT专用网卡驱动ecpkt · 05-接收
QNX开发之ECAT专用网卡驱动ecpkt · 05-接收上一章结束时驱动的发送路径已经闭环50 条测试报文全部被 PC 端收到write() 一路畅通。但驱动还一帧报文都收不到——接收路径还是空的。这一篇我们来实现接收路径把报文从网线一路送到应用程序的 read() 里。在发送篇里我们已经理解了 SG-DMA 和 bdring接收功能同样是基于这两个模块。它与发送功能不一样的地方在于发送是由驱动主动发起接收则是被动响应的。这种被动响应的处理机制一般是周期轮询或中断两种方案各有优点周期轮询对应用的节奏控制更稳定但数据处理会有一些延迟中断模式的数据处理更及时但中断会打断应用程序的节奏且因为要走中断处理器系统开销也更大。这里我们沿用 devnp 的中断方案在 RX 中断里处理接收事件。注实际上对于 EtherCAT 通信来说发送和接收的节奏都是固定可控的使用周期轮询机制反倒实时性会更好。比如 Ubuntu 上的主站方案 IGH 也会为某些网卡芯片比如 Intel 的 e1000 等提供专用的实时驱动这些实时驱动相比通用驱动的一大改动就是把中断改成了轮询这里有一部分原因是 Linux 的中断处理属于软实时而不是硬实时会引入较大的抖动。我们这里先使用中断模式快速完成 ecpkt 的开发后续如果要进一步调优再考虑改成周期轮询的方式来实现接收功能。1. 同样基于SG-DMA和bdring的接收路径把发送路径倒过来就是接收路径SG-DMA、bdring、frame pool 这套机制全部原样复用只是数据流向反过来。发送是 write() 把用户数据写进槽位驱动把槽位的物理地址和长度填进 BDDMA 沿 bdring 把数据搬给 MAC 发出去接收则是 MAC 收到帧DMA 沿 bdring 找到 BD 指向的槽位把帧写进去驱动再把这一帧交给接收队列最后 read() 从队列里交给应用程序。接收路径和发送路径的主要区别在于槽位的生命周期发送的槽位是“过路的”——write() 时借一个发完就还槽位在 FREE、READY、INFLIGHT 之间流转接收的槽位则必须是“钉死的”——DMA 随时可能把一帧写到任何一个 BD 指向的槽位里如果槽位和 BD 的对应关系像发送那样动态变化DMA 在激活 BD 时 BD 里还没有可用地址DMA 就无法完成数据搬运对应的报文就直接丢了。所以接收路径下必须要保证可用 BD 里的地址是可用的。我们在初始化时一次性地把所有接收槽位和 BD 绑死——BD j 永远指向 slot j槽位的物理地址写进 BD 之后就不再改变BD 的状态切换与槽位的状态绑定在一起bdring 的更新依赖于槽位状态的更新“槽位可用”是 BD 可用的前提。为了区分这两种语义我们给 frame pool 的 slot 加了第五个状态 SLOT_BOUND绑定态发送走借还alloc / release接收走绑定bind / unbind两套生命周期在同一个池里并存。另外RX 环上任何时刻不能有空 BD。DMA 收到帧时是自己找 BD 写数据找不到可用的 buffer 就直接丢包不会等谁——所以初始化时必须把 128 个 BD 全部挂满 buffer 交给硬件同时每处理一帧回收 BD 和补挂新 buffer 必须成对出现。把 BD 从硬件收回来就要立刻重新挂回去少这一步这个槽位从此就收不到包了。2. 中断处理中断挂载与使能我们直接沿用 devnp 里的实现iid InterruptAttach(xzynq-irq, xzynq_isr, arg, 0, _NTO_INTR_FLAGS_PROCESS);devnp里的中断处理包含了中断上半段和中断下半段的处理const struct sigevent *xzynq_isr(void *arg, int iid) { xzynq_dev_t *xzynq arg; struct _iopkt_inter *ient xzynq-inter; /* Disable all interrupts */ out32(xzynq-regbase XZYNQ_EMACPS_IDR_OFFSET, XZYNQ_EMACPS_IXR_ALL_MASK); /* Clear interrupts */ xzynq-isr_status | in32(xzynq-regbase XZYNQ_EMACPS_ISR_OFFSET); out32(xzynq-regbase XZYNQ_EMACPS_ISR_OFFSET, xzynq-isr_status); return interrupt_queue(xzynq-iopkt, ient); }中断处理函数xzynq_isr完成上半段的寄存器操作之后往iopkt的任务队列里添加了一个事件相当于把下半段交给iopkt来处理iopkt的任务队列有点类似于linux下的workqueue属于iopkt特有的机制在ecpkt里面就需要我们自己来实现不过iopkt的任务队列机制是针对多网卡多应用的复杂情况来处理的ecpkt里可以大大简化我们直接起一个线程来处理中断下半段就可以了pthread_create(g_drv.int_thread_t, NULL, int_thread, g_drv.xzynq)补充一下开发接收功能时我想当然地把中断处理和接收数据分成两个模块屏蔽掉接收数据先专注调试中断——比如中断能否触发、中断处理路径是否正常执行等。但 Zynq 的 GEM 控制器上中断触发并不是在 GEM 收到数据时而是在 DMA 把数据完成搬运之后——中断触发的语义不是“有数据到达”而是“有数据可用”。如果没有接收数据逻辑bdring 里的 BD 不会被正常释放BD 很快就会耗尽从而 DMA 无法完成数据搬运进而无法触发“可用数据”中断。所以中断处理和数据接收两个功能是强耦合在一起的两者必须协同起来才能工作。基于上面两点接收路径要做的事情就清楚了初始化时把所有接收槽位预挂给硬件全占满中断里收帧排空接收环、记录长度、交给接收队列、成对补齐read() 把帧从接收队列交给应用程序下面我们具体展开这三件事。1. 预挂接收槽位初始化阶段对每个空闲 BD 做三件事从 bdring 申请一个 BD如果这个 BD 是第一次挂接rx_slot_idx[j] 还是 NONE就把 slot j 和它绑定并把槽位的物理地址写进 BD——这个地址从此不再改动最后把这个 BD 交给硬件。128 个 BD、128 个槽位、每槽 2048 字节一轮循环全部挂满。之后每次收帧后的补挂走的是同一段代码的另一条路径槽位和 BD 地址都不动只是把 BD 重新交给硬件。整个接收数据路径上没有任何 alloc / release——绑定态的槽位永远不进空闲栈也不会被发送路径误用。2. 中断里收帧中断上半段里完成现场保护读 ISR 寄存器并写回清除中断源GEM 的中断是电平触发源不清、中断线就一直拉高、屏蔽中断防止下半段处理期间 ISR 反复重入空转、返回一个 sigevent 唤醒下半段。下半段线程化InterruptWait 被唤醒后进 process_interrupt发现是帧接收完成FRAMERX就调 process_rx 排空整个接收环——from_hw_rx 把所有已完成的 BD 一并取回逐帧校验 SOF / EOF按 rx_slot_idx[j] 找到槽位发送那张是 BD 正持有哪个槽位的反向映射接收这张因为绑定恒成立本质上是一个恒等映射把 BD 报告的真实长度记到槽位上供后面的 read() 查询最后 rx_push 把这一帧交给接收队列。一轮的收尾是成对补齐bdring_free 回收这批 BDsetup_rx_buffers 把它们重新挂回硬件如果这期间又到了新帧继续下一轮循环。3. read() 取数据中断线程把帧塞进接收队列——一个 128 项的环每项记录槽位号和长度用户态的 read() 从环的另一头取。队列满时丢帧计数push 跑在中断线程上下文绝不能阻塞等待。用户 buffer 比帧小时返回 EMSGSIZE帧留在队头不消耗下次 read() 还能取到——“读缓冲太小”不该吃掉一帧数据。数据本身的交付是零拷贝的帧还在 NOCACHE 映射的槽位内存里read() 处理时直接用 _RESMGR_PTR 把槽位内存挂到回复的 iov 上客户端经内核取走全程没有一次 memcpy。这里有一个需要注意的地方read 操作是阻塞的等待数据到来时进程会挂在 read 里等事件。这就会带来一个问题——RM 的消息分发是单线程的等待 read 时 RM 的消息处理 dispatch 是无法被激活的。这种情况下如果一个客户端意外死亡正常情况下 RM 会收到一条消息交给 dispatch 去处理但由于此时 RM 阻塞在 read 里dispatch 不会运行这个客户端死亡的事件就无法被处理RM 就会一直阻塞在 read 里直到有数据到来。在此期间所有需要 dispatch 处理的消息比如新客户端连接的到达都无法被处理。直观来说就是用户程序退出后再次启动请求打开 RM 设备时无法响应。解决这个问题的办法是延迟回复把这次请求的 rcvid 停进一个 pending 数组返回 _RESMGR_NOREPLY——客户端那边看起来还在正常阻塞RM 的 dispatch 线程却已经回到分发循环继续干活新帧到达时驱动给自己投一个脉冲dispatch 线程醒来后由 service_pending 把帧交给停着的那个读请求。对客户端来说这就是一次普普通通的阻塞 read()。完成以上工作后接收功能就可以闭环验证了。我们用下面这套方法测试一下PC 端用小工具发送确定性的广播流量板端运行 gem_test阻塞 read() 收帧每收一帧打印摘要运行日志可以看到PC 发出的报文全都收到了。到这一篇为止驱动的数据收发通路就完整了驱动本身的功能开发也告一段落后续可以使用 SOEM 主站来基于这个驱动进行通信并测量实时性看看专用驱动的效果怎么样。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

看懂规律,守住本心,温柔而不失界限——《红楼梦天道》所传递的处世哲学一句话读懂这本书它不是宿命论说明书《红楼梦天道》以专题方式重读《红楼梦》,从木石前盟、太虚幻境、贾府盛衰,一直谈到人物关系 2026/10/1 8:26:35

看懂规律,守住本心,温柔而不失界限——《红楼梦天道》所传递的处世哲学一句话读懂这本书它不是宿命论说明书《红楼梦天道》以专题方式重读《红楼梦》,从木石前盟、太虚幻境、贾府盛衰,一直谈到人物关系

看懂规律,守住本心,温柔而不失界限——《红楼梦天道》所传递的处世哲学一句话读懂这本书它不是宿命论说明书《红楼梦天道》以专题方式重读《红楼梦》,从木石前盟、太虚幻境、贾府盛衰,一直谈到人物关系、青春聚散与命运终局。其真…

阅读更多 →
2026年10月深圳GEO优化公司精选三家盘点 2026/10/1 8:26:35

2026年10月深圳GEO优化公司精选三家盘点

进入2026年10月,生成式AI正在重写企业获客的底层逻辑,GEO(生成式引擎优化)也从一个新概念变成深圳企业年度营销规划中的明确预算项。在这一节点上梳理深圳本地的GEO服务机构,像方维网络这样深耕深圳十余年、把效果承诺写进合同的本土服务商,正在成为不少高新企业与制造企业试点…

阅读更多 →
ChatGPT、Codex工程方法:Agent一次要改几十个文件,为什么真正危险的不是改错,而是“验证覆盖不上”? 2026/10/1 8:26:35

ChatGPT、Codex工程方法:Agent一次要改几十个文件,为什么真正危险的不是改错,而是“验证覆盖不上”?

以前让 ChatGPT、Codex 改代码,任务通常很小。改一个函数。修一个Bug。补一个测试。这种情况下,验证也很直接:跑对应单测。看一下Diff。确认接口正常。基本就结束了。但现在越来越多任务不是这样。一个需求丢进去以后,Agent可能会…

阅读更多 →

最新相关资讯

【2027大数据毕设精品】基于大数据的社交媒体用户行为数据分析与可视化,附源码_数据可视化_数据分析_数据挖掘_Hadoop_spark_文档指导_毕设指导 2026/10/1 10:10:22

【2027大数据毕设精品】基于大数据的社交媒体用户行为数据分析与可视化,附源码_数据可视化_数据分析_数据挖掘_Hadoop_spark_文档指导_毕设指导

💖💖作者:计算机毕业设计杰瑞 💙💙个人简介:曾长期从事计算机专业培训教学,本人也热爱上课教学,语言擅长Java、微信小程序、Python、Golang、安卓Android等,开发项目包括…

阅读更多 →
TraeWork 自动签到技能分享 2026/10/1 10:10:21

TraeWork 自动签到技能分享

TraeWork 每日签到,普通用户每日签到领取 150 积分;升级会员,每日额外多领 50 积分,合计 200 积分,是免费用户稳定获取算力资源的渠道之一。但每天手动打开客户端完成签到,很容易遗忘导致断签,连…

阅读更多 →
测量显微镜是怎么走到你手里的:一个技术的落地简史 2026/10/1 10:10:20

测量显微镜是怎么走到你手里的:一个技术的落地简史

从“看清楚”开始:测量显微镜要解决什么问题测量显微镜最初要解决的,是人眼无法直接观察微小结构、缺陷和尺寸差异的问题。它以光学成像为基础,将微观对象放大,再结合标尺、成像和测量功能,用于工业检测、材料分析、科…

阅读更多 →
高低压电池融合系列之四:跨体系触类旁通—CTC、电池包集成与电子电气架构的共振 2026/10/1 10:10:19

高低压电池融合系列之四:跨体系触类旁通—CTC、电池包集成与电子电气架构的共振

摘要:如果只把"高低压融合"当成"少一块电瓶",就看小了。它其实是两条产业主线的交汇点:①电池包集成化——从CTP(电芯直接入包)到CTC(电芯直接入车)再到CTB(电芯…

阅读更多 →
QoderCN+python+playwright自动生成自动化脚本 2026/10/1 10:10:13

QoderCN+python+playwright自动生成自动化脚本

我用的是当前最主流、官方维护的playwright/mcp 1 Playwright MCP介绍 Playwright MCP 是一个服务端协议,它不能单独运行,需要挂载在一个支持 MCP 的 AI 客户端上。你平时写代码用哪个,就选哪个: Cursor / VS Code (推荐)&#…

阅读更多 →
读数据架构知识体系指南11数据建模方法(下) 2026/10/1 10:10:06

读数据架构知识体系指南11数据建模方法(下)

1. Kimball模型1.1. 更适合数据需求较简单的组织1.2. Kimball的自底向上方法1.2.1. 都是先将原始数据从每个OLTP源系统提取到临时关系暂存表中,不进行转换或清理1.2.2. 数据集市通过DW总线(有时也称为信息总线)进行整合,以实现数据…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉