尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

STM32H750VBT6+LAN8720A+LWIP以太网开发实战与避坑指南

STM32H750VBT6+LAN8720A+LWIP以太网开发实战与避坑指南 做物联网网关、设备监控或者板间通信总避不开“STM32H750VBT6 以太网”这套玩法。前阵子我替客户做一块数据采集板MCU选型锁定了STM32H750VBT6网络接口自然就想到LAN8720A这颗经典RMII接口PHY协议栈用LWIP系统跑FreeRTOS开发环境则用ST官方的CubeIDE。整套组合从CubeMX图形化配置到最终稳定跑TCP通信前后折腾了两天。这篇东西就是把我实际踩过的坑和验证过的配置一次说清楚适合正在从零开始搭H7网络工程的开发者也适合遇到ping不通、PHY读不到ID、跑一会儿就死机之类问题的朋友。项目本身不复杂H750的主频跑到480MHz硬件自带以太网MAC外部挂一颗LAN8720A做物理层收发再通过带网络变压器的RJ45座连到交换机软件侧用FreeRTOS调度LWIP协议栈最后在应用层起一个TCP服务用于接收上位机下发的指令。下面把硬件选型、Cube配置、代码逻辑和排查经验全部拆开讲内容足够“保姆级”但每一步我会解释为什么要这么选、这么配。1. 项目背景与方案选型思路1.1 为什么是STM32H750VBT6STM32H750VBT6这颗片子本质是H743的“青春版”但它的性能一点都不青春Cortex-M7内核主频最高480MHz带双精度FPU、32KB I-Cache和32KB D-Cache内置硬件以太网MAC支持RMII和MII两种接口。100脚LQFP封装板级布线压力小。最关键的是这颗芯片的价格比同系列的H743便宜不少做成本敏感的网关类产品很有吸引力。不过它有一个很“坑”的短板内置Flash只有128KB。官方手册上写的是2MB但那是通过QSPI外接Flash映射出来的不是片上真Flash。很多第一次用H750的人会把编译器的链接脚本改成2MB结果量产时固件一跑就崩。128KB空间跑一个FreeRTOS LWIP的工程只要设置合理是足够的但你必须知道怎么省Flash后面专门讲。选H750还有一个原因它的以太网MAC自带DMA收发数据不占用CPU太多时间配合LAN8720A这种带RMII接口的PHY硬件连接只需要十来根线非常适合做小型协议转换器、数据采集网关。1.2 LAN8720A这颗PHY的江湖地位说实话10/100M以太网PHY芯片可选的不少比如LAN8710A、LAN8742、DP83848但LAN8720A在国产开发板上的出镜率最高原因很朴素便宜、外围电路简单、资料多、不容易买假货。它支持RMII接口时钟方案灵活可以用25MHz晶振或外部50MHz时钟内带1.2V稳压器3.3V单电源供电即可。从功能上看LAN8720A支持10M/100M自适应支持自动协商、极性检测和纠正、MDI/MDIX自动翻转。10M半双工、100M全双工这些常规模式全部覆盖。对于绝大多数嵌入式网络应用比如TCP上传传感器数据、UDP广播、HTTP协议交互这颗芯片完全够用而且多年量产验证下来稳定性也不错。我个人的习惯是选PHY一定要看开发板的成熟方案。LAN8720A的参考电路我已经抄过好几轮基本没出过问题这也说明它的容错度比较高。1.3 FreeRTOS LWIP的组合逻辑为什么整体方案一定要引入FreeRTOS和LWIP先说FreeRTOS。H750裸机跑也不是不行但一旦网络协议栈需要处理重传、超时、socket连接管理裸机代码会越来越难维护。FreeRTOS提供了任务调度、信号量、消息队列这些基本设施可以把“网络协议栈”和“业务逻辑”彻底隔离开。LWIP则是开源的轻量级TCP/IP协议栈专门为嵌入式系统设计。它不需要依赖Linux内核可以在裸机或RTOS上运行支持TCP、UDP、ICMP、DHCP、HTTP等常见协议。LWIP为了适配FreeRTOS提供了sys层适配接口比如创建线程、使用信号量、邮箱等CubeMX生成代码时会自动把这些组合起来。用一句话总结这套方案的逻辑FreeRTOS负责“何时跑”LWIP负责“怎么收发”H750的ETH外设负责“数据进出”LAN8720A负责“物理介质上的电信号”。四层配合各管一段。1.4 数据流的直观理解为了后面调试方便我在动手前会把数据流画在纸上应用层任务调用netconn_write → LWIP协议栈封装成TCP报文 → 通过ETH DMA描述符送入MAC → MAC通过RMII接口把数据交给LAN8720A → PHY编码后从RJ45送出去。接收方向完全相反LAN8720A收到网络信号 → RMII接口给MAC → DMA搬运到内存Ring buffer → 协议栈解析 → 应用层任务通过netconn_recv读到数据。记住这条链路后面排查问题时只需要逐段定位。硬件问题多半出在“RJ45到PHY”这一段软件问题多半出在“MAC到内存”这一段。2. 硬件准备与关键电路检查2.1 物料清单和实物连接动手之前先把清单列清楚STM32H750VBT6核心板或自绘PCB板本文以100脚封装为例LAN8720A模块或者自己贴片LAN8720A RJ45带网络变压器ST-Link或J-Link调试器一个USB转TTL串口模块方便输出调试日志网线、路由器或交换机电脑一台12V或5V电源给板子供电我这次用的是自己画的最小系统板PHY部分直接参考LAN8720A官方数据手册的参考电路网络变压器集成在RJ45座子内部买的是HR911105A这颗座子。如果你用现成模块接线就按模块丝印来注意事项少很多。2.2 LAN8720A参考电路的几个关键点LAN8720A的参考电路不算复杂但有几个点必须抠细节第一时钟方案。RMII接口要求50MHz参考时钟。最稳妥的接法是LAN8720A的XTAL1和XTAL2之间接一个25MHz无源晶振然后把LAN8720A的CLKOUT引脚接到STM32的ETH_RMII_REF_CLK引脚。因为LAN8720A内部有PLL会把25MHz倍频到50MHz从CLKOUT输出给MCU。这种接法PHY自己产生时钟MCU这边只做输入时序最安全。第二PHY地址配置。LAN8720A的PHY地址由PHYAD0引脚决定接地为0x0接上拉为0x1。大多数模块默认接地所以SMI访问的PHY地址是0。如果读到ID全0xFFFF先检查这个引脚的焊接和电平。第三复位引脚。LAN8720A的nRST是低有效复位一般由STM32的GPIO控制。复位信号至少保持低电平25us再拉高否则PHY可能启动异常。我见过有人偷懒直接接RC复位电路但最好还是用IO控制这样软件可以随时硬复位PHY。第四LED指示灯。LAN8720A的LED0和LED1引脚可以做状态指示最常见配置是LED0表示Link状态、LED1表示活动状态。调试时这两个灯非常有用——网线插上后Link灯必须亮如果灯不亮后面谈什么都是空的。下面是STM32H750VBT6和LAN8720A之间的RMII信号连线表确认接线前先对着查一遍功能信号STM32引脚LAN8720A引脚说明REF_CLKPA1CLKOUT50MHz参考时钟由PHY输出给MACTXD0PG13TXD0发送数据位0TXD1PG14TXD1发送数据位1TX_ENPG11TX_EN发送使能RXD0PC4RXD0接收数据位0RXD1PC5RXD1接收数据位1CRS_DVPA7CRS_DV载波侦听/数据有效MDCPC1MDC管理接口时钟MDIOPA2MDIO管理接口数据2.3 电源和网络变压器注意事项LAN8720A的供电是3.3V内部稳压输出1.2V供核心逻辑。要注意它的VDDCR引脚上需要接一个1uF的去耦电容放置要尽量靠近引脚。PHY对电源纹波比较敏感如果电源不干净会出现随机断链、数据丢包这类很难查的问题。网络变压器的作用是隔离共模信号和静电它内部其实有一个中心抽头中心抽头通过RC接地还是接电源不同厂家的模块设计有差异。如果你买的是带变压器的RJ45一体座不用操心这个如果是分离式变压器按数据手册接。我吃过一次亏分离式网络变压器中心抽头悬空导致link指示灯不亮查了半天。另外提醒一句RJ45的差分线从PHY到变压器之间要等长、靠近长度差控制在5mm以内。PCB空间太紧张时至少保证REF_CLK这根线尽量短因为它跑50MHz串扰和反射都会造成间歇性通信异常。2.4 硬件上电后的第一件事连线完成后不要急着写代码。先用示波器或万用表确认三件事3.3V供电是否正常电流是否在100mA量级PHY的25MHz晶振是否起振如果是用示波器看CLKOUT引脚应能看到50MHz方波网线插上交换机后H750板子上如果接了LEDLink灯是否点亮我调试时最常用的工具是一根带指示灯的通断测试网线几块钱一根能快速排除线序问题。Link灯不亮先换网线、换交换机端口再考虑配置问题。Link灯亮说明PHY物理层已经通了接下来才是软件部分。3. CubeIDE CubeMX 网络工程配置实战3.1 新建工程与时钟树配置打开CubeIDE在文件菜单里新建STM32项目芯片型号输入STM32H750VBT6。需要注意的是CubeMX可能默认让你选H750VBT6的封装和Flash配置没问题直接确认。进入图形化配置界面之后先改时钟树。我用的外部晶振是25MHz在HSE处填入25然后在Clock Configuration里设置PLL源为HSE让SYSCLK跑到480MHz。CubeMX会自动算出AHB总线240MHz、APB1和APB2各120MHz。这里要留意ETH外设的时钟源不同的CubeMX版本界面略有差异但基本都能在图里看到“Ethernet”相关时钟选项确保它为50MHz即可。如果不会调PLL可以直接选CubeMX左上角的“Clock”小工具它会根据你选的外部晶振频率自动生成一套合法配置。个人建议还是自己手动调一遍因为后面如果改PHY时钟方案你至少知道这个50MHz是从哪来的。3.2 配置ETH外设在Categories里面找到Connectivity → ETH勾选ETH激活。在Mode选项卡里把Interface选为RMII。这样CubeMX会自动分配RMII所需的引脚你只需要核对PA1、PA2、PA7、PC1、PC4、PC5、PG11、PG13、PG14这些引脚是不是都对上了。接下来的关键项是LAN8720A的PHY地址。CubeMX的ETH配置里有一个Advanced Parameters里面有PHY Address字段默认可能是0。LAN8720A如果PHYAD0接地就是0那就保持默认如果接高电平要改成1。这一步不填对后面读PHY ID就会失败。还有一项是PHY寄存器的定义。CubeMX生成代码时会包含lwip相关的PHY驱动但它默认支持的可能是LAN8742和LAN8720A寄存器大体兼容但有些细节差异。我建议在生成代码后去stm32h7xx_hal_conf.h或者eth.c里检查一下PHY地址宏确保用的是同一个地址。ETH的DMA参数一般保持默认但要注意把DMA描述符数量、接收缓冲区大小这些项目留够内存余量后面如果跑大数据量TCP默认配置可能不够。3.3 配置LWIP中间件在Middleware里找到LWIP勾选Enabled。这里有几个要点协议栈版本CubeMX一般给你LwIP 2.1.2或2.2.x我用的是2.1.2稳定就好。API模式选择“Netconn API”而不是“Raw API”。理由很简单我们在FreeRTOS上开发Netconn API是阻塞式、线程安全的写业务代码更像传统socket逻辑清晰。Raw API虽然性能更高但回调满天飞维护成本高。IP版本选IPv4然后可以开启DHCP。我建议前期调试用静态IP比如192.168.1.100子网掩码255.255.255.0网关192.168.1.1。等确认通了再切DHCP否则你连设备IP都不知道。在Memory Settings里有几个参数是按需调大的MEM_SIZE堆内存池大小默认上千字节如果TCP窗口大可以适当调大。PBUF_POOL_SIZE网络包缓冲池数量我一般改成8个以上否则并发稍多就丢包。TCP_WND、TCP_SND_BUFTCP接收窗口和发送缓冲区要和协议交互的数据量匹配。我之前测试大数据传输把这两个提到4096以上才顺畅。不要一上来把每个参数都改大MCU内存有限够用就行。LWIP内存太小会一直报Out of memory太大又会撞上H750的RAM上限后面会专门讲内存平衡。3.4 配置FreeRTOS在Middleware里选择FreeRTOS勾选Enabled。CMSIS版本选V2它是ST官方推荐的API接口你如果用CubeMX的osThreadNew、osMessageQueue这些函数就需要V2。在Tasks里可以看到系统默认创建的defaultTask它的堆栈大小默认可能是128 words但我们后面要跑TCP任务这个堆栈明显偏小建议改成1024甚至2048 words。别心疼RAMH750有充足的内部SRAM但如果堆栈设太小一旦递归或深层调用触发溢出RTOS会跑飞而且十分难查。FreeRTOS的配置里还有一项USE_DAEMON_TASK如果后面要用软件定时器才需要开。网络应用如果用不上保持默认即可。FreeRTOS和LWIP的配合有一个优先级问题LWIP的核心线程tcpip_thread负责协议栈处理日志或业务任务的优先级如果比它高可能会长时间抢占CPU导致协议栈超时重传。建议CMD虚拟任务优先级不要设太高我用的是osPriorityNormal。3.5 生成代码后必须手动检查的几处CubeMX生成的代码不是开箱即用的有几个地方必须在烧录前检查第一检查main.c里的MX_ETH_Init函数确认PHY地址和你硬件实际一致。读一下类似#define LAN8720A_PHY_ADDRESS 0x00的宏。第二检查LWIP初始化时如果用的是Netconn API模式CubeMX会自动创建tcpip_thread不要自己在main函数里重复调用lwip_init。看main.c中MX_LWIP_Init()的调用顺序它应该放在外设初始化之后、启动RTOS调度器之前。第三MPU配置。这是H750和H743最容易出问题的环节。H7有D-Cache如果数据被DMA写进内存CPU读到的可能是缓存里的旧数据反之CPU写数据但DMA读到的可能是内存里的旧数据。CubeMX生成代码里通常会有一个MX_MPU_Config函数把ETH的DMA描述符和缓冲区设置成Non-cacheable。如果你的CubeMX版本没自动生成你必须在主函数最开始调用MPU_Config并且给以太网缓冲区所在RAM区域配置Non-cacheable属性。我第一次就是这个没配好现象是ping偶尔通、数据随机错位排查了整整半天。4. 应用层任务代码实现4.1 初始化顺序的合理安排main函数里外设初始化顺序按CubeMX生成就行但有几个原则ETH、LWIP要晚于引脚和时钟初始化但早于RTOS调度器启动。FreeRTOS任务创建要在调度器开始前完成但TCP Server任务里的具体逻辑等调度器跑起来再执行也没问题。日志串口初始化尽量放前方便从程序一启动就输出信息。我的main函数大致结构是HAL_Init()MPU_Config()SystemClock_Config()MX_GPIO_Init()MX_ETH_Init()MX_LWIP_Init()创建TCP Server任务osKernelStart()注意MX_LWIP_Init里其实会启动tcpip_thread这个线程不是业务线程它是LWIP内部处理协议栈消息的。你真正要做的是再创建一个自己的业务线程比如tcp_server_task专门负责监听和收发。4.2 TCP Server任务用Netconn API写起来像socket下面直接给一个可在H750上跑的TCP Server任务示例监听8080端口收到数据后原样回发。这个任务用Netconn API代码不长但你可以照着扩展成自己的协议解析逻辑void tcp_server_task(void *argument) { struct netconn *conn, *newconn; struct netbuf *buf; err_t err; char rx_buffer[256]; conn netconn_new(NETCONN_TCP); if (conn NULL) { for(;;) { vTaskDelay(pdMS_TO_TICKS(1000)); } } netconn_bind(conn, IP_ADDR_ANY, 8080); netconn_listen(conn); for (;;) { err netconn_accept(conn, newconn); if (err ! ERR_OK) { vTaskDelay(pdMS_TO_TICKS(10)); continue; } while ((err netconn_recv(newconn, buf)) ERR_OK) { do { u16_t len buf-p-len; if (len sizeof(rx_buffer)) { len sizeof(rx_buffer); } memcpy(rx_buffer, buf-p-payload, len); rx_buffer[len] \0; /* 这里做业务解析 */ netconn_write(newconn, rx_buffer, len, NETCONN_COPY); } while (netbuf_next(buf) 0); netbuf_delete(buf); } netconn_close(newconn); netconn_delete(newconn); } }这里有几个容易踩的细节netconn_recv是阻塞函数如果连接断开会返回非ERR_OK跳出内层循环。buf-p是pbuf结构payload指向实际数据len是当前pbuf长度。如果数据跨多个pbuf需要用netbuf_next遍历不能只看第一个。netconn_write最后一个参数选NETCONN_COPY表示数据会拷贝到内部缓冲区再发送这样你在调用后马上修改rx_buffer也没问题。代价是多一次内存拷贝但代码安全性高很多。4.3 数据收发机制与内存拷贝策略Netconn API的数据流向是内核把收到的数据放在pbuf链里netconn_recv拿到的是netbuf。你的应用层需要尽快把数据拷贝走然后调用netbuf_delete释放。如果你不拷贝直接拿指针长时间保存很容易导致缓冲区被内核复用数据被覆盖。发送数据时也同理使用NETCONN_COPY模式最安全适合小数据量场景。如果你要发送大块数据、对性能有要求可以用NETCONN_NOCOPY但必须保证发送期间数据缓冲区不被修改。我的建议是前期调试一律用COPY跑通了再根据性能测试决定是否优化。TCP是流协议数据到达边界可能不是整包。别看上面代码简单实际业务中你可能需要自己做分包和粘包处理。最常用办法是自定义协议头比如前4字节表示长度收到数据后先积累到环形缓冲区长度够了再解析。4.4 再加一个UDP广播任务做设备发现很多网关设备需要被上位机自动发现这里再附加一个UDP广播的示例简单实用void udp_broadcast_task(void *argument) { struct netconn *udpconn; struct netbuf *ubuf; char msg[] H750-Gateway-Online; udpconn netconn_new(NETCONN_UDP); if (udpconn ! NULL) { netconn_bind(udpconn, IP_ADDR_ANY, 8081); } for (;;) { ubuf netbuf_new(); if (ubuf ! NULL) { u32_t dst ipaddr_addr(192.168.1.255); netbuf_ref(ubuf, msg, strlen(msg)); netconn_sendto(udpconn, ubuf, (const ip_addr_t *)dst, 8082); netbuf_delete(ubuf); } vTaskDelay(pdMS_TO_TICKS(5000)); } }UDP广播的地址要跟你的网段匹配这里写的是192.168.1.255表示向192.168.1.x整个子网广播。上位机在8082端口监听就能收到设备上线信息。这个功能很适合做设备自动发现推荐加上。4.5 调试日志怎么打网络工程调试时日志是救命稻草。我会在关键位置打印三个级别的日志信息、错误、警告。用串口输出最省事波特率115200串口引脚根据你的板子来定。比如在TCP Server任务里连接建立和断开时打印“accept new connection from 192.168.1.x”和“connection closed”。LWIP本身有较完整的日志系统你可以打开LWIP_DEBUG但默认全开会刷屏调试完一定要关掉否则极其拖慢性能和Flash占用。5. 编译优化与烧录调试5.1 128KB Flash怎么够用STM32H750VBT6最需要动脑筋的就是128KB片上Flash。好在CubeIDE默认使用GCC编译参数改成-Os优化大小后一个完整的FreeRTOS LWIP工程能压到90KB左右甚至更低。这是我实测比较稳定的方案。在项目属性里找到C/C Build → Settings → Tool Settings → MCU GCC Compiler → Optimization把Optimization Level改成Optimize for size-Os。同时把Linker里的Optimization也打开。另外避免使用printf的完整版。CubeIDE默认可能把printf重定向到半主机模式这会引入不小的库代码。建议用轻量级printf或者直接用串口中断发送字符串的函数。如果不需要浮点格式化输出就别用%f。一个实用的诀窍是查看map文件看哪些.o文件占的Flash最多。有时你会发现只是包含了一个未使用的功能就吃掉好几KB。5.2 内存布局与任务栈大小H750VBT6的RAM其实不小有DTCM、AXI SRAM、SRAM1/2/3等好几块但CubeMX默认的内存分配不一定会均衡使用。编译时会看到类似“region RAM overflowed”的错误那就是内存不够了。解决思路有三个把LWIP的内存池适度调小比如PBUF_POOL_SIZE从默认的5改成4MEM_SIZE减小。优化任务栈大小TCP Server任务我用1024 wordsUDP广播任务512 wordsdefaultTask保持128 words。不要把每个任务都设成2048内存再大也经不起浪费。检查是否有巨型全局数组。如果接收缓冲区定义成1KB×4不会占太多但你要是开了大图片、大音频缓存那就另说。我一般会定期查看编译输出里的RAM占用百分比保持70%以下比较安全给堆栈的峰值留余量。5.3 烧录方式与首次运行判断H750可以用ST-Link通过SWD接口烧录。CubeIDE的Debug配置里选STM32 Cortex-M C/C Application连接ST-Link后直接下载。首次烧录成功后代码会停留在main函数入口。首次烧录后建议先跑一个最简单的测试板子连上网线启动后串口日志打印“LWIP init OK”然后打印当前IP地址。如果能看到IP说明PHY和协议栈都已经正常起来了。我常加一行代码在MX_LWIP_Init()后延时2秒然后打印当前网卡IPextern struct netif gnetif; printf(IP address: %s\n, ipaddr_ntoa((const ip_addr_t *)gnetif.ip_addr));连上路由器时这里应该显示你配置的静态IP或者是DHCP分配到的地址。如果这里打印的IP是0.0.0.0说明DHCP还没成功或者网线没接好。5.4 跑通Ping的成就感配置好之后先别急着写高级应用。拿电脑ping一下设备这是最直观的验证。我的测试步骤是将设备IP设为192.168.1.100电脑IP设为192.168.1.150直连或接交换机都行。在电脑命令行执行ping 192.168.1.100 -t观察响应。正常情况应看到连续“来自192.168.1.100的回复: 时间1ms”。第一次ping通的时候状态栏会显示“Reply from 192.168.1.100: bytes32 time1ms TTL64”那一刻就说明H750的MAC、PHY、LWIP协议栈、FreeRTOS调度已经整条链路全部跑通了。这是整个项目最关键的里程碑。6. 常见问题与避坑速查6.1 读不到PHY ID这是整个调试过程中概率最高、最容易打击信心的问题。现象是在CubeIDE调试器里看到HAL_ETH_ReadPHYRegister返回错误读出来的寄存器值全是0xFFFF或者0x0000。排查顺序确认PHY地址。LAN8720A的SMI地址是PHYAD0引脚电平决定的再次核对你的宏定义和硬件连接。确认MDIO和MDC引脚。在H750上MDIO是PA2MDC是PC1引脚冲突或者被其它外设占用就读不到。确认复位引脚已经拉高且维持足够时间。我常用的办法是给复位引脚一个100ms的低电平再拉高然后在读PHY ID前加10ms延时。确认REF_CLK时钟已经就绪。如果没有50MHz时钟PHY内部逻辑跑不起来SMI接口也不会响应。我见过最隐蔽的一个坑是有些LAN8720A模块上PHYAD0引脚默认接了上拉但你以为是接地结果实际地址是1而不是0。所以不要再猜用示波器或万用表实测PHYAD0引脚电平。6.2 link指示灯不亮Link灯不亮说明PHY没有物理连接这时候软件再怎么调也没用。按下面顺序排查先用一根确定没问题的网线把板子和路由器直接相连不要过墙壁面板。观察RJ45座的另一端如果网络变压器的变压器中心抽头有虚焊Link灯也不会亮。用示波器量PHY的CLKOUT引脚确认是否输出50MHz。如果这引脚没有时钟PHY可能还在复位状态或电源没起来。检查PHY供电引脚电压尤其是1.2V内部稳压输出是否正常。还有一种情况是Link灯亮了但不是闪烁而是常亮或者常灭。LAN8720A的LED配置由寄存器控制默认配置下LED0和LED1的含义可以通过读寄存器得到。如果灯接反了引脚Link状态可能被接到LED1上视觉效果会不一样。6.3 ping不通但link灯亮到了这一步硬件物理层没问题问题多半出在软件或协议栈配置。IP地址冲突确认设备IP和电脑IP不在同一网段或者设备IP和路由器地址冲突。静态IP的网关设置不对如果只是同一局域网内ping网关其实无所谓但如果你跨网段必须设置正确网关。配置了DHCP但路由器没开DHCP设备一直拿不到IP所以ping 192.168.1.100自然不通。这个情况建议用静态IP调试。电脑防火墙拦截了ICMP应答有时候设备其实已经通了但电脑ping不到因为有防火墙。可以在Windows防火墙里临时关闭ICMP回显。LWIP的代码使用了太长定时器导致ARP超时这个比较少见如果多次ping只通一次多半是ARP缓存老化可以尝试减少LWIP的ARP_TMR_INTERVAL。还有一种很隐蔽的情况如果你用的是一个老版本LAN8720A它的自动协商可能出现兼容性问题。建议在PHY初始化时强制配置成100M全双工排除自动协商的问题。6.4 系统卡死和Cache一致性H7上跑FreeRTOSLWIP卡死的头号嫌疑是Cache一致性。这是H750特有的大坑。当你使能了D-Cache但MPU没有把ETH DMA内存区域配置为Non-cacheable时数据不一致会造成接收时DMA把数据写进内存但CPU读到的是缓存里的旧数据导致收到的报文错乱。发送时CPU把数据写进内存但DMA可能读取到旧的内存数据导致发出去的是垃圾包。解决办法有两个在MX_MPU_Config里把ETH DMA描述符和缓冲池所在RAM区域配置为Non-cacheable。CubeMX通常会自动生成但你一定要确认它生效。如果你不想改MPU可以在每次收发前后调用SCB_CleanDCache和SCB_InvalidateDCache但这样性能会打折而且容易遗漏某个路径所以我强烈建议用MPU方案。卡死还有一个常见原因ETH中断优先级设置不当。FreeRTOS要求中断服务函数中调用FromISR系列API时中断优先级不能高于configMAX_SYSCALL_INTERRUPT_PRIORITY。如果ETH中断优先级设得太高网络中断一来FreeRTOS就懵了。解决办法是在NVIC设置里把ETH中断优先级调低一点我的做法是设为5或6数字越大优先级越低。6.5 常见问题速查表现象优先检查项进阶排查读PHY ID返回0xFFFFPHY地址、MDIO/MDC接线复位时序、REF_CLKLink灯不亮网线、交换机端口、网络变压器PHY供电、CLKOUT输出Link灯亮但ping不通IP地址冲突、DHCP设置电脑防火墙、ARP表ping通但数据传输错乱MPU/D-Cache配置DMA描述符数量、PBUF大小跑一段时间后卡死ETH中断优先级堆栈溢出检测、内存泄漏编译报RAM溢出减小LWIP内存池调整任务栈大小、检查全局数组最后再分享一个个人习惯这篇文章写到这里核心配置和坑都讲得差不多了。我最后还想强调一点做H750的网络工程不要一上来就追求跑满带宽先把Ping通了、TCP回显通了然后再逐步加业务。这个过程就像拼图先把硬件拼好、把协议栈拼好、把任务调度拼好任何一个环节出了问题都能准确定位。我自己在H750上做的那个数据采集网关用的就是这套FreeRTOSLWIP框架现在已经在现场连续运行了大半年中途只因为换网线重启过一次。这台设备稳定运行给我的信心是这套方案的底层框架是成熟的剩下的就看你怎么实现业务逻辑。如果你现在正在调试LAN8720A遇到问题建议先回去把PHY ID读出来这一步都过不去的话后面的网络通信全都是空中楼阁。
返回列表