完整教程下載地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980
第85章 STM32H7的SPI 總線應用之SPI Flash的STM32CubeProg下載算法制作
本章節為大家講解STM32CubeProg下載算法制作方法。
85.1 初學者重要提示
85.2 STM32CubeProg簡介
85.3 STM32CubeProg下載算法基礎知識
85.4 創建STM32CubeProg下載算法通用流程
85.4 SPI Flash的STM32CubeProg下載算法制作
85.5 SPI Flash的STM32CubeProg下載算法使用方法
85.6 實驗例程說明
85.7 總結
85.1 初學者重要提示
- QSPI Flash的相關知識點可以看第78章和79章。
- QSPI Flash下載算法文件直接采用HAL庫制作,方便大家自己修改。
- STM32CubeProg下載算法制作和MDK下載算法制作基本是一樣
- 本教程的第68章USB DFU和第69章串口IAP章節為大家介紹過STM32CubeProg的用法。STM32CubeProg下載http://www.armbbs.cn/forum.php?mod=viewthread&tid=97370 。
85.2 STM32CubeProg簡介
STM32CubeProg,此軟件實現了之前的 DfuSe,STLINK 小軟件和 Flashloader 三合一,並且支持外部 EEPROM,NOR Flash,SPI Flash,NAND Flash 等燒寫,也支持 OTA 編程。
85.3 STM32CubeProg下載算法基礎知識
STM32CubeProg下載算法是一種用於擦除應用程序或將應用程序下載到Flash的程序代碼。ST自家的芯片都自帶下載算法,存放在STM32CubeProg安裝目錄里面,但不支持的需要我們自己制作,本章教程為此而生。
85.3.1 程序能夠通過下載算法下載到芯片的核心思想
認識到這點很重要:通過IDE開發環境創建一批與地址信息無關的算法文件,實現的功能主要有初始化,擦除,編程,讀取,校驗等,然后STM32CubeProg下載階段,會將算法文件加載到芯片的內部RAM里面,然后STM32CubeProg通過與這個算法文件的交互,實現程序下載,數據讀取等操作。
85.3.2 算法程序中擦除操作執行流程
注:下面是MDK的算法執行流程,STM32CubeProg是類似的。
擦除操作大致流程:
- 加載算法到芯片RAM。
- 執行初始化函數Init。
- 執行擦除操作,根據用戶配置,這里可以選擇整個芯片擦除或者扇區擦除。
- 執行Uinit函數。
- 操作完畢。
85.3.3 算法程序中編程操作執行流程
注:下面是MDK的算法執行流程,STM32CubeProg是類似的(沒有Unint函數)。
編程操作大致流程:
- 針對IDE生成的axf(elf)可執行文件做Init初始化,這個axf(elf)文件是指的大家自己創建應用程序生成的。
- 查看Flash算法是否在FLM文件。如果沒有在,操作失敗。如果在:
- 加載算法到RAM。
- 執行Init函數。
- 加載用戶到RAM緩沖。
- 執行Program Page頁編程函數。
- 執行Uninit函數。
- 操作完畢。
85.3.4 算法程序中校驗操作執行流程
注:下面是MDK的算法執行流程,STM32CubeProg是類似的(沒有Unint函數)。
校驗操作大致流程:
- 校驗要用到IDE生成的axf(elf)可執行文件。校驗就是axf(elf)文件中下載到芯片的程序和實際下載的程序讀出來做比較。
- 查看Flash算法是否在FLM文件。如果沒有在,操作失敗。如果在:
- 加載算法到RAM。
- 執行Init函數。
- 查看校驗算法是否存在
- 如果有,加載應用程序到RAM並執行校驗。
- 如果沒有,執行計算CRC,將芯片中讀取數據出來和RAM中加載應用計算輸出的CRC值做比較。
- 執行Uninit函數。
- 替換BKPT(BreakPoint斷點指令)為 B. 死循環指令。
- 執行RecoverySupportStop,回復支持停止。
- 執行DebugCoreStop,調試內核停止。
- 運行應用:
- 執行失敗
- 執行成功,再執行硬件復位。
- 操作完畢,停止調試端口。
85.4 創建STM32CubeProg下載算法通用流程
下面是STM32CubeProg給的一種大致操作流程,不限制必須采用這種方法,自己創建也可以的。
85.4.1 第1步,使用STM32CubeProg提供好的程序模板
位於路徑:STMicroelectronics\STM32Cube\STM32CubeProgrammer\bin\ExternalLoader
以M25P64為例(注,其余步驟就以這個為例子進行說明):
85.4.2 第2步,修改工程名
STM32CubeProg提供的工程模板原始名字是M25P64_STM3210E-EVAL.uvproj,大家可以根據自己的需要做修改。比如修改為MyDevice.uvproj(MDK4的后綴)或者MyDevice.uvprojx(MDK5的后綴)。
85.4.3 第3步,修改使用的器件
在MDK的Option選項里面設置使用的器件。
85.4.4 第4步,修改輸出算法文件的名字
這個名字是方便用戶查看的,比如設置為stm32h7,那么輸出的算法文件就是stm32h7.stldr。
注:STM32CubeProg軟件里面別的文件名並不采用這個,而是由用戶在文件Dev_Inf.c里面定義的:
85.4.5 第5步,修改使用的庫文件和頭文件路徑
根據大家使用的主控芯片,添加相應的庫文件和頭文件路徑。
85.4.6 第5步,修改編程算法文件Loader_Src.c
模板工程里面提供的是M25P64,部分代碼如下:
/** * Description : * Initilize the MCU Clock, the GPIO Pins corresponding to the * device and initilize the FSMC with the chosen configuration * Inputs : * None * outputs : * R0 : "1" : Operation succeeded * "0" : Operation failure * Note: Mandatory for all types of device */ int Init (void) { SystemInit(); sFLASH_Init(); return 1; } /** * Description : * Read data from the device * Inputs : * Address : Write location * Size : Length in bytes * buffer : Address where to get the data to write * outputs : * R0 : "1" : Operation succeeded * "0" : Operation failure * Note: Mandatory for all types except SRAM and PSRAM */ int Read (uint32_t Address, uint32_t Size, uint8_t* buffer) { sFLASH_ReadBuffer(buffer, Address, Size); return 1; } /** * Description : * Write data from the device * Inputs : * Address : Write location * Size : Length in bytes * buffer : Address where to get the data to write * outputs : * R0 : "1" : Operation succeeded * "0" : Operation failure * Note: Mandatory for all types except SRAM and PSRAM */ int Write (uint32_t Address, uint32_t Size, uint8_t* buffer) { sFLASH_WriteBuffer(buffer, Address, Size); return 1; } /** * Description : * Erase a full sector in the device * Inputs : * None * outputs : * R0 : "1" : Operation succeeded * "0" : Operation failure * Note: Not Mandatory for SRAM PSRAM and NOR_FLASH */ int MassErase (void) { sFLASH_EraseBulk(); return 1; }
85.4.7 第6步,修改配置文件Dev_Inf.c
模板工程里面提供簡單的配置說明:
#if defined (__ICCARM__) __root struct StorageInfo const StorageInfo = { #else struct StorageInfo const StorageInfo = { #endif "M25P64_STM3210E-EVAL", // Device Name + version number SPI_FLASH, // Device Type 0x00000000, // Device Start Address 0x00800000, // Device Size in Bytes (8MBytes/64Mbits) 0x00000100, // Programming Page Size 16Bytes 0xFF, // Initial Content of Erased Memory // Specify Size and Address of Sectors (view example below) 0x00000080, 0x00010000, // Sector Num : 128 ,Sector Size: 64KBytes 0x00000000, 0x00000000, };
注:名字M25P64_STM3210E-EVAL就是我們第4步所說的。STM32CubeProg會識別出這個名字。
85.4.8 第7步,保證生成的算法文件中RO和RW段的獨立性,即與地址無關。
C和匯編的配置都勾選上:
匯編:
如果程序的所有只讀段都與位置無關,則該程序為只讀位置無關(ROPI, Read-only position independence)。ROPI段通常是位置無關代碼(PIC,position-independent code),但可以是只讀數據,也可以是PIC和只讀數據的組合。選擇“ ROPI”選項,可以避免不得不將代碼加載到內存中的特定位置。這對於以下例程特別有用:
(1)加載以響應運行事件。
(2)在不同情況下使用其他例程的不同組合加載到內存中。
(3)在執行期間映射到不同的地址。
使用Read-Write position independence同理,表示的可讀可寫數據段。
85.4.9 第8步,將程序可執行文件axf修改為stldr格式
通過下面的命令就可以將生成的axf可執行文件修改為stldr。
85.4.10 第9步,分散加載設置
我們這里的分散加載文件直接使用MDK模板工程里提供好的即可。
分散加載文件中的內容如下:
FLASH_LOADER 0x20000004 PI ; FlashLoader Functions { PrgCode +0 ; Code { * (+RO) } PrgData +0 ; Data { * (+RW,+ZI) } } DEVICE_INFO +0 ; Device Info { DevInfo +0 ; Info structure { dev_inf.o } }
這里要修改下Flash算法加載地址,將0x20000004修改為STM32H7的RAM地址,任何RAM塊地址均可,只要夠存儲Flash算法。推薦設置為AXI SRAM地址0x24000004,因為空間夠大,有512KB。
--diag_suppress L6305用於屏蔽L6503類型警告信息。
特別注意,設置了分散加載后,此處的配置就不再起作用了:
85.5 SPI Flash的STM32CubeProg下載算法制作
下面將SPI Flash算法制作過程中的幾個關鍵點為大家做個說明。
85.5.1 第1步,制作前重要提示
這兩點非常重要:
- 程序里面不要開啟任何中斷,全部查詢方式。
- HAL庫里面各種時間基准相關的API全部處理掉。簡單省事些,我們這里是直接注釋,采用死等即可。無需做超時等待,因為超時后,已經意味着操作失敗了,跟死等沒有區別。
85.5.2 第2步,准備一個工程模板
推薦大家直接使用我們本章工程准備好的模板即可,如果大家自己制作,注意一點,請使用當前最新的HAL庫。
85.5.3 第3步,修改HAL庫
這一步比較重要,主要修改了以下三個文件:
主要是修改了HAL庫時間基准相關的幾個API,並注釋掉了一批無關的API。具體修改內容,大家可以找個比較軟件,對比修改后的這個文件和CubeH7軟件包V1.8.0(軟件包里面的HAL庫版本是V1.9.0)的差異即可。
85.5.4 第4步,時鍾初始化
我們已經用不到滴答定時器了,直接在bsp.c文件里面對滴答初始化函數做重定向:
/* ********************************************************************************************************* * 函 數 名: HAL_InitTick * 功能說明: 重定向,不使用 * 形 參: TickPriority * 返 回 值: 無 ********************************************************************************************************* */ HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority) { return HAL_OK; }
然后就是HSE外置晶振的配置,大家根據自己的板子實際外掛晶振大小,修改stm32h7xx_hal_conf.h文件中HSE_VALUE大小,實際晶振多大,這里就修改為多大:
#if !defined (HSE_VALUE) #define HSE_VALUE ((uint32_t)25000000) /*!< Value of the External oscillator in Hz */ #endif /* HSE_VALUE */
最后修改PLL:
/* ********************************************************************************************************* * 函 數 名: SystemClock_Config * 功能說明: 初始化系統時鍾 * System Clock source = PLL (HSE) * SYSCLK(Hz) = 400000000 (CPU Clock) * HCLK(Hz) = 200000000 (AXI and AHBs Clock) * AHB Prescaler = 2 * D1 APB3 Prescaler = 2 (APB3 Clock 100MHz) * D2 APB1 Prescaler = 2 (APB1 Clock 100MHz) * D2 APB2 Prescaler = 2 (APB2 Clock 100MHz) * D3 APB4 Prescaler = 2 (APB4 Clock 100MHz) * HSE Frequency(Hz) = 25000000 * PLL_M = 5 * PLL_N = 160 * PLL_P = 2 * PLL_Q = 4 * PLL_R = 2 * VDD(V) = 3.3 * Flash Latency(WS) = 4 * 形 參: 無 * 返 回 值: 1 表示失敗,0 表示成功 ********************************************************************************************************* */ int SystemClock_Config(void) { RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; RCC_OscInitTypeDef RCC_OscInitStruct = {0}; HAL_StatusTypeDef ret = HAL_OK; /* 鎖住SCU(Supply configuration update) */ MODIFY_REG(PWR->CR3, PWR_CR3_SCUEN, 0); /* 1、芯片內部的LDO穩壓器輸出的電壓范圍,可選VOS1,VOS2和VOS3,不同范圍對應不同的Flash讀速度, 詳情看參考手冊的Table 12的表格。 2、這里選擇使用VOS1,電壓范圍1.15V - 1.26V。 */ __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {} /* 使能HSE,並選擇HSE作為PLL時鍾源 */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; RCC_OscInitStruct.HSEState = RCC_HSE_ON; RCC_OscInitStruct.HSIState = RCC_HSI_OFF; RCC_OscInitStruct.CSIState = RCC_CSI_OFF; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; RCC_OscInitStruct.PLL.PLLM = 5; RCC_OscInitStruct.PLL.PLLN = 160; RCC_OscInitStruct.PLL.PLLP = 2; RCC_OscInitStruct.PLL.PLLR = 2; RCC_OscInitStruct.PLL.PLLQ = 4; RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE; RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_2; ret = HAL_RCC_OscConfig(&RCC_OscInitStruct); if(ret != HAL_OK) { return 1; } /* 選擇PLL的輸出作為系統時鍾 配置RCC_CLOCKTYPE_SYSCLK系統時鍾 配置RCC_CLOCKTYPE_HCLK 時鍾,對應AHB1,AHB2,AHB3和AHB4總線 配置RCC_CLOCKTYPE_PCLK1時鍾,對應APB1總線 配置RCC_CLOCKTYPE_PCLK2時鍾,對應APB2總線 配置RCC_CLOCKTYPE_D1PCLK1時鍾,對應APB3總線 配置RCC_CLOCKTYPE_D3PCLK1時鍾,對應APB4總線 */ RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_D1PCLK1 | RCC_CLOCKTYPE_PCLK1 | \ RCC_CLOCKTYPE_PCLK2 | RCC_CLOCKTYPE_D3PCLK1); RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2; RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2; RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2; RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2; RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2; /* 此函數會更新SystemCoreClock,並重新配置HAL_InitTick */ ret = HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4); if(ret != HAL_OK) { return 1; } /* 使用IO的高速模式,要使能IO補償,即調用下面三個函數 (1)使能CSI clock (2)使能SYSCFG clock (3)使能I/O補償單元, 設置SYSCFG_CCCSR寄存器的bit0 */ __HAL_RCC_CSI_ENABLE() ; __HAL_RCC_SYSCFG_CLK_ENABLE() ; HAL_EnableCompensationCell(); __HAL_RCC_D2SRAM1_CLK_ENABLE(); __HAL_RCC_D2SRAM2_CLK_ENABLE(); __HAL_RCC_D2SRAM3_CLK_ENABLE(); return 0; }
85.5.5 第5步,配置文件Dev_Inf.c的實現
配置如下:
#if defined (__ICCARM__) __root struct StorageInfo const StorageInfo = { #else struct StorageInfo const StorageInfo = { #endif "ARMFLY_STM32H743_SPI_W25Q64", /* 算法名,添加算法到STM32CubeProg安裝目錄會顯示此名字 */ NOR_FLASH, /* 設備類型 */ 0xC0000000, /* Flash起始地址 */ 8 * 1024 * 1024, /* Flash大小,8MB */ 4096, /* 編程頁大小 */ 0xFF, /* 擦除后的數值 */ 2048 , 4 * 1024, /* 塊個數和塊大小 */ 0x00000000, 0x00000000, };
注釋已經比較詳細,大家根據自己的需要做修改即可。注意一點,算法名ARMFLY_STM32H743_SPI_W25Q64會反饋到這個地方:
85.5.6 第6步,編程文件Loader_Src.c的實現
下面將變成文件中實現的幾個函數為大家做個說明:
- 初始化函數Init
/* ********************************************************************************************************* * 函 數 名: Init * 功能說明: Flash編程初始化 * 形 參: 無 * 返 回 值: 0 表示失敗, 1表示成功 ********************************************************************************************************* */ int Init(void) { int result = 0; /* 系統初始化 */ SystemInit(); /* 時鍾初始化 */ result = SystemClock_Config(); if (result == 1) { return 0; } /* SPI Flash初始化 */ bsp_InitSPIBus(); bsp_InitSFlash(); return 1; }
- 整個芯片擦除函數MassErase
整個芯片的擦除實現如下:
/* ********************************************************************************************************* * 函 數 名: MassErase * 功能說明: 整個芯片擦除 * 形 參: 無 * 返 回 值: 1 表示成功,0表示失敗 ********************************************************************************************************* */ int MassErase(void) { sf_EraseChip(); return 1; }
- 扇區擦除函數SectorErase
/* ********************************************************************************************************* * 函 數 名: SectorErase * 功能說明: EraseStartAddress 擦除起始地址 * EraseEndAddress 擦除結束地址 * 形 參: adr 擦除地址 * 返 回 值: 1 表示成功,0表示失敗 ********************************************************************************************************* */ int SectorErase (uint32_t EraseStartAddress ,uint32_t EraseEndAddress) { uint32_t BlockAddr; EraseStartAddress -= SPI_FLASH_MEM_ADDR; EraseEndAddress -= SPI_FLASH_MEM_ADDR; EraseStartAddress = EraseStartAddress - EraseStartAddress % 0x1000; /* 4KB首地址 */ while (EraseEndAddress >= EraseStartAddress) { BlockAddr = EraseStartAddress & 0x0FFFFFFF; sf_EraseSector(BlockAddr); EraseStartAddress += 0x1000; } return 1; }
這里要注意兩點:
(1) 程序里面的操作EraseStartAddress-= SPI_FLASH_MEM_ADDR,實際傳遞進來的地址是帶了首地址的,即0xC0000000。
(2) 這里執行的擦除大小要前面Dev_Inf.c文件中配置的扇區大小一致,這里是執行的4KB為扇區進行擦除。
- 頁編程函數Write
頁編程函數實現如下:
/* ********************************************************************************************************* * 函 數 名: Write * 功能說明: 寫數據到Device * 形 參: Address 寫入地址 * Size 寫入大小,單位字節 * buffer 要寫入的數據地址 * 返 回 值: 1 表示成功,0表示失敗 ********************************************************************************************************* */ int Write(uint32_t Address, uint32_t Size, uint8_t* buffer) { Address -= SPI_FLASH_MEM_ADDR; sf_WriteBuffer(buffer, Address, Size); return 1; }
這里注意兩點:
(1) W25Q256的頁大小是256字節,前面FlashDev.c中將頁編程大小設置為4096字節,主要是方便擦除操作。
(2) 程序里面的操作Address-= SPI_FLASH_MEM_ADDR,實際傳遞進來的地址是帶了首地址的,即0xC0000000。
- 讀取函數
/* ********************************************************************************************************* * 函 數 名: Read * 功能說明: 從SPI Flash讀取數據 * 形 參: Address 讀取地址 * Size 讀取大小,單位字節 * buffer 讀取存放的數據緩沖 * 返 回 值: 1 表示成功,0表示失敗 ********************************************************************************************************* */ int Read(uint32_t Address, uint32_t Size, uint8_t* Buffer) { Address -= SPI_FLASH_MEM_ADDR; sf_ReadBuffer(Buffer, Address, Size); return 1; }
- 讀取和校驗函數
我們程序中未做校驗函數。如果程序中未做校驗函數,那么STM32CubeProg會讀取數據做校驗。
85.5.7 第7步,修改SPI Flash驅動文件(引腳,命令等)
最后一步就是SPI Flash(W25Q64)的驅動修改,大家可以根據自己的需求做修改。使用的引腳定義在文件bsp_spi_bus.c:
/* ********************************************************************************************************* * 時鍾,引腳,DMA,中斷等宏定義 ********************************************************************************************************* */ #define SPIx SPI1 #define SPIx_CLK_ENABLE() __HAL_RCC_SPI1_CLK_ENABLE() #define DMAx_CLK_ENABLE() __HAL_RCC_DMA2_CLK_ENABLE() #define SPIx_FORCE_RESET() __HAL_RCC_SPI1_FORCE_RESET() #define SPIx_RELEASE_RESET() __HAL_RCC_SPI1_RELEASE_RESET() #define SPIx_SCK_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE() #define SPIx_SCK_GPIO GPIOB #define SPIx_SCK_PIN GPIO_PIN_3 #define SPIx_SCK_AF GPIO_AF5_SPI1 #define SPIx_MISO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE() #define SPIx_MISO_GPIO GPIOB #define SPIx_MISO_PIN GPIO_PIN_4 #define SPIx_MISO_AF GPIO_AF5_SPI1 #define SPIx_MOSI_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE() #define SPIx_MOSI_GPIO GPIOB #define SPIx_MOSI_PIN GPIO_PIN_5 #define SPIx_MOSI_AF GPIO_AF5_SPI1
硬件設置了之后,剩下就是SPI Flash相關的幾個配置和片選引腳配置,在文件bsp_spi_flash.c:
主要是下面這幾個:
/* 串行Flash的片選GPIO端口, PD13 */ #define SF_CS_CLK_ENABLE() __HAL_RCC_GPIOD_CLK_ENABLE() #define SF_CS_GPIO GPIOD #define SF_CS_PIN GPIO_PIN_13 #define SF_CS_0() SF_CS_GPIO->BSRR = ((uint32_t)SF_CS_PIN << 16U) #define SF_CS_1() SF_CS_GPIO->BSRR = SF_CS_PIN #define CMD_AAI 0xAD /* AAI 連續編程指令(FOR SST25VF016B) */ #define CMD_DISWR 0x04 /* 禁止寫, 退出AAI狀態 */ #define CMD_EWRSR 0x50 /* 允許寫狀態寄存器的命令 */ #define CMD_WRSR 0x01 /* 寫狀態寄存器命令 */ #define CMD_WREN 0x06 /* 寫使能命令 */ #define CMD_READ 0x03 /* 讀數據區命令 */ #define CMD_RDSR 0x05 /* 讀狀態寄存器命令 */ #define CMD_RDID 0x9F /* 讀器件ID命令 */ #define CMD_SE 0x20 /* 擦除扇區命令 */ #define CMD_BE 0xC7 /* 批量擦除命令 */ #define DUMMY_BYTE 0xA5 /* 啞命令,可以為任意值,用於讀操作 */ #define WIP_FLAG 0x01 /* 狀態寄存器中的正在編程標志(WIP) */
85.6 QSPI Flash的STM32CubeProg下載算法使用方法
編譯本章教程配套的例子,生成的算法文件位於此路徑下:
85.6.1 下載算法存放位置
生成此文件后,需要大家將其存放到STM32CubeProg安裝目錄路徑:
\STMicroelectronics\STM32Cube\STM32CubeProgrammer\bin\ExternalLoader
85.6.2 STM32CubeProg下載配置
我們這里以STLINK連接開發板為例進行說明(USB DFU或者串口方式不支持下載外部Flash)。
點擊Connect后效果如下:
在這里選擇我們制作的下載算法:
任意加載個hex或者bin文件,並按照如下配置,然后點擊Start Programming
下載完成后的效果如下:
85.6.3 驗證算法文件是否可以正常使用
為了驗證算法文件是否可以正常使用,大家可以運行本教程第86章配套的例子。也可以使用STM32CubeProg直接讀取:
85.7 實驗例程說明
本章配套例子:V7-066_SPI Flash的STM32CubeProg下載算法制作。
編譯本章教程配套的例子,生成的算法文件位於此路徑下:
85.8 總結
本章節就為大家講解這么多,為了熟練掌握,大家可以嘗試自己實現一個Flash下載算法。