stm32h743 通过cumbex初始化 实现以太网(ent)动态申请ip地址(通过lwip协议)

1.前言

本来计划手动移植 LwIP 协议栈,但在实际操作中遇到了诸多棘手问题。为了简化移植流程、降低工程重置的复杂度,最终决定采用 STM32CubeMX 进行初始化配置。
这份笔记旨在记录移植过程中遇到的各类“坑”及其解决方案。希望通过这篇记录,不仅能解决当下的工程问题,更是通过记录问题解决的过程加深理解。
ETH 外设的内部工作机制;
CubeMX 如何移植 LwIP(涵盖有操作系统和无操作系统两种场景)。
网上相关资料虽多,但每个人的硬件环境和遇到的问题各不相同。因此,本文不追求理论的完美闭环,而是以解决工程实际问题为核心,力求讲透 LwIP 的工作方式,做到“知其然,更知其所以然”。
注:本文侧重于工程实践中的问题排查与解决,而非纯理论推导。

本文章使用的芯片是stm32h743iitx,使用的是野火挑战者v2开发板,依旧以这个为例子,希望诸位做到触类旁通。


2.硬件基础: ETH 外设与物理连接


本文以 STM32H743 为例(其以太网外设最为复杂),只要理清了 H7 的机制,F3、F4 等系列的以太网通讯原理基本大同小异。
以太网通信必须建立在完善的硬件连接之上。从工程落地的角度来看,物理链路可拆解为三个核心部分:
MAC 层:由单片机内部的 ETH 外设 实现;
PHY 芯片:负责物理信号处理,需根据需求自行选型;
网口(RJ45):物理接口,连接网线。
通俗的连接逻辑是:
单片机通过内部 ETH 外设(MAC 层)连接外部 PHY 芯片,PHY 芯片再连接网口,从而实现与外部网络的通讯。
常见误区一:为什么要额外买 PHY 芯片?
很多刚接触以太网的小白会问:“为什么连个网线还要单独买 PHY 芯片?”
解答:单片机内部只集成了 MAC 控制器(负责数据链路层的逻辑),不具备物理层的信号收发能力。因此,必须外接 PHY 芯片作为“翻译官”,将单片机的数字信号转换为网线能传输的模拟信号。
常见误区二:像串口一样“连上就能用”吗?
另一个常见误区是认为以太网像 CH340 (RS232)、RS485 或 CAN 模块一样,只要线连对了就能通信。
事实并非如此。这里必须厘清 ETH 外设与 PHY 芯片的连接细节:
接口方式:目前主流采用 RMII 接口(一种简化的媒体独立接口)。
关键差异——时钟信号:
RMII 接口强制要求一个 50MHz 的参考时钟总线。
这个时钟可以由 MAC 端(单片机)提供,也可以由 PHY 端提供。
特别注意:STM32 的 ETH 外设本身并不产生这个 50MHz 时钟。
注意:
在使用 RMII 接口时,必须连接 CLK 线(通常由外部晶振或 PHY 芯片输出时钟给单片机),以确保 ETH 外设拥有稳定的工作时钟。
后果:如果缺少这根时钟线,整个程序可能会直接跑飞或进入硬错误状态。
对比:这一点与 RS232、RS485 等无需独立高频时钟的接口有着本质区别,切勿混淆。

3.ARM-MPU(内存保护单元)


STM32H7 与 F3/F4 系列最大的架构区别,在于引入了 ARM-MPU(内存保护单元)。这也是 H7 开发中最大的“拦路虎”。


3.1. 理论认知:MPU 是什么?


从官方定义来看,MPU 主要用于系统安全与稳定性:
系统保护:阻止用户程序破坏操作系统内核数据。
任务隔离:防止一个任务非法访问其他任务的内存空间(在 RTOS 环境下尤为重要)。
关键数据保护:可将关键数据区设为“只读”,防止被意外篡改。
异常检测:能够捕捉堆栈溢出、数组越界等意外访问行为。


3.2. 工程视角:为什么它会影响 ETH 外设?


抛开理论,从工程应用的角度来看,MPU 的存在直接改变了我们操作 DMA(直接存储器访问)的方式。
机制变化:在 H7 上,ETH 外设及其相关的 DMA 控制器只能访问指定的内存地址区域。
双刃剑效应:
优势:这种机制让 CPU 的数据处理更加高效、安全,避免了总线冲突和数据竞争。
挑战:极大地增加了初始化的难度。如果我们不显式地告诉 MPU“这块内存是给 ETH 用的”,DMA 就可能因为权限不足或缓存一致性问题导致程序死机(HardFault)。


3.2.1.落地步骤:两步走策略


