【STM32 LWIP配置】STM32H723ZG + Ethernet +LWIP 配置 cubemx

发布于:2025-08-11 ⋅ 阅读:(47) ⋅ 点赞:(0)

STM32H723ZG + LAN8742 + Ethernet +LWIP 配置 cubemx

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

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

感谢
blog1
blog2
blog3
blog4
blog5

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

法一 直接用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 cacheable
     for 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 Cacheable
     for 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 cacheable
   for 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 Cacheable
   for 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 */
	//DCache
  SCB_CleanInvalidateDCache();

  //PHY
  HAL_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是否已被占用 !! 然后再配置


网站公告

今日签到

点亮在社区的每一天
去签到