ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

EtherCAT从站开发:AX58100与STM32的XML PDO映射配置指南

EtherCAT从站开发:AX58100与STM32的XML PDO映射配置指南 搞 EtherCAT 从站开发迟早要跟 AX58100 和 XML 文件打交道。我这里说的 AX58100是带 EtherCAT 从站控制器功能的通信芯片MCU 通过 SPI 接口和它配合整机就能作为一个符合 EtherCAT 协议的从站设备出现在主站总线上。很多做伺服驱动器、IO 模块、传感器采集卡的工程师拿到样品后的第一件事往往不是写协议栈而是先改 XML 文件的 PDO 映射。这个配置不改明白后面的 STM32 代码写得再完整也白搭。这篇文章适合刚入手 AX58100 的硬件工程师或者嵌入式工程师。你不需要精通 EtherCAT 协议栈全部细节但需要知道 XML 里哪些节点决定主站和从站交换什么数据怎么把它们改成自己需要的控制字、状态字、位置值然后让 STM32 从对应内存区域把数据接住。我会把修改 XML 的完整流程、STM32 侧的代码结构和踩过的坑一起写出来。1. 项目思路AX58100 STM32 的从站架构与 PDO 改动起点1.1 AX58100 在从站设备里到底干什么AX58100 这类芯片往大了说叫 EtherCAT 从站控制器往小了说它就是负责把 EtherCAT 数据帧里属于自己那一段报文拆出来放到芯片内部的一块 RAM 里同时把 MCU 写进去的数据重新组帧发到总线上。MCU 不需要去解析 EtherCAT 报文的物理层时序、CRC、寻址这些复杂东西这些都在芯片硬件状态机里完成了。实际从站设备里常见的搭配是 AX58100 加一颗 MCU比如 STM32F103 或者更高性能的 STM32F4/G4。AX58100 负责 EtherCAT 通信MCU 负责实际业务逻辑比如读传感器、算 PID、控制伺服电机。两者之间一般用 SPI 来交换数据。AX58100 内部的过程数据 RAM 会映射到 SPI 地址空间MCU 用 SPI 读写寄存器就能拿到主站发过来的控制字也能把状态字返回给主站。很多第一次接触的人会误以为“PDO 映射”是一个 STM32 程序里的结构体定义。实际上PDO 映射的首要载体是 EtherCAT 从站信息文件也就是 XML。主站软件启动时先读这个 XML知道从站支持哪些过程数据对象然后才进行配置。如果 XML 里没写主站根本不会给从站下发这些数据MCU 里定义了再漂亮的变量也收不到。1.2 PDO 映射为什么 XML 文件说了算EtherCAT 从站和主站之间的数据交换分成周期性过程数据和非周期性邮箱数据。邮箱数据类似 UDP适合配置参数、读写对象字典但速度慢、不定时。过程数据则类似一块固定的共享内存每个周期都交换适合控制字、目标位置、实际速度这类实时信号。PDO 就是过程数据对象它告诉主站从站的控制数据从对象字典的哪个索引、子索引取出来占多少位顺序怎么排列。XML 文件就是这块共享内存的“地图”。主站是地图的持有方从站的硬件内存是实现方。你在 XML 里把 0x6040 控制字映射到 RxPDO 第一个位置主站就会在周期性数据帧的第一个字段塞进控制字从站 AX58100 收到以后把这个字段放到过程数据 RAM 的对应位置STM32 再从对应的内存偏移读出来控制字就这样到了 MCU。整个过程XML 不参与实时运行但它决定了主站和从站在运行前怎么约好数据格式。1.3 方案选型为什么用 AX58100 STM32 组合选 AX58100 做从站芯片一个很现实的原因是成本可控而且片内集成了 PHY做两端口级联的拓扑很方便不需要外部再单独接网络变压器之外的物理层芯片。另一部分原因是它可以通过 SPI 和任意单片机连接不用被某家厂商的专用协议栈绑死。STM32 是这里很常用的搭档SPI 外设成熟DMA 传输方便定时器中断能做周期调度调试工具也多。做完 XML 修改之后STM32 侧的核心工作就变成了SPI 驱动 AX58100、周期性读写过程数据 RAM、把 PDO 数据映射成工程里的业务结构体。整个过程并不复杂但有一点需要提前说清楚先定好 XML 的 PDO 布局再写 STM32 代码顺序不要反。我见过有人先把 STM32 代码写完了回头再改 XML结果 PDO 顺序和结构体对不上数据错位查了半天。2. 看懂 XMLESI 文件里的对象字典、PDO 与同步管理器2.1 EtherCAT 从站信息文件的基本结构AX58100 的 XML 文件通常叫做 ESI 文件EtherCAT Slave Information。这个文件可以从芯片原厂、开发板厂商或者代码生成工具里拿到。用文本编辑器打开会看到一个大大的EthercatInfo根节点下面通常分成Vendor、Descriptions、Mailbox、Profile等部分。我们关心的过程数据配置主要在DescriptionsDevicesDevice节点下。一个简化但不失真的结构如下EthercatInfo Vendor Id#x00000042/Id NameDemo Vendor/Name /Vendor Descriptions Devices Device TypeAX58100_TestDevice/Type NameAX58100 Test Device/Name RxPdo Index#x1600/Index NameRxPDO_Control/Name Entry Index#x6040/Index SubIndex0/SubIndex BitLen16/BitLen NameControlword/Name DataTypeUINT/DataType /Entry /RxPdo TxPdo Index#x1A00/Index NameTxPDO_Status/Name Entry Index#x6041/Index SubIndex0/SubIndex BitLen16/BitLen NameStatusword/Name DataTypeUINT/DataType /Entry /TxPdo /Device /Devices /Descriptions /EthercatInfo这里#x前缀表示十六进制后面的数字就是对象字典索引。0x6040是 CiA402 标准里的控制字0x6041是状态字。实际文件里还会有 mailbox 配置、SyncManager 配置、FMMU 配置等但 PDO 相关的内容就是上面这些 Entry。2.2 对象字典、RxPDO 和 TxPDO 之间的关系对象字典是从站自己的“内部数据库”每个对象都有一个 16 位索引和可能的 8 位子索引。RXPDO 和 TXPDO 并不真正存储数据它们只是“引用”对象字典里的条目。比如 RxPDO 里的 Entry 用Index#x6040/Index指向对象字典中的控制字对象实际数据长度由对象的位长决定。在 EtherCAT 术语里RxPDO 表示主站发给从站的数据对应“输出”方向。对伺服来说就是控制字、目标位置、目标速度、模式切换这些命令。TxPDO 表示从站发给主站的数据对应“输入”方向常见的是状态字、实际位置、实际速度、报警代码。命名上有点反直觉但记住一个原则站在从站角度看Rx 是收Tx 是发。修改 XML 时最核心的就是增删Entry并保证它指向的对象字典条目已经存在。如果你把 0x60FF 映射进了 RxPDO但对象字典里根本没定义过 0x60FF主站加载 XML 时要么报错要么自动忽略这条映射。很多开发板自带的 XML 只保留最小 PDO你要新增功能就得先补对象字典定义。2.3 Sync Manager 和 PDO 的对应关系EtherCAT 从站内部有若干个同步管理器沟通 ESC 和本地应用之间的数据。SM0/SM1 一般给邮箱数据用SM2/SM3 给过程数据用。SM2 通常对应输出方向也就是 RxPDOSM3 对应输入方向也就是 TxPDO。在 XML 里SM 配置大致如下Sm StartAddress#x1000 ControlByte#x26 Enable1 NameOutputs/Name RxPdo1600/RxPdo /Sm Sm StartAddress#x1100 ControlByte#x22 Enable1 NameInputs/Name TxPdo1A00/TxPdo /Sm其实不用死记每个地址只要明白一点StartAddress决定了过程数据在 ESC 内存里的起点RxPdo/TxPdo的区域会把对应的 PDO 索引绑定到这块起始地址上。修改 XML 时新增 PDO 以后一定要确认对应的 SM 里已经把新 PDO 索引列进去了。否则主站能看到这个 PDO却不知道它该放到哪个同步管理器最后从站进入 OP 状态后数据还是不刷新。类型方向常见 SM数据示例RxPdo主站到从站SM2控制字、目标速度、模式TxPdo从站到主站SM3状态字、实际位置、报警3. 手把手修改 XML新增 RxPDO / TxPDO 的完整步骤3.1 改之前先备份再看设备描述拿到 XML 文件以后别急着动手。先用 VSCode、Notepad 这类支持 XML 语法高亮和格式化的编辑器打开不要用系统记事本直接保存容易把编码搞坏。我习惯先把整个文件格式化一遍再搜索自己设备对应的Type把目标 Device 段落找出来。另外建议把原始 XML 单独备份一份。改 PDO 看起来是加几行 Entry但实际牵涉对象字典、SM 配置、数据类型定义好几处联动。改乱了还能退回原厂配置重新开始。3.2 在 RxPDO 里新增一个目标速度对象假设现在的 RxPDO 只映射了控制字0x6040我们要在同一个 RxPDO 里增加目标速度0x60FF。先找到当前 RxPDO 段落RxPdo Index#x1600/Index NameRxPDO_Control/Name Entry Index#x6040/Index SubIndex0/SubIndex BitLen16/BitLen NameControlword/Name DataTypeUINT/DataType /Entry /RxPdo然后在Entry结束标签后面追加一个目标速度条目Entry Index#x60FF/Index SubIndex0/SubIndex BitLen16/BitLen NameTargetVelocity/Name DataTypeINT/DataType /Entry这里有一个很容易忽略的地方如果设备原来的 XML 对象字典里没有0x60FF你光加 PDO Entry 是没有用的。还要在对象字典区域补一个对象定义。以简化格式为例Dictionary Objects Object Index#x60FF/Index NameTargetVelocity/Name TypeINT16/Type BitSize16/BitSize /Object /Objects /Dictionary对象定义完成后还要检查这个对象的访问属性、存储属性是不是和从站固件一致。很多自带 XML 的对象字典是精简过的只有实际用到的那几个对象新增对象字典条目时最好参考 AX58100 的从站代码模板。3.3 修改 TxPDO 的注意事项TxPDO 的修改方法和 RxPDO 基本一样只是方向变成从站到主站。比如你原来只上报状态字0x6041现在要把实际位置0x6064也上报出来那就照猫画虎加一个 Entry。但这里要注意位长。0x6064实际位置在大多数伺服对象字典里是 32 位无符号整数所以 BitLen 要写成 32DataType 写UDINT。修改 TxPDO 之后STM32 侧接收结构体的字段顺序要和 XML 里的 Entry 顺序严格保持一致。比如 TxPDO 里先状态字后实际位置那么 STM32 从过程数据 RAM 读到的前 2 个字节是状态字紧接着 4 个字节是实际位置。如果把结构体定义成先实际位置后状态字主站那边显示的速度就会变成状态字拼接出的一个莫名其妙的大数非常典型。3.4 修改完成后的 XML 验证与加载XML 本质是文本文件最常见的低级错误就是标签不闭合、注释没结束、中文编码乱掉。修改完成后先做一次 well-formed 校验。在 VSCode 里安装 XML 插件后格式化成功就说明语法基本没问题用命令行工具xmllint --noout 你的文件.xml也能快速验证。接下来还要把这个 XML 加载到主站。这里有两种情况一种是用主站软件从设备 EEPROM 里读设备描述那就得把 XML 转换成 ESI binary 文件烧进从站 EEPROM另一种是直接把 XML 安装到主站的设备描述库再重启主站扫描设备。很多工程师只改了主站侧描述文件没有重新烧录从站 EEPROM结果从站上电后 ESC 用默认描述信息启动主站和从站两边信息对不上该出现的 PDO 就是不出来。4. STM32 侧代码SPI 读写、中断处理和 PDO 结构体设计4.1 STM32 初始化 AX58100SPI 加中断引脚AX58100 与 STM32 之间最常用的接口是 SPI 从模式。STM32 做主机AX58100 做从机。初始化时先配置 SPI 的时钟极性和相位。不同版本的 AX58100 对 SPI 模式要求可能不一样一定要对着自己手上的数据手册确认。有的默认是 CPOL0、CPHA0有的则工作在模式 3这个不能凭经验猜。基本初始化流程如下void AX58100_Init(void) { // 1. 初始化 SPI 引脚 SPI_InitTypeDef spi; spi.Mode SPI_MODE_MASTER; spi.Direction SPI_DIRECTION_2LINES; spi.DataSize SPI_DATASIZE_8BIT; spi.CLKPolarity SPI_POLARITY_LOW; // 以实际手册为准 spi.CLKPhase SPI_PHASE_1EDGE; spi.NSS SPI_NSS_SOFT; spi.BaudRatePrescaler SPI_BAUDRATEPRESCALER_16; HAL_SPI_Init(hspi); // 2. 片选脚、复位脚、中断脚配置为 GPIO MX_GPIO_Init(); // 3. 复位 AX58100低脉冲 HAL_GPIO_WritePin(RST_GPIO_Port, RST_Pin, GPIO_PIN_RESET); HAL_Delay(10); HAL_GPIO_WritePin(RST_GPIO_Port, RST_Pin, GPIO_PIN_SET); // 4. 读 ID 寄存器确认通信正常 uint16_t id AX58100_ReadReg16(0x0000); }读 ID 寄存器这一步非常重要。SPI 时序、GPIO 配置、复位电平只要有一个不对读回来的值基本是0xFFFF或者乱码。可以先把这个当作“Hello World”通了再继续往下做。4.2 封装 PDO 读写函数AX58100 的寄存器空间里有一块专用的过程数据 RAM具体物理地址要看 XML 里 SM 的StartAddress。一般会落在0x1000附近。不要写死地址就完事最好做成宏定义后续改 XML 时只需要改一个地方。示意代码如下#define ESC_PD_RAM_BASE 0x1000U // 需要和XML中SM的StartAddress对应 #define RX_PDO_OFFSET 0x0000U #define TX_PDO_OFFSET 0x0040U void AX58100_ReadReg(uint16_t addr, uint8_t *buf, uint16_t len) { HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_RESET); // 发送地址和读命令具体格式按AX58100手册 SPI_TransmitCommand(AX58100_CMD_READ, addr); HAL_SPI_Receive(hspi, buf, len, 100); HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_SET); } void AX58100_WriteReg(uint16_t addr, uint8_t *buf, uint16_t len) { HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_RESET); SPI_TransmitCommand(AX58100_CMD_WRITE, addr); HAL_SPI_Transmit(hspi, buf, len, 100); HAL_GPIO_WritePin(CS_GPIO_Port, CS_Pin, GPIO_PIN_SET); } void ReadTxPDO(uint8_t *buf, uint16_t len) { AX58100_ReadReg(ESC_PD_RAM_BASE TX_PDO_OFFSET, buf, len); } void WriteRxPDO(uint8_t *buf, uint16_t len) { AX58100_WriteReg(ESC_PD_RAM_BASE RX_PDO_OFFSET, buf, len); }注意AX58100_CMD_READ/AX58100_CMD_WRITE的具体编码以芯片手册为准。不同品牌的 ESC 可能有不同的命令格式甚至还有地址自动递增模式。我这里写的是示意逻辑直接照抄前一定要查手册。4.3 用定时器中断实现周期数据交换EtherCAT 的过程数据交换是周期性的常见周期在 125us 到 4ms 之间。STM32 侧一般用定时器产生固定周期中断在中断里完成读 TXPDO、处理业务、写 RXPDO。简单做法如下volatile uint8_t ethercat_cycle_flag 0; void TIM_UPD_IRQHandler(void) { if (__HAL_TIM_GET_FLAG(htim, TIM_FLAG_UPDATE)) { __HAL_TIM_CLEAR_FLAG(htim, TIM_FLAG_UPDATE); ethercat_cycle_flag 1; } } void MainLoop(void) { while (1) { if (ethercat_cycle_flag) { ethercat_cycle_flag 0; // 读从站状态字 uint8_t txBuffer[8]; ReadTxPDO(txBuffer, sizeof(txBuffer)); // 解析业务数据 ServoStatus_Handle(txBuffer); // 写入控制字 uint8_t rxBuffer[8]; ControlWord_Fill(rxBuffer); WriteRxPDO(rxBuffer, sizeof(rxBuffer)); } } }如果主站要求周期很短比如 250us主循环轮询加标志位的方式可能不够稳建议改成在定时器中断里直接调用读写函数或者用 SPI DMA。用 DMA 时记得等传输完成再把片选拉高否则最后一个字节可能还没发完设备就认为片选已经断了。4.4 让结构体和 XML 逐字段对齐这是最容易写错的地方。XML 里 RxPDO 的顺序必须和 STM32 结构体成员顺序一致。比如前面我们定义了 RXPDO 控制字 目标速度对应结构体可以写成#pragma pack(push, 1) typedef struct { uint16_t Controlword; // 对应 0x6040 int16_t TargetVelocity; // 对应 0x60FF } RxPdoData; typedef struct { uint16_t Statusword; // 对应 0x6041 uint32_t ActualPosition; // 对应 0x6064 } TxPdoData; #pragma pack(pop)#pragma pack(1)避免编译器自动加入的字节对齐填充否则结构体大小和 XML 的 BitLen 总和会对不上。比如 uint16_t 和 int32_t 如果默认四字节对齐中间可能被塞两个填充字节数据就全错位了。拿到主站发来的rxBuffer后直接强转成结构体指针RxPdoData *rxPdo (RxPdoData *)rxBuffer; if (rxPdo-Controlword 0x0006) { // 进入伺服使能状态 }如果结构体和 XML 对不齐最常见的现象就是控制字写成 0x0006主站那边看到的却是 0x0600 或者某个错乱的数字拨半天都没反应。5. 踩坑记录主站识别不到、数据错位和 SPI 异常排查5.1 主站扫描后没有出现新增的 PDO 对象这个坑我踩过不止一次。改完 XML主站重新扫描设备从站确实能发现但 PDO 列表还是旧内容。原因分两类。一类是主站没有重新加载设备描述文件。很多主站软件有“更新设备描述”或者“ESI 库更新”的操作不是直接把 XML 丢到某个文件夹就生效。更新频率不高的主站甚至需要重启软件。另一类是从站 EEPROM 里烧录的还是旧描述。如果主站和从站通信时以 EEPROM 里的描述为准那就要用专用烧录工具把新的 ESI 数据写进去。只改主机侧的 XML 并不能改变从站 EEPROM 的内容。最好的做法是改完 XML重新生成 ESI 镜像文件烧录到从站同时把 XML 安装到主站两边一起更新。5.2 OP 状态下数据全 0 或者全 F从站能进入 OP 状态说明基本通信已经建立但 PDO 数据不对通常不是主站问题而是从站本地数据没有从 SM 对应的地址拿。最典型的原因是 SM 的StartAddress和 STM32 代码里ESC_PD_RAM_BASE不一致。比如 XML 里 SM2 的StartAddress是0x1000代码里却写了0x1100读出来的自然就是另一块内存的内容。解决方法是把 XML 里的 SM 起始地址、PDO 里 Entry 的排列顺序全部列成一张表和代码中的偏移量一一对应。另一个原因是 BitLen 算错。如果你把 32 位的目标位置写成 16 位或者把 8 位的模式误写成 16 位ESC 的内存分配会按位对齐后面的所有字段都会偏移。这种问题靠肉眼看代码很难发现最好拿主站自带的协议分析或者过程数据监视界面看哪个字段错位一眼就看出来了。5.3 SPI 通信异常的快速排查AX58100 的 SPI 通信相对简单但出问题时现象很迷惑。常见的有读 ID 读到全 0xFF、全 0x00、或者时好时坏。快速排查路线如下先确认电源和复位。AX58100 的复位引脚要有明确的低脉冲释放释放后不能立刻操作最少等几十毫秒。再确认 CS 时序。CS 拉低后到 SCK 第一个时钟沿之间的时间不能太短有些芯片手册会给具体要求。然后用示波器看 SCK 频率。SPI 从机的最高时钟频率有限制并不是 STM32 SPI 分频能多高就多高。如果降频后正常了就是频率超了。最后看 DMA。用了 DMA 以后CS 拉高的时机必须在 DMA 传输完成中断之后不能在调用返回时立刻拉高。读 ID 寄存器这一步如果 SPI 模式不对读出来的数据一般是整段颠倒或者全是 1。先试 CPOL0、CPHA0不行再试模式 3很快就定位。5.4 维护 PDO 映射表和固件结构体同步每次改 XML我都会做一张三联映射表PDO 索引、Entry 对象字典索引/子索引/位长、STM32 结构体成员名。这张表放在工程注释最上面比文档管用得多。比如下面的表格就是维护文档里的一部分XML PDO对象索引子索引位长STM32 成员RxPDO 0x16000x6040016ControlwordRxPDO 0x16000x60FF016TargetVelocityTxPDO 0x1A000x6041016StatuswordTxPDO 0x1A000x6064032ActualPosition每次改完 XML拿这张表和代码核对一遍再把结构体长度和 XML 里所有 Entry 的 BitLen 总和核对一遍。比如 TxPDO 四个字段的 BitLen 总和应该是 163248 位也就是 6 个字节结构体大小也应该正好是 6。只要这边对得上数据错位的问题能消灭一大半。搞 EtherCAT 从站开发说到底不是智力活而是细活。XML、ESC 内存、STM32 结构体这三个地方的顺序必须保持完全一致少看一眼都会在后面某个深夜变成一脸茫然的排查现场。我个人习惯是先做映射表再动手改代码改完 XML 先验证格式再烧录再抓一次协议数据确认这样基本能一次跑通。希望这篇记录能帮你少走一点弯路。
返回列表