概述

產品後續維護,版本號管理是必不可少的一項,不管是開發中測試、量產、還是後期升級迭代都是需要版本號管理來區分。在此寫一篇文章做個筆錄,需要用的知識分散加載,如還不太懂這方面的知識,可去“百度”或者“deepseek”科普,這裏不再贅述。

這裏介紹有兩種方式:

1、第一種,使用__attribute__((at(ADDR_BASE))))

2、第二種,使用__attribute__((section(".version_info"))),需要在.sct文件中修改,才能使用

區別是第一種比第二種佔用空間大,後面會介紹。

一、開發環境

1、硬件平台

     STM32F401CEU6

     內部Flash : 512Kbytes,SARM : 96 Kbytes


STM32把產品信息寫入固件.hex / .bin文件中詳解(分散加載) - 指南_版本號

二、STM32CubeMx配置

 2.1、系統時鐘配置

STM32把產品信息寫入固件.hex / .bin文件中詳解(分散加載) - 指南_版本號_02

2.2、下載調試配置

STM32把產品信息寫入固件.hex / .bin文件中詳解(分散加載) - 指南_版本號_03

2.3、生成代碼

STM32把產品信息寫入固件.hex / .bin文件中詳解(分散加載) - 指南_#define_04

STM32把產品信息寫入固件.hex / .bin文件中詳解(分散加載) - 指南_#define_05

2.4、編譯工程

STM32把產品信息寫入固件.hex / .bin文件中詳解(分散加載) - 指南_#define_06

2.5、查看該型號芯片Falsh的地址、大小信息

STM32把產品信息寫入固件.hex / .bin文件中詳解(分散加載) - 指南_版本號_07

STM32把產品信息寫入固件.hex / .bin文件中詳解(分散加載) - 指南_#define_08

三、編碼         

1、main.c

