当前位置: 首页 > news >正文

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

STM32H723ZG + LAN8742 + Ethernet +LWIP 配置 cubemx

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

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

感谢这个blog

墙裂感谢我超级好的同事 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 完结 撒花撒花★,°:.☆( ̄▽ ̄)/$:.°★

http://www.dtcms.com/a/317660.html

相关文章:

  • 无人机图传的得力助手:5G 便携式多卡高清视频融合终端的协同应用
  • 中宇联5G云宽带+4G路由器:解锁企业办公高效协同与门店体验升级
  • 图解 Claude Code 子智能体 Sub-agent
  • [ java GUI ] 图形用户界面
  • 【软考系统架构设计师备考笔记4】 - 英语语法一篇通
  • ctfshow_vip题目限免-----SVN漏洞,git泄露
  • Git Cherry-Pick 指南
  • Leetcode——菜鸟笔记1
  • Git 分支管理:从新开发分支迁移为主分支的完整指南
  • 鸿蒙app 开发中 全局弹窗类的封装 基于PromptAction
  • C#之基础语法
  • 机器学习之朴素贝叶斯
  • Suno API V5模型 php源码 —— 使用灵感模式进行出创作
  • 基于PHP的论坛社交网站系统开发与设计
  • 排序算法详解
  • 媒体资产管理系统和OCR文字识别的结合
  • Ethereum: L1 与 L2 的安全纽带, Rollups 技术下的协作与区别全解析
  • 解决启动docker报错Cannot connect to the Docker daemon问题
  • 阿里 Qwen-Image:开源 20B 模型引领图像生成新纪元,中文渲染超越 GPT-4o!
  • 数据结构与算法的认识
  • 手动开发一个TCP服务器调试工具(二):无界面 TCP 通信服最小实现
  • ETF期权分仓的风险如何管理?
  • 基于Hadoop的股票大数据分析可视化及多模型的股票预测研究与实现
  • 四十、【高级特性篇】接口用例数据驱动:引入随机变量与动态数据生成
  • 生成式模型 ?判别式模型?用【猫狗分类器】帮助理解!
  • 【网络安全】入侵检测系统 Suricata 概述 | IDS
  • 2025年大语言模型与多模态生成工具全景指南(V2.0)
  • PyCharm vs. VSCode 到底哪个更好用
  • 5个数据库 存储系统精选 | C/C++ 项目深度解析
  • 支持向量机(SVM)算法依赖的数学知识详解