1. 首先启用 Flash模式.a) 确认 stm32f7xx_hal_conf.h 中 启用了 #defineHAL_FLASH_MODULE_ENABLEDb) 在 Drivers/STM32F7xx_HAL_Drivers中确认添加了源码 stm32f7xx_hal_cortex/flash/flash_ex.c 三个文件.2. 对flash进行分区.512K 共 8个扇区. 擦除的时候只能根据删除擦除./* Base address of the Flash sectors Bank 1 */#define ADDR_FLASH_SECTOR_0 ((uint32_t)0x08000000) /* Base @ of Sector 0, 16 Kbytes */#define ADDR_FLASH_SECTOR_1 ((uint32_t)0x08004000) /* Base @ of Sector 1, 16 Kbytes */#define ADDR_FLASH_SECTOR_2 ((uint32_t)0x08008000) /* Base @ of Sector 2, 16 Kbytes */#define ADDR_FLASH_SECTOR_3 ((uint32_t)0x0800C000) /* Base @ of Sector 3, 16 Kbytes */#define ADDR_FLASH_SECTOR_4 ((uint32_t)0x08010000) /* Base @ of Sector 4, 64 Kbytes */#define ADDR_FLASH_SECTOR_5 ((uint32_t)0x08020000) /* Base @ of Sector 5, 128 Kbytes */#define ADDR_FLASH_SECTOR_6 ((uint32_t)0x08040000) /* Base @ of Sector 6, 128 Kbytes */#define ADDR_FLASH_SECTOR_7 ((uint32_t)0x08060000) /* Base @ of Sector 7, 128 Kbytes */我们的要求.l 我们自己的 bootloader. l 信息区.l 程序区. 自己的程序l OTA升级区.所以设定#define NDADDR_BOOT ADDR_FLASH_SECTOR_0 //SECTOR_0 16K#define NDADDR_INFO ADDR_FLASH_SECTOR_1 //SECTOR_1 16K#define NDADDR_FW_APP ADDR_FLASH_SECTOR_5 //SECTOR_5 128K#define NDADDR_FW_OTA ADDR_FLASH_SECTOR_6 //SECTOR_6 128K#define FW_MAX_SIZE ((uint32_t)0x00020000) //固件最大 128K3. Flash 操作代码#ifndef _FIRMWARE_OTA_CONF_INC_H_#define _FIRMWARE_OTA_CONF_INC_H_#include#include/* Exported types ------------------------------------------------------------*/typedef void (*pFunction)(void);/* Base address of the Flash sectors Bank 1 */#define ADDR_FLASH_SECTOR_0 ((uint32_t)0x08000000) /* Base @ of Sector 0, 16 Kbytes */#define ADDR_FLASH_SECTOR_1 ((uint32_t)0x08004000) /* Base @ of Sector 1, 16 Kbytes */#define ADDR_FLASH_SECTOR_2 ((uint32_t)0x08008000) /* Base @ of Sector 2, 16 Kbytes */#define ADDR_FLASH_SECTOR_3 ((uint32_t)0x0800C000) /* Base @ of Sector 3, 16 Kbytes */#define ADDR_FLASH_SECTOR_4 ((uint32_t)0x08010000) /* Base @ of Sector 4, 64 Kbytes */#define ADDR_FLASH_SECTOR_5 ((uint32_t)0x08020000) /* Base @ of Sector 5, 128 Kbytes */#define ADDR_FLASH_SECTOR_6 ((uint32_t)0x08040000) /* Base @ of Sector 6, 128 Kbytes */#define ADDR_FLASH_SECTOR_7 ((uint32_t)0x08060000) /* Base @ of Sector 7, 128 Kbytes */#if 0#define ADDR_FLASH_SECTOR_8 ((uint32_t)0x08080000) /* Base @ of Sector 8, 128 Kbytes */#define ADDR_FLASH_SECTOR_9 ((uint32_t)0x080A0000) /* Base @ of Sector 9, 128 Kbytes */#define ADDR_FLASH_SECTOR_10 ((uint32_t)0x080C0000) /* Base @ of Sector 10, 128 Kbytes */#define ADDR_FLASH_SECTOR_11 ((uint32_t)0x080E0000) /* Base @ of Sector 11, 128 Kbytes *//* Base address of the Flash sectors Bank 2 */#define ADDR_FLASH_SECTOR_12 ((uint32_t)0x08100000) /* Base @ of Sector 0, 16 Kbytes */#define ADDR_FLASH_SECTOR_13 ((uint32_t)0x08104000) /* Base @ of Sector 1, 16 Kbytes */#define ADDR_FLASH_SECTOR_14 ((uint32_t)0x08108000) /* Base @ of Sector 2, 16 Kbytes */#define ADDR_FLASH_SECTOR_15 ((uint32_t)0x0810C000) /* Base @ of Sector 3, 16 Kbytes */#define ADDR_FLASH_SECTOR_16 ((uint32_t)0x08110000) /* Base @ of Sector 4, 64 Kbytes */#define ADDR_FLASH_SECTOR_17 ((uint32_t)0x08120000) /* Base @ of Sector 5, 128 Kbytes */#define ADDR_FLASH_SECTOR_18 ((uint32_t)0x08140000) /* Base @ of Sector 6, 128 Kbytes */#define ADDR_FLASH_SECTOR_19 ((uint32_t)0x08160000) /* Base @ of Sector 7, 128 Kbytes */#define ADDR_FLASH_SECTOR_20 ((uint32_t)0x08180000) /* Base @ of Sector 8, 128 Kbytes */#define ADDR_FLASH_SECTOR_21 ((uint32_t)0x081A0000) /* Base @ of Sector 9, 128 Kbytes */#define ADDR_FLASH_SECTOR_22 ((uint32_t)0x081C0000) /* Base @ of Sector 10, 128 Kbytes */#define ADDR_FLASH_SECTOR_23 ((uint32_t)0x081E0000) /* Base @ of Sector 11, 128 Kbytes */#endif#define NDADDR_BOOT ADDR_FLASH_SECTOR_0 //SECTOR_0 16K#define NDADDR_INFO ADDR_FLASH_SECTOR_1 //SECTOR_1 16K#define NDADDR_FW_APP ADDR_FLASH_SECTOR_5 //SECTOR_5 128K#define NDADDR_FW_OTA ADDR_FLASH_SECTOR_6 //SECTOR_6 128K#define FW_MAX_SIZE ((uint32_t)0x00020000) //固件最大 128K#define FW_PAGE_SIZE ((uint32_t)0x00000800) //写入的单位 2K./** 固件升级步骤.* 确定当前的 FW的位置是那个, FW1/FW2, 确定完毕后就知道要写那个.* YMODEM 获取满 2K 数据. FMC_FLASH_PAGE_SIZE, 然后写入一个页中.* 最后改写配置, 引导的 APROM 起始地址.*/void nd_FlashUnlock(void);void nd_FlashLock(void);bool ota_EraseSector(void);bool app_EraseSector(void);bool config_EraseSector(void);bool nd_flash_write(uint32_t Address, uint8_t *pData, uint32_t size);void nd_flash_read(uint32_t Address, uint8_t *pData, uint32_t size);//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////* 出厂设置内容. 保证4字节对齐. */typedef struct { uint32_t fw_addr; //最新有效的固件的flash地址. uint32_t page_cnt; //最新有效的固件的页数 (2K计数) uint64_t sn;}nd_ota_config_t;extern nd_ota_config_t g_ota_conf ;void load_factory_config(void);void save_factory_config(void);#endif //_FIRMWARE_OTA_CONF_INC_H_Flash部分的封装 实现#include "main.h"#include "fw_ota.h"void NVIC_SetVectorTable(uint32_t ApplicationFlashAddress){ SCB->VTOR = ApplicationFlashAddress;}//Unlocks the Flash to enable the flash control register access.void nd_FlashUnlock(void){ HAL_FLASH_Unlock(); __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_ERSERR);}void nd_FlashLock(void){ HAL_FLASH_Lock();}/*对指定地址上写入4字节数据. Address + data 必须 4字节对齐. 写完之后下次写入的 Address 和 data 都要+4. * @retval true: Data successfully written to Flash memory * false: Error occurred while writing data in Flash memory */static bool flash_Write_Word(uint32_t Address, uint32_t *Data){ return (HAL_OK == HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, Address, *Data));}static bool flash_Write_HalfWord(uint32_t Address, uint16_t *Data){ return (HAL_OK == HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, Address, *Data));}bool nd_flash_write(uint32_t Address, uint8_t *pData, uint32_t size){ if ((size % 4) != 0) return false; uint32_t nbWrites = size / 4; uint32_t idx; for (idx = 0; idx if (false == flash_Write_Word(Address, (uint32_t *)pData)) return false; pData+=4; Address+=4; } return true;}//读 不需要做 unlock.void nd_flash_read(uint32_t Address, uint8_t *pData, uint32_t size){ uint32_t idx; for (idx = 0; idx { *pData = *(__IO uint8_t *)Address; pData++; Address++; }}/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////bool ota_EraseSector(void){ nd_FlashUnlock(); FLASH_EraseInitTypeDef FLASH_EraseInitStruct; FLASH_EraseInitStruct.TypeErase = FLASH_TYPEERASE_SECTORS; FLASH_EraseInitStruct.Sector = FLASH_SECTOR_6; FLASH_EraseInitStruct.NbSectors = 1; FLASH_EraseInitStruct.VoltageRange = FLASH_VOLTAGE_RANGE_3; uint32_t SectorError = 0; return (HAL_OK == HAL_FLASHEx_Erase(&FLASH_EraseInitStruct, &SectorError));}bool app_EraseSector(void){ nd_FlashUnlock(); FLASH_EraseInitTypeDef FLASH_EraseInitStruct; FLASH_EraseInitStruct.TypeErase = FLASH_TYPEERASE_SECTORS; FLASH_EraseInitStruct.Sector = FLASH_SECTOR_5; FLASH_EraseInitStruct.NbSectors = 1; FLASH_EraseInitStruct.VoltageRange = FLASH_VOLTAGE_RANGE_3; uint32_t SectorError = 0; return (HAL_OK == HAL_FLASHEx_Erase(&FLASH_EraseInitStruct, &SectorError));}bool config_EraseSector(void){ nd_FlashUnlock(); FLASH_EraseInitTypeDef FLASH_EraseInitStruct; FLASH_EraseInitStruct.TypeErase = FLASH_TYPEERASE_SECTORS; FLASH_EraseInitStruct.Sector = FLASH_SECTOR_1; FLASH_EraseInitStruct.NbSectors = 1; FLASH_EraseInitStruct.VoltageRange = FLASH_VOLTAGE_RANGE_3; uint32_t SectorError = 0; return (HAL_OK == HAL_FLASHEx_Erase(&FLASH_EraseInitStruct, &SectorError));}/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////nd_ota_config_t g_ota_conf = {0};void load_factory_config(void){ nd_flash_read(NDADDR_INFO, (uint8_t *)&g_ota_conf, sizeof(nd_ota_config_t));}void save_factory_config(void){ nd_FlashUnlock(); nd_flash_write(NDADDR_INFO, (uint8_t *)&g_ota_conf, sizeof(nd_ota_config_t));}/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////4. 引导代码.static void exec_application(void){ uint32_t JumpAddress; pFunction Jump_To_Application; if ((((*(__IO uint32_t *) NDADDR_FW_APP) & 0x2FFE0000) == 0x20000000) /* 检查栈顶地址是否合法 */ || (((*(__IO uint32_t *) NDADDR_FW_APP) & 0xFF000000) == 0x10000000)) { /* Jump to user application */ JumpAddress = *(__IO uint32_t *) (NDADDR_FW_APP + 4); Jump_To_Application = (pFunction) JumpAddress; /* Initialize user application's Stack Pointer */ __set_MSP(*(__IO uint32_t *) NDADDR_FW_APP); Jump_To_Application(); }}static void update_app_from_ota(void){ app_EraseSector(); nd_FlashUnlock(); //g_ota_conf.page_cnt * 2K 的 数据从 OTA区 转移到 App区. uint32_t idx_pages, idx_oft; uint32_t src_addr = NDADDR_FW_OTA; uint32_t dst_addr = NDADDR_FW_APP; for (idx_pages = 0; idx_pages nd_flash_write(dst_addr, (uint8_t *)src_addr, FW_PAGE_SIZE); dst_addr += FW_PAGE_SIZE; src_addr += FW_PAGE_SIZE; }}int main(void){ //首先读取 g_ota_conf, 确定是否需要升级. memset(&g_ota_conf, 0, sizeof(g_ota_conf)); load_factory_config(); if (NDADDR_FW_OTA == g_ota_conf.fw_addr) { //不需要升级. //从OTA更新到APP. update_app_from_ota(); //改写配置. if (config_EraseSector()) { g_ota_conf.fw_addr = NDADDR_FW_APP; g_ota_conf.page_cnt = 0; //g_ota_conf.sn = 0x8010191120A90200; save_factory_config(); } } exec_application(); //升级完毕后, 调用应用端. while (1) { }}5. App区在 main.c 中开始位置写入SCB->VTOR = NDADDR_FW_APP; 即可. 最好的是写在 system_stm32f7xx.c 的 SystemInit的第一行同时设置 同样主要是起始地址 和大小下面就是实现协议从主机下载固件并更新到 OTA区即可.发现的问题, IAP到了App时候启动比较慢.MotorDrvEvb.zip