STM32H723ZG + LAN8742 + Ethernet +LWIP 配置 cubemx

🌞这边记录一下这块mcu 配置以太网的过程,IDE是KEIL MDK,其实就是在下面多次提到的blog的基础上 在scatter file进行配置

首先,如果想要简单一点 直接去cubemx 那边获取相关的例程,直接在例程上面改 根据实际要求注意改相关的引脚 和 时钟配置

感谢
blog1
blog2
blog3
blog4
blog5

墙裂感谢我超级好的同事 zxp哥 加班帮我解决问题!!

文章目录

    • STM32H723ZG + LAN8742 + Ethernet +LWIP 配置 cubemx
    • 法一 直接用cubemx 上面的库进行配置
    • 法二 用cubemx自己配置
      • 前置知识
        • 不同的外设存储区可访问的区域不同 所以要自己定义相应的内存区域
          • 为什么这么配置
        • MPU的配置
          • 1. MPU 区域 0:默认配置(Default Configuration)
          • 2. MPU 区域 1:以太网 DMA 描述符(Ethernet DMA Descriptors)
          • 3. MPU 区域 2:LwIP RAM 堆(LwIP RAM Heap)
      • 开始配置
        • 1.配置ETH 开启
        • 2.串口的配置
        • 3.LWIP配置
        • 4.PHY的复位引脚配置 参考上述博客
        • 5.MPU的配置
        • 6.打开ethernetif.c文件 对相应的scatter file文件进行配置
      • 测试
        • 测试说明
        • 最终我的main.c的代码
      • 后记

法一 直接用cubemx 上面的库进行配置

如果你的板子是stm32+lan8742 那可以参考这个方法进行配置

image-20250805193116021

输入相应开发板的型号 然后直接配置 比如这个开发板

到时候可以直接在这个例程上改 成功的概率会比自己用cubemx移植的概率高
ps:后面一些相关的例程也可以用这种方法参考
image-20250805193342084

法二 用cubemx自己配置

前置知识

ps 这两个前置知识 是两个坑点 当然也可以跳过这个前置知识 直接到cubemx的配置部分

不同的外设存储区可访问的区域不同 所以要自己定义相应的内存区域

以太网外设通常需要专用的内存区域来存储发送和接收的数据包。这些区域被称为DMA描述符(Descriptors)和 缓冲区Buffers

1️⃣ 首先以太网外设不是和其他外设一样 可以随意的放在单片机的不同地方​

❗️ 不能将以太网的数据缓冲区随意放在 CPU 的 ITCM 里,也不能将 LTDC 的图像数据放在 D2 域的 SRAM1 里,因为它们位于不同的总线域,并且由不同的 DMA 控制器管理。需要在软件中根据这个硬件架构,将不同的外设缓冲区分配到它们所属的或可访问的存储区域中。

image-20250805194109618

首先这张图清楚地说明了:不同的外设可以存储数据的地方是不一样的

  1. 分域存储:
    • D1 域(高性能域) 的外设(如 SDMMC, MDMA, DMA2D, LTDC)通常会访问 D1 域中的高速存储器,例如 AXI SRAMFlash。这是因为这些外设需要高速的数据吞吐量来处理大量数据(例如图形、视频、高速存储卡)。
    • D2 域(中速域) 的外设(如 Ethernet MAC, USBHS1)通常会访问 D2 域中的 SRAM1SRAM2。虽然这些也是SRAM,但它们位于不同的总线矩阵上,且可能由不同的 DMA 控制器(DMA1, DMA2)来管理。
  2. DMA控制器与存储区域的绑定:
    • D1 域 的 DMA 控制器(MDMA, DMA2D)通常用于在 D1 域的内存(AXI SRAM、Flash等)之间进行数据传输。
    • D2 域 的 DMA 控制器(DMA1, DMA2)通常用于在外设(Ethernet MAC、USBHS1)与 D2 域的内存(SRAM1、SRAM2)之间进行数据传输。
  3. 专用存储区:
    • D3 域 有一个 Backup SRAM,这个存储区通常是专门用来在低功耗或掉电模式下保留关键数据的。其他外设一般不会使用这块内存。
    • CPU 有专门的 ITCMDTCM,这些是紧耦合内存,只供CPU使用,用于存储最高速的指令和数据。

