你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【STM32H735DK测评】Ethernet+lwip DHCP获取IP地址

[复制链接]
EPTmachine 发布时间:2026-9-12 07:05

STM32H735-DK带有 Eth接口,可以用于以太网通讯。STM32 Hostpot提供STM32H7系列的lwip移植用于参考。

https://github.com/stm32-hotspot/STM32H7-LwIP-Examples

官方提供的示例程序是基于CubeMX 6.5.0 和 H7 V1.10.0 MCU package,高版本的CubeMX可以使用兼容包生成老版本的MCU对应的工程,但是无法创建老版本的MCU Package的工程,需要额外安装老版本的CubeMX程序用于生成代码。而且按照官方例程的步骤,在最新的CubeMX上进行相同的设置,无法正确获取DHCP地址,和lwip的版本相关。

CubeMX_version.png

STM32H735-DK带有RJ45以太网接口,可以用于网络通讯。CubeMX支持lwip协议栈,本文介绍在CubeMX中配置以太网外设、lwip协议栈,通过Ping指令测量网络连接情况。

1、CubeMX配置Ethernet外设

STM32H735DK使用的Ethernet芯片LAN8742的原理图如下。

Ethernet_Schematic.png

LAN8742的复位引脚连接在系统的NRST引脚上,在开发板复位的同时复位,无需在程序中对LAN8742进行复位操作,相应的LAN8742的复位引脚无需配置,对于其他NRST引脚连接到GPIO的情况,需要配置相应的引脚,并在软件中对NRST的控制引脚进行从低电平到高电平的复位操作。

“Connectivity->Eth”中使能以太网PHY芯片的接口形式为RMII,设置其中的TX/RX描述符的内存地址以及外设的引脚配置,默认配置中,部分引脚和原理图中的引脚不匹配,在Pinout视图中通过查找功能,调整相应的引脚设置。

Ethernet_paras_settings.png

使能Ethernet外设的中断。

Enable_Ethernet_IRQ.png

2、调整FreeRTOS和lwip模块参数

使能FreeRTOS模块并调整其中的参数如下。

FreeRTOS_Component_Config.png

使能lwip模块和DHCP功能

Enable_Lwip_dhcp.png

设置lwip协议栈使用的RAM Heap大小以及起始地址,调整TCP缓存区的大小。

Adjust_TCP_Paras.png

调整TCP/IP线程的Stack大小。

Adjust_TCPIP_Thread_Stack_Size.png

保存并生成相应的代码。

3、添加DTCM地址空间配置

官方的示例中,将Ethernet TX\RX 描述符以及LWIP HEAP的地址空间分配到SDRAM1中。在H7xx系列的Reference Manual中的内存组成章节可以找到地址空间的分配表格如下。

Memory_Region_Define.png

SDRAM1的其实地址为0x30000000,大小为32KB。在工程默认创建的连接脚本文件中,可以找到对应的内存区域定义。


/* Specify the memory areas */
MEMORY
{
ITCMRAM (xrw)    : ORIGIN = 0x00000000,   LENGTH = 64K
DTCMRAM (xrw)    : ORIGIN = 0x20000000,   LENGTH = 128K
FLASH    (rx)    : ORIGIN = 0x08000000,   LENGTH = 1024K
RAM_D1  (xrw)    : ORIGIN = 0x24000000,   LENGTH = 320K
RAM_D2  (xrw)    : ORIGIN = 0x30000000,   LENGTH = 32K
RAM_D3  (xrw)    : ORIGIN = 0x38000000,   LENGTH = 16K
}

SDRAM1对应的地址空间没有被分配用于链接,需要添加相应的链接定义。

分配到RAM_D1中的.bss字段添加(NOLOAD)描述表示.bss字段不在启动时进行初始化,添加.Rx_PoolSection字段用于RX Buffer的内存分配。SDRAM1对应的RAM_D2内存空间中添加.RxDecripSection.TxDecripSection,用于以太网芯片接口的TX\RX描述符数据的存储。


