☰
STM32F103+LAN9252 EtherCAT从站开发实战:SSC配置与移植避坑指南
2026/11/3 3:05:14 网站建设 项目流程

简介:面向嵌入式开发者的EtherCAT从站构建实践文档,聚焦STM32F103与LAN9252以太网PHY芯片的SPI连接方案,适合已具备一定单片机基础、希望入门工业实时以太网的中高级工程师参考。内容围绕LAN9252四种工作模式的选型依据展开,梳理从XML设备描述文件构建、SSC工具生成协议栈、原理图与PCB设计到代码移植调试的完整链路,并剖析HW_Init、MainInit、MainLoop骨架及SPI、定时器、外部中断的配置要点。资源包共1个docx文件,约1.75MB,以图文文档形式承载项目流程与关键代码片段。目前已有2921人学习,读者可从中获取从站开发的整体思路、XML与EEPROM烧录要点以及中断处理等排错参考,减少移植阶段的试错成本。

1. 从一块买来的学习板说起:STM32F103 挂 LAN9252 做 EtherCAT 从站到底难在哪

手头有一台只认 TwinCAT2.0 的老主站,一台 ARM 架构、跑 Windows CE 的工控 PC,项目要求周期交互 64 入 64 出纯数字 IO。主站改不动,只能自己做从站。选型很快落到 STM32F103 加 LAN9252 这套组合上:前者便宜、资料多、HAL 库成熟,后者把 PHY、网络交换、SPI 从机三件事全包了,两端口一进一出,满足 EtherCAT 从站不许终结总线的硬性要求。真正让人头疼的不是画板子,而是协议栈、XML 描述文件、EEPROM 配置数据这三者之间的耦合关系——任何一处对不上,TwinCAT 扫描时就只能看到一个红叉。这篇笔记按我实际拆解的路径走一遍:LAN9252 的四种工作模式怎么选、SSC 怎么生成协议栈和 XML、14 字节 ConfigData 为什么必须改、STM32 侧 SPI 与中断怎么配、移植时哪些地方一上电就翻车。

2. LAN9252 四种工作模式与 SPI 从站架构的选型理由

2.1 四种模式各自的边界

LAN9252 手册里列了四种工作模式,选型时不能只看“哪个简单”,要看主站侧的数据量和实时性要求。数字 IO 模式只有 8 入 8 出,适合极简的开关量模块,但本项目要 64 入 64 出,直接出局。并行 HBI 模式用 16 位或 8 位并口跟 MCU 交互,带宽高、时序直接,代价是占用大量 GPIO,STM32F103 的引脚资源会被吃掉一大块,PCB 布线也复杂。扩展模式是 SPI 加一路 MII 对外,能再挂一颗 PHY 多接一个 RJ45,适合需要三端口或级联更深的场景,本项目两端口够用,没必要增加 BOM。SPI 模式四根线(CS、SCK、MISO、MOSI),标准 SPI 时钟最高 30MHz,SQI 六线模式能到 80MHz,64+64 位的过程数据在 1ms 周期下用标准 SPI 完全跑得动,引脚省下来给别的东西。

选 SPI 还有一个隐性理由:协议栈里 PDI(Process Data Interface)层的抽象本来就是围绕 SPI 写的,SSC 生成的代码默认就是 SPI 时序,移植时少一层转换。并行模式虽然快,但协议栈里对应的接口要自己补,对不熟悉协议栈内部结构的人来说是额外风险。

2.2 LAN9252 在系统里到底干了三件事

第一是 PHY,所有跟 RJ45 的物理层交互、曼彻斯特编码解码、链路检测都由它完成,STM32 完全不碰以太网时序。第二是网络交换,EtherCAT 从站必须支持一拖一,数据帧从端口 0 进来、端口 1 出去,LAN9252 内部做转发,MCU 不需要参与。第三是 SPI 从机加数据解析,主站下发的过程数据帧里,属于本从站的那一段被 LAN9252 提取出来,通过 SPI 交给 STM32;STM32 写回的输出数据再由 LAN9252 塞回帧里。这三件事决定了 MCU 侧只需要关心 SPI 读写和中断响应,不用理解以太网帧结构。

2.3 整体开发流程的先后顺序

实际做下来,顺序不能乱:先拿学习板跑通官方例程,确认 TwinCAT 能扫到设备、能进 OP 状态;再用 SSC 按自己的 IO 需求生成 XML 和协议栈;然后改 XML 里的 ConfigData 适配 LAN9252;接着画自己的板子、配 STM32 外设;最后把协议栈往自己的工程里搬。跳过学习板直接上自绘板,出问题时分不清是硬件还是协议栈,血泪经验。

