十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

伺服驱动器内嵌EtherNet/IP的SPI通讯方案改造实践

伺服驱动器内嵌EtherNet/IP的SPI通讯方案改造实践 做伺服驱动器的朋友应该都有同感好几年都是CANopen和脉冲接口打天下突然有一天销售说“客户要求EtherNet/IP而且必须是内嵌到驱动器里不能外挂转换网关”。我当时接到的这个改造项目就是这么来的。项目本质是把一块带EtherNet/IP协议栈的嵌入式通讯小板通过SPI接口接到伺服主控板上然后把手上的供应商Demo程序适配成真正能用的伺服通讯固件。这篇文章会从方案选型开始把SPI通讯机制、Demo程序改造步骤、现场排错经验完整过一遍适合做伺服控制器、嵌入式通讯、以及准备在自家产品里内嵌EtherNet/IP从站技术的朋友参考。1. 先想明白为什么EtherNet/IP选择“内嵌SPI小板”方案1.1 面见客户之后的隐藏需求客户是给汽车产线做集成的产线上清一色AB PLC上位用了FactoryTalk设备联网点名要EtherNet/IP。当时我们拿了一台开发中的样机过去主控MCU是STM32H7系列目前只有CANopen和脉冲接口。客户的意思很直接不要外面挂一个协议转换器要驱动器本体上直接出网口。原因有三条柜内空间紧张、不希望额外供电和接线、维护备件时不想多一个“莫名奇妙的盒子”。外挂网关当然是最快的方案市面上各种协议转换器一抓一大把但客户不接受。剩下的路就是要么自己写EtherNet/IP从站协议栈要么买协议芯片/通讯模块内嵌到驱动器里。这个决定会直接影响项目周期和后期维护成本需要仔细权衡。1.2 三种实现路径的对比我实际调研了三种内嵌方案自研从站协议栈纯软件跑在主控MCU上用带EtherNet/IP能力的MCU或者通讯协处理器协议芯片/模块如Hilscher netX、Anybus CompactCom通过SPI接口与主控板连接三种路径的对比我整理了一张表方案开发周期认证成本维护难度适合场景自研协议栈6-12个月起步需要ODVA认证CT测试很苛刻协议更新、bug修复靠团队自身出货量很大的平台级产品带协议MCU3-6个月仍需认证依赖芯片厂商协议库质量通讯需求固定的产品线协议芯片/模块1-3个月模块通过认证即可驱动器做集成测试协议栈维护由芯片厂商负责快速切入新通讯协议我最终选了协议芯片方案。原因很朴素团队最熟的是伺服控制算法和电机驱动对CIP协议栈的细节了解有限ODVA的CT测试不是三五天能准备的。用协议芯片相当于把“协议栈翻译”这个活外包给了芯片我只需要通过SPI把数据喂进去/取出来就行。后面的事实证明这个选择确实帮我们避开了很多协议层面的坑。1.3 为什么Demo程序拿过来还要改造凡是接触过这类通讯板的朋友都知道芯片厂商会给你一份完整的Demo工程。它通常跑在一套开发板或者通用评估板上逻辑正确、协议流程完整。但你把它放到伺服驱动器里会发现Demo里跑的是“演示数据”——输入IO区放着递增计数器、拨码开关状态、LED闪烁控制输出IO区放着VLAN设置、自定义心跳值。这些数据流和伺服的“状态字、速度反馈、报警码”没有任何关系。所以这个项目的核心工作可以概括为三句话把Demo的通讯框架理解透SPI收发、事件处理、状态机把虚假的演示数据流替换成伺服的实时控制数据把协议栈暴露出来的配置接口映射到伺服的实际参数这也是我在这个改造项目里踩过最多坑的地方。下面先讲系统架构再讲具体的固件改造最后把我实际遇到的问题和一个比较典型的排错链路完整写出来。2. 硬件链路与数据流主控MCU是怎么“看见”EtherNet/IP的2.1 SPI连通后的内存映射关系先看硬件层面的连接方式。伺服主控MCU以STM32H7为例有多个SPI外设其中一个SPI接口连接着一块独立的通信小板。小板的核心是一颗EtherNet/IP协议芯片芯片外接一个标准RJ45网口小板上还有一颗负责上电时序、复位和配置的EEPROM。协议芯片对主控来说看起来就是“一个带中断的SPI从设备”。主控MCU需要做的事情就是协议芯片上电后主控向它写入握手命令这里通常有个“握手寄存器”的超时等待机制建立通讯后主控周期性读取输入缓冲区写入输出缓冲区当PLC发来连接请求、参数读写请求时协议芯片会拉高中断引脚主控产生中断并处理事件我用一个生活化的类比协议芯片像一位“外聘翻译”。PLC说英语EtherNet/IP报文伺服说中文伺服控制字、状态字翻译已经把英语语法全学会了你只需要把中文内容写在纸条SPI数据区上递给它它翻完会把英文回复再放回纸条上递给你。你不需要学英语但你得知道纸条放哪个抽屉、对方什么时候取走、什么时候放回。2.2 双向通路上的三类数据实际在SPI链路上跑的数据可以分成三类IO实时数据最重要的周期性数据 每次通讯周期主控MCU从协议芯片读取Input缓冲区内容PLC发给伺服的命令速度指令、控制字、目标位置同时把Output缓冲区内容写进去伺服回给PLC的状态实际速度、实际位置、状态字、报警码。这个数据在CIP里被组织成Assembly对象。对伺服来说常用的做法是Output Assembly主控→协议芯片→PLC方向实际速度、实际位置、状态字、报警码Input AssemblyPLC→协议芯片→主控方向控制字、目标速度/位置、模式字这里的“Input”“Output”很容易搞反我自己的记忆方法是站在PLC的角度看——PLC输出的数据就是“Output”方向的数据PLC输入的数据就是“Input”方向的数据。如果你站在自己的主控MCU角度看方向恰好相反所以做代码对接时一定要先确认你拿到的是哪个方向的缓冲区。显式报文非周期性 这部分承载的是参数读写请求。PLC通过MSG指令读驱动器的电子铭牌、运行参数或修改增益。协议芯片把它解析之后以事件消息的形式通过SPI发给主控主控处理完后再把应答数据写回SPI。配置管理数据 包含模块信息读取、MAC地址、IP设置、通道配置、通断状态等。一般在启动阶段或调试阶段使用。2.3 Demo初始化流程在做什么Demo程序的第一步不是直接开始读写IO数据而是先做一套“握手”。具体流程大概长这样主控上电拉高复位引脚等待协议芯片启动完成通常几十毫秒到几百毫秒主控通过SPI发送握手命令具体是向特定地址写入握手值然后回读直到芯片回应预期的值设置通讯参数如SPI驱动速率、中断极性、等待时间读取通道信息确认当前固件加载的是EtherNet/IP从站驱动注册中断进入正常循环这部分代码在Demo里往往是现成的我第一次做的时候以为不用动。实际上它是最关键的“地基”——后续所有数据交换都依赖这套握手建立起来的通道。如果你的主控MCU SPI从模式配置有误比如极性和相位不对可能连握手都完不成。我记得做硬件验证的时候逻辑分析仪抓SPI波形发现MISO一直在拉高全FF。排查了半天最后发现是协议芯片的SPI从设备要求CPOL1/CPHA1而Demo默认代码用CPOL0/CPHA0去通信。这就是典型的“Demo适配”第一课芯片手册的时序图一定要逐位对一遍别觉得供应商给的代码就一定是匹配你硬件设计的。3. Demo程序适配改造实操从厂商标杆到伺服产品3.1 差异化清单改哪些、留哪些、删哪些拿到Demo程序后我建议先建一张改造对照表。别急着改代码先把每一份源文件归类这样整个改造任务会清晰很多。文件/模块处理方式改造内容SPI底层驱动保留引脚、DMA/中断、时序参数按新板调整事件中断处理保留仅调整与主控其他中断的优先级握手与初始化保留微调超时时间IO数据交换主循环改造数据源从Demo变量换成伺服状态演示用途的界面/LED逻辑删除改为伺服告警灯/状态输出Assembly配置改造长度、实例编号、映射表信息对象改造厂商ID、产品代码、序列号必须换成自己的参数对象映射新增或改造把PLC要读写的参数接入伺服参数系统这样分区之后改动量很清晰。Demo程序的“通讯引擎”部分基本不用动动的是“业务数据”部分。这句话非常关键因为很多同事拿到Demo后东边改一下西边改一下最后SPI时序乱了通讯彻底瘫痪。我建议的原则是能不动的地方绝对不动能通过配置修改的就不改代码。3.2 把示例计数器换成伺服状态Assembly映射表的改造这一节是核心中的核心。EtherNet/IP的IO数据交换通过Assembly对象实例来承载。通俗讲Assembly实例就是“一段定好格式的缓冲区”。PLC侧配置IO大小的时候其实是在和这段缓冲区做对齐。Demo程序里Input Assembly可能长这样以我接触过的某个示例为例字节0供应商状态字节字节1拨码开关状态字节2~3内部计数器每10ms加1字节4~7VLAN配置预留这些数据对伺服毫无意义。我在改造时把它换成了和伺服控制相关的结构体对应关系如下输入端主控→PLC方向字节0~1驱动器状态字如0x0231表示运行就绪字节2~5实际速度int32单位0.1 rpm或mm/min根据EDS定义字节6~9实际位置int32字节10~11报警代码字节12~15扭矩反馈int16/int32输出端PLC→主控方向字节0~1控制字bit0使能bit1复位故障bit2急停等字节2~5目标速度字节6~9目标位置字节10模式切换速度/位置/转矩这里有个容易忽略的点字节序。CIP协议默认使用Little-Endian小端字节序而很多伺服主控MCU在DSP/浮点运算时习惯Big-Endian大端或者有独立的字节序配置。改造时必须在赋值阶段做字节序转换否则你会发现PLC监控到的速度反馈是百万级的随机数。我这边实际做法是在Assembly的读写函数里边统一加了一个字节序转换工具函数。这样通讯层看到的永远是标准Little-Endian伺服控制层内部用自己习惯的字节序两层通过透明转换解耦。在联调的时候先写一个固定值到Assembly里比如0x12345678然后看PLC侧读出来是不是0x12345678用来快速验证字节序是否正确这个办法比看实际电机数据直观得多。3.3 参数对象读写让PLC能改伺服增益IO数据只是“运行时的血和肉”但PLC工程师还需要读改参数。比如调试时在AB PanelView上写一个数值改动伺服的PID比例增益或者读取当前报警历史。这部分走的是EtherNet/IP的显式报文通道。在CIP里伺服参数一般映射到Class 0x64Vendor Specific Object或Class 0x93/0x94之类的厂商自定义类。Demo程序里通常留了一个示例对象给你一个框架。改造任务就是把示例对象里那几个假的属性比如“示例参数1”“示例参数2”替换成真正读伺服参数的接口。我当时的做法是这样定义一张伺服参数映射表把参数ID、名称、读写权限、数据长度、最小值、最大值列清楚。在协议芯片的事件回调里当收到CIP Set Attribute请求时先解析出请求的参数ID查映射表再调用伺服的参数写入函数。参数写入后返回成功状态如果不允许写就返回CIP规定的错误编码比如0x0E表示属性不支持。一个常见的坑是伺服参数中有一些是“运行中禁止修改”的比如电机极对数、编码器分辨率这类。在CIP显式报文的处理函数里必须检查伺服当前状态否则现场人员边转着电机边改参数轻则报错重则设备异常。这种检查逻辑Demo里没有需要自己加。后来我们还做了一个“只读/可写”属性表让PLC侧编辑时能直观看到灰色不可写项。这个功能一开始没人提但交付后现场工程师特别认可因为省掉了大量“为什么写不进去”的沟通。3.4 超时停机逻辑别让伺服在通讯断开时还转着几乎每个通讯型伺服产品都有这个要求通讯超时后伺服要进入安全状态而不是保持最后一条指令继续运行。这在EtherNet/IP里对应一个机制RPIRequested Packet Interval超时和Connection Timeout。协议芯片通常会提供一个超时回调或超时状态位。Demo里一般只实现“超时后打印日志”或者“LED闪烁报警”。但对一个伺服驱动器来说超时后必须切断使能让电机停止输出。我把超时处理接进伺服主状态机的高优先级分支里if (timeout_flag 1) { drive_set_state(DRIVE_STATE_FAULT); drive_output_torque_enable(0); drive_status_word | STATUS_COMM_TIMEOUT; }这里特别注意一点从SPI读出超时标志到实际封锁PWM输出中间延迟必须控制在几个毫秒以内。如果你把超时判断放在伺服环路比如1kHz外可能因为调度延迟让电机多转几圈。我的做法是在SPI中断里直接置一个原子标志然后伺服环路每个周期检查保证在下一个控制周期内完成停机动作。3.5 信息对象配置厂商ID、产品名、序列号这一块看似细节实则非常重要。EtherNet/IP从站有一个Identity ObjectClass 0x01里面包含Vendor IDDevice TypeProduct CodeRevisionSerial NumberProduct Name这些信息在Demo里全是厂商的默认值。适配改造时必须替换成自己公司的厂商ID在ODVA注册和伺服型号信息。否则现场用RSLogix扫描网络可能看到的是一台评估板而不是你的伺服型号。另外EDS文件里的这些字段必须和固件内实际值保持一致。我记得有一次就是因为EDS里Product Code写了0x000A固件里写的是0x0009PLC扫描后连线一直失败排查了很久才发现是这种“低级”不一致。所以后来我们在量产测试程序里加了一项自动比对固件读出的Identity信息要和标书/EDS完全一致。4. 实测排错AB PLC扫描不到数据的一个根因4.1 现象设备在线、IO不交换改造完第一版固件我们拿AB的CompactLogix PLC做了联调。硬件连接正常点击RSLogix的“Go Online”能够看到设备出现在网络里设备名称也正确显示为我们的伺服型号。但建立IO连接后PLC侧数据一直显示为0且通讯树里模块状态报“Connection Failure”。这里先说说我当时的操作顺序方便大家复现排查先用Wireshark在交换机镜像口抓PLC到伺服之间的EtherNet/IP报文确认PLC已经发出了ForwardOpen请求查看伺服侧是否回复了ForwardOpen响应如果响应是Error查看错误代码4.2 Wireshark抓包定位过程我抓包后看到了很典型的情况PLC发出了ForwardOpen报文目标IP是我们的伺服但从站返回了一个Connection Manager错误响应错误码是0x0001Connection failure或者更具体一点指向“Packet Rate / Connection Size”这一类问题。这里需要简单科普一下EtherNet/IP的连接建立过程PLC先广播/单播一个ForwardOpen请求告诉从站“我要建立一个连接输入数据X字节输出数据Y字节RPI是10ms超时是100msAssembly实例ID是xx”。从站收到后会拿这个请求和自身固件里配置的Assembly对象实例长度做匹配。如果从站觉得长度对不上就会拒绝连接。我们的现象就是PLC侧组态配置了32字节输入/32字节输出但从站侧固件里对应的Assembly实例长度只有8字节。所以每次PLC发起ForwardOpen从站都直接拒绝。4.3 根因Assembly实例长度与EDS不一致回看代码发现Demo的Assembly实例结构体定义是这样的typedef struct { uint8_t status; uint8_t mode; uint16_t counter; } assembly_in_t;这确实只有4字节或8字节。而我改造时虽然写好了40多行的数据映射代码但只改了映射函数忘了改Assembly实例的注册表。也就是说从站向协议栈注册的IO长度还是Demo默认值但主控这边一直以为要传32字节。两边信息不对称连接建立自然失败。这个问题的本质是Demo里有两处需要同步修改的地方实际的数据结构体定义你往里面塞了多少字段协议栈的“装配对象”配置向PLC广播这个实例有多大4.4 修复与验证修复方法就是在Assembly配置里把长度改为与EDS和结构体一致。我梳理了一个三条对齐原则固件里Assembly结构体长度 固件向协议栈注册的IO长度固件向协议栈注册的IO长度 EDS文件里声明的Input/Output大小三者不一致时以EDS文件为准因为PLC是按EDS组态的改完重新编译烧录PLC重新扫描IO连接几秒钟就建立起来了。之后用逻辑分析仪看SPI波形确认周期IO数据在稳定交换PLC侧看到了实时的伺服状态字。这里是第一次完整跑通了整个链路。这道坎过去以后我总结出一个调试经验凡是IO数据建立不起来先别急着看SPI和伺服控制代码第一件事就是核对Assembly实例长度。这个排查链路特别快往往几分钟就能定位是不是“尺寸”问题。另外如果固件和EDS是不同人维护的尤其容易出这种事。5. 现场稳坑SPI布线、字节序、IP设置那些事后才懂的事5.1 字节序与数据对齐的细节前面提到了字节序这里展开说一下实际测试场景。伺服速度反馈是int32比如0x0001C200。如果字节序反了PLC读到的可能是0x00C20100这种看起来毫无规律的数。工业现场很多人一看数据不对就说“通讯有问题”其实往往是字节序处理漏了。我们在固件里做了一个统一策略所有跨平台传输的数据统一切成Little-Endian并且写死了转换宏。日后再接别的PLC或者换主控平台这个策略可以复用。对于float类型的参数比如伺服增益建议按IEEE 754的字节序做转换。很多协议栈支持“在对象定义里指定数据类型”但底层SPI搬运的始终是裸字节转换还得自己来。联调的时候可以给PLC写一个浮点参数比如1.0然后PLC读出来看符不符合预期。5.2 SPI速率与线缆地上的一点教训实验室阶段SPI时钟用10MHz跑得很稳。到了现场出现偶发的通讯超时和参数读失败。检查发现是连接主控板与通讯小板的那根排线太长而且没有和地线配合好。SPI和I2C的一个明显区别是SPI没有内置的应答机制主设备发出数据从设备没有收到是不可能主动告知的。如果信号线上有严重的反射或者干扰就可能搬运到错误数据而协议栈因为校验字段没通过直接丢弃表现就是通讯超时或报文丢失。I2C虽然慢但有ACK机制至少能在协议层面感知到从设备是否应答SPI要靠物理层设计和上层超时来兜底。我最后的处理是SPI时钟从10MHz降到4MHz排线改短并且中间加GND隔离一信号线一地的蛇形走线方式在协议芯片的SPI片选和中断引脚上并联小电容滤波降速之后通讯稳定性明显改善。很多人误以为SPI跑越快越好但在工业现场产品中稳定大于速度。毕竟伺服通讯周期性数据也就几十个字节4MHz完全够用。5.3 MAC地址管理、EDS文件版本这些“小事”量产阶段还有一个问题容易被忽略MAC地址。协议芯片一般有全局唯一的MAC但如果每个模块烧录的固件版本不同或者你要求每个产品的IP地址由DHCP获取MAC地址的唯一性就必须和固件烧录流程绑定。我们最后在产线新增了一个工位读取协议芯片的MAC和伺服本体序列号一并写入“出厂铭牌”数据库同时把对应的EDS版本号也记录在案。现场如果报通讯故障客服只需按序列号查库就能知道这个驱动器用的哪版EDS、哪版固件排查效率会高不少。另外EDS文件的版本管理也值得多说一嘴。因为是改造项目固件迭代很快我们初期出现过一次EDS文件更新了但固件里Identity Object的Revision没同步改导致PLC客户端认为设备固件版本过旧连接时提示版本不匹配。所以建议把“固件版本号”、“EDS版本号”、“CIP Revision”三方绑定在一起发布时一起更新。在这次适配改造过程中我最深的体会是Demo程序不是“拿来就能用”的它更像一张地图让你知道协议栈的接口在哪、数据流往哪走但真正让它变成你自己的产品需要把业务逻辑一层层嵌进去。伺服和EtherNet/IP的组合难点不在于SPI本身——SPI通讯是成熟的协议栈是现成的——而在于两套完全不同的“世界观”如何对齐一边是电机的启停和速度环另一边是PLC的连接管理和数据块交换。做这个项目之前我对“通讯协议”的理解更多停留在“收发字节”的层面做完之后才明白真正的通讯适配是数据语义的映射是把一个驱动器的灵魂装进一个标准的壳里。希望这篇文章能帮同行的朋友少走一些弯路。
返回列表