/* Uninitialized data section */
. = ALIGN(4);
.bss (NOLOAD):
{
/* This is used by the startup in order to initialize the .bss section */
_sbss = .;         /* define a global symbol at bss start */
__bss_start__ = _sbss;
*(.bss)
*(.bss*)
*(COMMON)

/* ETH_CODE: add placement of RX buffer. STM32H72x/H73x has small D2 RAM, so we need to put it there.

* (NOLOAD) attribute used for .bss section to avoid linker warning (.bss initialized by startup code)
  */
  . = ALIGN(32);
  *(.Rx_PoolSection)

. = ALIGN(4);
_ebss = .;         /* define a global symbol at bss end */
__bss_end__ = _ebss;


} >RAM_D1

/* User_heap_stack section, used to check that there is enough RAM left */
._user_heap_stack :
{
. = ALIGN(8);
PROVIDE ( end = . );
PROVIDE ( _end = . );
. = . + _Min_Heap_Size;
. = . + _Min_Stack_Size;
. = ALIGN(8);
} >RAM_D1

/* ETH_CODE: add placement of DMA descriptors, rest is used by RX_POOL */
.lwip_sec (NOLOAD) :
{
. = ABSOLUTE(0x30000000);
*(.RxDecripSection)

. = ABSOLUTE(0x30000100);
*(.TxDecripSection)


} >RAM_D2

工程中对应的数组定义中,通过__attribute__((section("<xxxxx>")))语句,分配DMARxDscrTabDMATxDscrTab以及memp_memory_RX_POOL_base到不同的地址空间中。在ethernetif.c中可以找到相关的定义。

ETH_DMADescTypeDef DMARxDscrTab[ETH_RX_DESC_CNT] __attribute__((section(".RxDecripSection"))); /* Ethernet Rx DMA Descriptors */
ETH_DMADescTypeDef DMATxDscrTab[ETH_TX_DESC_CNT] __attribute__((section(".TxDecripSection")));   /* Ethernet Tx DMA Descriptors */

LWIP_MEMPOOL_DECLARE(RX_POOL, ETH_RX_BUFFER_CNT, sizeof(RxBuff_t), "Zero-copy RX PBUF pool");

__attribute__((section(".Rx_PoolSection"))) extern u8_t memp_memory_RX_POOL_base[];

4、添加lwipopts.h配置

lwip通过lwipopts.h头文件添加配置选项调整lwip的功能,工程中的lwipopts.h文件的用户自定义区段中,添加解决编译报错、多线程支持的宏和函数声明。

/* USER CODE BEGIN 1 */
/* ETH_CODE: first 2 macros solve errno issue with GCC 10 and ST LwIP
 * LWIPERF_CHECK_RX_DATA enables data check for iperf. Removing it might improve performance.
 */
#undef LWIP_PROVIDE_ERRNO
#define LWIP_ERRNO_STDINCLUDE
#define LWIPERF_CHECK_RX_DATA 1

/* ETH_CODE: macro and prototypes for proper (hopefuly?)
 * multithreading support
 */
#define LOCK_TCPIP_CORE sys_lock_tcpip_core
#define UNLOCK_TCPIP_CORE sys_unlock_tcpip_core

#define LWIP_ASSERT_CORE_LOCKED sys_check_core_locking
#define LWIP_MARK_TCPIP_THREAD sys_mark_tcpip_thread

void sys_lock_tcpip_core(void);
void sys_unlock_tcpip_core(void);

void sys_check_core_locking(void);
void sys_mark_tcpip_thread(void);
/* USER CODE END 1 */

ethernetif.c中添加相应的用于实现多线程支持的函数实现。

/* ETH_CODE: add functions needed for proper multithreading support and check */

static osThreadId_t lwip_core_lock_holder_thread_id;
static osThreadId_t lwip_tcpip_thread_id;

void sys_lock_tcpip_core(void){
    sys_mutex_lock(&lock_tcpip_core);
    lwip_core_lock_holder_thread_id = osThreadGetId();
}

void sys_unlock_tcpip_core(void){
    lwip_core_lock_holder_thread_id = 0;
    sys_mutex_unlock(&lock_tcpip_core);
}