3. 用 SSC 生成协议栈与 XML:从 Excel 点位表到可编译工程

3.1 SSC 的获取与模板选择

SSC 是 EtherCAT 协会给会员的免费工具,下载时要填 VendorID,这个 ID 是协会分配给会员企业的全球唯一标志,XML 里的 Vendor id 节点就来自它。打开 SSC 后 File->New,默认模板提示“All settings are available”,但更合适的是选 Custom 下拉里的EL9800 | 8Bit Digital I/O, 16Bit Analog Input,这个模板的 PDI 就是 SPI,跟我们的架构一致,省掉后面改配置的麻烦。

3.2 用 Excel 定义 64 入 64 出点位

建好项目后依次点 Tool->Application->Create New,保存工程,SSC 会弹出一个 Excel 模板(本机要装 Excel)。这份表就是过程数据的定义源,//0x6nnx段是输入、//0x7nnx段是输出,每个条目对应一个 bit。64 个输入就填 64 行,用 Excel 的批量拖拽往下拉,注意索引连续、名称不重复。最后把Maximum number of modules改成 3。保存后 SSC 自动弹导入对话框,点 OK 导入。

Excel 条目示例(输入段): Index Name Type BitLen 0x6000:01 Input_00 BOOL 1 0x6000:02 Input_01 BOOL 1 ... 0x6000:40 Input_63 BOOL 1 输出段: 0x7000:01 Output_00 BOOL 1 ... 0x7000:40 Output_63 BOOL 1

索引段的选择有讲究:0x6000 和 0x7000 是 CANopen 里约定的数字输入/输出对象区,TwinCAT 解析时按这个约定映射,换成别的段虽然语法上能过,但组态时 PLC 侧的变量映射会对不上。BitLen 全部填 1,表示每个点占一个 bit,64 个点正好 8 字节,跟 LAN9252 的 SM 通道 16 位对齐要求不冲突。

3.3 生成协议栈文件与目录结构

导入 Excel 后点 Project->Create new Slave Files,SSC 生成整套源码。关键目录是Src下的协议栈文件和ESI下的 XML。协议栈里SSC-DeviceObjects.h跟 XML 的字典节点一一对应,后面移植时要重点看。生成的代码不能直接烧进自己的板子,因为硬件抽象层(HW_Init、SPI 读写、中断入口)还是按 EL9800 评估板写的,但对象字典和状态机部分是通用的,价值就在这里。

提示:SSC 内置一份EtherCAT Slave Design Quick Guide.pdf,XML 各节点的含义、SM 通道的作用在里面讲得比手册清楚,生成完先翻一遍再动手改。

4. XML 文件解剖:ConfigData 那 14 个字节为什么必须改

4.1 设备基础信息节点

XML 顶层分 Vendor 和 Descriptions 两块。Vendor 下的 id 和 name 来自会员信息,ImageData16x14 是 16 色深、16x14 像素的 bmp 图标,用画图或 PS 做好后用十六进制查看器把数据填进去。Descriptions->Devices->Device 下的 Physics 节点,YY表示两个 RJ45 一进一出,K是倍福的 EBUS 口,本项目保持 YY。ProductCode 和 RevisionNo 是 TwinCAT 识别设备唯一性的依据,两份 XML 这两个字段相同的话,放到TwinCAT/Io/EtherCAT目录下只会认其中一个,迭代版本时务必同步升级 RevisionNo。

4.2 字典与 IO 点位的对应关系

Profile 节点下分 DataType 和 Objects,前者像 C 里的 typedef,后者像变量定义。比如Device name这个 Object,index 是#x1008,type 是STRING(10),往上找 DataType 里STRING(10)的 BitSize 是 80 bit,即 uchar[10],内容就是设备基础信息里定义的 Device Name。这种引用关系理不顺,TwinCAT 就连不上。IO 点位在 Device 下的四个 Sm 节点里,MBoxOut 和 MBoxIn 是邮箱通道管状态机,Inputs 和 Outputs 才是过程数据,分别指向 RxPdo 和 TxPdo,每个 Entry 就是 Excel 里的一行。SSC 生成了 128 个 Entry,手工写基本不可能。

4.3 ConfigData 从 ET1100 默认值改成 LAN9252 值

