STM32H723配置以太网+Freertos注意事项

由于STM32H743涨价到300元以上,项目换用了Pin2Pin替换的STM32H723,看上去cpu运行速度快了20%达到550Mhz。 但是内存布局存在很大不一样,而且ST官方代码库升级迭代快,要手动修改地方每个版本不一样,在有H743的经验下,花了2天时间搞好了记录一下。很多信息来源于英文ST支持论坛才搞定。

1.预备知识


  1. 熟悉H7系列都知道,以太网,DMA等设备,无法访问0x20000000,也就是TCM区的地址。为了让我们代码使用DMA搬运数据,整个代码的变量可以放在RAM D1区域,或者叫AXI区域,就要在.ld脚本中定义.data段,.bss段到 0x24000000. 这一块我们有320KB可以用。

  2. 而DTCM(0x20000000)的128K由于不能DMA访问,但是速度又很快,我们可以用于存放图像数据,高速ADC缓存数据,或者把定义RAMCode函数。

  3. 而涉及到ETH,以及Lwip 的收发缓存相关的地址,把他们定义到D2区域的固定地址。这样就可以使用MPU设置Cache规则,让CPU拿到正确的数据。

2.准备工作

有了以上2点准备,还要注意,如果使用的是CubeMXIDE 1.9.0 , FW库 1.9.0 以下的版本。 由于芯片比较新,ST官方仍然在进行迭代,最好进行升级,否则生成代码后仍然是不工作,不好查问题。现在是2022-12月, 下面基于1.11.0版本。

软件自动下载的固件库也是同样:STM32Cube_FW_H7_V1.11.0

调试过程中看了2个参考文章:

https://community.st.com/s/article/How-to-create-project-for-STM32H7-with-Ethernet-and-LwIP-stack-working
(其中提到到多处H723系列的特殊内存地址的问题,这个很关键)

https://blog.csdn.net/Motseturtle/article/details/126165780
(基本步骤有参考意义,但这个CSDN博文有一处内存地址0x3007ffff没写对是超范围的。另外几个步骤不适用于最新的1.11.0版本)

下面是具体生成步骤:

  1. 选择芯片
  2. 如果本机没有H7固件库会下载。1G,大概2分钟左右。

3.配置基本时钟外设

配置RCC,开启外置晶振,以太网不适合使用内置晶振。开启内置LDO,设置0档,这样支持芯片内核跑到500Mhz以上。

进入Clock Configuration, 自动求解时钟配置。一般硬件上是 16Mhz 或者 25Mhz无源晶振。按自己板子输入。路径选择圆点也要点上, 主频最高可以跑550Mhz。自动求解后,没有出现红色部分即可。

4.配置FreeRTOS

接下来准备配置 FreeRTOS。
把SYS内选择一个没用到的计时器。 用于HAL时钟,如自带的Delay,HAL API内超时等。
而原本的Systick要被RTOS占用,用于操作系统时钟节拍,上下文切换。

在中间件选项,打开Freertos,接口选择“CMSIS_V1”,这样代码体积小一些。功能是一样。

把默认任务的堆栈从128改为512以上,因为默认任务内有比较大的 LWIP 初始化。默认的128太小会导致初始化会Hardfault。 一般1024可以很够用了。

5.配置 Ethernet + Lwip

我用的LAN8742 / LAN8720(平替), 价格高一点,但是好处是可以代码全兼容不加额外PHY代码。组要要改的是 ETH涉及的GPIO要手动改为VeryHigh模式。默认是Low,是会导致PHY通信失败。

打开ETH全局中断

当使用CubeMXIDE时,是使用Gcc编译器, TX/RX Descriptor的内存地址由 *.LD链接脚本决定。这里可以不设置,但也可以设置一下。

TX/RX Descriptor 是给dma用的, 里面包括了 内存搬运的起始地址 结束地址 什么的,dma 分析这个结构体完成数据传输。所以这部分要单独存储,并且用MPU保护防止Cache引起的数据不一致。