回到我们的工程建立,为了解决这个问题,必须在代码初始化阶段完成以下两步操作:
开放内存权限:配置 MPU 寄存器,允许外设访问特定的内存区域。
指定内存位置:和ent相关的内容要放置在 MPU 允许的指定地址中。
注意:
具体哪些外设内存需要放在指定地址、地址范围是多少,不能凭空猜测,必须通过阅读  参考手册(Reference Manual) 来确认。

同时如果说在程序跑飞遇到和内存相关的错误,需要首先排查mpu可能产生的影响。

4.以太网协议(lwip)

lwip协议是一个轻量化的ent协议,它可以自己移植,也可以用cumbex一键完成,必须要清楚的一点是单单有ent外设而没有lwip协议是无法在进行任何ent工作的。

5.工程的创建:CubeMX 初始化的核心三要素

结合上文对硬件架构与 MPU 机制的探讨,我们在使用 CubeMX 进行工程初始化时,不能仅仅依赖默认设置。为了确保以太网功能在 STM32H7 上稳定运行,必须精准完成以下三个核心步骤。

这三步并非孤立存在,而是一条紧密咬合的链条:

5.1配置 MPU 权限(基础)

正如在“ARM-MPU”章节所述,H7 的内核机制决定了 DMA 无法随意访问所有内存。因此,第一步必须在 CubeMX 的 CORTEX_M7 设置中,开启 MPU 功能,并配置相应的区域(Region),明确“开放”哪些内存地址供 ETH 外设使用。这是后续一切工作的前提。

5.2初始化 ETH 外设(通路)

在 Connectivity 菜单下配置以太网接口(通常选择 RMII 模式)。这一步不仅仅是引脚分配,更是要确保物理层(PHY)的接口参数(如时钟源、MAC 地址)与硬件原理图严格对应,打通数据进出的物理通道。

5.3启用 LwIP 协议栈(灵魂)

在 Middleware 菜单中加载 LwIP 协议栈。这里需要根据项目需求(裸机或带操作系统)选择合适的配置,并设定好 IP 地址、端口等网络参数。

串联这三步的桥梁:内存

这三者看似独立,实则通过内存这一核心资源紧密相连:

MPU 负责定义内存的访问权限(谁能进);

ETH 外设 负责搬运内存中的数据(怎么进);

LwIP 负责使用内存来构建网络包(进什么)。

只有当这三者在内存管理上达成一致(即:LwIP 申请的缓冲区正好位于 MPU 允许 ETH 访问的区域内),整个以太网通信系统才能顺畅运转。

6.CubeMX 工程

6.1.时钟

关键点:时钟设置为480M。

6.2.MPU 设置

设置了三个地址。

地址1:0x3004 0000,大小256B

地址2:0x3004 0200  大小32kB

地址3:0x3004 4000  大小16KB   

ENT设置

这一步是连接 MPU 权限与 ETH 外设的关键。我们需要在 CubeMX 的以太网配置界面中,精确地填入内存地址。这些地址不能随意填写,必须严格落在我们在“MPU 设置”中划定的安全区域(即 0x30040000 起始的 D2 SRAM 区域)内。
以下是具体的地址规划与参数配置,以及它们背后的含义:
1. 地址规划与参数设置
基地址:0x30040000
这是 MPU 为 ETH 外设开放的“大门”,也是 DMA 能访问的最低起始地址。
DMA 发送描述符 (Tx Descriptor)
地址:0x30040000
数量:4
含义:描述符是 DMA 的“记事本”。发送描述符记录了“我要发什么数据”、“数据在哪”、“数据多长”。设置 4 个意味着我们准备了 4 个发送队列,允许数据包排队发送。
DMA 接收描述符 (Rx Descriptor)
地址:0x30040060 (注:发送描述符占用空间后,接收描述符紧接着排列)
数量:4
含义:这是 DMA 的“收货清单”。它告诉 DMA“把收到的数据放到哪里去”。
DMA 接收缓冲区 (Rx Buffer)
地址:0x30040200
长度:1528 (或 1536)
含义:这是真正的“仓库”。当网线传来数据时,DMA 会把数据包原封不动地搬到这里。长度通常略大于以太网最大传输单元(MTU 1500),以容纳帧头。
2. 核心概念解析:什么是描述符?什么是缓冲区?
为了彻底理解上述配置,我们需要搞清楚 DMA 描述符 和 接收缓冲区 的区别。
DMA 描述符 —— “传令官”
定义:描述符本质上是一个结构体数据,它不存储网络数据本身,而是存储关于网络数据的元数据。
作用:CPU 不需要亲自搬运数据,而是通过操作描述符来指挥 DMA 工作。
发送时:CPU 写好描述符(告诉 DMA:数据在内存 A,长度是 B,准备好发送),然后 DMA 看到描述符,自动把数据搬走发给 PHY。
接收时:CPU 提前给 DMA 一串描述符(告诉 DMA:如果收到数据,请放到内存 C),DMA 收到数据后,自动填充数据,并更新描述符状态告诉 CPU“货到了”。
为什么需要它?:它是 CPU 与 DMA 沟通的桥梁。没有描述符,CPU 就得寸步不移地守着外设搬运数据,效率极低。
接收缓冲区 —— “仓库”
定义:一段连续的内存空间,用于存放实际的网络数据包(如 IP 头、TCP 数据等)。
作用:
当网线传来一个数据包(比如一个 Ping 请求),PHY 把它转成电信号传给 MAC,MAC 通过 DMA 把它存入 接收缓冲区。
LwIP 协议栈随后会从缓冲区里把数据取出来分析。
为什么要单独指定地址?:因为 DMA 搬运数据需要物理上连续的内存,且必须避开 DTCM(DMA 访问不了)和 Cache 不一致的区域。所以我们必须强制把它放在 0x30040200 这样 MPU 允许且 DMA 可达的地方。
总结
配置这一步,实际上是在做“定岗定责”:
在 0x30040000 处设立调度台(描述符),负责指挥交通;
在 0x30040200 处设立仓库(缓冲区),负责存储货物;
确保这一切都在 MPU 划定的安全区内,这样 DMA 这位“搬运工”才能畅通无阻地工作