这是整个 XML 里最容易翻车的地方。SSC 默认按 ET1100 芯片生成,ConfigData 是050E03440A0000000000。换成 LAN9252 要按芯片手册 AN1907 的迁移说明改成800E00CC8813F0000000800000。第一个字节80对应 LAN9252 的 0x0140 寄存器,也就是 Process Data Interface 配置寄存器,值 80h 就是 SPI 模式。这一字节错了,LAN9252 上电后不会进 SPI 从机状态,TwinCAT 扫描时设备能认到 EEPROM 但进不了 OP。

ConfigData 修改对照: ET1100 默认:050E03440A0000000000 LAN9252 SPI:800E00CC8813F0000000800000 ^^ 0x80 -> 0x0140 寄存器 = SPI PDI

后面那些字节分别对应 PDI 控制、中断极性、EEPROM 大小等配置,手册 12.8 节有完整表格,暂时不理解就保持迁移文档给的值,不要自己改。EEPROM 节点里 ByteSize 一般写 2048,物理芯片建议用 24FC512(512Kbit),给后续 IO 扩展留余量。跟 LAN9252 配的 EEPROM 尽量选这颗,换别的型号有连接不稳定的案例。

5. STM32 侧外设配置:SPI、1ms 定时器与三个外部中断

5.1 CubeMX 里的外设清单

新建 STM32F103ZExx 工程,要配的外设就四样:SPI1 四线标准模式(时钟先给 15MHz 左右,跑通再往上提)、一个 1ms 定时器命名 ECAT_CheckTimer、三个外部中断分别对应 IRQ、SYNC0、SYNC1。SPI 不需要开中断,因为 SPI 是全双工,读的同时就在写,时序由硬件移位寄存器保证,中断反而添乱。

NVIC 优先级按 2 bit 抢先、2 bit 响应分配:ECAT_CheckTimer 设 1 抢先 0 响应,PDI_Isr 设 1 抢先 0 响应,Sync0_Isr 和 Sync1_Isr 设 2 抢先 0 响应。同步中断优先级低于主中断,是为了保证 PDI 处理不被时钟同步打断。

5.2 生成代码后必须注释掉的三处 Enable

CubeMX 生成代码时,外部中断和定时器中断的初始化函数末尾会自动加HAL_NVIC_EnableIRQ()。这三行必须注释掉,改由协议栈在初始化流程里按状态机需要去使能。一上电就开中断,LAN9252 还没完成配置,中断进来读到的全是无效数据,状态机直接卡死,现象就是 TwinCAT 一直停在 INIT 或 PREOP。

/* 在 gpio.c / tim.c 的 MX_xxx_Init() 末尾,注释掉类似下面这行 */ /* HAL_NVIC_EnableIRQ(EXTI15_10_IRQn); */ /* 协议栈内部会在合适时机调用,例如 HW_Init() 之后 */ void HW_EnableInterrupts(void) { HAL_NVIC_EnableIRQ(EXTI15_10_IRQn); /* PDI_Isr */ HAL_NVIC_EnableIRQ(TIM3_IRQn); /* ECAT_CheckTimer */ }

5.3 中断回调的统一入口

HAL 库把所有 GPIO 外部中断汇到HAL_GPIO_EXTI_Callback,在里面按引脚分发到协议栈的三个 ISR。SYNC0 和 SYNC1 处理前后要关/开 ESC 中断,防止同步事件被 PDI 中断打断造成时序抖动。

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { if (GPIO_Pin == LAN9252_IRQ_Pin) { PDI_Isr(); /* 主中断,必须实现 */ return; } if (GPIO_Pin == LAN9252_SYC0_Pin) { DISABLE_ESC_INT(); /* 关 ESC 中断,保护同步窗口 */ Sync0_Isr(); ENABLE_ESC_INT(); return; } if (GPIO_Pin == LAN9252_SYC1_Pin) { DISABLE_ESC_INT(); Sync1_Isr(); ENABLE_ESC_INT(); return; } }

PDI_Isr是必须实现的,SYNC0/SYNC1 只在启用分布式时钟时才需要,本项目纯数字 IO 可以先不接,但回调框架留着,后面加 DC 不用改结构。

5.4 SPI 读写函数的封装

协议栈期望的是一组简单的字节读写接口,名字按HW_EepromRead、HW_ReadPDI之类的约定来。用 HAL 的HAL_SPI_TransmitReceive一次收发一个字节,片选由软件控制。

uint8_t HW_SPI_ReadByte(void) { uint8_t tx = 0xFF, rx = 0; HAL_SPI_TransmitReceive(&hspi1, &tx, &rx, 1, 100); return rx; } void HW_SPI_WriteByte(uint8_t data) { uint8_t rx; HAL_SPI_TransmitReceive(&hspi1, &data, &rx, 1, 100); }