总结一下:

这张架构图的核心思想就是根据外设的性能需求和功能,将它们和相应的存储区域划分到不同的总线域中。

❗️ 所以,不能将以太网的数据缓冲区随意放在 CPU 的 ITCM 里,也不能将 LTDC 的图像数据放在 D2 域的 SRAM1 里,因为它们位于不同的总线域,并且由不同的 DMA 控制器管理。需要在软件中根据这个硬件架构,将不同的外设缓冲区分配到它们所属的或可访问的存储区域中。

从这个总线矩阵上可以看到,以太网外设可以被定义在SRAM1,SRAM2中,对应的就是0x30000000 - 0x30003FFF

image-20250805195138489

于是 以太网的DMA描述符就得后续这么定义在相应的存储区

image-20250805195352458

image-20250805195414937

从上面的图也可以看到有两种不同的定义方式,一个是直接在前面定义

__attribute__((at(0x30000000))) ETH_DMADescTypeDef  DMARxDscrTab[ETH_RX_DESC_CNT]; /* Ethernet Rx DMA Descriptors */
__attribute__((at(0x30000060))) ETH_DMADescTypeDef  DMATxDscrTab[ETH_TX_DESC_CNT]; /* Ethernet Tx DMA Descriptors */

将一个名为 DMARxDscrTab 的、由 ETH_RX_DESC_CNTETH_DMADescTypeDef 结构体组成的数组,精确地放置在内存地址 0x30000000 上。 这块内存区域将作为以太网控制器接收DMA描述符的存储区域。

将一个名为 DMATxDscrTab 的、由 ETH_TX_DESC_CNTETH_DMADescTypeDef 结构体组成的数组,精确地放置在内存地址 0x30000060 上。 这块内存区域将作为以太网控制器发送DMA描述符的存储区域。

memory_RX_POOL_base 0x30000100 0x3F00 {*(.Rx_PoolSection)}

这个意思就是:在链接器脚本中,定义了一个内存区域,其起始地址为 0x30000100,大小为 0x3F00 字节。然后,告诉链接器,将所有输入目标文件(*.o)中所有名为 .Rx_PoolSection 的代码或数据段,都链接到这块内存区域中。

这是专门为**以太网接收缓冲区(RX Pool)**分配一块特定的内存区域,并确保这个区域位于一个固定的、已知的高速内存地址(例如 SRAM),以便于 DMA 控制器可以高效地访问

.sct文件在魔法棒这边 点击edit就会出现了

image-20250805200142956

为什么这么配置
  • DMA控制器的局限性: 并非所有内存区域都能被DMA控制器访问。通常,DMA控制器只能访问特定的片上SRAM或外部SRAM/SDRAM。而像闪存(Flash)或CPU的私有内存(如ITCM/DTCM)等区域是无法直接被DMA访问的。
  • DMA描述符的存储位置: 以太网控制器(或任何DMA控制器)需要从一个预先配置好的内存地址读取DMA描述符,这些描述符包含了数据在内存中的地址、长度等信息。
  • 确保可访问性: 为了确保以太网控制器能够正确地找到并访问这些描述符,必须将它们放置在一个DMA控制器能够访问的内存地址上

通过 __attribute__((at(...))) 这样的方式,程序员手动指定了这些关键数据结构(DMA描述符)的内存地址,确保它们位于可被DMA访问的高速SRAM区域(例如,在STM32系列芯片中,0x30000000 通常指向D1域的高速SRAM)。

这与链接器脚本的 *(.Rx_PoolSection) 方式是异曲同工的,两者都是为了控制数据在内存中的绝对位置。前者是直接在代码中使用编译器扩展,后者是在链接阶段使用链接器脚本。在某些情况下,两者可以结合使用,以获得更精细的控制。

MPU的配置

