PRU-ICSS EtherCAT从站调试:从硬件到协议层的故障排查实战

1. PRU-ICSS EtherCAT 从站故障排查与调试指南

在工业自动化领域,EtherCAT 以其卓越的实时性和确定性,已经成为伺服驱动、远程 I/O 和复杂运动控制系统的首选网络协议。基于 TI Sitara 系列处理器及其内置的 PRU-ICSS(可编程实时单元工业通信子系统)实现 EtherCAT 从站,是许多嵌入式工程师的选择。这套方案的优势在于,它用一颗 SoC 集成了应用处理器和实时通信协处理器,省去了外置的 ESC(EtherCAT 从站控制器)芯片,降低了系统复杂性和成本。

然而,从技术文档到稳定运行的从站设备,这条路往往布满荆棘。EEPROM 配置错误、网络无法进入 OP 状态、分布式时钟同步抖动过大、LRW 访问异常导致数据为零……这些问题任何一个都足以让项目进度停滞。我经历过多次从站调试,从最初的茫然无措到后来的游刃有余,积累了不少实战经验。这份指南的目的,就是将这些经验系统化,为你提供一个清晰的排查思路和实用的操作步骤,让你在面对 PRU-ICSS EtherCAT 从站的各种“疑难杂症”时,能够快速定位问题根源,而不是在黑暗中盲目摸索。

1.1 核心排查逻辑:从宏观到微观

遇到 EtherCAT 从站不工作,最忌讳的就是一头扎进代码细节。一个高效的排查流程应该像医生问诊一样,由表及里,层层递进。我的经验是遵循“三看”原则:一看状态指示灯(AL Status),二看数据流(帧抓取与分析),三看底层硬件(信号与配置)。AL Status 寄存器(0x0130)是诊断的起点,它直接告诉你从站处于 INIT、PREOP、SAFEOP 还是 OP 状态。如果连 INIT 都进不去,那问题很可能出在硬件链路或最基本的固件加载上;如果能进入 PREOP 但无法进入 SAFEOP,则可能是邮箱通信或 SDO 配置有问题;如果能进入 SAFEOP 但卡在 OP 状态,那 Process Data 的映射、同步管理器配置或分布式时钟就可能是罪魁祸首。先通过主站软件或直接读取 ESC 寄存器确认状态,能把问题范围缩小一大半。

2. 硬件与基础环境检查

很多软件问题,其根源在于硬件。在开始复杂的协议分析之前,必须确保硬件平台和基础软件环境是健康的。这一步看似简单,却排除了至少一半的“玄学”问题。

2.1 硬件连接与端口确认

第一件要事是确认网线插对了地方。TI 的评估板(如 AM335x ICEv2, AM57xx IDK)通常有多个以太网口,分别连接至不同的子系统:CPSW(千兆交换)和 PRU-ICSS。EtherCAT 通信必须使用 PRU-ICSS 对应的端口。

以 AM335x ICEv2 板为例,其 J1 和 J2 网口通过跳线帽(J18, J19)选择连接到 CPSW 还是 PRU-ICSS。用于 EtherCAT 时,需要将跳线帽设置为连接 Pin2 和 Pin3,以选择 PRU-ICSS 模式。如果插错了口,或者跳线帽设置错误,物理链路都无法建立。对于 AM57xx IDK,通常 PRU-ICSS2 的端口是默认的 EtherCAT 端口。一个快速的验证方法是:在 U-Boot 或 Linux 下,尝试用ifconfigip link查看 PRU-ICSS 对应的网络接口(如eth2,eth3)是否能检测到链路(LINK状态)。但请注意,在运行 EtherCAT 从站固件后,这些接口在操作系统层面可能不可见,因为 PRU 已直接接管了 PHY。

注意:务必查阅你所使用的具体板卡的原理图和硬件指南,确认 PRU-ICSS 端口与 RJ45 接口的对应关系。错误连接是导致“链路灯不亮”或“主站扫描不到从站”的最常见原因之一。

2.2 PHY 配置与 MDIO 访问

PRU-ICSS 通过 MDIO(管理数据输入输出)接口管理外部的以太网 PHY 芯片(如 DP83822, DP83825)。PHY 初始化失败会导致链路始终处于 down 状态。常见的症状是:应用程序启动后,AL Status 停留在 0x0011(INIT),且 ESC DL Status 寄存器(0x0110)显示无物理链路。

