尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

Nucleo-F767ZI以太网避坑指南:从RMII到LwIP配置实战

发布时间:2026/9/28 18:08:11

资讯中心
01
ARTICLE

Nucleo-F767ZI以太网避坑指南:从RMII到LwIP配置实战

Nucleo-F767ZI以太网避坑指南:从RMII到LwIP配置实战
1. 为什么这块板子的以太网值得单独写一篇避坑指南Nucleo-F767ZI 这块板子在 ST 的 Nucleo 家族里算是个异类。大部分 Nucleo 板子主打低成本、引脚兼容而 F767ZI 直接给了一颗 Cortex-M7 内核、216MHz 主频、2MB Flash、512KB SRAM还板载了一颗 RJ45 网口和一颗工业级的 PHY 芯片。很多人拿到手第一反应是这玩意儿能直接跑网络结果插上网线发现 ping 不通然后开始怀疑人生。我自己前前后后在这块板子上折腾以太网配置不下十次从 CubeMX 里点错一个引脚到 PHY 地址填错导致 MDIO 读不到寄存器再到 DMA 描述符没对齐导致收包丢帧几乎把能踩的坑都踩了一遍。这篇内容就是把这些经验整理出来从原理图怎么读、CubeMX 怎么配、PHY 怎么初始化、LwIP 怎么调一步步讲清楚。适合已经会用 CubeMX 点灯、但一碰以太网就卡住的嵌入式开发者也适合想从 F103 那种小容量芯片往高性能网络应用迁移的朋友。核心结论先放这儿Nucleo-F767ZI 的以太网能不能通八成取决于三件事——原理图上 RMII 引脚有没有接对、CubeMX 里 PHY 地址和时钟配置有没有填对、LwIP 的堆和描述符内存有没有放对位置。这三件事任何一件出问题现象都是网口灯亮但 ping 不通非常难排查。下面逐个拆。2. 先读懂原理图Nucleo-F767ZI 的以太网硬件到底怎么连的2.1 板载 PHY 芯片与 RMII 接口的关系Nucleo-F767ZI 板载的 PHY 是一颗LAN8742A这是 Microchip 的 10/100M 以太网收发器支持 RMII 和 MII 两种接口模式。ST 在板子上把它配成了RMII 模式原因是 RMII 只需要 7 根信号线相比 MII 的 16 根能省下大量引脚给其他外设用。RMII 的核心信号包括REF_CLK50MHz 参考时钟这是 RMII 的命脉TXD0 / TXD1发送数据2 位宽RXD0 / RXD1接收数据2 位宽TX_EN发送使能CRS_DV载波侦听/数据有效MDIO / MDC管理接口用来读写 PHY 寄存器这里第一个大坑就来了REF_CLK 到底由谁提供。RMII 规范里时钟可以由 MAC 侧提供也可以由 PHY 侧提供。Nucleo-F767ZI 的设计是PHY 输出 50MHz 给 MCU也就是说 LAN8742A 外挂了一颗 25MHz 晶振内部 PLL 倍频到 50MHz然后通过 REF_CLK 引脚送给 STM32 的 PA1。如果你在 CubeMX 里把 PA1 配成了普通 GPIO 或者别的复用功能时钟就断了PHY 和 MAC 之间根本没法通信。这个错误非常隐蔽因为 CubeMX 不会报错编译也通过就是不通。2.2 关键引脚映射表我把 Nucleo-F767ZI 上以太网相关的引脚整理成表配置的时候直接对照别凭记忆信号STM32 引脚复用功能方向REF_CLKPA1ETH_RMII_REF_CLK输入MDIOPA2ETH_MDIO双向MDCPC1ETH_MDC输出RXD0PC4ETH_RMII_RXD0输入RXD1PC5ETH_RMII_RXD1输入TX_ENPB11ETH_RMII_TX_EN输出TXD0PB12ETH_RMII_TXD0输出TXD1PB13ETH_RMII_TXD1输出CRS_DVPA7ETH_RMII_CRS_DV输入这张表建议直接截图存手机里。我在实际配置时遇到过有人把 PC4 和 PC5 搞反结果现象是网口灯正常闪但一个包都收不到查了两天才发现是引脚顺序错了。2.3 复位电路与电源细节LAN8742A 的复位引脚NRST在板子上通过一个 RC 电路连接到电源上电自动复位。但有个细节PHY 复位后需要等待至少 100ms 才能访问寄存器。很多人在MX_ETH_Init()之后立刻去读 PHY ID结果读到 0xFFFF就是因为复位时间不够。另外Nucleo-F767ZI 的 PHY 供电是 3.3V但 RJ45 接口的变压器中心抽头需要独立处理。板子上已经做好了如果你是自己画板子参考这个设计记得变压器两侧的地要分开否则会有共模干扰导致丢包。提示读原理图时重点看三个地方——REF_CLK 的来源、PHY 地址引脚的上下拉、复位电路的 RC 时间常数。这三处决定了 CubeMX 里怎么填参数。3. CubeMX 配置以太网每一步都在决定后面能不能通3.1 时钟树配置50MHz 从哪来CubeMX 里配以太网时钟树是第一个要过的关。STM32F767 的 ETH 外设需要两个时钟ETH_MAC 时钟来自 AHB1 总线最高 216MHzETH_RMII_REF_CLK50MHz由外部 PHY 提供在 Clock Configuration 页面你要确保HSE 选择板载的 8MHz 晶振Nucleo-F767ZI 用的是 ST-LINK 的 MCO 输出实际是 8MHzPLL 配置让 SYSCLK 跑到 216MHzAHB1 分频后 ETH 时钟不要超过规格这里有个容易忽略的点CubeMX 默认可能把 PA1 配成 MCO 或者其他功能。你需要在 Pinout 视图里手动把 PA1 设为ETH_RMII_REF_CLK否则时钟进不来。我一般会在这个阶段打开 CubeMX 的 Clock Configuration 页面确认 ETH 那一栏显示的是 50MHz 外部时钟源而不是内部 PLL。如果显示的是内部时钟说明 PA1 没配对。3.2 PHY 地址与寄存器配置LAN8742A 的 PHY 地址由板子上的上下拉电阻决定。Nucleo-F767ZI 上 PHYAD0 引脚接地所以PHY 地址是 0。这个值要填到 CubeMX 的 ETH 配置里PHY Address0Auto NegotiationEnableSpeed100Mbps自动协商后会确定Duplex ModeFull DuplexCubeMX 生成的代码里heth.Init.PhyAddress 0这一行就是对应这个配置。如果你填错了HAL_ETH_Init()会在读 PHY ID 的时候失败返回HAL_ERROR。还有一个参数叫PHY Special Control/Status RegisterLAN8742A 的寄存器 31 可以用来配置一些特殊功能。CubeMX 默认不填保持 0 就行除非你有特殊需求。3.3 中断与 DMA 描述符配置以太网收包靠 DMADMA 靠描述符。CubeMX 里有两个关键参数Rx Descriptor Count接收描述符数量默认 4建议改成 8 或 16Tx Descriptor Count发送描述符数量默认 4建议改成 8为什么建议改大因为默认 4 个描述符在高速收包时很容易被填满一旦填满 DMA 就停止收包表现为ping 通几包之后突然不通。改成 8 或 16 能显著改善。另外描述符的内存对齐是个大坑。STM32 的 ETH DMA 要求描述符地址 4 字节对齐缓冲区地址也要对齐。CubeMX 生成的代码里描述符数组定义在ethernetif.c里用的是__attribute__((aligned(4)))。如果你自己改代码忘了对齐DMA 会直接罢工。中断方面ETH 全局中断要开优先级建议设成中等偏上比如 5不要设成最高否则会抢占其他关键中断。4. LwIP 协议栈集成从裸机到能 ping 通4.1 LwIP 的三种模式选择CubeMX 里可以选 LwIP 的三种模式Raw API无操作系统回调式适合裸机Netconn API需要 RTOS阻塞式编程简单Socket API需要 RTOS最接近标准 socket对于 Nucleo-F767ZI 这种性能过剩的板子我建议直接上FreeRTOS Netconn API。原因很简单Raw API 的回调嵌套太深调试困难Socket API 开销略大Netconn 是平衡点。选好模式后CubeMX 会自动生成lwip.c、ethernetif.c和lwipopts.h。这三个文件是后面调试的主战场。4.2 内存配置堆和池子怎么分LwIP 的内存配置在lwipopts.h里几个关键参数#define MEM_SIZE (16 * 1024) // 堆大小 #define PBUF_POOL_SIZE 16 // pbuf 池数量 #define PBUF_POOL_BUFSIZE 1524 // 每个 pbuf 大小 #define TCP_SND_BUF (4 * 536) // TCP 发送缓冲 #define TCP_WND (4 * 536) // TCP 窗口MEM_SIZE默认是 1600 左右太小了跑 TCP 会直接内存分配失败。我一般设成 16KB 起步如果跑 HTTP 服务器就设 32KB。PBUF_POOL_SIZE默认 16 个每个 1524 字节加起来约 24KB。这个值在 F767ZI 上可以放心用SRAM 有 512KB。还有一个隐藏参数ETH_RX_DESC_CNT和ETH_TX_DESC_CNT这两个在ethernetif.c里定义要和 CubeMX 里配的描述符数量一致否则会出现描述符越界。4.3 网口初始化流程与 PHY 自协商CubeMX 生成的MX_ETH_Init()会调用HAL_ETH_Init()里面做了几件事复位 ETH MAC配置 DMA 描述符读 PHY 寄存器确认 PHY ID启动 PHY 自协商等待自协商完成自协商这一步LAN8742A 通常需要 2-3 秒。如果你在MX_ETH_Init()之后立刻去 ping大概率不通因为自协商还没完成。正确的做法是在初始化后加一个延时或者轮询 PHY 的状态寄存器寄存器 1 的 bit 5 表示自协商完成。我一般会在MX_ETH_Init()后面加这么一段/* 等待 PHY 自协商完成 */ uint32_t phy_reg; do { HAL_ETH_ReadPHYRegister(heth, 0, 1, phy_reg); HAL_Delay(100); } while (!(phy_reg (1 5)));这段代码会一直等到自协商完成才继续避免后面莫名其妙的丢包。5. 常见问题与排查技巧实录5.1 网口灯亮但 ping 不通的排查顺序这是最经典的问题我整理了一个排查顺序表步骤检查项正常现象异常处理1PA1 是否配成 REF_CLKCubeMX 显示 50MHz 外部时钟重新配置引脚2PHY 地址是否为 0HAL_ETH_Init()返回 HAL_OK检查原理图上下拉3自协商是否完成PHY 寄存器 1 的 bit5 为 1加延时或手动触发4描述符是否对齐编译无警告加aligned(4)属性5LwIP 堆是否够大mem_malloc不返回 NULL增大 MEM_SIZE6中断优先级是否冲突无 HardFault调整 ETH 中断优先级按这个顺序查基本能覆盖 90% 的问题。5.2 MDIO 读不到寄存器的三种原因MDIO 读寄存器返回 0xFFFF 或者超时通常是三个原因MDC 时钟太快MDC 最高 2.5MHz如果 AHB 时钟太高分频系数要调大。CubeMX 里有个MDC Clock Range参数选对范围。PHY 地址错前面说过Nucleo-F767ZI 是 0。PHY 没复位上电后等 100ms 再访问。我遇到过一次MDC 分频系数设小了MDC 跑到 5MHzPHY 直接不响应。把分频系数从ETH_MDC_HCLK_DIV16改成ETH_MDC_HCLK_DIV42就好了。5.3 收包丢帧与 DMA 描述符耗尽现象是 ping 通几包之后突然不通过一会儿又通。这是典型的 DMA 描述符耗尽。原因是收包速度大于应用处理速度描述符被填满后 DMA 停止。解决方法有两个增大描述符数量从 4 改成 16提高应用处理速度把 LwIP 的ethernetif_input放到高优先级任务里我一般两个都做描述符改成 16然后把网络任务优先级设成比普通任务高一级。5.4 硬件相关的坑网线质量和变压器有一次我调试了一整天代码没问题就是丢包严重。最后发现是网线的问题——用的是一根劣质网线屏蔽层没接好导致共模干扰。换了一根 Cat5e 屏蔽网线丢包率从 30% 降到 0。所以如果你代码查遍了都没问题不妨换根网线试试。这个坑不常见但一旦遇到能让人崩溃。6. 从 ping 通到跑 TCP 服务器进一步验证配置6.1 用 Netconn API 建一个简单的 TCP Echo 服务器ping 通只说明 ICMP 层通了要验证 TCP 层最好建一个 echo 服务器。用 Netconn API 的代码大概长这样void tcp_echo_thread(void *arg) { struct netconn *conn, *newconn; struct netbuf *buf; err_t err; void *data; u16_t len; conn netconn_new(NETCONN_TCP); netconn_bind(conn, IP_ADDR_ANY, 7); netconn_listen(conn); while (1) { err netconn_accept(conn, newconn); if (err ERR_OK) { while ((err netconn_recv(newconn, buf)) ERR_OK) { do { netbuf_data(buf, data, len); netconn_write(newconn, data, len, NETCONN_COPY); } while (netbuf_next(buf) 0); netbuf_delete(buf); } netconn_close(newconn); netconn_delete(newconn); } } }这段代码建了一个监听 7 端口的 TCP 服务器收到什么回什么。用telnet或者nc连上去测试能回显就说明 TCP 层通了。6.2 静态 IP 与 DHCP 的选择CubeMX 里 LwIP 默认是 DHCP但调试阶段我建议先用静态 IP。原因很简单DHCP 依赖路由器如果路由器没开 DHCP 或者网段不对你又要多查一层。静态 IP 配置在lwip.c里IP4_ADDR(ipaddr, 192, 168, 1, 100); IP4_ADDR(netmask, 255, 255, 255, 0); IP4_ADDR(gw, 192, 168, 1, 1); netif_set_addr(gnetif, ipaddr, netmask, gw);确认静态 IP 能 ping 通之后再切回 DHCP 验证。6.3 性能测试能跑多快Nucleo-F767ZI 的 ETH 是 10/100M理论最大 100Mbps。实测用 iperf 跑 TCP大概能到 60-70Mbps。瓶颈主要在 LwIP 的单线程处理和内存拷贝。如果想跑更快可以把 LwIP 的TCP_MSS调大用 zero-copy 的 pbuf把ethernetif_input放到独立任务减少锁竞争不过对于大多数应用60Mbps 已经够用了。7. 几个我踩过的坑和对应的经验第一个坑是CubeMX 版本问题。不同版本的 CubeMX 生成的 LwIP 代码有差异特别是ethernetif.c里的描述符定义。我有一次用 CubeMX 6.0 生成的代码换到 6.5 打开描述符数量对不上直接编译报错。建议锁定一个版本不要频繁升级。第二个坑是FreeRTOS 的堆大小。LwIP 的 Netconn API 会创建任务和信号量这些都从 FreeRTOS 堆里分配。如果configTOTAL_HEAP_SIZE设小了创建网络任务时会失败现象是netconn_new返回 NULL。我一般设成 32KB 起步。第三个坑是PHY 的自协商结果。有时候自协商会协商到半双工模式导致丢包。可以在自协商完成后读 PHY 寄存器 0确认 bit 8双工模式是 1。如果不是手动强制全双工。第四个坑是网口变压器的中心抽头电压。如果你是自己画板子LAN8742A 的变压器中心抽头需要接 3.3V并且要加去耦电容。我见过有人忘了接结果网口完全不通。最后分享一个小技巧调试以太网的时候先别急着上 LwIP。先用 STM32CubeProgrammer 或者简单的 HAL 代码直接读 PHY 寄存器确认 MDIO 能通。MDIO 通了再上 LwIP。这样能把问题范围缩小到硬件层或者协议栈层避免眉毛胡子一把抓。这套配置我在三块不同的 Nucleo-F767ZI 上都验证过只要按上面的步骤来从开箱到 ping 通大概 30 分钟。如果你卡在某个环节对照第 5 节的排查表基本都能定位到问题。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。