Cortex-M7 的 **MPU (Memory Protection Unit,内存保护单元)**是一个硬件单元,它允许你定义多达 8 个独立的内存区域,并为每个区域设置不同的访问权限和属性。这些属性包括:

  • 访问权限(AccessPermission): 读/写/禁止访问。
  • 可执行性(DisableExec): 允许或禁止从该区域执行代码。
  • 缓存属性(IsCacheable, IsBufferable, IsShareable): 控制该区域的内存如何与 CPU 的数据缓存(D-Cache)和总线交互。

通过配置 MPU 的缓存属性,来解决 Cortex-M7 的高速缓存(D-Cache)与以太网 DMA 控制器之间的数据一致性问题。

  • 将 DMA 描述符和以太网数据缓冲区所在的内存区域设置为“不可缓存”,强制 CPU 每次都直接访问物理内存。
  • 这样做虽然牺牲了部分 CPU 访问这些特定区域时的性能(因为没有使用缓存),但换来了数据一致性的可靠性,这对于网络通信这类对数据完整性要求极高的应用是至关重要的。

以太网相应的MPU配置

void MPU_Config(void)
{MPU_Region_InitTypeDef MPU_InitStruct;/* Disable the MPU */HAL_MPU_Disable();/* Configure the MPU as Strongly ordered for not defined regions */MPU_InitStruct.Enable = MPU_REGION_ENABLE;MPU_InitStruct.BaseAddress = 0x00;MPU_InitStruct.Size = MPU_REGION_SIZE_4GB;MPU_InitStruct.AccessPermission = MPU_REGION_NO_ACCESS;MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE;MPU_InitStruct.Number = MPU_REGION_NUMBER0;MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;MPU_InitStruct.SubRegionDisable = 0x87;MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;HAL_MPU_ConfigRegion(&MPU_InitStruct);/* Configure the MPU attributes as Device not cacheablefor ETH DMA descriptors */MPU_InitStruct.Enable = MPU_REGION_ENABLE;MPU_InitStruct.BaseAddress = 0x30000000;MPU_InitStruct.Size = MPU_REGION_SIZE_256B;MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;MPU_InitStruct.Number = MPU_REGION_NUMBER1;MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;MPU_InitStruct.SubRegionDisable = 0x00;MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;HAL_MPU_ConfigRegion(&MPU_InitStruct);/* Configure the MPU attributes as Normal Non Cacheablefor LwIP RAM heap which contains the Tx buffers */MPU_InitStruct.Enable = MPU_REGION_ENABLE;MPU_InitStruct.BaseAddress = 0x30004000;MPU_InitStruct.Size = MPU_REGION_SIZE_16KB;MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE;MPU_InitStruct.Number = MPU_REGION_NUMBER2;MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1;MPU_InitStruct.SubRegionDisable = 0x00;MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;HAL_MPU_ConfigRegion(&MPU_InitStruct);/* Enable the MPU */HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
}
1. MPU 区域 0:默认配置(Default Configuration)
/* Configure the MPU as Strongly ordered for not defined regions */
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
MPU_InitStruct.BaseAddress = 0x00;
MPU_InitStruct.Size = MPU_REGION_SIZE_4GB;
...
HAL_MPU_ConfigRegion(&MPU_InitStruct);
  • 作用: 这部分配置了一个覆盖整个 4GB 地址空间的默认区域(区域0)。
  • 属性: 它被设置为 Strongly ordered(强排序),No Access(禁止访问),Not Cacheable(不可缓存)。SubRegionDisable 设置为 0x87,这通常是为了禁用某些子区域,从而让其他区域的配置生效。
  • 为什么这么做? 这是一个安全和规范的默认设置。它相当于一个“看门狗”,将所有未被明确配置的内存区域都设置为最严格的“禁止访问”和“强排序”属性。这样可以防止程序意外访问到未分配的内存区域,从而引发硬件异常,提高系统的鲁棒性。