排查时,可以在应用程序初始化阶段,加入 MDIO 读写测试代码。例如,尝试读取 PHY 的标识寄存器(PHY_ID1/2,地址 0x02 和 0x03)。如果读取失败,可能的原因有:

  1. PHY 地址错误:原理图上 PHY 的 MDIO 管理地址需要与软件配置一致。
  2. 复位信号问题:PHY 的复位引脚(通常由 GPIO 控制)时序或电平不对。需要确认复位信号的 GPIO 配置是否正确,复位脉冲宽度是否满足 PHY 数据手册要求。
  3. MDIO 时钟频率:PRU-ICSS 的 MDIO 模块时钟配置可能不正确,导致通信失败。

TI 的应用报告《Ethernet PHY Configuration Using MDIO for Industrial Applications》是解决此类问题的宝典,它详细解释了 PRU-ICSS 内部 MDIO 模块的配置流程和常见陷阱。

2.3 软件版本与依赖项匹配

“我这个版本和那个版本能不能一起用?”——这是社区里最常见的问题。PRU-ICSS EtherCAT 从站软件包是 TI Processor SDK RTOS 的一个附加组件。版本不匹配是导致编译失败、运行异常甚至难以捉摸的运行时错误的元凶。

必须严格遵守发布说明中的系统要求。例如,EtherCAT Slave 1.0.6 版本是基于 Processor SDK RTOS 4.3 构建的,虽然它可能与 SDK 5.0 兼容,但最稳妥的做法是使用文档明确指明的版本。混合使用版本可能导致头文件不匹配、库函数接口变化或底层驱动行为不一致。

特别需要注意的是DDR-less 模式(用于 AMIC110, AMIC120 等无外置 DDR 内存的芯片)。此模式需要特殊的二级引导加载程序(SBL)。例如,对于 AMIC110,SDK 4.3 需要手动打一个 Thumb 模式补丁(AM335x_PDK_thumb_mode.patch),而 SDK 5.0 则已集成此支持。对于 AMIC120,则需要打另一个补丁(AMIC12x_DDR-less_MLO.patch)来将 L2 Cache 配置为 SRAM。如果忽略了这一步,应用程序在加载后可能会立即跳转到异常处理向量,在 CCS 调试器中看到程序计数器(PC)指向像0x0002008C这样的 ROM 默认异常处理地址。

3. EEPROM 与从站身份标识配置

EEPROM(或它的虚拟仿真)存储着 EtherCAT 从站的“身份证”和“能力清单”,主站依靠它来识别和配置从站。这里出问题,从站可能根本无法被正确识别。

3.1 EEPROM 内容解析与生成

EEPROM 的前 16 个字(16-bit 宽)包含关键配置信息。你可以通过 CCS 的内存浏览器查看0x0000开始的 EEPROM 模拟区域。

表:EEPROM 头部关键字段

字偏移寄存器地址描述典型值/含义
00x0140:0x0141PDI 控制寄存器0x0080 表示 PDI 类型为“片上总线”(PRU-ICSS内部)。0x0005 表示 SPI 从机模式。
10x0150:0x0151PDI 配置寄存器与 PDI 类型相关的具体配置。
20x0982:0x0983同步信号脉冲长度分布式时钟同步信号的脉冲宽度。
30x0152:0x0153扩展 PDI 配置更多 PDI 相关设置。
40x0012:0x0013配置的站别名如果不使用站别名,通常为 0。
5-6-保留
7-CRC16 校验和用于验证 EEPROM 数据完整性。
8-15-设备标识(Vendor ID, Product Code, Revision, Serial Number)例如 Vendor ID: 0x000001C2 (TI), Product Code 需与 ESI 文件一致。

PDI 控制寄存器(0x0140)是排查重点。在 PRU-ICSS 内部总线模式下,应用程序在初始化后会轮询此寄存器,直到其值变为0x80。如果一直等不到,说明 PRU 固件没有正确初始化或加载。在 SPI 模式(如 C2000+AMIC110 架构)下,则轮询等待值0x05

