ARTICLE DETAIL

资讯详情

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

STM32F407以太网开发实战:DP83848 PHY从电路设计到lwIP调试指南

STM32F407以太网开发实战:DP83848 PHY从电路设计到lwIP调试指南 简介面向 STM32F407 与 DP83848 PHY 联合调试场景的压缩包是一份完整以太网驱动开发参考资料重点解决 PHY 芯片驱动移植、MII/RMII 接口配置以及 MAC 层与物理层通信问题。包内代码基于 HAL/LL 库组织覆盖 GPIO、DMA、中断、定时器和 USART 等外设初始化文档还对 DP83848 控制寄存器、模式切换、状态机和常见网络错误做了说明便于对照代码理解调试流程。资源共 899 个文件总大小约 7.98 MB其中 125 个 C 源文件与 150 个头文件构成驱动主体217 个 HTML 为接口文档128 个 PNG 为原理图或调试截图另有 Keil/IAR 工程文件、PDF 说明及链接脚本目录结构清晰。目前已有 575 人浏览/学习。对需要完成 STM32F4 以太网协议栈对接、中断驱动和 DMA 传输优化的开发者来说这份资料能提供从初始化配置到抓包排错的完整参照尤其适合驱动移植与网络调试初学者。1. 为什么 STM32F407 的以太网项目绕不开 DP83848 这颗 PHY做 STM32F407 以太网项目的工程师迟早会在一张原理图上同时写下两个名字STM32F407和DP83848。F407 的 ETH 外设只到 MAC 层物理层收发必须外挂而 DP83848 是这个场景里最老牌的搭档支持 MII/RMII 双接口引脚和寄存器都透明抗踩坑能力比只能走 RMII 的 LAN8720A 强一截。这篇文章按电路设计、标准库初始化、接收不稳定排查、lwIP 对接四层往下写覆盖从画原理图到测吞吐的完整路径。新手能照着接线上电老手可以直接拿着 strap 电阻和 MMC 计数表去对板子。2. DP83848 电路设计MII/RMII 引脚、strap 电阻与 50MHz 时钟怎么接2.1 先定 MII 还是 RMII两种接口的引脚代价和时钟来源MII 和 RMII 的差别不只是线多线少。MII 收发各 4 bit工作在 25MHz时钟由 DP83848 用自己的 25MHz 晶振产生后回给 MAC整个链路对时钟源最宽容RMII 收发各 2 bit共用一个 50MHz REF_CLKMAC 和 PHY 必须同步在这个时钟上少一根线却多了一堆时钟约束。有个容易误会的点STM32F407 的 ETH 外设没有“MII/RMII”寄存器位模式完全由 PCB 接法和 GPIO 复用决定。从 STM32F105/107 标准库移植过来的同事常去找ETH_MediatInterface这种字段F4 库里有几个方向都对不上原因就是 F4 把模式选择下放到了物理连接层面而不是一个软开关。对比项MIIRMII数据线TXD[3:0]、RXD[3:0]TXD[1:0]、RXD[1:0]时钟25MHz 晶振PHY 回给 MAC TX_CLK/RX_CLK共用 50MHz REF_CLKF407 引脚占用约 16 根约 9 根稳定度高依赖 50MHz 源质量我一般建议引脚富余且追求一次稳的项目选 MIIRMII 留给引脚紧、必须缩板子的场景。DP83848 本来就是少数能把 MII 和 RMII 都做全的 PHY别浪费。2.2 RMII 模式下 F407 与 DP83848 的引脚对照RMII 在 F407 上的引脚分布很典型画原理图前对着下表过一遍能省掉后面一半的飞线功能F407 引脚方向DP83848 对应信号备注REF_CLKPA1输入XIRMII 模式50MHz同一时钟网络分两路CRS_DVPA7输入CRS_DV载波侦听/数据有效RXD0 / RXD1PC4 / PC5输入RXD[1:0]TXD0 / TXD1PG13 / PG14输出TXD[1:0]TX_ENPB11输出TX_ENMDCPC1输出MDC管理时钟MDIOPA2双向MDIO必须外部上拉这些引脚全部复用成GPIO_AF_ETHGPIO 初始化时别用默认输入模式去接。RMII 的 REF_CLK 和 DP83848 的 XI 要看成“同一个 50MHz 时钟网络上的两个负载”而不是两个独立信号。如果板子已经定死走 MIIPA1 变成 RX_CLK、PC3 变成 TX_CLK引脚散在 PA/PB/PC 各组比 RMII 更容易接错原理图评审时逐根对。2.3 strap 引脚和复位电路PHY 地址和 MODE 都不能悬空DP83848 的很多配置不是软件写的而是上电或复位释放瞬间通过 strap 引脚采样锁存PHYAD[4:0]决定 MDIO 地址ST 评估板常见是 0x01MODE决定 MII/RMIIANEG决定自动协商。strap 引脚必须用 10kΩ 电阻接死到确定电平悬空等于把配置交给噪音。PHYAD[4:0] 00001 ; MDIO 地址 0x01也常见 0x00扫描为准 MODE 1 ; RMII 模式MODE0 为 MII ANEG 1 ; 使能自动协商 LED_ACT 0 ; 活动指示低有效最容易被忽略的是 LED 引脚同时参与 strap。直接把 LED 串电阻接地的做法会把 strap 拉错导致 PHY 地址或模式不对上电后 MDIO 怎么扫都扫不到设备。RESET_N 别用 RC 延时用 MCU 上一个 GPIO 控制复位拉低保持 10ms 再释放保证 strap 电平稳定后再让 PHY 采样。提示strap 引脚的具体编号在不同封装和批次上有差异原理图定稿前以你手里那份数据手册的 Strap Options 表为准。2.4 网络变压器、MDIO 上拉画板时最容易漏的两处以太网变压器要选 10/100M 的 1:1 网络变压器集成 RJ45 的模块HR911105A 这类最省事共模电感和中心抽头都按 PHY 手册的推荐网络接。用飞线把 MAC 到 PHY 的信号拉出来调试可以理解但差分对和变压器之间不要飞线接收不稳定有一半问题出在这段密集走线上。MDIO 是开漏信号线上必须有 4.7kΩ 上拉到 3.3V。漏掉这个电阻的症状很典型读 PHY 寄存器大多数时候正常偶尔回 0xFFFF而且频率没有明显规律。MDC 不需要上拉。另外 DP83848 的每个电源引脚旁边放 0.1µF 去耦别用一片大电容代替。3. 标准库下初始化 DP83848PHY 地址扫描、复位时序与 ETH_Init 顺序3.1 先扫 PHY 地址DP83848 的地址不一定都是 0x01很多教程把 DP83848 的 MDIO 地址直接写死 0x01那是因为 ST 评估板的 strap 恰好贴成 0x01。自己画的板子如果抄了别人的 PHYAD 电阻网络地址可能是 0x00也可能是 0x03。标准库里ETH_ReadPHYRegister已经封装好 MDIO 时序开机先扫描 32 个地址比写死任何一个值都可靠。/* 标准库的 ETH_ReadPHYRegister(addr, reg) 封装了 MDIO 读时序 */ #define DP83848_ID1 0x2000 #define DP83848_ID2 0x5C90 static uint8_t g_phy_addr 0xFF; uint8_t dp83848_probe(void) { uint32_t id1, id2; for (uint8_t addr 0; addr 32; addr) { id1 ETH_ReadPHYRegister(addr, 0x02); /* PHYIDR1 */ id2 ETH_ReadPHYRegister(addr, 0x03); /* PHYIDR2 */ if (id1 DP83848_ID1 (id2 0xFFF0) DP83848_ID2) { g_phy_addr addr; return 1; /* 找到 DP83848记录实际地址 */ } } return 0; /* 全扫描失败先查硬件再继续 */ }MDIO 帧里带 5 bit 的 PHY 地址所以正好扫 0~31。DP83848 的 ID 是 0x20005C90ID1 固定 0x2000ID2 低 4 位是硅片版本号要屏蔽掉再比较。如果 32 个地址全部返回 0xFFFF别急着调软件先量 MDC 有没有波形、MDIO 上拉电阻在不在、复位引脚有没有被拉死。扫描依赖 MDC 频率MDC 要控制在 2.5MHz 以内对应到 STM32F407 的 MACMIIAR 寄存器 CR 位段就是这张表HCLK (MHz)CR[2:0]分频MDC 约20~35001161.25~2.2 MHz35~60010261.3~2.3 MHz60~100000421.4~2.4 MHz100~150011621.6~2.4 MHz150~2501001021.5~2.5 MHz168MHz 主频对应 CR100分频 102。标准库的老版本如果不暴露这个字段直接改 MACMIIAR 的 CR 位段别让它默认停在 HCLK/42 上。3.2 复位时序与 DP83848 寄存器配置DP83848 的复位建议挂在 GPIO 上而不是和 MCU 的 NRST 绑在一起。绑在一起的代价是调试器复位 MCU 时 PHY 不复位strap 和寄存器状态残留在上一次运行的值上问题很难复现。void dp83848_hw_reset(void) { /* 复位引脚由 GPIO 控制拉低 10ms 释放比手册最小值留足余量 */ HAL_GPIO_WritePin(ETH_RST_GPIO_Port, ETH_RST_Pin, GPIO_PIN_RESET); HAL_Delay(10); HAL_GPIO_WritePin(ETH_RST_GPIO_Port, ETH_RST_Pin, GPIO_PIN_SET); HAL_Delay(10); /* 等 PHY 内部自检完成 */ } void dp83848_phy_init(void) { uint16_t bmsr; if (!dp83848_probe()) { return; } /* BMCR 0x8000: 软件复位把寄存器全部拉回默认值 */ ETH_WritePHYRegister(g_phy_addr, 0x00, 0x8000); HAL_Delay(2); /* BMCR 0x1000: 使能自动协商让 PHY 和对端谈速率/双工 */ ETH_WritePHYRegister(g_phy_addr, 0x00, 0x1000); /* BMSR bit5 自动协商完成协商过程一般 2~3 秒 */ do { bmsr (uint16_t)ETH_ReadPHYRegister(g_phy_addr, 0x01); } while ((bmsr 0x0020) 0); }BMCR 的 0x8000 是自复位位写完就自动清0x1000 是自动协商使能位。BMSR 的 bit5 是协商完成bit2 是 link 状态但 link 位是锁存型的直接读一次会带上历史状态变化判断前先读一次把它清掉。协商久久不完成时先怀疑网线、对端设备再怀疑变压器端接。3.3 ETH_Init 顺序与 DMA 描述符标准库里 ETH 初始化的顺序是固定的ETH_DeInit复位整个 MAC 和 DMAETH_SoftwareReset软复位 DMA等 SWR 标志清除后再填参数、挂描述符、调用ETH_Init。extern ETH_DMADescTypeDef DMARxDescTab[], DMATxDescTab[]; uint8_t eth_bsp_init(uint8_t phy_addr, uint8_t *mac) { ETH_InitTypeDef eth_init; ETH_DeInit(); ETH_SoftwareReset(); while (ETH_GetSoftwareResetStatus() SET) { /* 等 DMA 软复位结束正常几十个周期 */ } ETH_StructInit(eth_init); /* 先用默认值打底再逐项覆盖 */ eth_init.ETH_Mode ETH_Mode_FullDuplex; eth_init.ETH_MACAddr[0] (mac[0] 24) | (mac[1] 16) | (mac[2] 8) | mac[3]; eth_init.ETH_MACAddr[1] (mac[4] 24) | (mac[5] 16); eth_init.ETH_RxDescList DMARxDescTab; eth_init.ETH_TxDescList DMATxDescTab; eth_init.ETH_RxBuffLen 1524; /* 4 的倍数且大于 1518CRC */ eth_init.ETH_TxDescCount 4; eth_init.ETH_RxDescCount 6; ETH_Init(eth_init, phy_addr); /* 第二个参数就是扫描到的 PHY 地址 */ ETH_DMAITConfig(ETH_DMA_IT_R | ETH_DMA_IT_NIS, ENABLE); return 0; }MAC 地址的高 32 位和低 16 位是分两个寄存器写的标准库的ETH_MACAddr[0]/[1]按这个高低字顺序填。各个 SPL 版本对这个成员的封装不完全一样有的用uint8_t[6]赋值前看头文件确认原则是最终写进 MACA0HR 和 MACA0LR 的值要对。RX 缓冲长度必须设成 4 的倍数描述符和收发缓冲都放在普通 SRAM 里放到 CCM RAM 是后面接收不稳定的一大来源。注意自动协商完成后MAC 的速率和双工参数要和 PHY 协商结果一致。调试环境里对端是固定 100M 全双工的老交换机时可以把 PHY 写成强制模式ETH_WritePHYRegister(addr, 0x00, 0x2100)关闭协商反而比开着稳定。4. STM32F407 与 DP83848 接收数据不稳定的排查时钟、回环与 FCS 计数4.1 第一嫌疑是 PA1 上的 50MHz 不是 50MHz“dp83848 接收数据不稳定”这个症状我见到的第一梯队原因几乎都是 RMII 参考时钟不对。常见做法是用 STM32F407 的 MCO1PA8输出时钟给 PHY 用但 8MHz 晶振配 168MHz 主频时MCO1 从 PLLCLK 分频只能得到 42MHz不是 50MHz。拿 42MHz 当 RMII REF_CLK现象就是 ping 小包能通大流量一上来就掉包而且掉得没规律。正确的做法是外部 50MHz 有源晶振输出同时接到 PA1 和 DP83848 的 XI一个源驱动两个负载晶振的频率精度和抖动指标直接决定 RMII 能不能稳。上电后用示波器或频率计量 PA1频率要在 50MHz ±50ppm 以内占空比 45%~55%。测的时候探头地线要短RMII 的 REF_CLK 对毛刺敏感探头悬空量出来的抖动会把问题引到错误的方向。4.2 用 PHY 回环测试做二分定位怀疑接收不稳时先跑一次 DP83848 的 PHY 回环能在五分钟内把问题切成“MAC/DMA 侧”和“物理链路侧”两块。回环信号不经过网线和变压器在 PHY 内部就绕回去了。uint8_t dp83848_loopback(uint8_t on) { uint16_t bmcr; /* 进回环前先读一次 BMSR清掉锁存的 link 变化位 */ ETH_ReadPHYRegister(g_phy_addr, 0x01); bmcr (uint16_t)ETH_ReadPHYRegister(g_phy_addr, 0x00); if (on) { ETH_WritePHYRegister(g_phy_addr, 0x00, bmcr | 0x4000); /* BMCR bit14 */ } else { ETH_WritePHYRegister(g_phy_addr, 0x00, bmcr ~0x4000); } return 1; }回环模式下让 MAC 发一帧RX 描述符能收到同一帧说明 PHY、MAC、DMA、时钟这整条数字通路是通的问题大概率在网线、变压器或对端收不到回头查 RMII 引脚接线、REF_CLK 频率和描述符初始化。回环测试要分别用 64 字节小包和 1500 字节大包各跑一遍小包通大包不通的描述符缓冲长度配置有问题。4.3 描述符、CCM RAM 与 MMC FCS 计数STM32F407 的 CCM RAM0x10000000 起始是 DMA 访问不到的。把 RX 描述符或 DMA 缓冲放进 CCM RAM编译不报错跑起来就是接收全乱、死机或者 HardFault而且只在流量大的时候触发极具迷惑性。用标准外设库时DMARxDescTab和DMATxDescTab以及收发缓冲要放在普通 SRAM1/SRAM2链接脚本里把 CCM 区域对存量代码关掉。判断物理层到底有没有错帧不用接抓包工具STM32F407 的 MAC 自带 MMC 统计/* 上电累计值不是增量值对比两次快照才能看趋势 */ uint32_t eth_mmc_crc_error_snapshot(void) { return ETH-MMCRFCECR; /* Receive frame with CRC error counter */ }把两次调用结果的差值当作这个时间段内的 CRC 错帧数。ping 的同时读这个值如果它跟着上涨说明物理层真的在产错帧方向指向变压器、晶振和 REF_CLK如果它一直停在 0 但应用层还在丢包问题在 MAC/DMA 描述符释放逻辑或者在 lwIP 的缓冲区池和 PHY 无关。4.4 复位、协商和板级现象对照现象首先查原因方向ping 通大流量吞吐上不去PA1 频率和占空比RMII 参考时钟不对ping 时通时断MDIO 读值、link 状态协商不稳、描述符耗尽MMC CRC 计数上涨变压器、晶振、复位时序物理层信号质量大流量一跑就 HardFault描述符所在内存区域描述符放进了 CCM RAM调试器只复位 MCU 不复位 PHY 时PHY 停留在上一次的 strap 采样结果里出现“断电重上电就正常按复位键就故障”的现象就是复位分离没做好。Link 指示灯亮了但收不到数据先量 CRS_DV 和 RXD[1:0] 的波形确认 RMII 的 RX 通路是不是被接到 MII 的 RX 引脚上去了。5. 跑 lwIP 前把 DP83848 这 3 个参数设好窗口、描述符和 MMC 验收5.1 lwIP 裸机下最容易拖垮接收的 3 个参数F407 跑 lwIP 以 NO_SYS 裸机方式最常见接收路径是被动收包参数配小了DP83848 本身没问题也会表现出“接收不稳定”。lwipopts.h 参数建议值说明PBUF_POOL_SIZE不小于 16收包缓存池突发时池子空就直接丢包TCP_WND不小于 4×TCP_MSS约 5840窗口小于 4 个 MSS 时约等于停等协议吞吐被压死TCP_SND_BUF / TCP_SND_QUEUELEN不小于 4×TCP_MSS连续 send 时发送队列满表现为发送阻塞或丢包同时ETH_RxDescCount不要低于 6RX 描述符太少时 100M 突发一进来MAC 没有空闲描述符承接包被硬件丢弃丢得多的时候 ping 都会露馅。注意这些参数互相吃 RAM改大之前先看剩余 SRAM 量F407 上常见配置是 RX 描述符 6 个、TX 4 个、PBUF 池 16 个。5.2 验收技巧直连、长短包和 MMC 快照板子调通后别急着上协议栈压力测试按三步验收。第一步 PC 和板子静态 IP 直连ping 1500 字节左右的包连续 100 次丢包必须为 0第二步用 UDP 向板子打一段 1Mbps 的突发流量同时串口打印 MMC CRC 计数快照第三步把流量拉到接近 100M观察吞吐是否平稳这时 F407 配合 lwIP 跑出 5~9MB/s 都是正常范围远低于这个值优先看窗口参数而不是 PHY。最后留一个现场技巧把eth_mmc_crc_error_snapshot()和 DP83848 的 link 状态放进一个周期任务每 5 秒往串口推一条快照。CRC 计数在大量收发时上涨先量 PA1 和变压器CRC 全零但应用层丢包回头查描述符释放顺序和 PBUF 池快照里连 link 都在抖动就去查网线和协商。现场工程师拿到这条串口快照能直接把“DP83848 接收数据不稳定”收窄到时钟、物理层还是协议栈剩下的就是照表换器件。本文还有配套的精品资源点击获取
返回列表