接下来配置 LWIP
由于我要固定IP地址,把DHCP设为Disbale,下面输入固定IP的信息。

由于 STM32H723 / STM32H733 的 D2 RAM 是0x3000000开始,它的头16K用于ETH的DMA,后16K可以用于LWIP堆栈。默认的值0x30044000是适用于H743系列等,这里一定要改对,否则LWIP开机内存初始化函数会访问0x30044000(不存在于H723)会导致HardFault。

PHY就选一下,而且只有一种选项。 如果要改为DP83848或者RTL8201 低成本PHY可以参考其他文章,就是代码内PHY相关寄存器和地址改一下。
![
LWIP其余选项默认就行。

6.配置MPU

关于H7的MPU和Cache 可以看这个文章有了解
番外篇:STM32H7的Cache和MPU以及内存分配问题

H7主频工作在400MHz-550Mhz,除了ITCM DTCM 和Cache以满速度工作,其它AXI SRAM,SRAM1-4等都是以200MHz工作。数据缓存D-Cache就是解决CPU加速访问SRAM。

而以太网数据由于数据流量大,会被快速更新。被D-Cache缓存后已经是面目全非,所以我们使用MPU关闭以太网用的相关内存区域的Cache访问权,一旦Cache失效,CPU就老实去真实地址拿数据。这部分数据会慢一点,但是由于不是CPU自己生成的,来源于外部所以只能这样。


第一部分,把32K整个 D2区的SRAM 1 /2 处理为Level 1,关闭所有Cache行为。
第二部分,把头256B,也就是DMA描述符部分配置为Level 0。具体这里不展开。
可以参考:
STM32H743+CubeMX-梳理MPU的设置

7.配置LD脚本

根据ST支持论坛,1.11.0 版本的以太网驱动经过重构要手动加上一块代码,让我们能够指定RX_buff区域。打开 LWIP\Target\ethernetif.c, #120行附近
实现 memp_memory_RX_POOL_base 数组由.Rx_PoolSection段指定地址

/* USER CODE BEGIN 2 */
#if defined ( __ICCARM__ ) /*!< IAR Compiler */
#pragma location = 0x30000400
extern u8_t memp_memory_RX_POOL_base[];

#elif defined ( __CC_ARM )  /* MDK ARM Compiler */
__attribute__((at(0x30000400)) extern u8_t memp_memory_RX_POOL_base[];

#elif defined ( __GNUC__ ) /* GNU Compiler */
__attribute__((section(".Rx_PoolSection"))) extern u8_t memp_memory_RX_POOL_base[];

#endif
/* USER CODE END 2 */

在LD脚本 STM32H723VETX_FLASH.ld 下部添加:

  .lwip_sec (NOLOAD) : {
    . = ABSOLUTE(0x30000000);
    *(.RxDecripSection) 
    
    . = ABSOLUTE(0x30000200);
    *(.TxDecripSection)
    
    . = ABSOLUTE(0x30000400);
    *(.Rx_PoolSection) 
  } >RAM_D2 AT> FLASH

到此配置结束,测试 Ping

后记: 测试发现,UDP接受超过1180字节后,LWIP协议栈停止工作,无法ping通收发数据。排查后发现是LWIP的TX堆栈位置(下图是设置为0x30004000)有问题,因为RAM2 的32K已经被ETH DMA用完了。改为0x2404B000,占用320K的RAM D1的末尾20KB就行了。同时在LD脚本把RAM D1 改小一点,改为300K,防止编译器占用我们需要的20K。
LD脚本把RAM D1 改小一点,改为300K,防止编译器占用我们需要的20K。
LD脚本把RAM D1 改小一点,改为300K,防止编译器占用最后20K。

物联沃分享整理
物联沃-IOTWORD物联网 » STM32H723配置以太网+Freertos注意事项

发表评论