EEPROM 数据来源于 ESI(EtherCAT Slave Information)XML 文件。TI 提供的软件包中包含一个默认的 ESI 文件。如果你需要自定义从站对象字典,就需要修改或创建新的 ESI 文件,并使用 TI 提供的工具链(如bin2header.exe)将其转换为tiesc_eeprom.h头文件,并重新编译整个从站应用程序项目。这个过程务必确保 XML 文件格式正确,且生成的二进制数据 CRC 校验无误。

3.2 主站配置与 ESI 文件匹配

主站(如 TwinCAT, SOEM, IgH)通过 ESI 文件来了解从站的能力。如果主站导入的 ESI 文件与你从站固件中定义的 EEPROM 数据不匹配,主站可能会错误地配置同步管理器(SM)或过程数据映射,导致无法进入 OP 状态。

一个常见的陷阱是PDO 映射是否重叠。TI 的 PRU-ICSS ESC 实现有一个重要的已知限制(Errata PDINSW-141):它不支持非重叠的输入/输出过程数据区的 LRW 访问。TwinCAT 默认生成的配置通常是重叠的(最优配置),但一些开源主站如 SOEM 的默认配置可能是非重叠的。这会导致主站发送的 LRW 命令被从站处理为畸形报文,工作计数器错误,过程数据全零。

解决方案:对于 SOEM,必须使用其提供的ec_config_overlap_map()ecx_config_overlap_map_group()API 函数,强制将输入和输出 PDO 映射到相同的逻辑地址空间,模拟 TwinCAT 的行为。对于 IgH Master,也有相应的补丁分支支持重叠映射。这是让从站与这些主站正常协作的关键一步,在官方文档中可能不会特别强调,但却是实战中必踩的坑。

4. 状态诊断与帧级分析

当硬件和基础配置确认无误后,就需要深入到协议层,通过寄存器和网络抓包来诊断通信状态。

4.1 关键状态与错误寄存器解读

PRU-ICSS ESC 提供了一系列状态寄存器,是诊断的“仪表盘”。除了之前提到的 AL Status,以下寄存器尤为重要:

  • ESC DL Status (0x0110): bit0-bit1 指示端口 0 和端口 1 的物理链路状态。bit8-bit9 指示端口通信状态。如果物理链路已起但通信状态异常,可能涉及 PRU 固件或数据路径问题。
  • AL Status Code (0x0134): 当 AL Status 不是 OP 时,此寄存器提供详细错误码。例如,0x001A通常表示“同步错误”或“分布式时钟配置问题”,这在尝试过低的循环周期时间时常见。
  • RX Error Counter (0x0300-0x0307): 记录无效帧和接收错误。如果计数器持续增加,检查物理链路质量、PHY 配置或外部干扰。
  • Processing Unit Error Counter (0x030C): 处理单元错误计数器。特别注意:非 EtherCAT 报文(如网络中的 LLDP 协议发现帧)也可能被 ESC 误认为是错误的数据报结构,导致此计数器增加。在共享网络中,可能需要配置交换机或网卡过滤这些报文。
  • Watchdog Status (0x0440): 过程数据看门狗状态。如果看门狗超时,从站会将过程数据输出置为安全状态(通常全零)。

在调试初期,编写一个简单的寄存器读取函数,定期打印或通过调试器观察这些关键寄存器的值,可以快速定位问题方向。

4.2 网络抓包与工作计数器分析

协议分析器(如 Wireshark)是理解 EtherCAT 通信的终极工具。你需要将网卡设置为混杂模式,并过滤 EtherCAT 协议(ethertype 0x88a4)。

抓包分析要点:

  1. 初始化阶段:观察主站发送的APRD/APWR/FPWR等命令,配置从站的 FMMU(现场总线内存管理单元)和 SM(同步管理器)。确认配置的物理地址、逻辑地址、长度是否正确。
  2. SM 激活:在进入 OP 状态前,主站会激活 SM。在抓包中,你会看到针对 SM 控制寄存器(如0x0800,0x0808等)的写操作,将其Enable位置 1。
  3. 过程数据通信:在 OP 状态下,主站会周期性地发送 LRW(逻辑读写)或 LRD/LWR(逻辑读/写)数据报。工作计数器(Working Counter)是这里的关键诊断字段。每个数据报末尾的 16 位工作计数器,记录了有多少个从站成功处理了该命令。主站会将其与期望值比较。