void sys_check_core_locking(void){
  /* Embedded systems should check we are NOT in an interrupt context here */

  LWIP_ASSERT("Function called from interrupt context", (SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk) == 0);

  if (lwip_tcpip_thread_id != 0) {
      osThreadId_t current_thread_id = osThreadGetId();

#if LWIP_TCPIP_CORE_LOCKING
    LWIP_ASSERT("Function called without core lock", current_thread_id == lwip_core_lock_holder_thread_id);
    /* ETH_CODE: to easily check that example has correct handling of core lock
     * This will trigger breakpoint (__BKPT)
     */
#warning Below check should be removed in production code
    if(current_thread_id != lwip_core_lock_holder_thread_id) __BKPT(0);
#else /* LWIP_TCPIP_CORE_LOCKING */
    LWIP_ASSERT("Function called from wrong thread", current_thread_id == lwip_tcpip_thread_id);
#endif /* LWIP_TCPIP_CORE_LOCKING */
    LWIP_UNUSED_ARG(current_thread_id); /* for LWIP_NOASSERT */
  }
}
void sys_mark_tcpip_thread(void){
    lwip_tcpip_thread_id = osThreadGetId();
}

ethernet_link_thread函数中添加TCPIP多线程支持的函数调用。

/* USER CODE BEGIN ETH link init */
  /* ETH_CODE: call HAL_ETH_Start_IT instead of HAL_ETH_Start
   * This is required for operation with RTOS.
   * This trick allows to keep this change through
   * code re-generation by STM32CubeMX
   */
#define HAL_ETH_Start HAL_ETH_Start_IT
  /* ETH_CODE: workaround to call LOCK_TCPIP_CORE when accessing netif link functions*/
  LOCK_TCPIP_CORE();
/* USER CODE END ETH link init */

/* USER CODE BEGIN ETH link Thread core code for User BSP */

    /* ETH_CODE: workaround to call LOCK_TCPIP_CORE when accessing netif link functions*/
    UNLOCK_TCPIP_CORE();
    osDelay(100);
    LOCK_TCPIP_CORE();
    continue; /* skip next osDelay */

/* USER CODE END ETH link Thread core code for User BSP */

lwip.c中添加tcpip 封装,用于支持多线程

/* USER CODE BEGIN 2 */
/* ETH_CODE: workaround to call LOCK_TCPIP_CORE after tcpip_init in MX_LWIP_Init
 * This is to keep the code after MX code re-generation */
static inline void tcpip_init_wrap(tcpip_init_done_fn tcpip_init_done, void *arg){
    tcpip_init(tcpip_init_done, arg);
    LOCK_TCPIP_CORE();
}
#define tcpip_init tcpip_init_wrap



/* USER CODE END 2 */

lwip.c中的MX_LWIP_Init中添加以下代码

/* USER CODE BEGIN 3 */
  /* ETH_CODE: call UNLOCK_TCPIP_CORE after we are done */
  UNLOCK_TCPIP_CORE();
/* USER CODE END 3 */

5、使能lwip debug特性

lwip支持调试信息输出,lwipopts.h文件中添加使能Debug和DHCP DEGUB的宏定义,用于输出DHCP调试信息。

#define LWIP_DEBUG
#define DHCP_DEBUG  LWIP_DBG_ON

开发板的PD8和PD9配置为USART3,可以用于printf函数输出重定向到串口输出。

USART3_paras_config.png

添加以下代码,用于USART3串口重定向。

extern UART_HandleTypeDef huart3;

#ifdef __GNUC__
/* With GCC, small printf (option LD Linker->Libraries->Small printf
   set to 'Yes') calls __io_putchar() */
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */

PUTCHAR_PROTOTYPE
{
  /* Place your implementation of fputc here */
  /* e.g. write a character to the USART1 and Loop until the end of transmission */
  HAL_UART_Transmit(&huart3, (uint8_t *)&ch, 1, 0xFFFF);

  return ch;
}

编译并烧录程序到开发板,通过串口可以看到以下的输出。DHCP可以正常访问网关,并获取地址信息。

DHCP_Success_Log.png

收藏 评论0 发布时间:2026-9-12 07:05

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版