NUCELO-H5E5ZJ的CubeMX配置中没有集成LWIP配置选项,运行Lwip需要参考ST官方社区的说明和官方示例仓库代码移植到工程中。
ST官方社区提供的移植教程:
https://community.st.com/stm32-mcus-60/how-to-use-the-lwip-ethernet-middleware-on-the-stm32h5-series-135644
STM32 H5系列示例教程仓库
https://github.com/STMicroelectronics/stm32h5-classic-coremw-apps
1、CubeMX工程配置
根据开发板型号NUCLEO-H5E5ZJ创建CubeMX工程,勾选BSP相关的外设

开发板创建的工程默认的时钟使用内部时钟,CubeMX中使能HSE使用外部晶振。

开发板板载有48MHz的时钟用于提供外部时钟源

Clock界面中配置开发板时钟参数,配置MCU达到最高主频250MHz。

使能ETH外设为RMII,NUCLEO-H5E5ZJ以分配好相关的RMII引脚,修改RMII引脚的Speed参数为Very High。

修改Project Manager->Advanced Settings中的MX_ETH_Init函数的生成配置如下,不生成函数的调用,并可以在其他源文件引用该函数,用于lwip适配函数中调用ETH外设的初始化函数。

保存并生成STM32CubeIDE工程。
2、添加和配置lwip代码
STM32 H5系列示例教程仓库中有相应的lwip代码仓库。
https://github.com/STMicroelectronics/stm32h5-classic-coremw-apps
复制仓库中的"stm32h5-classic-coremw-apps\Middlewares"目录到到工程所在的工作空间文件夹中。

在工程中创建文件夹并连接到LwIP仓库文件夹

代码仓库中源码需要添加到工程索引中,其中不需要的代码通过设置过滤项将其排除到编译流程外。

工程的头文件路径中添加lwip协议栈相关的头文件路径。

复制"stm32h5-classic-coremw-apps\Projects\NUCLEO-H563ZI\Applications\LwIP\LwIP_UDP_Echo_Client\LWIP"文件夹中的应用代码到工程中。
添加应用代码的路径到源码路径,相应的头文件路径也添加到工程管理中


开发板的以太网芯片的型号为lan8742,驱动代码在stm32h5-classic-coremw-apps\Drivers\BSP\Components\lan8742文件夹中可以找到,复制其中的lan8742.c和lan8742.h到工程中。
3、修改代码
移植的代码是适配NUCLEO-H563ZI开发板的,在NUCLEO-H5E5ZJ开发板上运行该代码,需要修改进行相应的修改。
3.1 LWIP\Target\ethernetif.c 代码修改
根据添加源码的路径,修改包含路径设置。

由于CubeMX生成会自动生成Ethernet相关的数据结构体,造成重定义问题,修改文件中的变成的声明。
extern ETH_DMADescTypeDef DMARxDscrTab[ETH_RX_DESC_CNT]; /* Ethernet Rx DMA Descriptors */
extern ETH_DMADescTypeDef DMATxDscrTab[ETH_TX_DESC_CNT]; /* Ethernet Tx DMA Descriptors */
/* Global Ethernet handle*/
extern ETH_HandleTypeDef heth;
extern ETH_TxPacketConfig TxConfig;
low_level_init函数初始化ETH外设部分的代码调用CubeMX生成的ETH初始化函数MX_ETH_Init,并修改netif中的MAC地址赋值代码。删除代码中的TxConfig参数配置代码。
/* Set Tx packet config common parameters */
memset(&TxConfig, 0 , sizeof(ETH_TxPacketConfig));
TxConfig.Attributes = ETH_TX_PACKETS_FEATURES_CSUM | ETH_TX_PACKETS_FEATURES_CRCPAD;
TxConfig.ChecksumCtrl = ETH_CHECKSUM_IPHDR_PAYLOAD_INSERT_PHDR_CALC;
TxConfig.CRCPadCtrl = ETH_CRC_PAD_INSERT;
修改后的low_level_init函数代码如下
static void low_level_init(struct netif *netif)
{
/* configure ethernet peripheral (GPIOs, clocks, MAC, DMA) */
MX_ETH_Init();
/* set MAC hardware address length */
netif->hwaddr_len = ETH_HWADDR_LEN;
netif->hwaddr[0] = heth.Init.MACAddr[0];
netif->hwaddr[1] = heth.Init.MACAddr[1];
netif->hwaddr[2] = heth.Init.MACAddr[2];
netif->hwaddr[3] = heth.Init.MACAddr[3];
netif->hwaddr[4] = heth.Init.MACAddr[4];
netif->hwaddr[5] = heth.Init.MACAddr[5];
/* maximum transfer unit */
netif->mtu = ETH_MAX_PAYLOAD;
/* device capabilities */
/* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */
netif->flags |= NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP;
/* Initialize the RX POOL */
LWIP_MEMPOOL_INIT(RX_POOL);
/* Set PHY IO functions */
LAN8742_RegisterBusIO(&LAN8742, &LAN8742_IOCtx);
/* Initialize the LAN8742 ETH PHY */
if(LAN8742_Init(&LAN8742) != LAN8742_STATUS_OK)
{
netif_set_link_down(netif);
netif_set_down(netif);
return;
}
ethernet_link_check_state(netif);
}
由于CubeMX自动生成的代码重定义,删除void HAL_ETH_MspInit(ETH_HandleTypeDef *heth)函数的定义。
替换EthHandle变量名为eth