/* USER CODE BEGIN 0 */
#define ENABLE_SCT	1		//需要添加 .sct文件裏面的內容才行。
/* 編譯信息結構體 - 將存儲在Flash中 */
typedef struct {
	char compile_data[12];		/* 編譯日期 "MMM DD YYYY" */
	char compile_time[10];		/* 編譯時間 "HH:MM:SS" */
	char compiler_info[10];		/* 編譯器信息 */
	char hardware_version[10];	/* 硬件版本號 */
	char firmware_version[10];	/* 軟件版本號 */
	char mcu_type[15];			/* MCU型號 */
} __attribute__((packed)) build_info_t;
//#define INFO_ADDR_BASE   (0x8000000 + 0x80000 - 0x800)	//最後的1k地址,起始地址: 0x8000000, 大小是: 0x80000(512k), 預留2k空間存儲, 有個弊端就是固件空間佔很大
#define INFO_ADDR_BASE   (0x8000000 + 0x4000)	//最後的1k地址,起始地址: 0x8000000, 偏移16k地址用來存放, 通過map得知,改個合理的地址專門存放該信息即可
/* 編譯信息實例 - 使用特定段存儲 */
//const build_info_t firmware_build_info __attribute__((section(".build_info"), used)) = {
#if ENABLE_SCT
	const build_info_t firmware_build_info __attribute__((section(".build_info"))) = {	//要在.sct文件中修改,才能使用
#else
	const build_info_t firmware_build_info __attribute__((at(INFO_ADDR_BASE + 0x00))) = {
#endif
	__DATE__,
	__TIME__,
#ifdef __ICCARM__
	"IAR-ARM",		/* IAR編譯器*/
#elif defined(__CC_ARM) || defined(__ARMCC_VERSION)
	"KEIL-MDK",		/* keil編譯器 */
#else
	"Unknown",
#endif
	"HW_V1.2.1",	/* 硬件版本 */
	"FW_V1.0.1",	/* 軟件版本 */
	"STM32F401CEUx"	/* MCU型號 */
};
/* 詳細版本信息字符串 */
//const char firmware_build_info[] __attribute__((section(".version_info"), used)) =
#if ENABLE_SCT
	const char detailed_version_info[] __attribute__((section(".version_info"))) =
#else
	const char detailed_version_info[] __attribute__((at(INFO_ADDR_BASE + 0x400))) =  // 偏移1k地址空間
#endif
	"===  heihei === \r\n"
	"Firmware Version: 1.0.1\r\n"
	"Build Data:" __DATE__ "\r\n"
	"Build TIME:" __TIME__ "\r\n"
	"Cocyright (c) 2025 heihei\r\n";
////------------------------------------------------------------------------------#include //------------------------------------------------------------------------------
//#define VERINFO_ADDR_BASE   (0x8004F00) // 版本信息在FLASH中的存放地址
//const char Hardware_Ver[] __attribute__((at(VERINFO_ADDR_BASE + 0x00)))  = "Hardware: 1.0.0";
//const char Firmware_Ver[] __attribute__((at(VERINFO_ADDR_BASE + 0x20)))  = "Firmware: 1.0.0";
//const char Compiler_Date[] __attribute__((at(VERINFO_ADDR_BASE + 0x40))) = "Date: "__DATE__;
//const char Compiler_Time[] __attribute__((at(VERINFO_ADDR_BASE + 0x60))) = "Time: "__TIME__;
////------------------------------------------------------------------------------
//volatile int test_num 	__attribute__((at(0x20018040))) = 0;
//volatile int num 		__attribute__((at(0x8080400))) = 0;
//
//void AA(void)			__attribute__((section("RAM1")));
//void AA(void)
//{
//	volatile int a = 1;
//}
//void BB(void)			__attribute__((section("ROM1")));
//void BB(void)
//{
//	volatile int test_num = 2;
//}
/* USER CODE END 0 */
int main(void)
{
  /* USER CODE BEGIN 1 */
//	void AA(void);
//		AA();
//	void BB(void);
//		BB();
//	test_num = 9;
//	num = 6;
  /* 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_USART1_UART_Init();
  MX_TIM1_Init();
  MX_IWDG_Init();
  MX_USART6_UART_Init();
  /* USER CODE BEGIN 2 */
	HAL_TIM_Base_Start_IT(&htim1);
	HAL_UART_Receive_IT_Enable();
	printf("heihei min task \r\n");
//    printf("buildData: %s\r\n", firmware_build_info.compile_data);
//    printf("buildTime: %s\r\n", firmware_build_info.compile_time);
//	printf("buildInfo: %s\r\n", firmware_build_info.compiler_info);
//	printf("firwareVersion: %s\r\n", firmware_build_info.firmware_version);
//	printf("mcu_type: %s\r\n", firmware_build_info.mcu_type);
  /* USER CODE END 2 */
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

四、結果

A、第一種方式

1、在main.c文件第 62行代碼 

#define ENABLE_SCT    1

改成

#define ENABLE_SCT    0

STM32把產品信息寫入固件.hex / .bin文件中詳解(分散加載) - 指南_#endif_09

STM32把產品信息寫入固件.hex / .bin文件中詳解(分散加載) - 指南_#define_10

2、再次編譯工程,如下所示

STM32把產品信息寫入固件.hex / .bin文件中詳解(分散加載) - 指南_版本號_11

3、編譯時間

STM32把產品信息寫入固件.hex / .bin文件中詳解(分散加載) - 指南_版本號_12

4、使用.map文件查看地址分配信息

STM32把產品信息寫入固件.hex / .bin文件中詳解(分散加載) - 指南_#define_13

5、使用ST- LINK 查看hex文件內容

STM32把產品信息寫入固件.hex / .bin文件中詳解(分散加載) - 指南_版本號_14

STM32把產品信息寫入固件.hex / .bin文件中詳解(分散加載) - 指南_#endif_15

STM32把產品信息寫入固件.hex / .bin文件中詳解(分散加載) - 指南_#endif_16

STM32把產品信息寫入固件.hex / .bin文件中詳解(分散加載) - 指南_版本號_17

6、使用軟件debug模式,查看內容信息

STM32把產品信息寫入固件.hex / .bin文件中詳解(分散加載) - 指南_版本號_18

STM32把產品信息寫入固件.hex / .bin文件中詳解(分散加載) - 指南_版本號_19

B、第二種方式

1、在main.c文件第 62行代碼 

#define ENABLE_SCT    1

改成

#define ENABLE_SCT    0

STM32把產品信息寫入固件.hex / .bin文件中詳解(分散加載) - 指南_#endif_20

2、找到.sct文件,重新命名避免原文件的覆蓋。

STM32把產品信息寫入固件.hex / .bin文件中詳解(分散加載) - 指南_#endif_21

STM32把產品信息寫入固件.hex / .bin文件中詳解(分散加載) - 指南_#endif_22

3、修改.sct文件內容

STM32把產品信息寫入固件.hex / .bin文件中詳解(分散加載) - 指南_#endif_23

STM32把產品信息寫入固件.hex / .bin文件中詳解(分散加載) - 指南_#endif_24

; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************
LR_IROM1 0x08000000 0x00080000  {    ; load region size_region
  ER_IROM1 0x08000000 0x00080000  {  ; load address = execution address
   *.o (RESET, +First)
   *(InRoot$$Sections)
   .ANY (+RO)
   .ANY (+XO)
  }
  ; 新增代碼 start
  ER_BUILD_INFO 0x08040000 0x1000 {
	main.o (.build_info, +First) ;
  }
  ER_VERSION_INFO 0x08050000 0x1000 {
	main.o (.version_info, +First) ;
  }
  ; 新增代碼 end
  RW_IRAM1 0x20000000 0x00018000  {  ; RW data
   .ANY (+RW +ZI)
  }
}

4、同理上面都修改好後,再次編譯工程。

STM32把產品信息寫入固件.hex / .bin文件中詳解(分散加載) - 指南_版本號_25

STM32把產品信息寫入固件.hex / .bin文件中詳解(分散加載) - 指南_#endif_26

5、使用.map文件查看地址分配信息

STM32把產品信息寫入固件.hex / .bin文件中詳解(分散加載) - 指南_版本號_27

6、使用ST-LINK 查看hex固件內容

STM32把產品信息寫入固件.hex / .bin文件中詳解(分散加載) - 指南_版本號_28

STM32把產品信息寫入固件.hex / .bin文件中詳解(分散加載) - 指南_#endif_29

五、總結

        好了,講解完畢,希望能幫助到大家,蟹蟹參閲。

參考文章:1、

3、大佬B站視頻分享https://www.bilibili.com/video/BV12BWzzAEav/?spm_id_from=333.1391.0.0&vd_source=9333592be49ce686d634d8027764755c