工作计数器不匹配的常见原因:

  • 从站未响应:物理断开、从站处于错误状态(如 SafeOP)、FMMU/SM 配置错误导致从站无法访问映射的内存区域。
  • 报文畸形:如前所述的 LRW 非重叠访问问题,会导致 PRU 固件处理异常,工作计数器错误,甚至产生畸形报文(在 Wireshark 中解析为 “Malformed Packet”)。
  • 拓扑变化:网络中有从站掉线或重新加入。

通过对比正常和异常通信时的抓包,特别是关注工作计数器和数据区内容,可以精确锁定问题发生在哪个配置环节或哪个从站上。

5. 分布式时钟同步与性能调优

分布式时钟(DC)是 EtherCAT 实现高精度同步的核心。调试 DC 相关问题时,目标有两个:一是让同步成功建立(从站进入 OP),二是优化同步精度(降低抖动)。

5.1 最低循环周期与抖动测量

不同 Sitara 处理器能达到的最低稳定循环周期不同,这主要取决于 ARM 内核的主频和 PRU 固件的处理能力。例如,AM335x (600MHz) 通常可达 62.5 µs,而 AM57xx (1GHz) 可达 31.25 µs。注意:这个极限值是在理想的、负载较轻的测试环境下得出的。实际应用中,如果 ARM 侧应用任务繁重,可能会影响 PRU 与 ARM 之间过程数据交换的及时性,导致看门狗超时或同步丢失。因此,实际项目中的周期时间应留有足够余量。

同步抖动(Jitter)是衡量同步精度的关键指标。TI 文档中给出了 AM335x 在特定拓扑下的典型抖动值为 23 ns。要测量抖动,你需要:

  1. 一个支持 DC 模式的主站(如 TwinCAT 或高性能 PLC)。
  2. 一台示波器。
  3. 从 SYNC0 信号引脚(通常在评估板的扩展接头上有引出,需查原理图)测量同步脉冲。
  4. 配置主站以固定周期(如 100 µs 或 1 ms)发送同步信号。
  5. 在示波器上测量 SYNC0 脉冲的实际周期,并启用统计功能查看周期时间的标准差或最大-最小值,这个波动就是抖动。

5.2 降低抖动的关键配置

过大的抖动通常源于系统时序的不确定性。除了优化 ARM 侧的中断和任务调度外,PRU-ICSS 层面的两个配置至关重要:

  1. SoC PLL 配置:确保为 PRU-ICSS 提供时钟的 PLL 配置稳定,且输出频率满足需求。不稳定的时钟源会直接引入抖动。
  2. TX_START_DELAY 参数:这个参数定义了 PRU 在接收到一帧数据后,需要等待多长时间才开始转发下一帧。它直接影响网络中的帧间间隔(IPG)。增加 TX_START_DELAY 可以给 PRU 更多的��理时间,有助于解决某些边界条件下的时序问题(如处理非重叠 LRW 时的开销),但会略微增加网络延迟,并在从站数量多时可能限制最小循环周期。调整此参数需要在 PRU 固件或配置中修改,通常需要重新编译。

实操心得��在调试 DC 同步时,如果从站反复在 OP 和 SafeOP 之间切换,并报告0x001A错误,首先检查循环周期是否设置得过低,超过了从站的处理能力。其次,用示波器测量 SYNC0 信号,如果发现周期严重不稳定或丢失脉冲,则重点检查主站性能、网络负载以及上述的TX_START_DELAY设置。对于 PC 作为主站的情况,由于其非实时操作系统,很难达到微秒级的稳定周期,建议使用专业的 EtherCAT 主站卡或嵌入式主站。

6. 高级故障案例:LRW 非重叠访问问题深度解析

Errata PDINSW-141 是 PRU-ICSS EtherCAT 开发中最常遇到也最令人困惑的问题之一。现象很明确:使用 SOEM 等主站时,从站能进入 OP 状态,但过程数据始终为 0,抓包能看到畸形报文或全零数据的 LRW 帧。

6.1 问题根源与三种解决方案

