一、项目背景

近期在 STM32H750 平台上实现基于 Ethernet + LwIP 的 TCP 在线升级(IAP)功能。

系统架构如下:

PC
 │
TCP
 │
Bootloader
 │
QSPI(W25Q64)
 │
APP(SRAM运行)

其中:

  • Bootloader 固化在 Flash

  • APP 存储在 W25Q64

  • Bootloader 通过 TCP 接收固件

  • 固件写入 W25Q64

  • Bootloader 将 APP 搬运到 SRAM 运行

目标是实现:

TCP升级
↓
APP运行
↓
APP通过TCP触发升级
↓
返回Bootloader
↓
再次升级

二、第一个问题:TCP升级成功但APP无法运行

升级日志如下:

TCP BIN CRC OK
Write IAP info...
IAP info written

Load APP from W25Q64 to SRAM...
Copy to SRAM done

APP Stack: 0x20005120
APP Reset: 0x00000359

Start SRAM APP!!

此时系统无任何输出。

怀疑:

  • APP未成功拷贝

  • 跳转失败

  • VTOR错误

  • MSP错误

经过排查发现:

APP链接地址仍为0x00000000

实际上:

APP Reset = 0x00000359

明显不是 SRAM 地址。

修改 APP 工程链接地址后:

APP Reset = 0x240012B1

说明 APP 已经被正确链接到 SRAM。


三、第二个问题:小APP正常,大APP不运行

最小测试 APP:

while(1)
{
    printf("APP RUN\r\n");
}

可以正常运行。

但是加入 LwIP 后:

Netif_Config();

程序立即失效。

当时怀疑:

  • Cache

  • MPU

  • ETH DMA

  • 中断

  • SysTick

进行了大量排查。


四、定位到 lwip_init()

通过逐层打印:

printf("1\r\n");
lwip_init();
printf("2\r\n");

发现:

1

打印后程序失效。

继续深入:

stats_init();
mem_init();
memp_init();
pbuf_init();
...
sys_timeouts_init();

最终发现:

sys_timeouts_init();

执行后 APP 无法继续运行。

于是开始怀疑:

LwIP内存区配置异常

五、定位到 netif_add()

进一步排查发现:

lwip_init();

实际上已经成功。

真正卡死位置:

netif_add(...)

通过打印:

ethernetif_init 1
low_level_init 1
before HAL_ETH_GetMACConfig
before HAL_ETH_SetMACConfig
before netif_set_up

程序停止。

最开始认为:

netif_set_up()有问题

后来发现并不是。


六、错误方向:一直怀疑TCP

由于现象表现为:

TCP无法连接
netif_set_up卡死

因此一直怀疑:

  • TCP配置

  • netif回调

  • DHCP

  • ETH初始化

甚至尝试:

gnetif.flags |= NETIF_FLAG_UP;
gnetif.flags |= NETIF_FLAG_LINK_UP;

强行绕过。

结果依然无法解决。


七、关键突破:直接烧录Flash竟然正常

做了一个关键实验。

方案A

APP直接烧录Flash:

0x08000000

运行:

正常
TCP正常
LwIP正常

方案B

Bootloader加载SRAM:

异常

说明:

代码本身没问题

问题一定在:

SRAM运行环境

八、发现AXI SRAM空间问题

查看工程配置:

IROM1 = 0x24001000

同时:

IRAM2关闭

此时:

APP代码
LwIP Heap
TCP PCB
PBUF Pool
MEMP Pool

全部挤在 AXI SRAM 中。

而 map 文件显示:

ram_heap               16403
memp_memory_PBUF_POOL  15443

仅这两项:

≈31KB

实际上 AXI SRAM 已经严重紧张。


九、最终验证

经过测试发现:

只有下面配置同时存在:

__attribute__((at(0x30040000)))
ETH_DMADescTypeDef DMARxDscrTab[];

__attribute__((at(0x30040060)))
ETH_DMADescTypeDef DMATxDscrTab[];

__attribute__((at(0x30040200)))
uint8_t Rx_Buff[][];

并且:

IRAM2启用

TCP 才能正常工作。

这说明:

LwIP必须拥有足够的AXI SRAM空间

十、最终解决方案

最终内存布局:

APP代码区

ROM
Start = 0x24060000
Size  = 0x20000

即:

128KB

AXI SRAM

IRAM2
Start = 0x24000000
Size  = 0x60000

即:

384KB

用于:

LwIP Heap
TCP PCB
PBUF Pool
MEMP Pool

DTCM

IRAM1
0x20000000
Size = 0x20000

用于:

栈
全局变量
普通数据

ETH DMA

固定:

__attribute__((at(0x30040000)))
DMARxDscrTab

__attribute__((at(0x30040060)))
DMATxDscrTab

__attribute__((at(0x30040200)))
Rx_Buff

十一、Bootloader修改

APP基地址:

#define SRAM_APP_ADDR 0x24060000

跳转:

SCB->VTOR = 0x24060000;

APP工程:

SCB->VTOR = 0x24060000;

同时更新:

Load_APP_From_QSPI()
Jump_To_APP()

相关地址检查。


十二、最终结果

实现:

PC
 │
TCP
 │
Bootloader
 │
W25Q64
 │
SRAM APP
 │
TCP业务
 │
TCP触发升级
 │
返回Bootloader
 │
再次升级

全部稳定运行。


十三、经验总结

本次调试最大的收获是:

很多时候程序表现为:

TCP异常
LwIP异常
netif_set_up卡死

并不一定是网络问题。

真正原因可能是:

内存布局不合理
AXI SRAM不足
Heap空间不足
DMA缓冲区位置错误

STM32H7 的 ETH + LwIP 对内存区域非常敏感。

最终问题本质上并不是:

TCP有Bug

而是:

APP代码占用了AXI SRAM
导致LwIP失去了足够的运行空间

这是本次调试中最重要的结论。

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