在自动化现场调了这么多年设备我到现在还记得第一次给几十台伺服驱动器挨个刷固件的场景拆盖板、找调试线、一台一台连电脑、刷完还要核对版本号一天下来腰都直不起来。后来换了个思路直接用 EtherCAT 的 FOE 功能从主站通过网络把固件推送下去省掉了大量往返和拆装时间。FOE 的全称是 File over EtherCAT说白了就是一个跑在 EtherCAT 邮箱通信上的文件传输协议。它最常见也最实用的场景就是给从站设备升级固件比如伺服驱动器、IO 端子、阀岛、编码器只要从站固件支持 FOE就能用这根现成的 EtherCAT 网线把固件刷进去不需要额外拉线、不需要专用下载器更不用停机拆设备。这篇文章不只讲概念我会把从协议原理、环境准备、TwinCAT 3 界面操作到 PLC 里用 FB_EcFOEWrite 写远程升级功能块的完整代码一步一步拆开来讲。适合正在做设备调试、产线维护、或者准备做设备远程运维的工程师参考。1. 为什么我劝你直接走 EtherCAT FOE而不是手动刷固件1.1 手动刷固件的三个痛点搞自动化和设备维护的最怕的不是故障本身而是设备明明没坏却要为一次版本升级付出大量时间成本。第一是设备位置和时间成本。产线设备分布在车间各个角落驱动器装在电柜里IO 端子排成一排升级时要把设备停下来打开电柜找出调试口把电脑搬过去运气不好还得爬到设备底下跪着操作。一次两次没关系设备一多时间全花在拆装上。第二是操作过程容易出低级错误。USB 线接触不良、驱动装错、固件选错版本、刷到一半电脑休眠这些我都踩过。特别是老旧设备调试口和版本号五花八门手一抖刷错版本轻则多花几个小时回退重则可能把引导程序弄坏直接返厂处理。第三是记录和追溯困难。每次刷完固件版本号、时间、操作人、设备序列号要是有记录习惯还好没有记录习惯等到设备出了问题排查了半天才发现是现场固件版本没有统一。这种事最憋屈。后来我换了 FOE 升级方式之后这些问题得到了很大改善。1.2 FOE 到底能省什么EtherCAT 本身是主站和从站之间最正常不过的实时通信网络但 FOE 的出现让这条网线多了一个“传文件”的能力。它的作用相当于在 EtherCAT 网线上内建了一个迷你 FTP 服务只不过传输的文件通常是固件、配置或日志。用 FOE 升级固件最直接的好处是不需要额外动线、动设备。只要从站还在 EtherCAT 网络上、还能正常通信就可以通过网络把固件文件直接写到从站的存储区域里。对于分布式 IO、伺服驱动器这种布置在危险或者不方便接触位置的设备尤其实用。第二点是可以把升级动作编进 PLC 程序。设备上电后先读一次从站固件版本版本不对就自动触发 FOE更新完成再继续运行整个过程不需要人工干预。如果配合上位机、云平台或者远程运维网关还能做到远程批量升级这也符合目前 OTA 远程升级在工业设备领域不断普及的趋势。第三点是 FOE 不只是从主站向从站“写文件”还可以反向把从站里的日志、配置、固件备份读出来。碰到设备异常现场又拿不出数据的情况通过 FOE 直接拉日志能让排查问题省下非常多的时间。当然FOE 本身不是万能的它适合传输中等大小的文件比如几百 KB 到几十 MB 的固件镜像。如果动辄数百 MB 甚至 GB 级的大文件就要考虑换通道了这个后面我会详细说。2. FOE 升级前要确认的 4 个条件2.1 从站支不支持 FOE怎么确认不是所有 EtherCAT 从站都支持 FOE这一点必须放在最前面。最简单的确认方式是查设备手册。一般的伺服驱动器、功能安全的 IO 模块、阀岛厂商会在手册里单独写一章“固件更新”或者“Bootloader”里面明确说明是否支持 FOE。第二个方式是从站 ESI 文件里看从站的 XML 描述文件中会声明邮箱协议的通讯能力如果支持 FOE通常能看到 FOE 相关的标识或者对应邮箱初始化参数。第三个方式更直接在 TwinCAT 里扫描到设备以后把从站信息窗口打开看 Mailbox 一栏是否显示支持 FOE DownLoad/UpLoad。需要提醒的是有些从站虽然有邮箱功能但只支持 CoECanOpen over EtherCAT不支持 FOE。这类设备仍然可以通过对象字典做配置读写但没法直接传固件文件想远程升级就要看厂商是否提供了专门的 OEM 升级命令。2.2 固件文件不是随便拿一个就能用固件文件表面上看就是一个二进制文件但实际讲究很多。首先是格式。不同厂商习惯不同常见的有 .bin、.hex、.s19、.efw、.mot 等等。.bin 是纯二进制.hex 和 .s19 往往是带地址信息的文本格式。FOE 传输时一般要求的是二进制的固件镜像.hex 和 .s19 需要先用厂家的转换工具或者专门的 SRecord 工具转换成 .bin 再传否则从站收到文件后可能无法识别。其次是内容。有些从站的固件文件同时包含了 Bootloader 和 Application有些则只是 Application。如果只刷 Application一般要求 Bootloader 版本要匹配。刷之前最好对照厂商的版本兼容表别看到文件名字像就往上刷。第三是校验。好的固件文件自带 CRC 或者 SHA 校验从站写入后会自己验证验证失败会反馈错误。但也有一些老设备不做校验这时候刷错固件可能直接变砖。所以刷之前做好归档把固件文件按照设备型号、版本、日期命名放到专门目录不要直接丢在桌面。2.3 TwinCAT 3 主站这边要把环境装对TwinCAT 3 本身不带现成的 FOE 界面也不代表装了 TwinCAT 就能直接用你还需要确认三件事。第一Twincat 3 运行时版本和库版本要匹配。虽然本文章里的示例主要基于常见版本但不同小版本之间的功能块参数会有细微差异。建议在 Package Manager 里检查已安装的 Tc2_EtherCAT、Tc3_EtherCAT 等库。第二EtherCAT 主站设备和网卡驱动要安装正确。TwinCAT 安装时会把兼容网卡驱动替换成 TwinCAT 专用驱动如果你不是在目标机上直接开发而是在工程机编程需要先通过 TwinCAT 的“目标浏览器”把程序放到目标机上并且保证目标机能扫描到 EtherCAT 从站。第三AMS NetID 要搞清楚。FB_EcFOEWrite 里有一个 sNetId 参数填的是 EtherCAT 主站的 AMS NetID一般就是目标机的 AMS NetID不是从站的 ID。很多新手在配置远程升级时会误把从站地址填到 sNetId 里结果一直超时。2.4 升级窗口从站停在什么状态才安全EtherCAT 从站有明确的状态机INIT、PREOP、SAFEOP、OP部分从站还有 BOOTSTRAP 状态。FOE 属于邮箱通信服务邮箱通信一般从 PREOP 阶段开始就可用所以理论上在 PREOP 状态下就能刷固件。但这里有一个关键点你刷固件的时候从站最好不要处于 OP 状态。OP 状态下从站正在实时交换过程数据如果此时数据区被改写或者从站被强制重启轻则通信断一下重则轴上直接掉使能造成安全风险。所以稳妥的做法是先在 PLC 程序里把设备切到安全状态比如伺服先解除使能、阀门先回到安全位、不需要的过程数据全部停止输出再把从站的状态切到 PREOP然后执行 FOE 写入。还有一类从站更特殊它要求先通过 CoE 写一个特殊命令让从站进入“固件下载模式”或者“Bootloader 模式”之后才能接受 FOE 文件。这个动作一般在手册里有明确说明常见的是写某个厂商自定义对象比如 0x2A00 之类的写完后从站自动断开过程数据进入引导模式这时再执行 FOE 写入完成后再重启从站。总之FOE 升级不是一个随随便便就能按下去的按钮它是一个有明确时序要求的过程。处理不好轻则升级失败重则影响产线安全。3. 先走通不写代码的方式TwinCAT 3 界面里直接刷固件3.1 三个步骤在界面中完成升级如果你现在手里只有一个从站、一个固件文件想快速验证 FOE 能不能通最快的办法是用 TwinCAT 3 自带的界面功能不需要写一行 PLC 代码。第一步在 Solution Explorer 中打开你的 EtherCAT 设备把从站扫描出来确保它处于在线状态。扫描完成后设备树里能看到这台从站状态一般是 PREOP、SAFEOP 或 OP。第二步右键点击目标从站节点选择“Firmware Update”或者“更新固件”。不同版本 TwinCAT 的菜单名称略有差异有的版本叫“Firmware Update”有的版本叫“Update Firmware”功能一样。第三步在弹出的对话框里选择固件文件点击确定。TwinCAT 会自动将你的从站状态切到合适的位置开始通过 FOE 传输文件界面会显示进度条。传输完成后它会提示你重新启动从站。重启后可以重新扫描右键查看从站的固件版本号确认是否升级成功。整个过程大概几分钟具体时间取决于固件文件大小和网络负载。通常几百 KB 的固件在标准 EtherCAT 网线上也就是几十秒的事。3.2 界面升级需要留意的几个细节界面操作虽然方便但有几个坑必须提前知道。一个坑是界面升级只能针对单个从站一个一个点如果现场有几十台设备你就要一台一台右键、选择文件、确认操作还是繁琐。当然后面我会讲怎么用代码批量跑。另一个坑是界面升级过程中TwinCAT 会短暂地把从站状态切走如果此时你的 PLC 程序还在正常运行并且程序里还有对这个从站的 IO 操作就会出现瞬时错误。所以升级前最好把程序停下或者至少在程序里做一个互锁确保升级过程中不访问这个从站。第三个坑是界面升级不一定会校验固件文件是否匹配。TwinCAT 只管通过 FOE 把文件送过去至于从站能不能识别、能不能写入是由从站固件决定的。刷完以后如果版本号没变化大概率是文件格式或者写入地址不对这时候要从厂商手册里找答案。界面方式的最大价值不在生产使用而在验证。我先在公司测试台上用界面方式刷了一次确认了从站 FOE 功能正常、固件文件没有问题之后才有信心去写代码。4. 手写远程升级功能块FB_EcFOEWrite 完整代码解析4.1 库的选择与功能块清单当界面方式验证通过以后下一步就是把升级逻辑写进 PLC 程序这样才可以做到自动判断、批量执行、集中管理。首先要把库引用加上。TwinCAT 3 里和 EtherCAT 操作相关的功能块主要在 Tc2_EtherCAT 库中。如果你在工程中看不到这个库可以在 Package Manager 里添加 TwinCAT 3 EtherCAT 相关的库。添加完成后在 PLC 中直接声明 FB_EcFOEWrite、FB_EcFOERead、FB_EcCoESdoWrite 这几个功能块就可以调用。这几个功能块分工不太一样FB_EcFOEWrite把主站侧的数据通过 FOE 写给从站这是固件升级的核心。FB_EcFOERead从从站读取文件可以用于读取日志、备份固件。FB_EcCoESdoWrite用来向从站对象字典写入命令常用于先让从站进入固件下载模式。我之前第一次写的时候以为只要用一个 FB_EcFOEWrite 就能搞定一切实际上不少设备在 FOE 之前都需要一个 CoE 命令“预热”否则从站根本不会进入等待文件的状态。所以安全起见把 FB_EcCoESdoWrite 也准备好根据实际从站手册决定要不要用。4.2 FB_EcFOEWrite 参数逐个拆解FB_EcFOEWrite 是 FOE 写入功能块如果想灵活使用它必须把它的参数含义彻底搞清楚。我根据常用版本整理了一份参数清单参数类型说明sNetIdT_AmsNetIDEtherCAT 主站的 AMS NetID格式类似 192.168.1.100.1.1nSlaveAddrDWORD从站的 EtherCAT 地址常见第一台为 16#1000sFileSTRING要传给从站的文件名注意是不含路径的文件名cbLenUDINT数据缓冲区长度单位字节pDataBufPVOID指向固件数据缓冲区的指针bExecuteBOOL启动信号上升沿触发或者置位触发tTimeoutTIME超时时间建议不要短于 10 秒bBusyBOOL正在执行标志bDoneBOOL完成标志bErrorBOOL错误标志hrErrorHRESULT错误码用于定位具体问题sNetId 填的是主站地址不是从站地址这一点特别容易搞混。nSlaveAddr 填的是从站在 TwinCAT 设备树里的 EtherCAT 地址一般可以在从站属性的 EtherCAT 页面里看到。第一台从站通常是 0x1000第二台是 0x1001或者按实际显示值来填。sFile 参数比较有意思它只是“文件名”不包含路径。因为 FOE 是从站侧的存储系统文件名最终由从站固件来解释。也就是说从站收到文件名后是按照它自己的规则去找存储位置。所以你传过去的文件名必须和厂商规定的名字一致比如有的厂家要求固定叫 “firmware.bin”有的要求带版本号后缀不能随便起。cbLen 和 pDataBuf 共同描述待传输的数据来源。实际工程里固件内容一般有两个来源一是由上位机或 HMI 从本地读取固件文件通过接口传给 PLC二是 PLC 直接读取本地存储介质的文件写入缓冲区后再触发 FOE。无论哪种方式要保证在整个 FOE 传输期间这个缓冲区内容不能被其他任务修改否则会出现数据不一致从站校验失败。4.3 一个可复用的 FB_FirmwareUpgrade 功能块既然要做远程升级就别把操作逻辑写在主程序里强烈建议封装成一个独立的功能块。这一个功能块可以反复调用每次传入不同的从站地址和文件名就能批量处理多台设备。我习惯先定义一个枚举类型用来表示升级状态TYPE E_FW_STATE : ( FW_IDLE : 0, // 空闲 FW_WRITE : 1, // FOE 写入中 FW_DONE : 2, // 升级完成 FW_ERROR : 3 // 升级出错 ); END_TYPE然后定义功能块FUNCTION_BLOCK FB_FirmwareUpgrade VAR_INPUT sNetId : T_AmsNetID; // 主站 AMS NetID nSlaveAddr : DWORD; // 从站地址如 16#1000 sFileName : STRING(255); // 固件文件名 pFwData : POINTER TO BYTE; // 固件数据缓冲区 cbFwLen : UDINT; // 固件数据长度 bStart : BOOL; // 启动命令 tTimeout : TIME : T#30S; // 超时时间 END_VAR VAR_OUTPUT bBusy : BOOL; // 忙 bDone : BOOL; // 成功完成一次 bError : BOOL; // 错误 hrError : HRESULT; // 错误码 eState : E_FW_STATE; // 当前状态 END_VAR VAR fbFoeWrite : FB_EcFOEWrite; bExecute : BOOL; bWriteDone : BOOL; bWriteError : BOOL; bWriteBusy : BOOL; hrWriteError : HRESULT; bStartPrev : BOOL; END_VAR功能块的内部状态机如下CASE eState OF FW_IDLE: bBusy : FALSE; bDone : FALSE; bError : FALSE; hrError : 0; bExecute : FALSE; // 检测启动上升沿 IF bStart AND NOT bStartPrev THEN bExecute : TRUE; eState : FW_WRITE; END_IF FW_WRITE: bBusy : TRUE; fbFoeWrite( sNetId : sNetId, nSlaveAddr : nSlaveAddr, sFile : sFileName, cbLen : cbFwLen, pDataBuf : pFwData, bExecute : bExecute, tTimeout : tTimeout, bBusy bWriteBusy, bDone bWriteDone, bError bWriteError, hrError hrWriteError ); // 保持 bExecute 为 TRUE直到 FOE 执行完成或报错 bExecute : TRUE; IF bWriteDone THEN bExecute : FALSE; bBusy : FALSE; bDone : TRUE; eState : FW_DONE; ELSIF bWriteError THEN bExecute : FALSE; bBusy : FALSE; bError : TRUE; hrError : hrWriteError; eState : FW_ERROR; END_IF FW_DONE: // 等待用户复位 bStart IF NOT bStart THEN eState : FW_IDLE; END_IF FW_ERROR: // 等待用户复位 bStart IF NOT bStart THEN eState : FW_IDLE; END_IF END_CASE // 记录上一周期启动信号 bStartPrev : bStart;这个功能块把所有和 FOE 交互的细节都封装起来了上层调用者只需要关注 bStart、bBusy、bDone、bError 这四个信号非常直观。4.4 完整调用流程从版本校验到重启验证单纯把固件文件“写”进从站只是升级过程的一半。真正工程化的升级流程至少包含下面几个步骤第一步读取当前版本。一般在从站对象字典里会有厂商版本号比如 0x1009、0x1018 或者厂商自定义对象协议不同对象不同。通过 FB_EcCoESdoRead 先读出来和期望版本比对如果版本已经是最新就跳过升级避免重复写入。第二步切换从站状态。通过 CoE 或状态控制把从站从 OP 切到 PREOP。如果是特殊设备再额外发送一个进入 Bootloader 模式的命令。第三步调用 FB_FirmwareUpgrade 执行 FOE 写入。第四步等待完成后让从站重新启动。有的从站需要远程掉电重启有的从站只需要把状态切到 INIT 再回到 OP。TwinCAT 自身也提供了状态切换功能块可以根据实际设备选择。第五步重新读取版本号校验升级结果。这一步非常重要不能只看 FOE 报 Done 就认为升级成功因为有些从站 FOE 写入成功但应用层校验失败版本号还是旧的。调用示例可以这样写PROGRAM MAIN VAR fbUpgrade : FB_FirmwareUpgrade; stSdoRead : FB_EcCoESdoRead; fwData : ARRAY [1..1024] OF BYTE; // 这个示例只放前 1K 数据 fwLength : UDINT; bCmdStart : BOOL; sCurrentVersion : STRING; END_VAR具体到某台从站固件文件内容怎么进入 fwData取决于你的应用环境。你可以用 TwinCAT 自身的文件读取功能从本地磁盘读入也可以从上位机通过 ADS 接口把固件文件下发到 PLC 缓冲区。总体原则是缓冲区要在调用期间保持一致不能被中途修改。4.5 错误处理别让功能块卡死在现场远程升级最怕的就是功能块卡在一个中间状态既没有完成也没有报错现场人员只能干瞪眼。我总结了几条经验。第一超时时间一定要给够。固件传输不光是网线速度的问题还包含从站内部 Flash 擦写的时间。有些从站只有在 FOE 数据发送完之后才开始擦写 Flash这个过程可能持续几十秒如果超时时间设成 5 秒基本必超时。我一般会设成 30 秒到 2 分钟具体看固件大小。第二出错之后必须能复位。功能块要允许现场人员按复位按钮或者重新触发 bStart 来回到 IDLE 状态否则一旦出错整个流程就僵死了。第三错误码要能解析。FB_EcFOEWrite 报错后hrError 里包含的是 FOE 错误码比如错误命令、文件不存在、Flash 写入失败等等。拿到错误码后要记录下来和厂商错误码表对应再决定下一步动作。现场最忌讳的是看到 bError 亮了就直接断电重启这样往往找不到真正的根因。第四升级流程和设备运行逻辑要做互锁。功能块内部只管刷固件但刷之前必须由外层逻辑确认设备已经安全停机。这个互锁做在程序的最外面千万不要省。5. 现场踩坑排查从报错到断电恢复的实操记录5.1 高频报错与排查思路我整理了一份高频报错排查表都是这几年实际用 FOE 升级时遇到的虽然具体错误码因设备而异但排查思路是通用的。现象可能原因排查方向FOE 启动后很快报错bError 为 TRUE从站没有进入 Bootloader 模式检查是否需要先发 CoE 命令检查设备手册传输超时长时间 bBusy 不结束网络负载过高或固件文件太大降低网络负载加大 tTimeout升级后版本号不变文件名不匹配或者固件校验失败查看从站对象字典版本号重新确认固件文件格式FOE 报文件不存在sFile 文件名和从站要求不一致和厂商确认有的从站要求名字必须固定从站状态切不回 OP升级后未重启或固件写入部分错误尝试重新上电或重新执行一次完整升级报错码和通信相关网线质量差电磁干扰检查网线屏蔽层换一个 EtherCAT 网口试试这里特别想说一下网线问题。很多现场设备 FOE 升级失败不是程序问题而是网线或者接线端子老化导致链路误码率偏高。升级前如果批量操作先确认物理层没有问题否则你会被各种莫名的超时折磨到崩溃。5.2 升级中断或掉电怎么救FOE 升级过程中如果突然断电或者拔了网线从站固件损坏的概率比较大但也不是无药可救。多数正规厂商设计的从站有 Bootloader 保护机制也就是说从站内部有两个区域Bootloader 区域和 Application 区域。即使 Application 区域被写坏Bootloader 仍然会正常工作从站上电后会进入一个“固件下载等待状态”这时候你只要再次用 FOE 把正确的固件刷进去就能恢复。但也要注意不是所有从站都这么设计。有些低成本设备没有独立 Bootloader升级断电后可能真的变砖只能返厂用编程器恢复。所以升级前先确认从站的 Bootloader 机制然后在操作流程上做好防断电措施。最稳妥的方法是给从站和 PLC 都接到 UPS 上或者选择产线计划性停电的时间窗口做升级。如果刷了一半发现中断了第一步不是重复刷而是先扫描从站看它还能不能出现在 EtherCAT 设备树里状态是什么。如果还能扫描到说明 Bootloader 还在直接重新执行完整升级即可。如果扫描不到检查 EtherCAT 网线、从站供电再尝试给从站重新上电。还是不行就要参考厂商手册的强制恢复流程了。5.3 批量升级的实用技巧当你需要升级几十台甚至上百台从站时单纯在界面里一台一台点已经不够高效也不是简单的循环调用就行。我提供几个批量升级的经验。先把设备列表整理成表格包括从站地址、设备型号、当前版本、目标版本、升级结果。然后按照设备位置或者从站地址的顺序一个一个执行升级。千万注意不要同时给两台从站同时发 FOE 写命令这会让 EtherCAT 主站负载瞬间升高也可能引起从站状态错乱。批量升级建议用一个“扫描比对升级校验”的流水线式状态机。先依次扫描所有从站的当前版本自动生成需要升级的设备清单。然后逐个执行升级每台设备升级完都验证版本号并记录日志失败的重试两次仍失败则标记为异常等全部跑完再人工处理异常设备。另外升级程序的触发权限也要做好。远程升级虽然方便但一旦误触发后果比手动刷固件更严重。我的习惯是做一个双重确认第一步在 HMI 或者上位机上输入目标批次号第二步必须有一个工程密码或确认按钮确认后程序才开始执行。这样能避免误碰按钮就把全产线设备给刷了。写日志也特别重要。每次升级无论成功还是失败都要把时间、从站地址、固件版本、错误码写进一个可以查询的表单或者数据块里。后面有人问“这台设备什么时候刷的、刷的什么版本”你不用翻聊天记录直接把日志导出来就行。6. 最后分享几条我的实操习惯做固件远程升级这件事本质上不是“会调用一个功能块”就够了它是一个系统工程。从我自己的经验来说有几点特别值得坚持。一是先在测试台上把完整流程跑通。至少验证三件事从站能通过 FOE 正常写入、固件文件本身没问题、升级后从站能恢复 OP 状态。这三件事有一件没验证就不要上现场。二是把固件文件管理好。我现在的习惯是所有固件按“厂商_设备型号_版本号_日期”命名存放在统一的网络目录里每次升级前由上位机程序读取目录列表PLC 只负责接收指定文件。版本管理做好了远程升级才有底。三是保持对从站状态的敬畏。FOE 写入操作虽然看起来只是传文件但它对从站来说是一次“深度干预”。任何时候都不要在设备还在正常运行、轴上还带负载的情况下触发升级。安全停机这个步骤永远放在升级逻辑的最前面。四是不要把所有内容都放在一个功能块里硬写。我吃过亏一开始把所有逻辑写在一个 FB 里结果后来想增加“版本比对”和“日志记录”改起来非常痛苦。现在我会拆成几个模块版本读取模块、状态切换模块、FOE 写入模块、日志记录模块。每个模块只做一件事组合起来就是一个完整的远程升级流程。最后再分享一个小技巧调试 FOE 功能时先用 1 个字节或者几个字节的小文件模拟传输确认通讯链路通再去刷真实固件。这样能把“网络问题”和“固件问题”分开定位省下大量排错时间。希望这篇文章能把 FOE 远程升级这条路径讲透。只要把协议原理、从站状态、功能块参数和批量流程这四块连起来你完全可以做出一个稳定、可追溯、还带保护机制的固件升级系统。