超时参数 100ms 是保守值,实际单字节传输在微秒级,给大一点防止偶发调度延迟误判超时。片选拉低、发命令、读数据、拉高,这套时序在 LAN9252 手册的 SPI 访问章节有图,照着对一遍再联调。

6. 移植避坑:五个让 TwinCAT 连不上的具体问题

6.1 现象:TwinCAT 扫描到设备但进不了 OP,状态停在 PREOP

原因:XML 里 ConfigData 还是 ET1100 的默认值,LAN9252 上电后 PDI 没配成 SPI 模式,MCU 发的 SPI 命令它不响应。解决:按 AN1907 改成800E00CC8813F0000000800000,重新在 TwinCAT 里烧录 EEPROM,断电重启再扫。

6.2 现象:一上电就进 HardFault,或者状态机乱跳

原因:CubeMX 生成的代码里外部中断和定时器中断默认使能了,协议栈还没初始化完中断就进来,访问了未初始化的指针。解决:注释掉MX_GPIO_Init和MX_TIM_Init末尾的HAL_NVIC_EnableIRQ,改由协议栈的HW_Init流程控制使能时机。

6.3 现象:SPI 读回的数据全是 0xFF 或 0x00

原因:片选时序不对,或者 SPI 模式(CPOL/CPHA)跟 LAN9252 要求不匹配。LAN9252 的 SPI 是模式 0(CPOL=0,CPHA=0),CubeMX 里如果选了模式 3 就读不到。解决:核对 SPI 配置为 Mode 0、MSB First、8 位数据帧,用逻辑分析仪抓 CS 和 SCK 的时序确认。

6.4 现象:能进 OP 但过程数据不刷新,PLC 侧变量一直是初值

原因:MainLoop()没在 while(1) 里持续调用,或者 1ms 定时器中断里没调ECAT_CheckTimer()。协议栈的看门狗和状态机推进都靠这个周期函数。解决:确认主循环结构是HW_Init(); MainInit(); while(1){ MainLoop(); },定时器中断服务函数里只调ECAT_CheckTimer(),不要塞别的逻辑。

6.5 现象:换用非 24FC512 的 EEPROM 后偶发连接失败

原因:部分 EEPROM 的上电时序或页写周期跟 LAN9252 的访问节奏不匹配,TwinCAT 烧录时校验失败。解决:按手册推荐用 24FC512,PCB 上 I2C 上拉电阻按 4.7k 配,烧录后断电等两秒再上电。

7. 进阶验证:用状态机日志和 SPI 抓包定位移植问题

协议栈跑起来之后,最有效的验证手段不是盯着 TwinCAT 界面猜,而是在MainLoop()里加状态打印。EtherCAT 状态机有 INIT、PREOP、SAFEOP、OP 四个主状态,每次切换时把nAlStatus打出来,配合串口输出,能直接看到卡在哪一步。我一般会在AL_ControlInd回调里加一行日志,记录请求状态和当前状态,TwinCAT 点“请求 OP”时串口上就能看到状态迁移序列。

void AL_ControlInd(uint8_t alControl) { printf("AL req=%02X cur=%02X\r\n", alControl, nAlStatus); /* 协议栈内部处理 */ }

第二个手段是 SPI 抓包。逻辑分析仪挂 CS、SCK、MOSI、MISO 四根线,触发条件设 CS 下降沿,看第一字节是不是 LAN9252 期望的命令码。如果 MCU 发出去的命令码对、但 LAN9252 回的字节全 FF,基本就是 ConfigData 没烧对或者 EEPROM 里数据损坏,重新烧录一次 EEPROM 再试。

第三个手段是分布式时钟验证。如果项目后面要加 DC 同步,先确认 SYNC0 中断周期跟主站配置的周期一致,用示波器量 SYNC0 引脚,偏差超过几十微秒就要查Sync0_Isr里有没有做耗时操作。纯数字 IO 场景可以先不启用 DC,等基础通信稳定了再往上加。

验证项工具正常现象异常指向
状态机迁移串口日志INIT→PREOP→SAFEOP→OP 逐级卡在 PREOP 查 ConfigData
SPI 命令响应逻辑分析仪首字节命令码正确、回读非 FF全 FF 查 EEPROM 烧录
过程数据刷新TwinCAT 变量表64 入 64 出实时变化不刷新查 MainLoop 调用
SYNC0 周期示波器与主站周期一致偏差大查 ISR 耗时

从那以后我每次移植新板子,都强制先跑一遍“串口日志 + SPI 抓包”这两步再动 TwinCAT 组态,省掉大量在界面和代码之间来回猜的时间。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询