ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

伺服内嵌EtherNet/IP:SPI从站适配改造与联调避坑全记录

伺服内嵌EtherNet/IP:SPI从站适配改造与联调避坑全记录 最近在做伺服驱动器的EtherNet/IP内嵌方案核心工作是把手上的嵌入式通信小板和主控板用SPI对接再把厂商给的Demo固件适配改造到我们的硬件平台上。这块小板本身跑的是EtherNet/IP从站协议栈但Demo程序原本基于另一款评估板写的SPI从机参数、中断方式、数据缓冲区映射都和我们主控对不上。这篇文章就把整个过程完整记录下来从为什么要内嵌通信小板到怎么梳理Demo固件再到SPI适配改造和联调避坑。适合正在做伺服、变频器或者工业设备网络化接入的嵌入式工程师参考尤其是卡在“Demo能收发但和主控对接不上”这个阶段的人。1. 为什么是“伺服内嵌EtherNet/IP”通信小板到底解决什么问题1.1 从网关方案到内嵌小板的切换逻辑在早期方案里伺服驱动器接入EtherNet/IP通常外置一个总线网关。PLC主站通过EtherNet/IP连到网关网关再通过RS485、CANopen或者模拟量接口去控制伺服。这个架构最大的问题不在通信本身而在延迟和映射复杂度。PLC发一个目标位置整个过程是“PLC - 网关 - 驱动主控板”。网关要做协议转换把EtherNet/IP报文拆开解析出目标位置数据再通过串口或CAN转发给伺服。网关的CPU性能有限主站RPI即使设到1ms经过网关后的实际数据刷新周期也会被拖到3~5ms再加上串口本身波特率上限整个链路很难支持多轴插补和电子齿轮同步。更麻烦的是网关和驱动器之间多一层协议映射意味着所有参数都要重复做地址映射现场调试时一旦两端数据库对不上排查问题非常痛苦。内嵌通信小板之后结构变成“PLC - 通信小板 - SPI - 伺服主控板”。通信小板上直接跑EtherNet/IP从站协议栈主控板只负责电机控制和驱动器逻辑。原来串口或CAN被SPI替代数据交互变成主控主动读写小板内存不再需要中间层做协议翻译。对主控来说小板看起来就是一个SPI从设备协议栈内部细节被隔离了主控代码只处理固定格式的输入输出缓冲区。这个架构明显更适合运动控制场景尤其是在需要多轴同步、快速响应的场合。1.2 小板硬件组成和SPI在整个链路中的位置硬件上典型内嵌方案分成三层。最上层是PLC主站通过工业以太网标准连接到伺服。中间是通信小板板上包含以太网PHY、协议栈处理器、存放节点配置和对象字典的EEPROM以及对外提供的一个SPI从机接口。最下层是伺服主控板它的DSP或MCU实现电流环、速度环和位置环并且作为SPI主站周期性地和小板交换数据。SPI在这条链路里相当于“小板协议栈和大板控制核心之间的数据管道”搬运两类数据。一类是周期性过程数据包括控制字、状态字、目标位置、实际位置、速度、电流等另一类是非周期性服务数据比如参数读写、诊断信息、固件版本等。选择SPI而不是UART或CAN原因很直接SPI是全双工同步通信速率可以轻松做到10Mbps以上比普通UART和CAN都快而且没有CAN的仲裁延迟和等待也没有UART的波特率误差问题。对于伺服这种固定通信周期的场景SPI在时钟同步性和确定性上都更友好。另外SPI几乎在所有MCU/DSP上都有外设支持不存在授权费问题布线也简单。只要主从双方约定好CPOL/CPHA、位宽和字节序数据搬运就是很“纯”的事情。不像EtherNet/IP报文本身那样需要繁琐的封装解析SPI更适合做板级内部传输。1.3 Demo固件为什么还要“适配改造”这可能是大部分第一次接触通信小板的工程师容易忽略的点。厂商提供的Demo程序通常是在原厂评估板上编译跑通的它验证的是“芯片能工作、协议栈能上线、SPI口能收发”但绝不是“拿过来就能塞进你的伺服驱动器里”。首先硬件差异就摆在那里评估板的MCU型号、晶振频率、GPIO片选引脚、中断引脚、DMA通道、SPI外设编号都可能和你自己的小板不一样。其次Demo程序里通常定义了一套示例数据区用来做回环测试或者点灯测试比如主控通过SPI写一个寄存器然后小板再把这个寄存器值通过EtherNet/IP发给主站。这个示例数据区和伺服控制真正需要的对象字典映射完全不沾边。适配改造的目标是保留EtherNet/IP协议栈的核心代码替换和简化平台相关部分把SPI从机的数据交互行为改成能对接伺服主控的状态机。说得更直白一点要把“Demo自嗨模式”切成“对接生产模式”这也是整篇文章后面所有内容的中心。2. 拿到Demo固件后第一件事梳理启动流程和地址映射2.1 Demo固件的整体工程结构拿到Demo工程不要急着打开main.c开始改。第一遍要做的是一张“地图”把工程里有哪些模块、每个模块干死什么搞清楚。常见的Demo工程结构大致是这几个部分协议栈库一般是静态库或预编译库存放CIP协议栈、EtherNet/IP连接管理、对象字典等。平台驱动包括以太网PHY驱动、PHY复位、中断处理、定时器、GPIO。应用层对象CIP对象和Assembly映射这部分决定过程数据怎么映射到内存区域。示例主循环轮询协议栈任务、通信状态机、Demo调试接口。SPI从机驱动包含SPI外设初始化、中断/DMA处理、寄存器读写命令解析。我一般会在工程里加串口日志把每一步启动过程打出来。上电以后应该能观察到这些顺序系统时钟和GPIO初始化、PHY复位和配置、IP和协议栈初始化、注册CIP对象、启动周期性任务、最后开启SPI接收。日志输出到这一步说明DEMO固件本身没问题可以开始下一步硬件适配。2.2 Demo默认的SPI参数为什么不能直接用Demo里的SPI从机参数基本都是评估板的配置常见是SPI模式0、时钟2MHz、8位数据位、高位在前。这个配置本身没问题但问题在于你的伺服主控侧可能并不是这个模式。很多伺服主控DSP的SPI主模式默认工作在模式0但如果你在主控上挂了其他外设比如外部EEPROM或者编码器接口SPI模式可能被改成模式3。这时候通信小板的从机如果不跟着改两边对不上。而且Demo里给的2MHz也不一定满足你的要求伺服主控通常希望用10MHz甚至更高来缩短SPI传输占用的时间但协议栈芯片的SPI从机最高支持多少必须查芯片手册不能盲目拉高时钟。这里有个经验硬件设计阶段就要确定主控SPI主模式的时钟参数然后让通信小板的从机去适应它。因为主控侧SPI时钟往往和主控自身的外设时钟有关改起来牵一发动全身而通信小板的SPI从机参数一般在应用层可以直接配置适配成本更低。千万不要先接了硬件再反过来改主控SPI时钟那样很容易引入不必要的系统时钟抖动。2.3 主从对接前先解决“字节序”和“帧格式”两个隐性问题Demo程序里如果用结构体直接收发数据那么结构体里的字段排列、字节序以及通信链路层有没有帧头校验都直接影响联调结果。EtherNet/IP报文本身是大端网络字节序但CIP对象内部很多数据是小端。SPI通道上如果还是直接沿用某种默认字节序不和主控约定清楚就会出现“单字节字段正确多字节数据大小端互换”的诡异问题。建议在SPI链路层明确一个硬性规定所有多字节数据统一按小端传输。协议栈收到主控的数据后如果需要转成网络字节序在入口处做转换函数处理不要在SPI驱动里到处散落字节序判断。帧格式方面很多Demo为了演示方便SPI命令格式非常简单比如“地址数据”两三个字节就完了没有帧长字段也没有校验。这在评估板上足够用但到了伺服环境现场电磁干扰一上来错帧会直接影响控制。我自己的经验是如果Demo里没有完善的帧同步必须自己补一个固定格式第0~1字节帧头magic固定为0xAA55。第2字节命令码区分读配置、写配置、读过程数据、写过程数据。第3~4字节数据长度大端。第5~6字节寄存器地址大端。第7字节起数据区。最后2字节CRC16校验。有了帧头和CRC主控和小板才能互相确认收到的是有效帧而不是因为某个GPIO毛刺触发的一次错误读取。2.4 从Demo到目标板先跑通SPI自发自收再连EtherNet/IP我在这阶段卡过两天原因就是低估了“先跑通SPI物理层”的意义。拿到目标板后先把EtherNet/IP协议栈晾在一边用主控板和通信小板互相收发固定字节确认SPI时钟线、数据线、片选线的时序都正常。如果这一步都没搞定后面接EtherNet/IP只会更难排查。当时的问题出在片选上。Demo板上的SPI CS引脚用的是普通GPIO软件控制不是硬件NSS而且初始化里默认拉高。我主控侧配置成硬件片选拉低以后从机没反应因为从机等待的其实是GPIO驱动的软件片选信号而GPIO在初始化后一直保持高电平。后来把原理图核对了一遍才发现这个差异。所以拿到Demo固件第一件该做的事是核对原理图确认每个SPI相关引脚的实际连接和复用功能而不是直接改代码。3. SPI通讯适配改造把Demo从“自发自收”改成“主控对接”3.1 从机侧SPI的数据搬运机制中断、DMA还是轮询通信小板的SPI从机侧数据搬运方式直接决定协议栈能不能及时响应主控。如果只用主循环轮询SPI接收标志一旦EtherNet/IP报文正在处理主控发过来的帧可能被漏掉。如果每个字节都用中断处理中断频率太高协议栈的实时任务容易被挤占严重时会造成EtherNet/IP连接超时。更稳的方案是接收用DMA配合空闲中断发送用DMA完成中断。DMA搬运的好处是主控把整个帧写进小板小板DMA接收结束后再统一解析CPU不需要为每个字节中断。但DMA要预先知道接收长度SPI从机本身没有长度信息所以一般有两种做法主控先发送一个长度字节从机收到长度后再触发DMA接收剩余字节。或者固定帧长度周期过程数据固定32字节/64字节参数帧固定128字节用帧头类型判断。对伺服场景我强烈建议主控侧把周期性过程数据做成固定长度。比如输入输出各32字节主控每次都固定发32字节给小板小板固定回32字节。这样小板从机侧的DMA缓冲区可以固定开成32字节不需要动态解析长度极大降低出错概率。参数读写走另一条通道用非周期的长帧处理不影响周期数据。3.2 按EtherNet/IP对象模型设计网关缓存区EtherNet/IP核心是CIP对象跟伺服密切相关的对象有Identity对象0x01、Connection Manager0x06、Assembly对象0x04。主控不关心协议栈内部怎么建立连接、维护会话它只需要通过SPI读写固定缓冲区所以说到底适配改造的重点是把协议栈应用层里的几个数据区域映射到SPI缓冲区上。我的做法是在协议栈应用层增加一个“SPI接口对象”专门做三件事主控 - 小板控制字、目标速度、目标位置、模式字等通过这些字段映射到输出Assembly再由协议栈周期性发送给PLC主站。小板 - 主控状态字、实际速度、实际位置、驱动报警等从输入Assembly映射到发送缓冲区。参数读写主控通过SPI发起读/写参数请求小板解析命令后去CIP对象的参数区做相应操作。这样主控只需要周期性地读写这两个固定缓冲区完全不用关心EtherNet/IP报文怎么封装。协议栈侧的Assembly对象和CIP连接在初始化时一次性注册好后续就一直复用同一块内存。3.3 软件片选和硬件片选在伺服高实时场景下的取舍SPI片选有两种常见控制方式硬件片选和软件片选。很多工程师在资源紧张时会用GPIO模拟CS但在伺服高实时场景下这个选择要非常慎重。软件片选的核心问题在于时序抖动。主控如果把CS拉低后因为中断嵌套或者更高优先级任务抢占导致CS到第一个SCK时钟沿的间隔变得不稳定从机的帧开始时间就会抖动严重时从机直接丢掉帧。更麻烦的是如果主控在SPI传输中间被打断CS保持低电平但时钟停了有些从机SPI状态机会卡在中间状态必须外部复位才能恢复。硬件片选由SPI外设控制CS引脚的拉低时机一般可以做到CS有效到第一个时钟沿的时间固定不受CPU任务影响。只要硬件片选引脚没有被其他外设占用优先使用硬件片选。如果单片机的SPI外设支持NSS脉冲模式或者高级定时器联动还能把CS控制在非常精确的时间窗口内。我只是在MCU的硬件片选确实不够用的情况下才用软件片选且软件片选拉低后至少延时两个SPI时钟周期再打时钟给从机一个可靠的准备窗口。下面这个表是我在电气设计时常用的对比对比维度软件片选硬件片选时序可控性受中断影响抖动大由外设硬件控制稳定CPU占用需要手动拉高拉低不占用额外软件开销多从机扩展灵活任意GPIO都可需要多个硬件片选引脚抗干扰能力较弱容易误触发较强边沿由外设产生适用场景低速、非实时伺服、高实时同步在伺服主控上做EtherNet/IP内嵌通信如果MCU支持硬件SPI我不推荐省这个引脚。3.4 周期刷新和SPI访问频率的同步问题EtherNet/IP主站会按RPI周期发送数据常见RPI是1ms、2ms或4ms。伺服主控的SPI访问周期可能也是1ms但这两者并不是同一个硬件时钟域。主控的定时器由自己产生小板的RPI由协议栈定时器产生两者频率完全同频但相位不一定一致甚至会有微小时钟漂移。如果不加保护主控读写缓冲区时小板恰好也在更新同一块内存就会产生数据撕裂。解决办法很简单双缓冲区加有效标志。主控写输入数据缓冲后把写完成标志置位小板在发送EtherNet/IP报文时读取这个标志如果置位就取走当前缓冲然后切换指针到另一个缓冲。反过来小板更新输出数据后也置一个新数据标志主控读取后清除。切换缓冲区尽量用指针翻转实现而不是把整块数据拷贝来拷贝去。伺服周期通常是微秒级任务在主线SPI传输上做memcpy很容易引入额外延迟。另外无论主控有没有新数据都必须在每个通信周期至少给小板发一次SPI帧。哪怕数据内容没有变化帧头CRC也要照发。这样既能让小板保持SPI链路活跃也能让EtherNet/IP连接不会因为长时间没有通信而被主站判定超时。4. 调试过程中最容易被卡住的几个地方4.1 时钟极性和相位不匹配——先别慌用示波器看SPI联调遇到传感器数据全是0x00或者0xFF第一反应不是去改代码而是拿示波器抓SCLK、MOSI、MISO三根线。用示波器或逻辑分析仪同时观察时钟空闲电平和数据采样沿就能立刻判断CPOL/CPHA是否一致。模式0空闲低上升沿采样模式3空闲高下降沿采样。如果主控是模式3从机是模式0MISO上会出现典型的数据窗口错位。曾有一次我把主控改成模式0又从机也改成模式0结果还是不对。重新查代码才发现我只改了SPI外设配置结构体里的CPOL和CPHA但GPIO复用初始化顺序不对新的配置根本没被装载到SPI外设里。后来我在初始化函数里加了一句读取SPI寄存器回读打印确认配置真的生效再继续联调。这个方法后来帮我省了很多时间。4.2 Demo里的“魔改”寄存器配置与芯片手册对不上有一次我遇到SPI从机FIFO阈值设置导致丢后两字节的问题。现象是主控每次发32字节帧小板收到的最后两个字节总是不稳定有时候是零有时候是上一次的值。查代码发现FIFO阈值被设置成0x07而芯片手册推荐用0x01。奇怪的是协议栈跑起来并没有崩溃数据错误只是偶尔出现。后来联系原厂FAE才知道这个阈值是他们评估板在某次改版之后为了避开一个布线问题特意改的成了Demo工程里的“遗留配置”。平台不同这个值反而成了干扰。所以我养成了一个习惯拿到Demo固件后把所有看起来“非默认”的寄存器配置列一张表逐个对照芯片手册确认用途并标注来源。这个过程很机械但能筛掉很多莫名其妙的问题。4.3 DMA传输长度和环形缓冲区不一致导致的数据撕裂数据撕裂问题出现在长时间运行之后不是一上电就能复现。具体表现是在EtherNet/IP监视窗口看到的状态字偶尔会跳变比如实际位置突然出现一个异常大的值又立刻恢复正常。排查了很久最终定位在DMA配置上。为了省事我把SPI接收DMA配成了环形模式并在DMA传输中断里切换缓冲区。但这个环形模式的循环计数和软件解析逻辑之间存在时间差如果主控连续发两帧中间没有足够间隔软件还没有完成上一帧解析DMA已经覆盖到下一块数据于是解析到半个新帧加半个旧帧。解决方法很直接关闭环形模式改用普通DMA传输完成中断在每个帧接收完成后切换双缓冲同时让主控确保帧与帧之间有至少一个SPI空闲周期。固定帧长也非常重要主控不能“想发几个字节就发几个字节”必须严格按约定长度对齐否则DMA完成中断触发时机和帧边界永远对不上。4.4 EtherNet/IP连接建立后超时断连还有一类问题在SPI联调通过之后才出现PLC主站能扫描到通信小板但建立了EtherNet/IP连接几秒钟后又报超时断开。这个坑多数和小板主循环调度有关。协议栈需要周期性调用它的main loop函数来处理CIP连接维护报文。如果SPI接收逻辑里用了大循环等待或者SPI中断里做了消耗时间过长的任务协议栈主循环可能被阻塞导致它无法及时回应主站的周期性心跳。排查方法是在小板固件里加一个10ms周期的定时器在定时器中断里做一个运行指示灯翻转然后用手敲代码把SPI接收逻辑改成“既不阻塞也不在中断里做重活”。SPI中断里只置标志位和切换DMA缓冲具体解析放到主循环的一个状态机里确保协议栈任务有固定时间片可以运行。主控侧也有配合点。如果在硬件上没有“新数据”主控也必须周期发空帧保持EtherNet/IP连接活跃。有些协议栈在主控长时间不访问SPI缓冲区后会认为本地应用层故障主动断开连接。这个不是芯片坏了而是协议栈“自我保护”机制的体现。5. 联调验证和稳定性从跑通到能出厂5.1 用PLC做主站做一致性测试跑通SPI和EtherNet/IP后先不要急着接真实伺服电机而是用PLC主站建立一个测试工程把输入输出Assembly分别配置到SPI缓冲区的固定位置。然后给主控发一组固定控制字比如0x0006对应快速停止子状态机再去PLC监视端看反馈状态字是不是0x0231。如果值完全一致说明SPI路径和EtherNet/IP路径的数据映射正确。接下来做动态测试。让PLC每10ms切换一次目标速度数值可以是从0到500递增之类的离散值观察SPI缓冲区和EtherNet/IP报文中的数据是否一一对应。这里有个注意点不要用正弦波或者随机值用线性递增递减最好因为一旦有一帧数据错位你能在趋势图上直接看到跳变点。5.2 长时间运行的监控手段稳定性测试至少要跑72小时并且要比实际工况更恶劣。我会在通信小板固件里增加一组统计变量包括SPI CRC错误次数、DMA接收超时次数、EtherNet/IP连接掉线次数、协议栈复位次数然后把这些统计值通过EtherNet/IP映射到PLC可以读取的对象属性里。这样不拆机也能实时看到小板的运行健康状况。测试期间让伺服主控频繁做启停、正反转、点动和参数修改。尤其要在电机启动和急停时抓SPI时序动态负载比静态跑更容易暴露SPI抗干扰问题。如果SPI CRC错误次数持续增长先检查通信小板和主控板之间的排线长度和走向SPI线要尽量短建议不超过10cm不要靠近功率线。必要时在CLK和MOSI线上加22~33Ω串联电阻同时考虑在靠近小板接口处加TVS管。软件上也可以做重试机制但不要把重试放在控制周期内只能在非周期参数帧上重试周期数据如果出错直接报一次通信错误更安全。5.3 固件升级和量产预留最后再提一个很容易被忽略的事情固件升级。通信小板的协议栈固件和伺服主控固件最好是分开升级否则量产之后发现协议栈版本要更新你得整块主板返工工作量会让人崩溃。建议在通信小板的SPI接口上设计一个Bootloader通道。主控可以通过SPI给小板发送特定的升级命令让小板进入Bootloader模式然后通过SPI把新的应用固件写入Flash。这个流程里固件签名校验和Flash区域保护一定不能省工业现场最怕升级过程中断电导致变砖。我在实际项目里会给Bootloader和App各分配独立Flash区域Bootloader只有“擦除、写入、校验、跳转”这四个功能越简单越不容易出问题。另外每次固件版本更新都在代码仓库里附带一份README写清楚这个版本适配了哪些SPI参数、改了哪些寄存器配置、验证过哪些PLC主站型号。很多问题都是因为半年前改过一个寄存器半年后换了一台伺服平台新工程师拿着旧源码一脸懵。别让Demo坑你第二遍。我在实际调试中还有一个小技巧在小板固件里保留一个“开发者模式”DMA命令。主控可以通过SPI发送固定魔数然后小板会把协议栈连接状态、RPI时间、最近一次CRC错误码、缓冲区指针位置全部打包回来。这个功能不需要在量产版本开放只保留在工程固件的调试宏后面但对排障非常有价值。很多时候EtherNet/IP连接断掉或者数据偶发错误你差的就是这么一条快速定位问题在哪一层的通道。
返回列表