diff --git a/bootloader/Core/Src/main.c b/bootloader/Core/Src/main.c index f193a8f..9554f32 100644 --- a/bootloader/Core/Src/main.c +++ b/bootloader/Core/Src/main.c @@ -175,50 +175,43 @@ int main(void) // 如果没按下KEY1, 且有APP程序, 则运行APP, 没有APP则 else { - uint32_t data1, data2; - char *str_flag; - uint32_t address = 0x08008000; // Flash 中数据的起始地址 + UpgradeInfo_t app_info; + pFunction Jump_To_Application; - // 读取地址为 0x08008000 的数据 - data1 = *(uint32_t *)address; + // 1. 从独立的校验区(Sector 3)读取升级信息结构体 + memcpy(&app_info, (void*)UPGRADE_INFO_ADDRESS, sizeof(UpgradeInfo_t)); - // 读取地址为 0x08008004 的数据 - data2 = *(uint32_t *)(address + sizeof(uint32_t)); - - // 将数据转换为字符数组 - char str1[5], str2[5]; - memcpy(str1, &data1, sizeof(data1)); - memcpy(str2, &data2, sizeof(data2)); - str1[4] = '\0'; - str2[4] = '\0'; - - // 拼接两个字符数组 - char combined_str[9]; - strcpy(combined_str, str1); - strcat(combined_str, str2); - - // 检查是否与 "APP FLAG" 相同 - if (strcmp(combined_str, "APP FLAG") == 0) + // 2. 检查标志是否有效 (魔法字和完成状态) + if (app_info.magic_word == MAGIC_WORD && app_info.upgrade_status == UPGRADE_STATUS_COMPLETE) { - // 如果相同则跳转 - USB_PutString("APP FLAG OK, jump to app\r\n"); - //user code here - SysTick->CTRL = 0X00;//禁止SysTick - SysTick->LOAD = 0; - SysTick->VAL = 0; - __disable_irq(); + // 3. 校验APP固件的完整性 + uint32_t current_crc = Calculate_CRC32(APPLICATION_ADDRESS, app_info.new_app_size); - //set JumpAddress - JumpAddress = *(__IO uint32_t*) (APPLICATION_ADDRESS + 4); - /* Jump to user application */ - Jump_To_Application = (pFunction) JumpAddress; - /* Initialize user application's Stack Pointer */ - __set_MSP(*(__IO uint32_t*) APPLICATION_ADDRESS); - Jump_To_Application(); + if (current_crc == app_info.new_app_crc32) + { + // 4. 校验成功,执行跳转 + USB_PutString("Valid APP found, jumping to application...\r\n"); + // 获取APP的堆栈指针和跳转地址 + uint32_t JumpAddress = *(__IO uint32_t*) (APPLICATION_ADDRESS + 4); + Jump_To_Application = (pFunction) JumpAddress; + // 在跳转前反初始化所有Bootloader用过的外设 + USER_USB_DEVICE_DeInit(); + HAL_RCC_DeInit(); + HAL_DeInit(); + SysTick->CTRL = 0; + SysTick->LOAD = 0; + SysTick->VAL = 0; + __disable_irq(); + + // 设置APP的堆栈指针并跳转 + __set_MSP(*(__IO uint32_t*) APPLICATION_ADDRESS); + Jump_To_Application(); + } } // no legal APP else { + USB_PutString("No App found, enter firmware update mode\r\n"); LCD_ShowString(74, LCD_H/3, (uint8_t*)"No App!", WHITE, BLACK, 24, 0);//12*6,16*8,24*12,32*16 LCD_ShowString(24, LCD_H/3+48, (uint8_t*)"Plz Download APP", WHITE, BLACK, 24, 0); HAL_Delay(2000); diff --git a/bootloader/Ymodem/common.c b/bootloader/Ymodem/common.c index 57ffad6..ff7c5ae 100644 --- a/bootloader/Ymodem/common.c +++ b/bootloader/Ymodem/common.c @@ -325,5 +325,22 @@ void GetInputString (uint8_t * buffP) buffP[bytes_read] = '\0'; } +/** + * @brief Calculates the CRC32 of a given memory area. + * @param start_address: Start address of the data + * @param size: Size of the data in bytes + * @retval Calculated CRC32 value + */ +uint32_t Calculate_CRC32(uint32_t start_address, uint32_t size) +{ + // ??CRC???? + __HAL_RCC_CRC_CLK_ENABLE(); + CRC_HandleTypeDef CrcHandle; + CrcHandle.Instance = CRC; + HAL_CRC_Init(&CrcHandle); + + return HAL_CRC_Calculate(&CrcHandle, (uint32_t*)start_address, size / 4); +} + /*******************(C)COPYRIGHT 2011 STMicroelectronics *****END OF FILE******/ diff --git a/bootloader/Ymodem/common.h b/bootloader/Ymodem/common.h index 9feee3f..7492c8d 100644 --- a/bootloader/Ymodem/common.h +++ b/bootloader/Ymodem/common.h @@ -46,6 +46,20 @@ #define USBPutString(x) USB_PutString((uint8_t*)(x)) +// 定义升级信息结构体 +typedef struct { + uint32_t magic_word; // 魔法字,如 0xDEADBEEF,用于标识此结构体有效 + uint32_t upgrade_status; // 升级状态标志 + uint32_t new_app_size; // 新APP的固件大小 + uint32_t new_app_crc32; // 新APP的CRC32校验和 +} UpgradeInfo_t; + +// 定义升级状态 +#define UPGRADE_STATUS_NONE 0xFFFFFFFF +#define UPGRADE_STATUS_START 0xABCD1234 +#define UPGRADE_STATUS_COMPLETE 0x5A5A5A5A +#define MAGIC_WORD 0xDEADBEEF + /* Exported functions ------------------------------------------------------- */ void Int2Str(uint8_t* str,int32_t intnum); uint32_t Str2Int(uint8_t *inputstr,int32_t *intnum); @@ -55,9 +69,7 @@ uint8_t GetKey(void); void USB_PutChar(uint8_t c); void USB_PutString(char *s); void GetInputString(uint8_t * buffP); - -//???? - +uint32_t Calculate_CRC32(uint32_t start_address, uint32_t size); #endif /* __COMMON_H */ diff --git a/bootloader/Ymodem/flash_if.h b/bootloader/Ymodem/flash_if.h index 12ddb68..14dde77 100644 --- a/bootloader/Ymodem/flash_if.h +++ b/bootloader/Ymodem/flash_if.h @@ -48,21 +48,15 @@ #define USER_FLASH_SIZE (USER_FLASH_END_ADDRESS - APPLICATION_ADDRESS + 1) /* Define the address from where user application will be loaded. - Note: the 1st sector 0x08000000-0x08003FFF is reserved for the IAP code */ -#define APPLICATION_ADDRESS (uint32_t)0x0800C000 + Note: the 1st sector 0x08000000-0x0800FFFF is reserved for the IAP code */ +#define APPLICATION_ADDRESS ADDR_FLASH_SECTOR_4 + +/* Sector 3 (16KB) 被保留用作升级校验区 */ +#define UPGRADE_INFO_SECTOR_ADDR ADDR_FLASH_SECTOR_3 +#define UPGRADE_INFO_SECTOR_NUM FLASH_SECTOR_3 +#define UPGRADE_INFO_ADDRESS UPGRADE_INFO_SECTOR_ADDR /* Exported types ------------------------------------------------------------*/ - -#define UPGRADE_INFO_ADDRESS (USER_FLASH_END_ADDRESS - sizeof(UpgradeInfo_t) + 1) -// 定义升级信息结构体 -typedef struct { - uint32_t magic_word; // 魔法字,如 0xDEADBEEF,用于标识此结构体有效 - uint32_t upgrade_status; // 升级状态标志 - uint32_t new_app_size; // 新APP的固件大小 - uint32_t new_app_crc32; // 新APP的CRC32校验和 -} UpgradeInfo_t; - - /* Exported macro ------------------------------------------------------------*/ /* Exported functions ------------------------------------------------------- */ void FLASH_If_Init(void); diff --git a/bootloader/Ymodem/menu.c b/bootloader/Ymodem/menu.c index c32058a..da5f6b1 100644 --- a/bootloader/Ymodem/menu.c +++ b/bootloader/Ymodem/menu.c @@ -40,11 +40,6 @@ /* Private typedef -----------------------------------------------------------*/ /* Private define ------------------------------------------------------------*/ -// 定义升级状态 -#define UPGRADE_STATUS_NONE 0xFFFFFFFF -#define UPGRADE_STATUS_START 0xABCD1234 -#define UPGRADE_STATUS_COMPLETE 0x5A5A5A5A - /* Private macro -------------------------------------------------------------*/ /* Private variables ---------------------------------------------------------*/ pFunction Jump_To_Application; @@ -68,11 +63,9 @@ void USB_Download(void); */ static void Write_Upgrade_Info(UpgradeInfo_t* info) { - // 假设校验区在最后一个扇区 (Sector 7 for 512KB device) - // 注意:擦除会擦除整个扇区,如果扇区很大,需要先备份再写入 - // 为简化,我们直接擦除并写入 - FLASH_If_Erase_One_Sector(7); - + // 1. 擦除专门用于校验的 Sector 3 + FLASH_If_Erase_One_Sector(UPGRADE_INFO_SECTOR_NUM); + // 2. 写入升级信息 uint32_t flash_address = UPGRADE_INFO_ADDRESS; FLASH_If_Write((__IO uint32_t*)&flash_address, (uint32_t*)info, sizeof(UpgradeInfo_t) / 4); } @@ -87,21 +80,16 @@ static void Read_Upgrade_Info(UpgradeInfo_t* info) memcpy(info, (void*)UPGRADE_INFO_ADDRESS, sizeof(UpgradeInfo_t)); } -/** - * @brief Calculates the CRC32 of a given memory area. - * @param start_address: Start address of the data - * @param size: Size of the data in bytes - * @retval Calculated CRC32 value - */ -static uint32_t Calculate_CRC32(uint32_t start_address, uint32_t size) +// Int-to-Hex函数 +static void Int2Hex(uint8_t* str, uint32_t intnum) { - // 启用CRC外设时钟 - __HAL_RCC_CRC_CLK_ENABLE(); - CRC_HandleTypeDef CrcHandle; - CrcHandle.Instance = CRC; - HAL_CRC_Init(&CrcHandle); - - return HAL_CRC_Calculate(&CrcHandle, (uint32_t*)start_address, size / 4); + const char hex_chars[] = "0123456789ABCDEF"; + for (int i = 0; i < 8; i++) + { + str[7 - i] = hex_chars[intnum & 0x0F]; + intnum >>= 4; + } + str[8] = '\0'; } /** @@ -134,12 +122,11 @@ void USB_Download(void) USB_PutString("\n\n\r File reception complete. Verifying...\n\r"); // 4. 最终校验 - // 理想情况下,这里应该有一个从上位机获取的CRC32值进行对比 - // 作为演示,我们只计算并保存 + // 理想情况下,这里应该有一个从上位机获取的CRC32值进行对比, 此处不对比 uint32_t calculated_crc = Calculate_CRC32(APPLICATION_ADDRESS, file_size); // 5. 写入校验信息到Flash末尾 - received_info.magic_word = 0xDEADBEEF; + received_info.magic_word = MAGIC_WORD; received_info.upgrade_status = UPGRADE_STATUS_COMPLETE; // 标记为升级完成 received_info.new_app_size = file_size; received_info.new_app_crc32 = calculated_crc; @@ -152,14 +139,15 @@ void USB_Download(void) USB_PutString(Number); USB_PutString(" Bytes\r\n"); USB_PutString(" CRC32: 0x"); - // 打印CRC值 (需要实现一个Int-to-Hex函数) + uint8_t calculated_crc_str[9]; + Int2Hex(calculated_crc_str, calculated_crc); + USB_PutString(calculated_crc_str); USB_PutString("\r\n-------------------\n"); USB_PutString("Please reboot the device.\r\n"); } else /* An error occurred while writing to Flash memory */ { - // 升级失败,清除标志区,强制下次进入Bootloader - FLASH_If_Erase_One_Sector(7); // 假设校验区在最后一个扇区 + FLASH_If_Erase_One_Sector(UPGRADE_INFO_SECTOR_NUM); // 擦除升级校验区,避免误跳转 USB_PutString("\n\rUpgrade failed!\r\n"); if (file_size == -1) { @@ -239,7 +227,11 @@ void Main_Menu(void) } else if (key == 0x33) /* execute the new program */ { - USBD_DeInit(&hUsbDeviceFS); + USB_PutString("Start to execute the user application...\r\n"); + HAL_Delay(1000); + USER_USB_DEVICE_DeInit(); + HAL_RCC_DeInit(); + HAL_DeInit(); //user code here SysTick->CTRL = 0X00;//禁止SysTick SysTick->LOAD = 0;