128、STM32H723ZGT6实现串口IAP
Bootloader程序通过串口接收*.bin文件数据,写入到内部flash区域,然后跳转APP应用程序
flash读写数据参考我的博客:127、stm32h743XI内部flash
注意:H723系列flash必须32字节写入,并且擦除时别重启|断电,不然会下次读取导致HardFault_Handler
STM32H723ZGT6内部flash扇区如下所示:
1、工程项目设置:
本例程中Bootloader程序使用Sector0扇区0x08000000区域的128KB,其余区域为应用程序区域
Bootloader程序项目设置如下:
APP项目程序设置如下所示:
输入命令内容:
C:\app_work\keil531\ARM\ARMCC\bin\fromelf.exe --bin -o ./IAP_APP\IAP_APP.bin ./IAP_APP\IAP_APP.axf
2、Bootloader程序设计:
1、主函数调用iap_Process();函数
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 "dma.h"
#include "usart.h"
#include "gpio.h"/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "stm32_iap.h"
#include "stm32h7_flash.h"/* 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);
/* USER CODE BEGIN PFP *//* USER CODE END PFP *//* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
int fputc(int ch, FILE *f)
{HAL_UART_Transmit(&huart9, (uint8_t *)&ch, 1, 0xFFFF);return ch;
}/* USER CODE END 0 *//*** @brief The application entry point.* @retval int*/
int main(void)
{/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* USER CODE END Init *//* Configure the system clock */SystemClock_Config();/* USER CODE BEGIN SysInit *//* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();MX_DMA_Init();MX_UART8_Init();MX_UART9_Init();/* USER CODE BEGIN 2 */iap_Process();/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE */HAL_Delay(100);/* USER CODE BEGIN 3 */}/* 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_SCALE0);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_ON;RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;RCC_OscInitStruct.PLL.PLLM = 4;RCC_OscInitStruct.PLL.PLLN = 34;RCC_OscInitStruct.PLL.PLLP = 1;RCC_OscInitStruct.PLL.PLLQ = 2;RCC_OscInitStruct.PLL.PLLR = 2;RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_3;RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;RCC_OscInitStruct.PLL.PLLFRACN = 3072;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_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;if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_3) != HAL_OK){Error_Handler();}
}/* USER CODE BEGIN 4 *//* USER CODE END 4 *//*** @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 */
2、IAP处理程序:接收文件、写入flash、跳转应用程序
stm32_iap.h
#ifndef _stm32_iap_H_
#define _stm32_iap_H_
#include "main.h"void iap_ReceiveDataStart(void);
void iap_ReceiveDataStop(void);
void iap_ReceiveData_Callback(void);
uint32_t iap_ReceiveDataNumber(void);
void iap_nvic_set_vector_table(uint32_t baseaddr, uint32_t offset);
void iap_Process(void);#endif
stm32_iap.c
/**********************************************************************
*file:IAP所需函数文件:STM32H723ZGT6
*author:残梦
*versions:V1.0
*date:2025.5.30
*note:
**********************************************************************/
#include "stm32_iap.h"
#include "stm32h7_flash.h"
#include "usart.h"
#include "stdbool.h"volatile uint8_t iap_buffer[1024*127] = {0};//能接收bin文件最大字节数,必须为1024的整数倍
uint8_t iap_receive_complete = 0;//接收完成1024字节计数一次
bool iap_receive_state = false;//串口接收状态
uint32_t iap_receive_size = 0;//临时缓存停止时刻接收字节数:若此值等于iap_buffer区域大小说明文件太大了,无法接收完毕/****************************************************
@function:开始接收bin文件数据
@param:void
@return:void
@note:
****************************************************/
void iap_ReceiveDataStart(void)
{iap_receive_complete = 0;iap_receive_state = true;HAL_UART_Receive_DMA(&huart8,(uint8_t *)iap_buffer,\(sizeof(iap_buffer) > 1024)?1024:((uint16_t )sizeof(iap_buffer)));
}/****************************************************
@function:停止接收数据
@param:void
@return:void
@note:
****************************************************/
void iap_ReceiveDataStop(void)
{iap_receive_size = iap_ReceiveDataNumber();HAL_UART_DMAStop(&huart8);iap_receive_state = false;
}/****************************************************
@function:IAP串口接收数据处理
@param:void
@return:void
@note:
****************************************************/
void iap_ReceiveData_Callback(void)
{if(sizeof(iap_buffer) < 1024)return;if(++iap_receive_complete >= (sizeof(iap_buffer)/1024)){iap_receive_complete--;//避免计算字节数时重复计算iap_ReceiveDataStop();return;}//超过缓冲区域就结束HAL_UART_Receive_DMA(&huart8,(uint8_t *)(iap_buffer + iap_receive_complete * 1024),1024);
}/****************************************************
@function:获取当前已接收数据字节数
@param:void
@return:字节数
@note:
****************************************************/
uint32_t iap_ReceiveDataNumber(void)
{if(iap_receive_state)return ((uint32_t )1024 - (uint32_t )(__HAL_DMA_GET_COUNTER(huart8.hdmarx))) + (uint32_t )iap_receive_complete * 1024;else return iap_receive_size;
}/****************************************************
@function:设置中断向量表偏移地址
@param:baseaddr: 基址offset: 偏移量
@return:void
@note:
****************************************************/
void iap_nvic_set_vector_table(uint32_t baseaddr, uint32_t offset)
{/* 设置 NVIC 的向量表偏移寄存器,VTOR 低 9 位保留,即[8:0]保留 */SCB->VTOR = baseaddr | (offset & (uint32_t)0xFFFFFE00);
}/****************************************************
@function:跳转到应用程序段(执行APP)
@param:app_address:应用程序的起始地址
@return:0-成功,否则-跳转失败
@note:跳转成功不会退出此函数APP程序main函数开头做如下事:开头就设置中断向量表所在起始地址:例如iap_nvic_set_vector_table(0x08000000,(app_address - 0x08000000));//设置中断向量表偏移地址硬件初始化后打开全局中断:__enable_irq();
****************************************************/
typedef void (*iap_ApplicationFunc)(void);
static int32_t iap_LoadApp(uint32_t app_address)
{// 声明函数指针iap_ApplicationFunc jump_app = NULL;uint32_t stack_top = 0;uint32_t reset_vector = 0;// 检查应用程序地址是否在有效范围内// STM32H723的Flash范围是0x08000000-0x081FFFFFif (app_address < 0x08000000 || app_address > 0x081FFFFF) {return -1; // 地址超出Flash范围}// 读取栈顶地址stack_top = *(volatile uint32_t *)app_address;// 检查栈顶地址是否合法// SRAM1+SRAM2区域(0x30000000-0x3003FFFF, 256KB)// AXI SRAM区域(0x24000000-0x2407FFFF, 512KB)if (!((stack_top >= 0x24000000 && stack_top <= 0x2407FFFF) || (stack_top >= 0x30000000 && stack_top <= 0x3003FFFF))) {return -2; // 栈顶地址不在有效RAM区域内}// 读取复位向量地址reset_vector = *(volatile uint32_t *)(app_address + 4);// 检查复位向量地址是否在有效Flash范围内if (reset_vector < 0x08000000 || reset_vector > 0x081FFFFF) {return -3; // 复位向量地址无效}// 确保所有外设和中断都已禁用__disable_irq(); // 禁用全局中断SCB->AIRCR = 0x05FA0000 | SCB_AIRCR_VECTKEY_Pos; // 复位所有外设// 清除所有挂起的中断NVIC->ICPR[0] = 0xFFFFFFFF;NVIC->ICPR[1] = 0xFFFFFFFF;NVIC->ICPR[2] = 0xFFFFFFFF;NVIC->ICPR[3] = 0xFFFFFFFF;// 重置SysTickSysTick->CTRL = 0;SysTick->LOAD = 0;SysTick->VAL = 0;// 设置应用程序的堆栈指针__set_MSP(stack_top);// 获取应用程序的复位处理函数jump_app = (iap_ApplicationFunc)reset_vector;// 跳转到应用程序jump_app();//跳转成功后需要在应用函数开头使能全局中断和新的中断向量表所在起始地址// 如果执行到这里,说明跳转失败return -4;
}/****************************************************
@function:IAP运行,等待程序更新跳转
@param:void
@return:void
@note:
****************************************************/
#include "stdio.h"
#define dIAP_Debug(...) printf(__VA_ARGS__)//iap调试信息输出
#define FLASH_APP_ADDR ((uint32_t)0x08020000)//stm32h723zgt6第二扇区做起始地址,第一扇区做bootloader程序区域;每个扇区都是128KB
void iap_Process(void)
{uint32_t BytesLast = 0,val_u32 = 0;uint8_t UpdataFinishWait = 0;iap_ReceiveDataStart();//等待接收bin文件dIAP_Debug("Waiting for file[*.bin] transfer...\n");while(1){HAL_Delay(100);if((BytesLast != iap_ReceiveDataNumber()) || (BytesLast == 0)){BytesLast = iap_ReceiveDataNumber();UpdataFinishWait = 0;continue;}if(UpdataFinishWait < 30){UpdataFinishWait++;continue;}//3秒内接收字节数不变,判定为文件接收结束iap_ReceiveDataStop();//关闭接收if(BytesLast == sizeof(iap_buffer))//文件超过接收限制大小{dIAP_Debug("The file is larger than %.0fKB. The reception failed.\n",(float)BytesLast / 1024.0f);goto SystemReset;}dIAP_Debug("file transfer completed:%dbyte\n",BytesLast);val_u32 = *((uint32_t *)iap_buffer);printf("Stack top address:0x%04X\n",val_u32);val_u32 = *(((uint32_t *)iap_buffer) + 1);printf("Reset vector address:0x%04X\n",val_u32);if(((*(((uint32_t *)iap_buffer) + 1)) & 0xFF000000) != 0x08000000)//检查复位向量地址{printf("Receiving files is not a flash application\n");goto SystemReset;}if(flash_WriteData(FLASH_APP_ADDR,(uint8_t *)iap_buffer,BytesLast) != 0)//写入内部flash区域{printf("Flash data writing failed\n");goto SystemReset;}if(iap_LoadApp(FLASH_APP_ADDR) != 0)//跳转应用程序{printf("Failed to switch to the application\n");goto SystemReset;}while(1);}SystemReset:__set_FAULTMASK(1);//close all interruptNVIC_SystemReset();//resetwhile(1);
}
3、flash读写
stm32h7_flash.h
#ifndef _stm32h7_flash_H_
#define _stm32h7_flash_H_
#include "main.h"int32_t flash_WriteData(uint32_t address,uint8_t *buf,uint32_t size);
int32_t flash_ReadData(uint32_t address,uint8_t *buf,uint32_t size);
HAL_StatusTypeDef flash_SectorErase(uint32_t address,uint32_t size);#define dFlash_test 0//定义此宏则开启flash测试函数
#if dFlash_test
void flash_test(void);
#endif
#endif
stm32h7_flash.c
/**********************************************************************
*file:stm32h723zgt6系列内部flash读写
*author:残梦
*versions:V1.0
*date:2025.5.30
*note:
**********************************************************************/
#include "stm32h7_flash.h"
#include "string.h"//以下是stm32h723zgt6内部flash信息
/* Base address of the Flash sectors */
#define ADDR_FLASH_SECTOR_0 ((uint32_t)0x08000000) /* 128 Kbytes */
#define ADDR_FLASH_SECTOR_1 ((uint32_t)0x08020000) /* 128 Kbytes */
#define ADDR_FLASH_SECTOR_2 ((uint32_t)0x08040000) /* 128 Kbytes */
#define ADDR_FLASH_SECTOR_3 ((uint32_t)0x08060000) /* 128 Kbytes */
#define ADDR_FLASH_SECTOR_4 ((uint32_t)0x08080000) /* 128 Kbytes */
#define ADDR_FLASH_SECTOR_5 ((uint32_t)0x080A0000) /* 128 Kbytes */
#define ADDR_FLASH_SECTOR_6 ((uint32_t)0x080C0000) /* 128 Kbytes */
#define ADDR_FLASH_SECTOR_7 ((uint32_t)0x080E0000) /* 128 Kbytes */#define ADDR_FLASH_BASE ADDR_FLASH_SECTOR_0//内部Flash起始地址
#define ADDR_FLASH_SIZE ((uint32_t)(1024*1024))//内部Flash大小/****************************************************
@function:根据地址计算扇区首地址
@param:address:flash地址
@return:扇区号(0-7)
@note:
****************************************************/
static uint8_t flash_SectorGet(uint32_t address)
{uint8_t sector = 0;//由于h723内部flash扇区大小都是128K所以这样计算sector = (address - ((uint32_t)0x08000000)) / (128*1024);sector = (sector > 7)?7:sector;//限制范围return sector;
}/****************************************************
@function:擦除CPU flash扇区
@param:address:flash地址size:从地址开始的字节数区域对应扇区都擦除
@return:
@note:
****************************************************/
HAL_StatusTypeDef flash_SectorErase(uint32_t address,uint32_t size)
{FLASH_EraseInitTypeDef EraseInit;uint32_t PageError = 0;HAL_StatusTypeDef state;EraseInit.TypeErase = FLASH_TYPEERASE_SECTORS;EraseInit.Banks = FLASH_BANK_1;EraseInit.Sector = flash_SectorGet(address);EraseInit.NbSectors = flash_SectorGet(address + size) - flash_SectorGet(address) + 1;EraseInit.VoltageRange = FLASH_VOLTAGE_RANGE_3;HAL_FLASH_Unlock();state = HAL_FLASHEx_Erase(&EraseInit,&PageError);HAL_FLASH_Lock();return state;
}/****************************************************
@function:写数据到CPU内部Flash(支持跨扇区)
@param:address:flash地址;address必须 32 字节对齐,即要编程的 Flash 地址对 32 求余为 0
@return:0:成功;-1:数据长度或地址溢出
@note:stm32h7:必须按32字节整数倍写。支持跨扇区。扇区大小128KB.写之前需要擦除扇区.长度不是32字节整数倍时,最后几个字节末尾补0写入.由于 H7 的 BANK1 和 BANK2 是独立的,当前正在擦除的扇区所处的 BANK 会停止所有在此 BANK 执行的程序,包含中断也会停止执行。比如当前的应用程序都在 BANK1,如果要擦除或者编程 BANK2,是不会不影响 BANK1 里面执行的程序。这里安全起见加上了开关中断。
****************************************************/
int32_t flash_WriteData(uint32_t address,uint8_t *buf,uint32_t size)
{uint32_t i = 0;uint64_t FlashWord[4] = {0};int32_t err = 0;HAL_StatusTypeDef state;if(((address + size) > (ADDR_FLASH_BASE + ADDR_FLASH_SIZE))\|| (address < ADDR_FLASH_BASE)\|| (address % 32)\|| (size == 0))return -1;__disable_irq();if(flash_SectorErase(address,size) != HAL_OK){err = -2;goto ERROR;}HAL_FLASH_Unlock();for(i = 0;i < size/32;i++){memcpy(((uint8_t *)FlashWord),buf,32);buf += 32;state = HAL_FLASH_Program(FLASH_TYPEPROGRAM_FLASHWORD,address,((uint32_t)FlashWord));if(state != HAL_OK){err = -2;goto ERROR;}address += 32;//递增,操作下一个256位数据}if(size%32)//长度不是32字节的整数倍{memset(FlashWord,0,32);memcpy(((uint8_t *)FlashWord),buf,size%32);if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_FLASHWORD,address,((uint32_t )FlashWord)) != HAL_OK){err = -2;goto ERROR;}}ERROR:HAL_FLASH_Lock();__enable_irq();return err;
}/****************************************************
@function:从CPU内部Flash读取数据
@param:address:flash地址buf:目标缓冲区size:数据大小(单位是字节)
@return:0-成功,否则失败
@note:
****************************************************/
int32_t flash_ReadData(uint32_t address,uint8_t *buf,uint32_t size)
{if(((address + size) > (ADDR_FLASH_BASE + ADDR_FLASH_SIZE))\|| (address < ADDR_FLASH_BASE)\|| (size == 0))return -1;memcpy(buf,(uint8_t *)address,size);return 0;
}#if dFlash_test
uint8_t xbuf[1024*128+5] = {0};
void flash_test(void)
{uint32_t i = 0,num = 0;if(flash_SectorErase(ADDR_FLASH_SECTOR_2,sizeof(xbuf)) != HAL_OK){printf("SectorErase fail\n");while(1);}HAL_Delay(1);for(i = 0;i < sizeof(xbuf);i++)xbuf[i] = i%256;if(flash_WriteData(ADDR_FLASH_SECTOR_2,xbuf,sizeof(xbuf)) != 0){printf("write fail\n");}printf("write finish\n");memset(xbuf,0,sizeof(xbuf));printf("start read:\n");if(flash_ReadData(ADDR_FLASH_SECTOR_2,xbuf,sizeof(xbuf)) != 0){printf("read fail\n");}else{for(i = 0;i < sizeof(xbuf);i++){if(xbuf[i] != i%256)num++;}printf("num=%d\n",num);}printf("flash_test finish\n");
}
#endif
3、APP程序设计:
/* 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"/* 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 ---------------------------------------------------------*/UART_HandleTypeDef huart9;/* USER CODE BEGIN PV *//* USER CODE END PV *//* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_UART9_Init(void);
/* USER CODE BEGIN PFP *//* USER CODE END PFP *//* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
int fputc(int ch, FILE *f)
{HAL_UART_Transmit(&huart9, (uint8_t *)&ch, 1, 0xFFFF);return ch;
}/****************************************************
@function:设置中断向量表偏移地址
@param:baseaddr: 基址offset: 偏移量
@return:void
@note:
****************************************************/
void iap_nvic_set_vector_table(uint32_t baseaddr, uint32_t offset)
{/* 设置 NVIC 的向量表偏移寄存器,VTOR 低 9 位保留,即[8:0]保留 */SCB->VTOR = baseaddr | (offset & (uint32_t)0xFFFFFE00);
}
/* USER CODE END 0 *//*** @brief The application entry point.* @retval int*/
int main(void)
{/* USER CODE BEGIN 1 */iap_nvic_set_vector_table(0x08000000,0x20000);//0x20000偏移128KB,到内部flash第2扇区起始地址/* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* USER CODE END Init *//* Configure the system clock */SystemClock_Config();/* USER CODE BEGIN SysInit */__enable_irq();//打开所有中断/* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();MX_UART9_Init();/* USER CODE BEGIN 2 *//* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE */printf("IAP_APP run...\n");HAL_Delay(1000);/* USER CODE BEGIN 3 */}/* 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_DIV2;RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2;RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2;RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2;if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK){Error_Handler();}
}/*** @brief UART9 Initialization Function* @param None* @retval None*/
static void MX_UART9_Init(void)
{/* USER CODE BEGIN UART9_Init 0 *//* USER CODE END UART9_Init 0 *//* USER CODE BEGIN UART9_Init 1 *//* USER CODE END UART9_Init 1 */huart9.Instance = UART9;huart9.Init.BaudRate = 115200;huart9.Init.WordLength = UART_WORDLENGTH_8B;huart9.Init.StopBits = UART_STOPBITS_1;huart9.Init.Parity = UART_PARITY_NONE;huart9.Init.Mode = UART_MODE_TX;huart9.Init.HwFlowCtl = UART_HWCONTROL_NONE;huart9.Init.OverSampling = UART_OVERSAMPLING_16;huart9.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;huart9.Init.ClockPrescaler = UART_PRESCALER_DIV1;huart9.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;if (HAL_UART_Init(&huart9) != HAL_OK){Error_Handler();}if (HAL_UARTEx_SetTxFifoThreshold(&huart9, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK){Error_Handler();}if (HAL_UARTEx_SetRxFifoThreshold(&huart9, UART_RXFIFO_THRESHOLD_1_8) != HAL_OK){Error_Handler();}if (HAL_UARTEx_DisableFifoMode(&huart9) != HAL_OK){Error_Handler();}/* USER CODE BEGIN UART9_Init 2 *//* USER CODE END UART9_Init 2 */}/*** @brief GPIO Initialization Function* @param None* @retval None*/
static void MX_GPIO_Init(void)
{
/* USER CODE BEGIN MX_GPIO_Init_1 */
/* USER CODE END MX_GPIO_Init_1 *//* GPIO Ports Clock Enable */__HAL_RCC_GPIOD_CLK_ENABLE();__HAL_RCC_GPIOA_CLK_ENABLE();/* USER CODE BEGIN MX_GPIO_Init_2 */
/* USER CODE END MX_GPIO_Init_2 */
}/* USER CODE BEGIN 4 *//* USER CODE END 4 *//*** @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 */
运行信息:
4、完整工程下载:
通过网盘分享的文件:43_stm32h723zgt6串口IAP程序.rar
链接: https://pan.baidu.com/s/1bcXCWyt35dhba0jvanxFtQ 提取码: 3rsh
感想:
stm32h723zgt6在无外部DRAM|SARM内存的场景下,在应用程序较小时倒没事,在应用程序较大比如400K时,由于flash每个扇区都是128KB,那么擦除扇区内容时需要记忆之前的数据就需要开创一个大数组来缓冲,可是这样一来就比较耗用应用程序的内存了;如不记忆采用接收文件一次接收完毕,那么缓冲文件数据则就需要一个大数组了,也会导致这个弊端,所以程序较大的场景又无外部内存的条件下是不方便用IAP的
该芯片SRAM全部才564KB