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 那可以參考這個方法進行配置
輸入相應開發板的型號 然后直接配置 比如這個開發板
到時候可以直接在這個例程上改 成功的概率會比自己用cubemx移植的概率高
ps:后面一些相關的例程也可以用這種方法參考
法二 用cubemx自己配置
前置知識
ps 這兩個前置知識 是兩個坑點 當然也可以跳過這個前置知識 直接到cubemx的配置部分
不同的外設存儲區可訪問的區域不同 所以要自己定義相應的內存區域
以太網外設通常需要專用的內存區域來存儲發送和接收的數據包。這些區域被稱為DMA描述符(Descriptors)和 緩沖區Buffers
1?? 首先以太網外設不是和其他外設一樣 可以隨意的放在單片機的不同地方?
?? 不能將以太網的數據緩沖區隨意放在 CPU 的 ITCM 里,也不能將 LTDC 的圖像數據放在 D2 域的 SRAM1 里,因為它們位于不同的總線域,并且由不同的 DMA 控制器管理。需要在軟件中根據這個硬件架構,將不同的外設緩沖區分配到它們所屬的或可訪問的存儲區域中。
首先這張圖清楚地說明了:不同的外設可以存儲數據的地方是不一樣的。
- 分域存儲:
- D1 域(高性能域) 的外設(如 SDMMC, MDMA, DMA2D, LTDC)通常會訪問 D1 域中的高速存儲器,例如 AXI SRAM 和 Flash。這是因為這些外設需要高速的數據吞吐量來處理大量數據(例如圖形、視頻、高速存儲卡)。
- D2 域(中速域) 的外設(如 Ethernet MAC, USBHS1)通常會訪問 D2 域中的 SRAM1 和 SRAM2。雖然這些也是SRAM,但它們位于不同的總線矩陣上,且可能由不同的 DMA 控制器(DMA1, DMA2)來管理。
- DMA控制器與存儲區域的綁定:
- D1 域 的 DMA 控制器(MDMA, DMA2D)通常用于在 D1 域的內存(AXI SRAM、Flash等)之間進行數據傳輸。
- D2 域 的 DMA 控制器(DMA1, DMA2)通常用于在外設(Ethernet MAC、USBHS1)與 D2 域的內存(SRAM1、SRAM2)之間進行數據傳輸。
- 專用存儲區:
- D3 域 有一個 Backup SRAM,這個存儲區通常是專門用來在低功耗或掉電模式下保留關鍵數據的。其他外設一般不會使用這塊內存。
- CPU 有專門的 ITCM 和 DTCM,這些是緊耦合內存,只供CPU使用,用于存儲最高速的指令和數據。
總結一下:
這張架構圖的核心思想就是根據外設的性能需求和功能,將它們和相應的存儲區域劃分到不同的總線域中。
?? 所以,不能將以太網的數據緩沖區隨意放在 CPU 的 ITCM 里,也不能將 LTDC 的圖像數據放在 D2 域的 SRAM1 里,因為它們位于不同的總線域,并且由不同的 DMA 控制器管理。需要在軟件中根據這個硬件架構,將不同的外設緩沖區分配到它們所屬的或可訪問的存儲區域中。
從這個總線矩陣上可以看到,以太網外設可以被定義在SRAM1,SRAM2中,對應的就是0x30000000 - 0x30003FFF
于是 以太網的DMA描述符就得后續這么定義在相應的存儲區
從上面的圖也可以看到有兩種不同的定義方式,一個是直接在前面定義
__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_CNT
個 ETH_DMADescTypeDef
結構體組成的數組,精確地放置在內存地址 0x30000000
上。 這塊內存區域將作為以太網控制器接收DMA描述符的存儲區域。
將一個名為 DMATxDscrTab
的、由 ETH_TX_DESC_CNT
個 ETH_DMADescTypeDef
結構體組成的數組,精確地放置在內存地址 0x30000060
上。 這塊內存區域將作為以太網控制器發送DMA描述符的存儲區域。
memory_RX_POOL_base 0x30000100 0x3F00 {*(.Rx_PoolSection)}
這個意思就是:在鏈接器腳本中,定義了一個內存區域,其起始地址為 0x30000100
,大小為 0x3F00
字節。然后,告訴鏈接器,將所有輸入目標文件(*.o
)中所有名為 .Rx_PoolSection
的代碼或數據段,都鏈接到這塊內存區域中。
這是專門為**以太網接收緩沖區(RX Pool)**分配一塊特定的內存區域,并確保這個區域位于一個固定的、已知的高速內存地址(例如 SRAM),以便于 DMA 控制器可以高效地訪問
.sct文件在魔法棒這邊 點擊edit就會出現了
為什么這么配置
- 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)))
是相對應的。 - 屬性:
BaseAddress
和Size
: 準確地指定了 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)進行配置,這個堆通常用于存儲發送和接收數據包的緩沖區。
- 屬性:
BaseAddress
和Size
: 指定了 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 開啟
引腳全部配置成高速
注意mac地址不能隨便配 默認就好 其他的需要好好配 對應于上面的前置知識所說的 地址
2.串口的配置
3.LWIP配置
這一部分開始大部分參考這篇blog 大家可以直接看原文
這里用dhcp 也就是用路由器給單片機分配ip
選擇LAN8742
checksum 默認的就行
4.PHY的復位引腳配置 參考上述博客
5.MPU的配置
參考blog
最后導出到KEIL_MDK 按照這個blog說的 該加的地方就加 該添的地方添
6.打開ethernetif.c文件 對相應的scatter file文件進行配置
參考這邊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文件
然后就可以開始編輯了
加上這一句
memory_RX_POOL_base 0x30000100 0x3F00 {*(.Rx_PoolSection)}
測試
測試說明
用一根網線 一端連接單片機 一端連接路由器
在原有的代碼加上這幾句
/* USER CODE BEGIN PFP */
extern struct netif gnetif;
struct dhcp *pdhcp;
/* USER CODE END PFP */
pdhcp = netif_dhcp_data(&gnetif);
打開debug模式 把pdhcp添加到監控區 這邊看到的就是路由器給我們板子分配的ip啦! 這樣就說明連接上了。 后面就可以進行相應的udp/tcp測試~~ 偷個懶可以直接在cubemx上面下載相應的庫 然后直接移植,親測可用
最終我的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是否已被占用 !! 然后再配置