6.3.ENT外设

6.4.ENT中断设置

有了中断就不需要一直去轮询。

6.5.LWIP

只需要简单的使能就够了。

6.5.1.PHY驱动

首先,这是为了确保生成代码的“可编译性”与“完整性”。
LwIP协议栈虽然独立,但其以太网接口层(Ethernet Interface)必须依赖底层的PHY驱动来完成初始化及链路状态检测。如果不选择任何PHY驱动,生成的工程在链接阶段往往会因为缺失底层函数定义而报错。CubeMX默认选中LAN8742,本质上是提供了一个“占位符”实现,确保用户拿到的代码是一个逻辑闭环、能够直接编译通过的最小系统。
其次,它提供了一个极佳的“参考实现”与“代码风格范本”。
PHY驱动的核心逻辑万变不离其宗,无非是通过MDIO/SMI总线读写寄存器。LAN8742的驱动程序(通常是lan8742.c)清晰地展示了如何定义寄存器映射、如何封装读写函数、以及如何解析链路状态(Link Status)。
因此,我们在开发时应采取“先继承,后替换”的策略:
保留接口:在CubeMX中保留LAN8742选项以生成基础架构。
借鉴风格:参考其xxx_Init、xxx_ReadID及xxx_GetLinkStatus等函数的封装方式。
替换内核:在生成代码后,只需将驱动文件中的寄存器地址定义和具体逻辑替换为自己硬件所用芯片的参数,即可快速完成适配。
这种做法不仅规避了配置陷阱,更让我们能够站在ST官方代码风格的肩膀上,高效地完成异构硬件的驱动移植。

6.5.2.静态ip

协议栈配置选项
在中间件配置中,需根据项目需求使能以下核心协议:
LWIP_DHCP Enabled:使能 DHCP 协议,作为动态获取 IP 地址的路径。
TCP Enabled:使能 TCP 传输控制协议。
UDP Enabled:使能 UDP 用户数据报协议。
调试建议流程
为了确保网络通信的稳定性,建议遵循“先静后动”的调试策略:
静态 IP 验证:程序初步调试阶段,建议优先配置静态 IP,通过 ping 命令验证物理链路及协议栈的基础连通性。
动态 IP 部署:在静态 IP 通信无误后,再启用 DHCP 协议以获取动态 IP。
注意:使用 DHCP 模式的前提是网络环境中必须存在有效的 DHCP 服务器。
工程连接拓扑与网关设置
本次工程采用 单片机 - 路由器 - PC机 的级联连接方式,网关配置需依据具体的物理拓扑进行调整。
当前工程配置(经路由器):
    连接方式:单片机 → 路由器 → PC机
    网关设置:指向路由器的 LAN 口 IP 地址(例如:192.168.001.253)。
对比情况(直连):
    连接方式:单片机 PC机(网线直连)
    网关设置:此时双方需互为网关,即单片机的网关指向 PC 的 IP,PC 的网关指向单片机的 IP。

6.5.3.dhcp获取动态ip

如果要使用动态获取ip则需要启动dhcp协议,注意一定需要dhcp服务器才行。

6.5.4.lwip 