2. MPU 区域 1:以太网 DMA 描述符(Ethernet DMA Descriptors)
/* Configure the MPU attributes as Device not cacheablefor ETH DMA descriptors */
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
MPU_InitStruct.BaseAddress = 0x30000000;
MPU_InitStruct.Size = MPU_REGION_SIZE_256B;
...
MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;
...
HAL_MPU_ConfigRegion(&MPU_InitStruct);
  • 作用: 为以太网 DMA 描述符所在的内存区域(0x30000000)进行配置。这与你之前提到的代码 __attribute__((at(0x30000000))) 是相对应的。
  • 属性:
    • BaseAddressSize: 准确地指定了 DMA 描述符表所在的内存地址和大小(256B)。
    • IsCacheable = MPU_ACCESS_NOT_CACHEABLE: 这是最关键的配置之一! 它告诉 CPU,这个区域的内存不能被缓存
    • IsBufferable = MPU_ACCESS_BUFFERABLE: 允许写操作进行写缓冲(Write Buffer)
  • 为什么这么做?
    • 缓存一致性问题: DMA 控制器和 CPU 是两个独立的实体,它们都可以访问同一块内存区域。当 CPU 读取数据时,它可能会将数据从 SRAM 拷贝到它的高速缓存(D-Cache)中。如果 DMA 在此期间更新了 SRAM 中的数据,但 CPU 仍然使用缓存中的旧数据,就会导致缓存不一致(Cache Incoherence)的问题,从而引发程序错误。
    • 解决方案: 将 DMA 描述符所在的内存区域设置为 不可缓存(Not Cacheable)强制 CPU 每次读写该区域时都直接访问 SRAM。这样就保证了 CPU 看到的数据永远是最新的,与 DMA 控制器看到的数据是一致的。
3. MPU 区域 2:LwIP RAM 堆(LwIP RAM Heap)
/* Configure the MPU attributes as Normal Non Cacheablefor LwIP RAM heap which contains the Tx buffers */
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
MPU_InitStruct.BaseAddress = 0x30004000;
MPU_InitStruct.Size = MPU_REGION_SIZE_16KB;
...
MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
...
HAL_MPU_ConfigRegion(&MPU_InitStruct);
  • 作用: 为 LwIP(一个轻量级TCP/IP协议栈)的 RAM 堆(Heap)进行配置,这个堆通常用于存储发送和接收数据包的缓冲区。
  • 属性:
    • BaseAddressSize: 指定了 RAM 堆的地址和大小。
    • IsCacheable = MPU_ACCESS_NOT_CACHEABLE: 同样,这个区域被设置为不可缓存
    • IsBufferable = MPU_ACCESS_NOT_BUFFERABLE: 也被设置为不可缓冲。
  • 为什么这么做?
    • 原因与区域1类似,都是为了解决缓存一致性问题。LwIP 的数据缓冲区同样会被以太网 DMA 控制器读写,同时也可能被 CPU 读写。
    • 如果这个区域可缓存,CPU 可能会读到过时的数据,或者 CPU 写入的数据还在缓存中,还没有写回 SRAM,而 DMA 却去读取了旧的数据。这都会导致网络通信的错误。
    • 将该区域设置为不可缓存,确保 CPU 读写缓冲区时都直接操作物理内存,从而保证了 CPU 和 DMA 之间的数据一致性。

开始配置

这边配置ETH的部分多数是参考这个blog 后面也会多次提及

我主要是针对我这个板子 在keil MDK上的配置

首先RCC SYS 这些就不说了 就是比较常规的配置

1.配置ETH 开启

引脚全部配置成高速

image-20250805202208537

注意mac地址不能随便配 默认就好 其他的需要好好配 对应于上面的前置知识所说的 地址

image-20250805202111687

2.串口的配置

image-20250805201922394

3.LWIP配置

这一部分开始大部分参考这篇blog 大家可以直接看原文

这里用dhcp 也就是用路由器给单片机分配ip

image-20250805202352717

image-20250805202503806

image-20250805202540021

选择LAN8742

image-20250805202606535

image-20250805202651552

checksum 默认的就行

4.PHY的复位引脚配置 参考上述博客

image-20250805202748454

image-20250805202809145

5.MPU的配置

参考blog

最后导出到KEIL_MDK 按照这个blog说的 该加的地方就加 该添的地方添

