128、STM32H723ZGT6实现串口IAP

article/2025/7/15 21:02:31

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


http://www.hkcw.cn/article/jbeIvcuWAu.shtml

相关文章

【Netty系列】Reactor 模式 2

目录 流程图说明 关键流程 以下是 Reactor 模式流程图&#xff0c;结合 Netty 的主从多线程模型&#xff0c;帮助你直观理解事件驱动和线程分工&#xff1a; 流程图说明 Clients&#xff08;客户端&#xff09; 多个客户端&#xff08;Client 1~N&#xff09;向服务端发起连…

接口自动化测试用例的编写方法

&#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 phpunit 接口自动化测试系列 Post接口自动化测试用例 Post方式的接口是上传接口&#xff0c;需要对接口头部进行封装&#xff0c;所以没有办法在浏览器下直接调…

2025030给荣品PRO-RK3566开发板单独升级Android13的boot.img

./build.sh init ./build.sh -K ./build.sh kernel 【导入配置文件】 Z:\Android13.0\rockdev\Image-rk3566_t\config.cfg 【更新的内核】 Z:\Android13.0\rockdev\Image-rk3566_t\boot.img 【导入分区表&#xff0c;使用原始的config.cfg会出错的^_】 Z:\Android13.0\rockdev\…

伊拉克军方打死6名“伊斯兰国”武装分子

