拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

STM32F767 Nucleo以太网实战:从CubeMX配置到LwIP ping通

STM32F767 Nucleo以太网实战:从CubeMX配置到LwIP ping通 1. 为什么选Nucleo-F767ZI做以太网实战拿到Nucleo-F767ZI这块板子的时候我第一反应是这板子做网络应用简直是作弊。STM32F767ZI自带MAC控制器板载还焊了一颗Micrel的KSZ8081RNB PHY芯片RJ45接口也是现成的连网线就能跑。但真正动手配置的时候从CubeMX点选到ping通中间踩的坑足够写满两页A4纸。这篇内容适合三类人看第一类是刚拿到Nucleo-F767ZI想跑通以太网但被CubeMX里一堆选项搞晕的嵌入式新手第二类是从F103或者F407转过来发现老经验在新平台上不太管用的老手第三类是做工业网关、数据采集终端需要快速验证以太网通信方案的工程师。我会把原理图分析、CubeMX配置、PHY寄存器调试、LwIP协议栈适配这几个环节串起来讲重点放在为什么这么配和配错了会怎样上面。先说一下这块板子的硬件底子。Nucleo-F767ZI的以太网部分用的是RMII接口不是MII。RMII省引脚但时钟要求更严格REF_CLK必须是50MHz由PHY或者外部晶振提供。板子上KSZ8081的REF_CLK是从STM32的PA1引脚输出的这个引脚在CubeMX里要配置成RCC_MCO_2或者直接用ETH_REF_CLK。很多人卡在第一步就是没搞清楚这个时钟路径导致PHY一直处于复位状态MDIO读出来全是0xFFFF。另外Nucleo-F767ZI的RJ45座子自带网络变压器但如果你是自己画板子变压器和终端电阻的匹配网络一定要照着PHY手册来差分对走线阻抗控制在50欧姆否则链路能协商上但丢包率会高得离谱。我实测过一块差分线没做阻抗控制的板子ping大包的时候丢包率能到30%换成Nucleo原板就稳在0%。2. 原理图里必须盯死的几个关键网络2.1 RMII信号线的引脚映射Nucleo-F767ZI的原理图在ST官网能下到MB1137这个文档。翻到以太网那一页重点看这几个信号ETH_RMII_REF_CLKPA150MHz参考时钟输出ETH_RMII_MDIOPA2管理接口数据ETH_RMII_MDCPC1管理接口时钟ETH_RMII_CRS_DVPA7载波侦听/数据有效ETH_RMII_RXD0PC4ETH_RMII_RXD1PC5ETH_RMII_TX_ENPB11ETH_RMII_TXD0PB12ETH_RMII_TXD1PB13这些引脚在CubeMX里配置ETH外设的时候会自动分配但你要知道它们对应的是哪个物理引脚因为一旦你外接了其他模块占用了这些脚就得重新规划。比如PA1如果被用作ADC输入那REF_CLK就得改由PHY自己产生这时候KSZ8081的REF_CLK输入要接25MHz晶振然后内部PLL倍频到50MHz。2.2 PHY复位电路和地址配置KSZ8081的复位引脚是低电平有效Nucleo板上通过一个10k上拉电阻接到3.3V同时连到STM32的复位电路。这意味着每次MCU复位PHY也会跟着复位。这个设计省了一个GPIO但有个隐患如果你在程序里想单独复位PHY而不复位MCU就做不到。我遇到过一次PHY寄存器被写乱的情况只能按板子上的复位键才能恢复。PHY地址方面KSZ8081的PHYAD[0]引脚在Nucleo板上是下拉到地的所以PHY地址是0x00。在CubeMX的ETH配置里PHY Address要填0。如果你用的是自己画的板子PHYAD引脚悬空或者上拉地址就变了这时候MDIO扫描会找不到设备。2.3 时钟树配置的坑STM32F767的ETH外设需要两个时钟一个是AHB总线时钟一个是REF_CLK。在CubeMX的Clock Configuration页面ETH的时钟源要选HCLK然后分频。我一般把HCLK设到200MHzETH分频系数设成2得到100MHz的ETH内核时钟。REF_CLK那边如果选的是Output from PA1CubeMX会自动把PA1配置成50MHz输出这个50MHz是从PLL48CLK或者外部晶振分频来的。这里有个细节STM32F767的PLL配置里PLLQ分频出来的时钟要正好是48MHz因为USB和SDIO都依赖它。如果你把PLLQ设错了ETH的REF_CLK也会跟着偏PHY可能能协商上但通信不稳定。我建议在CubeMX里直接点Resolve Clock Issues让它自动算然后手动核对一遍PLLQ的值。3. CubeMX配置以太网的完整流程3.1 新建工程和引脚分配打开CubeMX选STM32F767ZITx然后开始配置。第一步先把调试接口打开SYS里的Debug选Serial Wire不然下载一次程序后SWD引脚被占用下次就连不上了。RCC里HSE选Crystal/Ceramic ResonatorNucleo板上的晶振是8MHz。接下来在Connectivity里选ETHMode选RMII。这时候CubeMX会自动把PA1、PA2、PA7、PC1、PC4、PC5、PB11、PB12、PB13这些引脚标成绿色。检查一下有没有冲突特别是PA1如果之前被其他外设占了要先释放。3.2 ETH参数配置详解在ETH的Parameter Settings里有几个关键选项PHY InterfaceRMIIAuto NegotiationEnableSpeed100Mbps如果PHY支持也可以选10MbpsDuplex ModeFull DuplexCarrier Sense During TransmitDisableReceive Own TransmitDisableLoopback ModeDisableChecksum OffloadDisableLwIP里可以软件校验硬件校验有时候和协议栈配合有问题PHY Address0PHY Special Control/Status Register这个不用填CubeMX会自动处理Advanced Parameters里Rx Buffer Size我一般设成ETH_RX_BUF_SIZE_256Tx Buffer Size设成ETH_TX_BUF_SIZE_256。这两个值影响内存占用和吞吐量256字节是折中方案跑TCP吞吐能到80Mbps左右。如果要跑UDP高速传输可以设成512或者1024但F767的SRAM要规划好别把堆栈挤爆了。3.3 LwIP协议栈的添加在Middleware里选LwIPMode选Enabled with DHCP。DHCP方便快速验证但如果你要固定IP就选Static IP然后填IP地址、子网掩码、网关。我建议先用DHCP跑通再改静态因为DHCP能自动获取网络参数减少配置错误。LwIP的配置里MEM_SIZE设成16KBMEMP_NUM_PBUF设成16PBUF_POOL_SIZE设成16。这些值根据你的应用调整如果只是ping和简单TCP默认值够用。如果要跑HTTP服务器或者MQTT得适当加大。注意LwIP的LWIP_NETIF_HOSTNAME可以设成nucleo-f767这样在路由器里能看到设备名方便识别。3.4 生成代码前的检查清单生成代码之前我习惯做这几件事在Project Manager里把Toolchain设成Makefile或者STM32CubeIDE看你用什么开发环境。Code Generator里勾选Generate peripheral initialization as a pair of .c/.h files这样代码结构清晰。检查Clock Configuration确认ETH时钟是100MHzREF_CLK是50MHz。在NVIC Settings里ETH全局中断要使能优先级设成5左右别太高也别太低。点Generate Code之后CubeMX会生成完整的工程包括HAL库、LwIP协议栈、ETH驱动。接下来就是编译下载然后看能不能ping通。4. 从编译到ping通实操过程记录4.1 编译下载和串口输出生成的工程直接编译一般不会有错误。下载到板子后用USB转串口模块接Nucleo的USART3PD8/PD9波特率115200。程序跑起来后串口会打印LwIP的初始化信息包括PHY地址、协商速度、IP地址。如果串口没输出先检查串口线有没有接对Nucleo-F767ZI的USART3默认是PD8和PD9但如果你在CubeMX里改了引脚就要对应调整。另外LwIP的调试输出要打开LWIP_DEBUG和UART_DEBUG不然看不到信息。4.2 PHY寄存器读取和链路状态检查如果串口打印出PHY not found或者Link down就要手动读PHY寄存器。在代码里加一段uint32_t phyreg; HAL_ETH_ReadPHYRegister(heth, 0, PHY_BSR, phyreg); printf(PHY BSR: 0x%04X\r\n, phyreg);PHY_BSR是基本状态寄存器地址0x01。如果读出来是0xFFFF说明MDIO通信失败检查MDC时钟和MDIO上拉电阻。正常值应该是0x786D左右bit2是Link Status1表示链路已连接。如果Link Status是0检查网线有没有插好对端设备是不是千兆口。KSZ8081是百兆PHY接千兆路由器也能协商到100M但有些老路由器兼容性不好可以换一个口试试。4.3 ping测试和常见网络问题链路通了之后在电脑上ping板子的IP。如果ping不通按这个顺序排查电脑和板子是不是同一网段板子DHCP获取的IP是192.168.1.x电脑也要在这个网段。防火墙有没有拦ICMPWindows防火墙默认允许ping但有些安全软件会拦。板子的ARP表有没有响应在串口里打印LwIP的ARP表看有没有电脑的MAC地址。网线是不是好的换一根网线试试我遇到过网线水晶头氧化导致链路不稳定。ping通之后可以试试TCP通信。LwIP自带一个echo服务器示例在lwip.c里把LWIP_ECHO_SERVER打开然后电脑上用telnet连板子的7端口发什么回什么。5. 常见问题速查表和避坑技巧5.1 PHY初始化失败排查表现象可能原因解决方法MDIO读回0xFFFFMDC时钟太快降低MDC时钟CubeMX里ETH的MDC分频设成HCLK/42PHY地址不对PHYAD引脚配置错误检查原理图确认PHYAD[0]是下拉还是上拉链路协商不上网线或对端设备问题换网线换路由器端口强制设置PHY为100M全双工ping丢包严重差分线阻抗不匹配检查PCB走线差分对要等长阻抗50欧姆中断不触发NVIC优先级配置错误把ETH中断优先级设成5确保没有其他中断抢占5.2 时钟配置的独家经验STM32F767的ETH对时钟很敏感。我试过把HCLK超频到216MHzETH分频后是108MHz结果PHY能协商上但TCP传输大量丢包。后来老老实实回到200MHzETH 100MHz就稳了。所以别为了跑分去超频ETH外设的时钟范围是25MHz到100MHz超了就不保证稳定。REF_CLK那边如果你用PA1输出50MHzCubeMX会自动配置RCC。但要注意PA1的GPIO速度要设成Very High不然50MHz方波边沿会变缓PHY可能识别不了。在GPIO配置里把PA1的Maximum output speed改成Very High。5.3 LwIP内存配置的坑LwIP默认的MEM_SIZE是1600字节跑ping没问题但一开TCP服务器就崩。我建议至少设成16KBPBUF_POOL_SIZE设成16。如果跑HTTPMEM_SIZE要32KB以上。F767有512KB SRAM别省这点内存。另外LWIP_NETIF_TX_SINGLE_PBUF这个选项要打开不然发送大包的时候LwIP会分配多个pbuf增加内存碎片。打开之后发送缓冲区是连续的DMA直接搬效率高很多。5.4 中断和DMA的配合ETH的收发中断和DMA是绑定的。CubeMX生成的代码里ETH中断处理函数会调用HAL_ETH_IRQHandler然后回调到LwIP的ethernetif_input。如果你在中断里做了太多事情比如打印日志会导致中断响应变慢丢包。我一般只在中断里置个标志然后在主循环里处理。DMA描述符的地址要对齐到4字节CubeMX生成的代码已经处理了。但如果你自己改描述符数量记得改ETH_RX_DESC_CNT和ETH_TX_DESC_CNT这两个值在ethernetif.c里定义。我一般设成4个RX、4个TX够用了。6. 从ping通到实际应用下一步怎么走ping通只是第一步实际项目里还要跑TCP、UDP、MQTT、HTTP这些协议。LwIP自带这些协议栈但配置起来又是一堆坑。比如MQTT要开LWIP_MQTT然后实现mqtt_connection_cb回调。HTTP服务器要开LWIP_HTTPD然后把网页文件放到文件系统里。我个人的习惯是先用ping验证链路层再用TCP echo验证传输层最后上应用层协议。每一步都单独测试出问题了容易定位。如果一上来就堆一堆功能调试的时候根本不知道是哪一层的问题。另外Nucleo-F767ZI的以太网性能其实不错我实测TCP吞吐能到80Mbps左右UDP能到90Mbps。如果做数据采集网关这个性能足够了。但如果要跑千兆就得换F7系列里带千兆MAC的型号比如F767的某些版本或者H7系列。最后分享一个调试技巧如果LwIP跑着跑着就死机先看mem_free和memp_free的统计在lwipopts.h里打开LWIP_STATS和MEMP_STATS然后定期打印。如果内存一直减少说明有内存泄漏检查pbuf有没有正确释放。我遇到过一次pbuf没释放导致跑几个小时就死机后来在ethernetif_input里加了pbuf_free就解决了。
返回列表