6.打开ethernetif.c文件 对相应的scatter file文件进行配置

image-20250805204031864

参考这边blog2可以看到相应的scatter file文件的编辑

现在这样操作可以让KEIL自动生成一个sct文件:
1.去掉勾选Usw Menory Layout from Target Dialog,这时Scatter File自动生成一个sct文件在obj文件的输出路径下
2.重新勾选Usw Menory Layout from Target Dialog,编译工程
3.编译成功后就生成了一个默认的sct文件,其配置与Target页面的内存布局含义一样,再回到Options->Linker就可以点击Edit打开该sct文件

image-20250805204139456

然后就可以开始编辑了

image-20250805204235039

加上这一句

   memory_RX_POOL_base 0x30000100 0x3F00 {*(.Rx_PoolSection)}

image-20250805204348477

测试

测试说明

用一根网线 一端连接单片机 一端连接路由器

在原有的代码加上这几句

image-20250806164952119

/* USER CODE BEGIN PFP */
extern struct netif gnetif;
struct dhcp *pdhcp;
/* USER CODE END PFP */

image-20250806165037663

pdhcp = netif_dhcp_data(&gnetif);

打开debug模式 把pdhcp添加到监控区 这边看到的就是路由器给我们板子分配的ip啦! 这样就说明连接上了。 后面就可以进行相应的udp/tcp测试~~ 偷个懒可以直接在cubemx上面下载相应的库 然后直接移植,亲测可用

image-20250806165210898

