简介:这份文档面向嵌入式开发工程师与工业以太网学习者,聚焦用STM32F103配合LAN9252构建EtherCAT从站这一典型方案,解决从硬件选型、协议栈移植到TwinCAT联调的完整落地问题。内容围绕LAN9252的四种工作模式展开,重点讲解SPI串口模式的选用理由,并梳理XML设备描述文件生成、SSC工具使用、EEPROM烧录、原理图与PCB设计、协议栈代码移植等关键环节,还给出HW_Init、MainInit、MainLoop的代码骨架以及SPI、定时器、外部中断的配置要点与中断回调处理思路。资源包为1个docx文档,约1.75MB,适合作为项目开发时的参考手册。目前已有2921人学习,读者可从中获得从站开发的整体流程认知、XML与SSC的实操方向以及移植排错的具体切入点。
1. 一块 F103 加一片 LAN9252,怎么把 EtherCAT 从站跑起来
手头有一台倍福 CX9020 主站,只认 TwinCAT2.0,跑在 Windows CE 上,项目要求周期交互 64 入 64 出。主站定了,从站得自己搭。选型落到 STM32F103 加 LAN9252 这套组合上,原因很直接:LAN9252 自带两颗 PHY 和内部交换,能实现 EtherCAT 要求的“一拖一”端口拓扑,MCU 只管通过 SPI 跟它换数据,物理层和网络交换的活它全包了。这份资料拆的就是从硬件连接、SSC 生成协议栈、XML 描述文件到 SPI 适配的完整链路,适合正在做 EtherCAT 从站、卡在协议栈移植或者 XML 配置上的嵌入式工程师,新手能照着步骤走,熟手能对着参数和坑位做交叉验证。
2. LAN9252 四种工作模式怎么选:SPI 模式的取舍与硬件连接
2.1 四种模式的边界与选型理由
LAN9252 的 Datasheet 里列了四种工作模式,选错了后面全白搭。数字 I/O 模式最省事,8 入 8 出直接由芯片管脚出,但点位数量被焊死,项目要 64 入 64 出,直接排除。并行通信模式(HBI)走 16/8 位数据总线,吞吐高,代价是 MCU 侧要占用大量 GPIO,F103 的引脚资源本来就紧,划不来。扩展模式是在 SPI 基础上再引一组 MII 接第二颗 PHY,多一个 RJ45,适合需要额外网口的场景,本项目两个端口已经够用,没必要加复杂度。SPI 模式四根线搞定,时钟标准模式最高 30M,高速 SQI 模式能到 80M,对 64+64 个 bit 的周期 IO 来说带宽绰绰有余。
选 SPI 的另一个隐性理由是协议栈生态。SSC 生成的参考代码里,SPI 接口的适配层最成熟,函数命名和调用时序都有现成模板,移植时改动量最小。并行模式虽然快,但协议栈里对应的接口要自己补不少东西,对第一次做从站的人来说不划算。
2.2 原理图连接要点
STM32F103 作 SPI 主,LAN9252 作从,四根线是 SCK、MISO、MOSI、CS。除此之外还有三根中断线必须接:IRQ 是 EtherCAT 主中断,SYNC0 和 SYNC1 是分布式时钟同步用的。IRQ 必须实现,SYNC0/SYNC1 看项目要不要用分布式时钟,不用可以悬空,但建议还是留出焊盘,后面想加不用改板。
EEPROM 挂在 LAN9252 的 I2C 接口上,选型上有个血泪经验:尽量用 24FC512 这颗,别的型号在 EtherCAT 上电配置阶段容易出现连接困难。XML 里 EEPROM 节点的 ByteSize 一般写 2048,但物理芯片用 512Kbit(64KB)的容量,防止后面 IO 点位增加时数据存不下。这个“逻辑大小写小、物理容量选大”的做法是常见操作,别被 ByteSize 的数值误导。
提示:LAN9252 的 ConfigData 那 14 个字节决定了芯片上电后的工作方式,第一个字节 0x80 对应寄存器 0x0140 配置为 SPI 模式。SSC 默认按 ET1100 生成的是 050E03440A...,必须按 LAN9252 手册 AN1907 改成 800E00CC8813F0000000800000,不改的话芯片上电进不了 SPI 模式,SPI 读回来全是 0xFF。
2.3 电源与复位时序
LAN9252 有 3.3V 和 1.2V 两路供电,1.2V 是内核电压,别漏了。复位脚要接 RC 延时,保证上电时 MCU 和 PHY 的复位释放顺序合理。实际调试中遇到过 PHY 先起来、MCU 后起来导致 SPI 首次通信失败的情况,后来在 MCU 初始化里加了一段延时再拉 CS,问题消失。这类时序问题不会在手册里明说,只能靠示波器抓波形定位。
3. SSC 生成协议栈与 XML:从 Excel 配置到 64 入 64 出点位
3.1 SSC 建工程与模板选择
SSC 是 EtherCAT 协会给会员的从站协议栈代码工具,装好后 File->New,模板别用默认的,选 Custom 下拉里的 EL9800 | 8Bit Digital I/O, 16Bit Analog Input。这个模板的 SPI 配置和数字 IO 结构跟本项目最接近,后面改起来省事。建工程前先保存到一个路径,保存后会弹出一个 Excel 模板,这是配置 IO 点位的入口。
3.2 Excel 配置 64 入 64 出
Excel 里 //0x6nnx 段是输入,//0x7nnx 段是输出,每个条目对应一个 bit。64 个输入就是 0x6000 到 0x6007 八个字节,每个字节 8 个 bit,用 Excel 的批量拖拽往下拉就行。输出同理走 0x7000 段。最后把 Maximum number of modules 改成 3。改完保存,SSC 会自动弹导入对话框,点 OK 导入。
导入后界面变化不大,要点 Project->Create new Slave Files 才真正生成协议栈和 XML。生成完的工程目录里,XML 在 esi 文件夹下,协议栈源码在 src 下。这里有个容易翻车的点:Excel 里 bit 的命名和顺序如果跟实际硬件面板的键盘 LED 排布对不上,后面 TwinCAT 里映射会错位,调试时表现为按了键但 PLC 收到的位不对。建议在 Excel 里就把命名写成 KEY0~KEY63、LED0~LED63,跟原理图丝印一一对应。
3.3 XML 里必须手改的三处
SSC 生成的 XML 大部分能用,但有三处必须动。第一处是 Vendor 下的 id 和 name,填自己企业的 VendorID,没有的话先用占位值调试。第二处是 Device 下的 ProductCode 和 RevisionNo,TwinCAT 靠这两个字段区分设备,两份 XML 这两个值一样的话只会识别其中一个,迭代版本时记得同步升 RevisionNo。第三处就是前面说的 ConfigData,改成 LAN9252 的 SPI 配置值。
XML 里 DataTypes 和 Objects 的关系类似 C 语言的 typedef 和变量定义,SSC 已经按 Excel 生成好了 64+64 个 Entry,手工改这部分工作量恐怖且极易出错,别碰。SM 通道的 size 要 16 位对齐,这个细节 SSC 处理好了,但如果自己改 Entry 的 bitlen 要注意别破坏对齐。
<!-- XML 中 ConfigData 节点,LAN9252 SPI 模式必须改成这组值 --> <ConfigData>800E00CC8813F0000000800000</ConfigData> <!-- ProductCode 和 RevisionNo 决定设备唯一性,迭代时同步升级 --> <Type ProductCode="#x00000001" RevisionNo="#x00000001">SSC-Device</Type>上面这段是 XML 里最关键的改动位置。ConfigData 第一个字节 0x80 对应 LAN9252 寄存器 0x0140 的 SPI 配置,后面字节控制 PHY 和交换模式,不理解的保持手册默认值别乱动。ProductCode 建议用有意义的编号,RevisionNo 每次硬件或 IO 定义变更就加一,否则 TwinCAT 缓存旧描述会导致组态异常。
4. STM32 侧 SPI 与中断适配:CubeMX 配置到协议栈对接
4.1 CubeMX 外设配置
新建 STM32F103ZExx 工程,配四类外设。SPI 选 4 线标准模式,时钟先给 15M 左右,跑通后再往上提。定时器配 1ms 周期,命名 ECAT_CheckTimer,协议栈的看门狗和日常处理都挂在这个中断里。三个外部中断 IRQ、SYNC0、SYNC1 配成下降沿触发,NVIC 里 ECAT_CheckTimer 和 PDI_Isr 给 1 抢先 0 响应,SYNC0/SYNC1 给 2 抢先 0 响应。
关键操作:CubeMX 里三个外部中断和定时器中断都勾了 enable,生成代码后要去 Keil 里把初始化函数最后那行使能语句注释掉。中断什么时候开、什么时候关,必须由协议栈的接口函数决定,一上电就使能外部中断基本连不上主站。这是整个移植里最容易踩的坑,没有之一。
// stm32f1xx_it.c 中生成的中断服务函数,把处理逻辑转到 main.c 的回调 void EXTI0_IRQHandler(void) { HAL_GPIO_EXTI_IRQHandler(LAN9252_IRQ_Pin); } // main.c 中统一回调,按引脚分发到协议栈的 ISR void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { if (GPIO_Pin == LAN9252_IRQ_Pin) { PDI_Isr(); // EtherCAT 主中断,必须实现 return; } if (GPIO_Pin == LAN9252_SYC0_Pin) { DISABLE_ESC_INT(); // 同步中断期间屏蔽主中断,防重入 Sync0_Isr(); ENABLE_ESC_INT(); return; } if (GPIO_Pin == LAN9252_SYC1_Pin) { DISABLE_ESC_INT(); Sync1_Isr(); ENABLE_ESC_INT(); return; } }这段回调的逻辑是:IRQ 直接进 PDI_Isr,SYNC0/SYNC1 在调用前后分别关和开 ESC 中断,防止同步处理过程中被主中断打断造成状态机错乱。DISABLE_ESC_INT 和 ENABLE_ESC_INT 是协议栈提供的宏,别自己用 __disable_irq 替代,那样会把整个系统的中断都关掉。
4.2 SPI 读写函数封装
协议栈期望的 SPI 接口是一组特定命名的函数,核心是单字节读写和块读写。F103 的 HAL 库有 HAL_SPI_TransmitReceive,但协议栈的调用节奏是“发一个字节同时收一个字节”,用这个函数正好。封装时注意 CS 的拉低拉高要包住整次事务,不要在字节之间抖动。
// 协议栈期望的单字节读写,SPI 全双工,发的同时收 uint8_t SPI_ReadWriteByte(uint8_t data) { uint8_t rx = 0; HAL_SPI_TransmitReceive(&hspi1, &data, &rx, 1, 100); return rx; } // 块读,先发命令再连续读,CS 全程拉低 void SPI_ReadBlock(uint8_t *buf, uint16_t len) { HAL_SPI_Receive(&hspi1, buf, len, 1000); }参数上,超时给 100ms 单字节、1000ms 块读足够,SPI 时钟 15M 时一次 64 字节读不到 1ms。如果调试时读回全 0xFF,先查 CS 有没有真的拉低,再查 ConfigData 有没有改对,最后查 SPI 模式是 CPOL/CPHA 是否跟 LAN9252 匹配(模式 0 或 3 都试一下)。
4.3 协议栈骨架与移植顺序
协议栈的 main 骨架就三行:HW_Init()、MainInit()、while(1) 里 MainLoop()。移植时按这个顺序来:先把 HW_Init 里的 SPI 初始化和 GPIO 初始化对接好,再让 MainInit 跑通,最后进 MainLoop 看能不能响应主站扫描。SSC 生成的代码里 SSC-DeviceObjects.h 定义了对象字典,跟 XML 里的 Objects 一一对应,改 IO 点位时两边要同步看。
5. 避坑排查:从站连不上主站的五条血泪记录
5.1 上电就使能中断导致扫描失败
现象:TwinCAT 扫描不到设备,或者扫到但进不了 OP 状态。原因:CubeMX 生成的代码里外部中断和定时器中断在初始化时就使能了,协议栈还没准备好就进中断,状态机乱掉。解决:注释掉初始化函数末尾的使能语句,由协议栈的接口函数在合适时机打开。
5.2 ConfigData 没改导致 SPI 读回全 0xFF
现象:SPI 通信完全无响应,读任何寄存器都是 0xFF。原因:XML 里 ConfigData 还是 ET1100 的默认值,LAN9252 上电没进 SPI 模式。解决:按 AN1907 改成 800E00CC8813F0000000800000,重新烧 EEPROM。
5.3 EEPROM 型号不对导致偶发连接困难
现象:有时能连上,有时扫描超时,换一块板子现象不同。原因:EEPROM 用了非 24FC512 的型号,上电配置时序有偏差。解决:换 24FC512,或者在 XML 里把 EEPROM 时序参数按实际芯片调整。
5.4 ProductCode 重复导致设备识别错乱
现象:两个不同版本的从站,TwinCAT 只认出一个。原因:两份 XML 的 ProductCode 和 RevisionNo 相同。解决:每个版本给唯一组合,RevisionNo 随迭代递增。
5.5 SYNC 中断没做防重入导致状态机卡死
现象:启用分布式时钟后,运行一段时间从站掉线。原因:SYNC0 处理过程中被 IRQ 打断,ESC 寄存器读写冲突。解决:SYNC 回调里前后加 DISABLE_ESC_INT/ENABLE_ESC_INT,保证临界区不被主中断侵入。
6. 用 TwinCAT2 验证从站:XML 部署与 IO 映射的实操技巧
XML 改好后放到 TwinCAT 安装路径的 /Io/EtherCAT 目录下,重启 TwinCAT 或者刷新设备列表。主站扫描到设备后,右键把 XML 烧进 EEPROM,这一步会把 ConfigData 和对象字典的关键部分写进 24FC512。烧录完成后给从站断电重启,再扫描应该能稳定识别。
验证 IO 映射时有个技巧:先在 TwinCAT 里建一个 PLC 工程,把 64 入 64 出映射成 BOOL 数组,然后在线监控。按键盘看输入位变化,写输出看 LED 亮灭。如果位序对不上,回 Excel 查命名顺序,别在 TwinCAT 里硬改映射,那样下次重新生成 XML 又乱了。
分布式时钟要不要开,取决于主站对同步精度的要求。64 入 64 出的面板类应用,不开分布式时钟也能跑,开了之后 SYNC0 中断的周期要跟主站 DC 配置对齐,配错了反而掉线。我一般先在不开 DC 的情况下把 IO 跑通,再开 DC 做压力测试,分两步走比一步到位稳。
从那以后我每次做新从站,都强制走一遍“ConfigData 核对、中断使能注释、ProductCode 唯一性检查”这三步,少一步就得在 TwinCAT 里多耗半天。希望帮到你。
本文还有配套的精品资源,点击获取