关键配置项
在 LwIP 的底层配置(通常是 lwipopts.h 或 CubeMX 配置界面)中,涉及内存管理的参数至关重要,主要包括:
内存堆大小:决定协议栈可用的动态内存总量。
接收缓冲区数量 (ETH_RX_BUFFER_CNT):影响网络数据吞吐与丢包率。
LWIP_RAM_HEAP_POINTER:核心配置,定义堆的起始地址。
LWIP_RAM_HEAP_POINTER 详解
该宏定义了 LwIP 协议栈内部动态内存堆(Heap)的起始物理地址。
作用:LwIP 进行动态内存分配(如调用 mem_malloc、pbuf_alloc)时,都会从这块指定的内存区域中划分空间。
配置值:本次工程设置为 0x30044000。
地址选择与 MPU 协同原则
为什么必须将 LWIP_RAM_HEAP_POINTER 设置为 0x30044000?这并非随意选择,而是基于以下硬件架构的约束:
MPU 区域映射:
    该地址 (0x30044000) 必须对应我们在 MPU(内存保护单元) 配置中已开启访问权限的特定区域之一。如果地址落在 MPU 保护区域之外或权限不匹配,会导致 HardFault。
DMA 访问权限(核心原因):
    LwIP 的内存池直接决定了接收缓冲区 (PBUF) 的物理位置。
    硬件机制:以太网外设(ETH)通过 DMA(直接存储器访问)将网络数据包直接写入内存。
    约束条件:DMA 控制器只能访问特定的内存区域(如 SRAM1/2/3 或特定的 AXI SRAM)。
    结论:必须将堆指针指向 ETH 外设能够访问的地址空间。如果指向了 DMA 无法触及的内存(如某些 DTCM 区域),以太网接收数据时将无法写入,导致网络不通。

6.6.生成工程文件

在完成上述所有核心配置后,还需完成最后两项基础设置,方可生成工程:
时钟配置:确保系统时钟及外设时钟频率正确,保障通信时序稳定。
调试配置:比如烧录的引脚。
完成上述步骤后,即可点击“生成代码”,获得一个基础的、可编译的 LwIP 工程框架。
2.开发路线:从“裸机”到“系统”
关于 LwIP 的运行环境,通常有两种形态,本系列教程将遵循“先裸机,后系统”的递进逻辑:
当前阶段:裸机模式
    - 定义:不依赖任何操作系统,程序在 main 函数的 while(1) 循环或中断中运行。
    - 目的:剥离操作系统的复杂性,专注于理解 LwIP 协议栈本身的初始化流程、内存管理机制以及数据收发原理。
    - 核心任务:验证网络连通性,跑通基础例程。
后续阶段:操作系统模式
    - 定义:结合 RTOS(如 FreeRTOS、RT-Thread)运行。
    - 场景:这是工业界最常见的用法。利用操作系统的任务调度与信号量机制,解决网络协议栈的阻塞与非阻塞处理问题。
    - 过渡:在掌握了裸机模式下的底层逻辑后,移植到操作系统将水到渠成。

6.7总结

排除初始化与调试步骤(如USART打印),核心配置流程可精炼为“MPU划区→外设填址→协议栈填址”三步,关键是厘清ETH与LwIP接收缓冲区的功能差异。
第一步:MPU内存区域划分
在MPU中划分两块关键存储空间,设置精准缓存属性以保证数据一致性:
ETH交互区(设备共享区)
用途:存放ETH发送/接收描述符、ETH接收缓冲区(暂存DMA从网线采集的原始数据)
MPU属性:必须配置为Device(Shared)(TEX=000、C=0、B=1),禁用缓存、启用共享,避免ETH DMA与CPU核心访问数据时出现不一致(脏数据问题)
LwIP堆区(协议栈内存池)
用途:存放LwIP协议栈运行所需的内存池(pbuf),为数据包解析、组装提供空间
MPU属性:配置为Normal(Non-cacheable),保证协议栈稳定访问,避免缓存干扰
第二步:ETH外设配置(填地址)
在CubeMX的ETH外设配置页面,填入第一步中“ETH交互区”对应的物理地址,包含三项关键地址:
ETH发送描述符起始地址
ETH接收描述符起始地址
ETH接收缓冲区起始地址(DMA将原始数据搬运至该地址)
第三步:LwIP协议栈配置(填地址)
在CubeMX的LwIP配置页面,填入第一步中“LwIP堆区”对应的物理地址,即LwIP堆内存起始基地址,让协议栈能从该区域申请内存处理数据包。
核心区分:ETH接收缓冲区 vs LwIP接收缓冲区
ETH接收缓冲区:仅作为ETH DMA的“原始数据暂存区”,负责接收网线传输的底层数据,DMA完成搬运后通知协议栈,CPU不直接干预该阶段数据读取。
LwIP接收缓冲区:本质是LwIP协议栈的“数据处理区”,协议栈从该区域读取原始数据,解析IP/TCP协议头,最终将应用层数据交给CPU批量处理,避免频繁中断。
关键关联:在STM32H7零拷贝架构中,ETH DMA会直接将原始数据搬运至LwIP管理的内存区域,因此MPU需将ETH交互区配置为Device(Shared),同时满足DMA搬运与协议栈处理的一致性需求。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值