根源:PRU 固件在处理一个 LRW 命令访问多个从站的、逻辑地址空间上不重叠的输入区和输出区时,在切换 FMMU/SM 上下文时需要额外的处理周期。如果网络时序紧张(IPG 较小),PRU 可能没有足够时间完成切换,导致数据未正确处理或报文组装错误。

解决方案(按推荐顺序):

  1. 方案二(最优):配置重叠的 FMMU/SM 映射。这是 TwinCAT 的默认做法,也是 TI 强烈推荐的。即,将输入过程数据(RxPDO)和输出过程数据(TxPDO)映射到相同的逻辑地址范围。这样,PRU 在处理一个 LRW 帧时,无需在读写上下文间切换,开销最小。对于 SOEM,调用ec_config_overlap_map()即可实现。
  2. 方案一:使用独立的 LRD(逻辑读)和 LWR(逻辑写)命令代替 LRW。这样每个命令只执行一种操作(读或写),避免了上下文切换。缺点是增加了协议开销(每个命令都有独立的报文头和工作计数器),效率较低。
  3. 方案三:调整网络时序,增加TX_START_DELAY。这为 PRU 的上下文切换提供了更多时间。但这是全局调整,会影响整个网络的性能,尤其是在长链路上,可能无法满足苛刻的循环时间要求。

6.2 实战配置示例与验证

以 SOEM 主站为例,启用重叠映射的代码修改非常简单。在主站配置从站后,初始化过程数据映射前,调用以下函数:

// 假设 context 是你的 ecx_contextt 结构体 ecx_config_overlap_map_group(&context, iomap, 0); // 0 表示对所有组应用

修改后,重新编译主站程序。此时,再用 Wireshark 抓包,你会观察到主站发送的 LRW 帧中,读写数据的逻辑地址范围是相同的(例如,都从0x00001000开始)。同时,从站的过程数据开始正常更新。

验证步骤

  1. 修改主站配置,启用重叠映射。
  2. 启动主站和从站,进入 OP 状态。
  3. 使用 Wireshark 过滤 EtherCAT 帧,找到周期性的 LRW 数据报。
  4. 展开帧详情,查看 “EtherCAT Datagram” 下的 “Logical Memory Address” 和 “Data” 字段。确认读写地址相同,且数据区不再全零。
  5. 在主站和从站应用层验证数据收发是否正常。

这个问题的解决,完美诠释了 EtherCAT 调试中“知其然,更要知其所以然”的重要性。仅仅知道要“打补丁”或“改配置”是不够的,理解其背后的硬件限制(PRU 处理周期)和协议交互原理(LRW 与 LRD/LWR 的区别),才能在未来遇到类似架构问题时举一反三。

7. 内存转储与 PRU 固件调试

当问题非常底层,例如怀疑是 PRU 固件本身运行异常时,就需要借助 CCS 对 PRU 核心进行调试和内存分析。虽然 TI 提供的 PRU-ICSS EtherCAT 固件是二进制的,我们无法进行源码级调试,但连接和检查其状态是可能的。

7.1 连接 PRU 核心与查看反汇编

  1. 在 CCS 中,先挂起(Halt)ARM 核心。
  2. 在 “Debug” 视图中,找到 “PRU_0” 和 “PRU_1” 核心,右键选择 “Connect Target”。
  3. 连接成功后,可以挂起 PRU 核心,然后选择 “View” -> “Disassembly” 查看反汇编代码。虽然可读性差,但你可以观察程序计数器(PC)是否在预期的代码区域运行,或者是否卡在了某个循环或异常地址。
  4. 你可以使用单步(Step Into/Over)指令,但需谨慎,因为实时通信可能会被中断。

7.2 PRU-ICSS 内存转储

有时,为了对比不同版本固件的行为,或者捕获某个错误发生时的瞬时状态,需要将 PRU-ICSS 的内部内存内容转储出来。

  1. 在 CCS 中,选择 “View” -> “Memory Browser”。
  2. 在内存浏览器中,输入 PRU-ICSS 的基地址加上偏移量。例如,对于 AM335x,PRU-ICSS 的基地址是0x4A300000
  3. 要转储数据 RAM0(8KB),起始地址就是0x4A300000。要转储共享 RAM,起始地址是0x4A301000(基址 + 偏移0x0001_0000)。具体的内存映射表需要查阅芯片的《技术参考手册》。
  4. 在内存浏览器工具栏,点击 “Save Memory” 图标。
  5. 选择保存路径和文件名(如pru_memory_dump.dat),格式选择适合的(如 Hex)。
  6. 输入要转储的起始地址和长度(以字为单位),然后完成保存。

