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 下,尝试用ifconfig或ip 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)。如果读取失败,可能的原因有:
- PHY 地址错误:原理图上 PHY 的 MDIO 管理地址需要与软件配置一致。
- 复位信号问题:PHY 的复位引脚(通常由 GPIO 控制)时序或电平不对。需要确认复位信号的 GPIO 配置是否正确,复位脉冲宽度是否满足 PHY 数据手册要求。
- 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 头部关键字段
| 字偏移 | 寄存器地址 | 描述 | 典型值/含义 |
|---|---|---|---|
| 0 | 0x0140:0x0141 | PDI 控制寄存器 | 0x0080 表示 PDI 类型为“片上总线”(PRU-ICSS内部)。0x0005 表示 SPI 从机模式。 |
| 1 | 0x0150:0x0151 | PDI 配置寄存器 | 与 PDI 类型相关的具体配置。 |
| 2 | 0x0982:0x0983 | 同步信号脉冲长度 | 分布式时钟同步信号的脉冲宽度。 |
| 3 | 0x0152:0x0153 | 扩展 PDI 配置 | 更多 PDI 相关设置。 |
| 4 | 0x0012: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)。
抓包分析要点:
- 初始化阶段:观察主站发送的
APRD/APWR/FPWR等命令,配置从站的 FMMU(现场总线内存管理单元)和 SM(同步管理器)。确认配置的物理地址、逻辑地址、长度是否正确。 - SM 激活:在进入 OP 状态前,主站会激活 SM。在抓包中,你会看到针对 SM 控制寄存器(如
0x0800,0x0808等)的写操作,将其Enable位置 1。 - 过程数据通信:在 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。要测量抖动,你需要:
- 一个支持 DC 模式的主站(如 TwinCAT 或高性能 PLC)。
- 一台示波器。
- 从 SYNC0 信号引脚(通常在评估板的扩展接头上有引出,需查原理图)测量同步脉冲。
- 配置主站以固定周期(如 100 µs 或 1 ms)发送同步信号。
- 在示波器上测量 SYNC0 脉冲的实际周期,并启用统计功能查看周期时间的标准差或最大-最小值,这个波动就是抖动。
5.2 降低抖动的关键配置
过大的抖动通常源于系统时序的不确定性。除了优化 ARM 侧的中断和任务调度外,PRU-ICSS 层面的两个配置至关重要:
- SoC PLL 配置:确保为 PRU-ICSS 提供时钟的 PLL 配置稳定,且输出频率满足需求。不稳定的时钟源会直接引入抖动。
- 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 可能没有足够时间完成切换,导致数据未正确处理或报文组装错误。
解决方案(按推荐顺序):
- 方案二(最优):配置重叠的 FMMU/SM 映射。这是 TwinCAT 的默认做法,也是 TI 强烈推荐的。即,将输入过程数据(RxPDO)和输出过程数据(TxPDO)映射到相同的逻辑地址范围。这样,PRU 在处理一个 LRW 帧时,无需在读写上下文间切换,开销最小。对于 SOEM,调用
ec_config_overlap_map()即可实现。 - 方案一:使用独立的 LRD(逻辑读)和 LWR(逻辑写)命令代替 LRW。这样每个命令只执行一种操作(读或写),避免了上下文切换。缺点是增加了协议开销(每个命令都有独立的报文头和工作计数器),效率较低。
- 方案三:调整网络时序,增加
TX_START_DELAY。这为 PRU 的上下文切换提供了更多时间。但这是全局调整,会影响整个网络的性能,尤其是在长链路上,可能无法满足苛刻的循环时间要求。
6.2 实战配置示例与验证
以 SOEM 主站为例,启用重叠映射的代码修改非常简单。在主站配置从站后,初始化过程数据映射前,调用以下函数:
// 假设 context 是你的 ecx_contextt 结构体 ecx_config_overlap_map_group(&context, iomap, 0); // 0 表示对所有组应用修改后,重新编译主站程序。此时,再用 Wireshark 抓包,你会观察到主站发送的 LRW 帧中,读写数据的逻辑地址范围是相同的(例如,都从0x00001000开始)。同时,从站的过程数据开始正常更新。
验证步骤:
- 修改主站配置,启用重叠映射。
- 启动主站和从站,进入 OP 状态。
- 使用 Wireshark 过滤 EtherCAT 帧,找到周期性的 LRW 数据报。
- 展开帧详情,查看 “EtherCAT Datagram” 下的 “Logical Memory Address” 和 “Data” 字段。确认读写地址相同,且数据区不再全零。
- 在主站和从站应用层验证数据收发是否正常。
这个问题的解决,完美诠释了 EtherCAT 调试中“知其然,更要知其所以然”的重要性。仅仅知道要“打补丁”或“改配置”是不够的,理解其背后的硬件限制(PRU 处理周期)和协议交互原理(LRW 与 LRD/LWR 的区别),才能在未来遇到类似架构问题时举一反三。
7. 内存转储与 PRU 固件调试
当问题非常底层,例如怀疑是 PRU 固件本身运行异常时,就需要借助 CCS 对 PRU 核心进行调试和内存分析。虽然 TI 提供的 PRU-ICSS EtherCAT 固件是二进制的,我们无法进行源码级调试,但连接和检查其状态是可能的。
7.1 连接 PRU 核心与查看反汇编
- 在 CCS 中,先挂起(Halt)ARM 核心。
- 在 “Debug” 视图中,找到 “PRU_0” 和 “PRU_1” 核心,右键选择 “Connect Target”。
- 连接成功后,可以挂起 PRU 核心,然后选择 “View” -> “Disassembly” 查看反汇编代码。虽然可读性差,但你可以观察程序计数器(PC)是否在预期的代码区域运行,或者是否卡在了某个循环或异常地址。
- 你可以使用单步(Step Into/Over)指令,但需谨慎,因为实时通信可能会被中断。
7.2 PRU-ICSS 内存转储
有时,为了对比不同版本固件的行为,或者捕获某个错误发生时的瞬时状态,需要将 PRU-ICSS 的内部内存内容转储出来。
- 在 CCS 中,选择 “View” -> “Memory Browser”。
- 在内存浏览器中,输入 PRU-ICSS 的基地址加上偏移量。例如,对于 AM335x,PRU-ICSS 的基地址是
0x4A300000。 - 要转储数据 RAM0(8KB),起始地址就是
0x4A300000。要转储共享 RAM,起始地址是0x4A301000(基址 + 偏移0x0001_0000)。具体的内存映射表需要查阅芯片的《技术参考手册》。 - 在内存浏览器工具栏,点击 “Save Memory” 图标。
- 选择保存路径和文件名(如
pru_memory_dump.dat),格式选择适合的(如 Hex)。 - 输入要转储的起始地址和长度(以字为单位),然后完成保存。
获取的内存转储文件可以发送给 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.h的ApplicationObjDic[]数组中,添加新对象的引用。
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 映射是否生效。这个过程虽然繁琐,但一旦掌握,你就能完全自定义从站的数据接口,适应各种复杂的应用需求。