△伊拉克联合行动指挥部发布视频截图当地时间5月30日,伊拉克联合行动指挥部下属安全媒体中心发表声明称,29日晚至30日早间,伊军方出动战机对位于该国北部萨拉赫丁省沙伊谷地的极端组织“伊斯兰国”武装分子藏匿点发动空袭,打死了6名武装分子,并摧毁其藏匿点。(总台记者 米…

Python打卡训练营Day40

DAY 40 训练和测试的规范写法 知识点回顾&#xff1a; 彩色和灰度图片测试和训练的规范写法&#xff1a;封装在函数中展平操作&#xff1a;除第一个维度batchsize外全部展平dropout操作&#xff1a;训练阶段随机丢弃神经元&#xff0c;测试阶段eval模式关闭dropout 作业&#x…

Haproxy搭建web群集

目录 一&#xff1a;Haproxy 1.Haproxy常见的调度算法 二&#xff1a;环境案例 1.配置web主机 2.配置haproxy主机 3.Haproxy日志 一&#xff1a;Haproxy Haproxy 是目前比较流行的一种群集调度工具&#xff0c;同类群集调度工具有很多,如 LVS 和 Nginx。相比较而言&#…

ansible自动化playbook简单实践

方法一&#xff1a;部分使用ansible 基于现有的nginx配置文件&#xff0c;定制部署nginx软件&#xff0c;将我们的知识进行整合 定制要求&#xff1a; 启动用户&#xff1a;nginx-test&#xff0c;uid是82&#xff0c;系统用户&#xff0c;不能登录 启动端口82 web项目根目录/…

一句话开发Chrome摸鱼插件

本文所使用的 CodeBuddy 免费下载链接&#xff1a;腾讯云代码助手 CodeBuddy - AI 时代的智能编程伙伴&#xfeff;。 CodeBuddy 一、CodeBuddy新功能特色 Craft智能体&#xff1a;自然语言驱动的全栈开发引擎Craft开发智能体的核心突破在于实现需求理解-任务拆解-代码生成的…

2024PLM系统实施案例:天水天轲零部件

一、行业背景与中小企业的现实挑战 汽车零部件行业竞争激烈&#xff0c;中小企业普遍面临研发周期长、数据管理混乱、供应链协同效率低等问题。天水天轲零部件作为一家年产值约700万元的小型制造企业&#xff0c;其痛点具有行业典型性&#xff1a; 研发数据分散&#xff1a…

Linux(8)——进程(控制篇——上)

目录 ​编辑 一、进程创建 1.fork函数的回顾 2.fork的返回值 3.写时拷贝 4.fork的常规用法 5.fork调用失败的原因 二、进程终止 1.进程退出的场景 2.进程常见的退出方法 3.进程退出码 4.进程正常退出 1&#xff09;_exit函数 2&#xff09;exit函数 3&#xff…

万亿小吃市场背后:冷链配送如何破解连锁门店“到店难题”?

在餐饮行业连锁化率突破23%、小吃快餐品类占据连锁门店半壁江山的今天&#xff0c;冷链配送已成为支撑品牌扩张的隐形基础设施。从田间到餐桌&#xff0c;从中央厨房到终端门店&#xff0c;冷链物流的每一次温度波动都直接关联着消费者的味蕾体验与品牌口碑。本文将解析冷链配送…

基于Java+MySQL 实现(Web)企业信息展示系统

基于java web企业信息展示系统设计和实现 摘要 随着企业经营环境的不断变化和竞争的口益加剧&#xff0c;企业经营管理水平的提高已成当务之急&#xff0c;人力资源管理作为企业管理中最重要的部分&#xff0c;其水平的高低已成企业发展的关键因素。随着计算机技术特别是互联…

11.2 java语言执行浅析3美团面试追魂七连问

美团面试追魂七连问&#xff1a;关于Object o New Object() ,1请解释一下对象的创建过程(半初始化) 2,加问DCL要不要volatile 问题(指令重排) 3.对象在内存中的存储布局(对象与数组的存储不同),4.对象头具体包括什么.5.对象怎么定位.6.对象怎么分配(栈-线程本地-Eden-Old)7.在…

SpringBoot+Vue+微信小程序校园自助打印系统

概述​​ 校园自助打印系统是现代化校园建设中不可或缺的一部分&#xff0c;基于SpringBootVue微信小程序开发的​​免费Java源码​​项目&#xff0c;包含完整的用户预约、打印店管理等功能模块。 ​​主要内容​​ ​​ 系统功能模块​​ ​​登录验证模块​​&#xff1a;…

特伦斯 S75 电钢琴:奏响极致音乐体验的华丽乐章

在音乐爱好者增多、音乐教育普及&#xff0c;以及科技进步的推动下&#xff0c;电钢琴市场蓬勃发展。其在技术、品质和应用场景上变化巨大&#xff0c;高端化、个性化产品受青睐&#xff0c;应用场景愈发多元。在此背景下&#xff0c;特伦斯 S75 电钢琴以卓越性能和独特设计&am…

OpenCV---pointPolygonTest

一、基本概念与用途 pointPolygonTest 是 OpenCV 中用于判断点与多边形关系的重要函数&#xff0c;常用于&#xff1a; 目标检测&#xff1a;判断像素点是否属于检测到的轮廓区域碰撞检测&#xff1a;检测物体是否重叠图像分割&#xff1a;确定点是否在分割区域内几何分析&am…

深入详解DICOMweb:WADO与STOW-RS的技术解析与实现

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家、CSDN平台优质创作者&#xff0c;高级开发工程师&#xff0c;数学专业&#xff0c;10年以上C/C, C#, Java等多种编程语言开发经验&#xff0c;拥有高级工程师证书&#xff1b;擅长C/C、C#等开发语言&#xff0c;熟悉Java常用开…

20250530-C#知识:万物之父Object

C#知识&#xff1a;万物之父Object Object类&#xff08;即object&#xff09;是所有类的基类&#xff0c;这里面的方法还是需要好好了解一下。 1、Object类 是顶级父类&#xff0c;其他类默认都是Object类的子类&#xff08;自定义类也会默认继承Object类&#xff09;可以用O…

ollama国内安装使用

解决国内下载慢和安装卡住问题 docker安装-优先推荐 https://hub.docker.com/r/ollama/ollama/tags docker pull ollama/ollama:latestGitHub 镜像加速 改安装脚本、使用 GitHub 镜像和文件加速服务 https://defagi.com/ai-case/ollama-installation-guide-china/ modelsco…

阻塞队列的学习以及模拟实现一个阻塞队列

前言 今天上午学习了阻塞队列。之前在数据结构的时候&#xff0c;学过队列。把队列放在多线程中&#xff0c;对队列会有新的体会。我自己也实现了一个阻塞队列结合生产消费模型&#xff0c;希望对于大家有帮助~ 阻塞队列的相关知识 结语 本次的分享就结束啦。端午安康~