获取的内存转储文件可以发送给 TI 技术支持进行分析,或者在你自己对比不同场景时作为参考。例如,你可以比较正常通信时和发生 LRW 错误时,PRU 数据 RAM 中特定缓冲区(如过程数据映射区)的内容差异。

8. 添加与修改过程数据对象

在实际项目中,你几乎肯定需要修改默认的 PDO 映射,以传输自定义的应用数据。TI 提供了两种方法,我强烈推荐第二种手动修改法,因为它更直接,对工具链依赖小,也更容易理解底层机制。

8.1 手动修改 PDO 映射步骤详解

假设我们要添加一个输入 PDO,包含两个条目:一个 32 位整数(对象 0x6020,子索引 1)和一个 16 位整数(对象 0x6020,子索引 2)。我们需要将其映射到一个新的 TxPDO(例如 0x1A02),并将这个 TxPDO 分配到同步管理器(0x1C13)。

步骤 1:在tiescappl.h中定义新对象你需要添加三个部分:TxPDO 映射对象(0x1A02)、同步管理器分配对象(0x1C13)以及实际的数据对象(0x6020)。

/* 1. 定义新的 TxPDO 映射对象 0x1A02 */ #ifdef _OBJD_ OBJCONST TSDOINFOENTRYDESC OBJMEM asEntryDesc0x1A02[] = { {DEFTYPE_UNSIGNED8, 0x8, ACCESS_READ }, /* 子索引 0:映射条目数 */ {DEFTYPE_UNSIGNED32, 0x20, ACCESS_READ}, /* 子索引 1:第一个条目的映射值 */ {DEFTYPE_UNSIGNED32, 0x20, ACCESS_READ} /* 子索引 2:第二个条目的映射值 */ }; OBJCONST UCHAR OBJMEM aName0x1A02[] = "MyTxPDO-Map\000Entry1\000Entry2\000\377"; #endif typedef struct STRUCT_PACKED_START { UINT16 u16SubIndex0; UINT32 aEntries[2]; } STRUCT_PACKED_END TOBJ1A02; PROTO TOBJ1A02 sMyTxPDOMap #ifdef _TIESC_HW_ = {0x02, {0x60200120, 0x60200210}} /* 0x02表示2个条目,0x60200120映射对象0x6020子索引1(32位),0x60200210映射对象0x6020子索引2(16位) */ #endif ; /* 2. 更新 TxPDO 分配对象 0x1C13 */ #ifdef _OBJD_ OBJCONST TSDOINFOENTRYDESC OBJMEM asEntryDesc0x1C13[] = { {DEFTYPE_UNSIGNED8, 0x08, ACCESS_READ | ACCESS_WRITE_PREOP}, {DEFTYPE_UNSIGNED16, 0x10, ACCESS_READ | ACCESS_WRITE_PREOP}, {DEFTYPE_UNSIGNED16, 0x10, ACCESS_READ | ACCESS_WRITE_PREOP}, {DEFTYPE_UNSIGNED16, 0x10, ACCESS_READ | ACCESS_WRITE_PREOP} }; OBJCONST UCHAR OBJMEM aName0x1C13[] = "TxPDO assign"; #endif typedef struct STRUCT_PACKED_START { UINT16 u16SubIndex0; UINT16 aEntries[3]; } STRUCT_PACKED_END TOBJ1C13; PROTO TOBJ1C13 sTxPDOassign #ifdef _TIESC_HW_ = {0x03, {0x1A00, 0x1A02, 0x1A03}} /* 分配了3个TxPDO: 0x1A00(默认), 0x1A02(新增), 0x1A03 */ #endif ; /* 3. 定义新的输入数据对象 0x6020 */ #ifdef _OBJD_ OBJCONST TSDOINFOENTRYDESC OBJMEM asEntryDesc0x6020[] = { {DEFTYPE_UNSIGNED8, 0x8, ACCESS_READ }, /* 子索引 0:条目数 */ {DEFTYPE_INTEGER32, 0x20, ACCESS_READ | OBJACCESS_TXPDOMAPPING}, /* 子索引 1:32位数据,允许映射到TxPDO */ {DEFTYPE_INTEGER16, 0x10, ACCESS_READ | OBJACCESS_TXPDOMAPPING} /* 子索引 2:16位数据,允许映射到TxPDO */ }; OBJCONST UCHAR OBJMEM aName0x6020[] = "My Inputs\000Data32\000Data16\000\377"; #endif typedef struct STRUCT_PACKED_START { UINT16 u16SubIndex0; INT32 my_data_32bit; INT16 my_data_16bit; } STRUCT_PACKED_END TOBJ6020; PROTO TOBJ6020 sMyInputs #ifdef _TIESC_HW_ = {0x02, 0, 0} /* 初始化两个数据为0 */ #endif ;

