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

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; 可將一個大類或一系列緊密相關的類拆分為抽象和實現兩個獨立的層次結構&…