最终我的main.c的代码
/* USER CODE BEGIN Header */
/********************************************************************************* @file           : main.c* @brief          : Main program body******************************************************************************* @attention** Copyright (c) 2025 STMicroelectronics.* All rights reserved.** This software is licensed under terms that can be found in the LICENSE file* in the root directory of this software component.* If no LICENSE file comes with this software, it is provided AS-IS.********************************************************************************/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "lwip.h"
#include "usart.h"
#include "gpio.h"/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes *//* USER CODE END Includes *//* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD *//* USER CODE END PTD *//* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD *//* USER CODE END PD *//* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM *//* USER CODE END PM *//* Private variables ---------------------------------------------------------*//* USER CODE BEGIN PV *//* USER CODE END PV *//* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MPU_Config(void);
/* USER CODE BEGIN PFP */
extern struct netif gnetif;
struct dhcp *pdhcp;
/* USER CODE END PFP *//* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 *//* USER CODE END 0 *//*** @brief  The application entry point.* @retval int*/
int main(void)
{/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MPU Configuration--------------------------------------------------------*/MPU_Config();/* Enable the CPU Cache *//* Enable I-Cache---------------------------------------------------------*/SCB_EnableICache();/* Enable D-Cache---------------------------------------------------------*/SCB_EnableDCache();/* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* Enable I-Cache---------------------------------------------------------*/SCB_EnableICache();/* Enable D-Cache---------------------------------------------------------*/SCB_EnableDCache();/* USER CODE END Init *//* Configure the system clock */SystemClock_Config();/* USER CODE BEGIN SysInit */
__HAL_RCC_D2SRAM1_CLK_ENABLE();/* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();MX_USART1_UART_Init();MX_LWIP_Init();/* USER CODE BEGIN 2 *///DCacheSCB_CleanInvalidateDCache();//PHYHAL_GPIO_WritePin(RMII_NRST_GPIO_Port, RMII_NRST_Pin, GPIO_PIN_RESET);HAL_Delay(100);HAL_GPIO_WritePin(RMII_NRST_GPIO_Port, RMII_NRST_Pin, GPIO_PIN_SET);HAL_Delay(100);pdhcp = netif_dhcp_data(&gnetif);/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */MX_LWIP_Process();}/* USER CODE END 3 */
}/*** @brief System Clock Configuration* @retval None*/
void SystemClock_Config(void)
{RCC_OscInitTypeDef RCC_OscInitStruct = {0};RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};/** Supply configuration update enable*/HAL_PWREx_ConfigSupply(PWR_LDO_SUPPLY);/** Configure the main internal regulator output voltage*/__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE3);while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}/** Initializes the RCC Oscillators according to the specified parameters* in the RCC_OscInitTypeDef structure.*/RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;RCC_OscInitStruct.HSIState = RCC_HSI_DIV1;RCC_OscInitStruct.HSICalibrationValue = 64;RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK){Error_Handler();}/** Initializes the CPU, AHB and APB buses clocks*/RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2|RCC_CLOCKTYPE_D3PCLK1|RCC_CLOCKTYPE_D1PCLK1;RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV1;RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV1;RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV1;RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2;RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV1;if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK){Error_Handler();}
}/* USER CODE BEGIN 4 *//* USER CODE END 4 *//* MPU Configuration */void MPU_Config(void)
{MPU_Region_InitTypeDef MPU_InitStruct = {0};/* Disables the MPU */HAL_MPU_Disable();/** Initializes and configures the Region and the memory to be protected*/MPU_InitStruct.Enable = MPU_REGION_ENABLE;MPU_InitStruct.Number = MPU_REGION_NUMBER0;MPU_InitStruct.BaseAddress = 0x30000000;MPU_InitStruct.Size = MPU_REGION_SIZE_256B;MPU_InitStruct.SubRegionDisable = 0x00;MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;HAL_MPU_ConfigRegion(&MPU_InitStruct);/** Initializes and configures the Region and the memory to be protected*/MPU_InitStruct.Number = MPU_REGION_NUMBER1;MPU_InitStruct.BaseAddress = 0x030004000;MPU_InitStruct.Size = MPU_REGION_SIZE_16KB;MPU_InitStruct.SubRegionDisable = 0x0;MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1;HAL_MPU_ConfigRegion(&MPU_InitStruct);/** Initializes and configures the Region and the memory to be protected*/MPU_InitStruct.Number = MPU_REGION_NUMBER2;MPU_InitStruct.BaseAddress = 0x30004000;MPU_InitStruct.SubRegionDisable = 0x00;MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE;MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;HAL_MPU_ConfigRegion(&MPU_InitStruct);/* Enables the MPU */HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);}/*** @brief  This function is executed in case of error occurrence.* @retval None*/
void Error_Handler(void)
{/* USER CODE BEGIN Error_Handler_Debug *//* User can add his own implementation to report the HAL error return state */__disable_irq();while (1){}/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/*** @brief  Reports the name of the source file and the source line number*         where the assert_param error has occurred.* @param  file: pointer to the source file name* @param  line: assert_param error line source number* @retval None*/
void assert_failed(uint8_t *file, uint32_t line)
{/* USER CODE BEGIN 6 *//* User can add his own implementation to report the file name and line number,ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) *//* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
param error has occurred.* @param  file: pointer to the source file name* @param  line: assert_param error line source number* @retval None*/
void assert_failed(uint8_t *file, uint32_t line)
{/* USER CODE BEGIN 6 *//* User can add his own implementation to report the file name and line number,ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) *//* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

最终我的代码 stm32H723ZG+LAN8742_HAL_KEIL 也上传到gitee上

然后墙裂安利一下可以比较文件的工具beyond compare 有兴趣的家人可以去看看

🌈ok 完结 撒花撒花★,°:.☆( ̄▽ ̄)/$:.°★


后记

用这个代码进行dhcp可以正常进行tcp/udp通信,然后就想着能不能用静态分配ip
后面找了很多教程 一直在找bug

最后结果居然是我给他的静态ip的地址冲突了!!!

总结一下!!
永远不要轻易相信一个静态IP地址是可用的,尤其是在一个复杂的网络环境中。在开发阶段,使用ping或arp -a命令检查目标IP是否已被占用,是一个非常好的习惯。

Wireshark是无可替代的神器。它让我们看到了“PC没有收到ARP回复”这一关键线索。

如果要配置静态ip 现在电脑的cmd端 输入arp -a命令检查目标IP是否已被占用 !! 然后再配置

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/918382.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/918382.shtml
英文地址,请注明出处:http://en.pswp.cn/news/918382.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

EI检索-学术会议 | 人工智能、虚拟现实、可视化

第五届人工智能、虚拟现实与可视化国际学术会议(AIVRV 2025)定于2025年9月5-7日在中国 成都召开。人工智能正驱动各行业智能化转型,提升效率与质量;虚拟现实技术以其沉浸感重塑教育、娱乐、医疗等领域体验;可视化技术…

力扣(H指数)

一、题目分析 (一)问题描述 给定一个整数数组 citations,其中 citations[i] 表示研究者的第 i 篇论文被引用的次数。我们需要计算并返回该研究者的 H 指数。根据维基百科定义:H 指数代表“高引用次数”,一名科研人员的…

标准io(1)

标准I/O基础概念标准I/O&#xff08;Standard Input/Output&#xff09;是C语言提供的一组高级文件操作函数&#xff0c;位于<stdio.h>头文件中。与低级I/O&#xff08;如Unix的系统调用read/write&#xff09;相比&#xff0c;标准I/O引入了缓冲机制&#xff0c;能显著提…

线性代数1000题学习笔记

1000题线代基础第一章1-101000题线代基础第二章1-171000题线代基础第三章1-11

LeetCode算法日记 - Day 8: 串联所有单词的子串、最小覆盖子串

目录 1.串联所有单词的子串 1.2 解法 1.3 代码实现 2. 最小覆盖子串 2.1 题目解析 2.2 解法 2.3 代码实现 1.串联所有单词的子串 30. 串联所有单词的子串 - 力扣&#xff08;LeetCode&#xff09; 给定一个字符串 s 和一个字符串数组 words。 words 中所有字符串 长度…

linux实战:基于Ubuntu的专业相机

核心组件就是QTimerOpenCV的组合方案摄像头启停控制用QPushButton实现&#xff0c;帧显示必须用QLabel而不能用普通控件&#xff0c;视频流刷新用QTimer比多线程更简单想快速实现摄像头控制功能&#xff0c;核心组件就是QTimerOpenCV的组合方案。摄像头启停控制用QPushButton实…

《深度剖析前端框架中错误边界:异常处理的基石与进阶》

错误边界作为一种特殊的组件机制&#xff0c;正悄然重塑着应用应对异常的底层逻辑。它并非简单的代码片段组合&#xff0c;而是一套贯穿组件生命周期的防护体系&#xff0c;其核心价值在于将局部错误的影响牢牢锁定在可控范围内&#xff0c;避免整个应用陷入不可挽回的崩溃状态…

6GB显存玩转SD微调!LoRA-scripts本地部署教程,一键炼出专属AI画师

一、介绍LoRA-scripts&#xff08;又名 SD-Trainer&#xff09;&#xff0c;是一个专为训练低秩自适应&#xff08;LoRA&#xff09;模型设计的开源工具集主要应用于Stable Diffusion等AI绘图模型的微调&#xff0c;帮助用户高效创建定制化风格、角色或概念的轻量级模型。目前已…

探索AI的数学奇迹:Gemini 2.5 Pro如何摘得IMO金牌

🌍 引言:从人类天才到AI奇才的跨越 想象一下,一个AI模型坐在国际数学奥林匹克(IMO)的考场里,手里拿着笔(好吧,其实是处理token),面对那些让高中生们头疼不已的难题。它不是靠死记硬背,而是通过深思熟虑的推理,一步步攻克难关。这听起来像科幻小说,但2025年,这已…

MCP学习与实践

目录 1.MCP简介 1.1 MCP是什么 1.2 MCP与Agent关系&#xff1a; 1.3 MCP的架构 2. MCP原理 2.1 MCP 工作过程 2.2 MCP 通讯方式 2. MCP使用 2.1 cursor中增加MCP-SSE(高德地图MCP) 2.2 cursor中增加MCP-STDIO&#xff08;12306-MCP&#xff09; 本文详细讲解了什么是…

MySQL(187)如何使用pt-query-digest进行查询分析?

使用 pt-query-digest 工具可以帮助分析 MySQL 查询的性能&#xff0c;找出慢查询、频繁查询以及消耗资源较多的查询&#xff0c;从而为优化提供依据。以下是详细深入的使用 pt-query-digest 进行查询分析的步骤和相关示例。 一、安装 pt-query-digest pt-query-digest 是 Perc…

分享一个基于Python和Hadoop的的电信客户特征可视化分析平台 基于Spark平台的电信客服数据存储与处理系统源码

&#x1f495;&#x1f495;作者&#xff1a;计算机源码社 &#x1f495;&#x1f495;个人简介&#xff1a;本人八年开发经验&#xff0c;擅长Java、Python、PHP、.NET、Node.js、Spark、hadoop、Android、微信小程序、爬虫、大数据、机器学习等&#xff0c;大家有这一块的问题…

初识STL

一 、STL的诞生在C发展早期&#xff0c;程序员在不同的项目中需要反复编写相似的数据结构和算法。重复开发带来以下问题&#xff1a;代码冗余&#xff1a;每个项目都要重新实现基本数据结构和算法维护困难&#xff1a;不同人编写的代码风格不一致&#xff0c;难以维护效率低下&…

DDoS 防护的未来趋势:AI 如何重塑安全行业?

随着网络攻击规模和复杂性的不断升级&#xff0c;分布式拒绝服务&#xff08;DDoS&#xff09;攻击已成为企业数字化转型中的一大威胁。传统防御手段在应对智能化、动态化的攻击时逐渐显露出局限性。而人工智能&#xff08;AI&#xff09;技术的崛起&#xff0c;正为 DDoS 防护…

【每天一个知识点】深度领域对抗神经网络

Deep Domain Adversarial Neural Network&#xff08;深度领域对抗神经网络&#xff0c;DDANN&#xff09; 是一类结合 深度学习 与 领域自适应&#xff08;domain adaptation&#xff09; 思想的神经网络结构&#xff0c;主要用于不同数据域之间的知识迁移&#xff0c;尤其是在…

【C语言】深入理解预处理

文章目录一、预定义符号二、#define定义常量&#xff1a;便捷的符号替换常见用法示例&#xff1a;注意事项&#xff1a;三、#define定义宏&#xff1a;带参数的文本替换关键注意点&#xff1a;四、带有副作用的宏参数五、宏替换的规则&#xff1a;预处理的执行步骤重要注意&…

展锐平台(Android15)WLAN热点名称修改不生效问题分析

前言 在展锐Android V项目开发中&#xff0c;需要修改softAp/P2P热点名称时&#xff0c;发现集成GMS后直接修改framework层代码无效。具体表现为&#xff1a; 修改packages/modules/Wifi/WifiApConfigStore中的getDefaultApConfiguration方法编译烧录后修改不生效 问题根源在…

wsl ubuntu访问(挂载)vmware vmdk磁盘教程

之前使用VMware Workstation 虚拟机跑了个ubuntu&#xff0c;现在改用wsl了&#xff0c; 想把vmware的磁盘挂载到wsl ubuntu。一、磁盘合并我原先的vmware跑的ubuntu存在多个vmdk文件&#xff08;磁盘文件&#xff09;&#xff0c;需要先将磁盘合并成一个才方便挂载。首先你电脑…

UGUI源码剖析(3):布局的“原子”——RectTransform的核心数据模型与几何学

UGUI源码剖析&#xff08;第三章&#xff09;&#xff1a;布局的“原子”——RectTransform的核心数据模型与几何学 在前几章中&#xff0c;我们了解了UGUI的组件规范和更新调度机制。现在&#xff0c;我们将深入到这个系统的“几何学”核心&#xff0c;去剖析那个我们每天都在…

c++注意点(15)----设计模式(桥接模式与适配器模式)

一、结构型设计模式两者有点相似&#xff0c;都是为了做到解耦的功能。适配器模式是一种结构型设计模式&#xff0c; 它能使接口不兼容的对象能够相互合作。桥接模式是一种结构型设计模式&#xff0c; 可将一个大类或一系列紧密相关的类拆分为抽象和实现两个独立的层次结构&…