步骤 2:在对象字典中注册新对象tiescappl.hApplicationObjDic[]数组中,添加新对象的引用。

TOBJECT OBJMEM ApplicationObjDic[] = { // ... 其他已有对象 ... /* Object 0x1A02 - 我们新增的TxPDO映射 */ {NULL, NULL, 0x1A02, {DEFTYPE_PDOMAPPING, 2 | (OBJCODE_REC << 8)}, asEntryDesc0x1A02, aName0x1A02, &sMyTxPDOMap, NULL, NULL, 0x0000 }, /* Object 0x1C13 - TxPDO分配 (已更新) */ {NULL, NULL, 0x1C13, {DEFTYPE_UNSIGNED16, 3 | (OBJCODE_ARR << 8)}, asEntryDesc0x1C13, aName0x1C13, &sTxPDOassign, NULL, NULL, 0x0000 }, /* Object 0x6020 - 我们新增的输入数据对象 */ {NULL, NULL, 0x6020, {DEFTYPE_RECORD, 2 | (OBJCODE_REC << 8)}, asEntryDesc0x6020, aName0x6020, &sMyInputs, NULL, NULL, 0x0000 }, // ... 其他已有对象 ... };

步骤 3:在应用代码中更新过程数据最后,在tiescappl.c文件中,找到处理 TxPDO 数据拷贝的函数(通常是APPL_Application或类似的周期函数),添加对新 PDO 映射的处理。

/* 在发送过程数据的循环中 */ UINT8 *pTmpData = (UINT8 *)pDataOut; // 假设 pDataOut 指向输出数据区 for(j = 0; j < sTxPDOassign.u16SubIndex0; j++) { switch(sTxPDOassign.aEntries[j]) { case 0x1A00: // 默认的 TxPDO *pTmpData++ = sDIInputs.switchs; break; case 0x1A02: // 我们新增的 TxPDO // 拷贝 0x6020 子索引1的32位数据 (小端字节序) *pTmpData++ = (sMyInputs.my_data_32bit) & 0xFF; *pTmpData++ = (sMyInputs.my_data_32bit >> 8) & 0xFF; *pTmpData++ = (sMyInputs.my_data_32bit >> 16) & 0xFF; *pTmpData++ = (sMyInputs.my_data_32bit >> 24) & 0xFF; // 拷贝 0x6020 子索引2的16位数据 *pTmpData++ = (sMyInputs.my_data_16bit) & 0xFF; *pTmpData++ = (sMyInputs.my_data_16bit >> 8) & 0xFF; break; case 0x1A03: // 其他已有的 TxPDO // ... 处理其他映射 ... break; } }

完成这些修改后,重新编译应用程序并加载到从站。同时,你需要根据修改后的对象字典,更新 ESI 文件,并让主站重新导入。之后,主站就可以通过映射的 PDO 来周期性地读取0x6020对象的数据了。

注意事项:修改 PDO 映射后,务必同步更新 ESI 文件,并确保主站配置与之匹配。否则,主站配置的 PDO 映射长度和内容与从站实际提供的不一致,会导致通信错误。在调试时,可以先用 SDO 访问确认新对象(0x6020)能否正常读写,再测试 PDO 映射是否生效。这个过程虽然繁琐,但一旦掌握,你就能完全自定义从站的数据接口,适应各种复杂的应用需求。