3.2 LWIP\App\app_ethernet.c
由于开发板的配置不同,修改相应的LED枚举常量

3.3 main.h和main.c 代码修改
main.h中添加UDP连接相关的宏定义。
/* UDP remote connection port */
#define UDP_SERVER_PORT ((uint16_t)7U)
/*Static DEST IP ADDRESS: DEST_IP_ADDR0.DEST_IP_ADDR1.DEST_IP_ADDR2.DEST_IP_ADDR3 */
#define DEST_IP_ADDR0 ((uint8_t)10U)
#define DEST_IP_ADDR1 ((uint8_t)157U)
#define DEST_IP_ADDR2 ((uint8_t)129U)
#define DEST_IP_ADDR3 ((uint8_t)84U)
/*Static IP ADDRESS: IP_ADDR0.IP_ADDR1.IP_ADDR2.IP_ADDR3 */
#define IP_ADDR0 ((uint8_t) 192U)
#define IP_ADDR1 ((uint8_t) 168U)
#define IP_ADDR2 ((uint8_t) 0U)
#define IP_ADDR3 ((uint8_t) 10U)
/*NETMASK*/
#define NETMASK_ADDR0 ((uint8_t) 255U)
#define NETMASK_ADDR1 ((uint8_t) 255U)
#define NETMASK_ADDR2 ((uint8_t) 255U)
#define NETMASK_ADDR3 ((uint8_t) 0U)
/*Gateway Address*/
#define GW_ADDR0 ((uint8_t) 192U)
#define GW_ADDR1 ((uint8_t) 168U)
#define GW_ADDR2 ((uint8_t) 0U)
#define GW_ADDR3 ((uint8_t) 1U)
main.c中添加相关的头文件
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "string.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "lwip/opt.h"
#include "lwip/init.h"
#include "netif/etharp.h"
#include "lwip/netif.h"
#include "lwip/timeouts.h"
#if LWIP_DHCP
#include "lwip/dhcp.h"
#endif
#include "ethernetif.h"
#include "app_ethernet.h"
#include "udp_echoclient.h"
/* USER CODE END Includes */
添加lwip 以太网接口变量gnetif
struct netif gnetif;
定义网络接口初始化函数,初始化网络接口的IP地址和注册回调函数。
static void Netif_Config(void);
/**
* @brief Setup the network interface
* @param None
* @retval None
*/
static void Netif_Config(void)
{
ip_addr_t ipaddr;
ip_addr_t netmask;
ip_addr_t gw;
#if LWIP_DHCP
ip_addr_set_zero_ip4(&ipaddr);
ip_addr_set_zero_ip4(&netmask);
ip_addr_set_zero_ip4(&gw);
#else
/* IP address default setting */
IP4_ADDR(&ipaddr, IP_ADDR0, IP_ADDR1, IP_ADDR2, IP_ADDR3);
IP4_ADDR(&netmask, NETMASK_ADDR0, NETMASK_ADDR1 , NETMASK_ADDR2, NETMASK_ADDR3);
IP4_ADDR(&gw, GW_ADDR0, GW_ADDR1, GW_ADDR2, GW_ADDR3);
#endif
/* add the network interface */
netif_add(&gnetif, &ipaddr, &netmask, &gw, NULL, ðernetif_init, ðernet_input);
/* Registers the default network interface */
netif_set_default(&gnetif);
ethernet_link_status_updated(&gnetif);
#if LWIP_NETIF_LINK_CALLBACK
netif_set_link_callback(&gnetif, ethernet_link_status_updated);
#endif
}
main函数中添加lwip初始化以及UDP Client启动函数。
int main(void)
{
...
/* Infinite loop */
/* USER CODE BEGIN WHILE */
printf("UDP Echo Client Application \r\n");
printf("STM32H5E5ZJ board \r\n");
printf("State: Ethernet Initialization ... \r\n");
/* Initialize the LwIP stack */
lwip_init();
/* Configure the Network interface */
Netif_Config();
/* UDP client connect */
udp_echoclient_connect();
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
/* Read a received packet from the Ethernet buffers and send it
to the lwIP for handling */
ethernetif_input(&gnetif);
/* Handle timeouts */
sys_check_timeouts();
#if LWIP_NETIF_LINK_CALLBACK
Ethernet_Link_Periodic_Handle(&gnetif);
#endif
#if LWIP_DHCP
DHCP_Periodic_Handle(&gnetif);
#endif
}
/* USER CODE END 3 */
}
4、运行效果
编译烧录程序到开发板,网络调试助手设置UDP连接参数,开发板用户按键中断函数发送UDP数据,网络调试助手接收到的数据如图。

