修复BOOT丢帧问题,优化标志位的存储

This commit is contained in:
cbb
2026-03-08 01:08:27 +08:00
parent 1e6d47ddae
commit 26cf5af14f
65 changed files with 2290 additions and 2174 deletions
+60 -52
View File
@@ -2,11 +2,11 @@
#include "Can.h"
#include "aes128.h"
#include "config.h"
#include "core_cmFunc.h"
#include "gd32c10x.h" // 主头文件,包含了gd32c10x_crc.h的内容
#include "gd32c10x_fmc.h"
#include "initial.h"
#include "systick.h"
#include <cstdio>
#include <cstring>
#include <stdint.h>
extern CAN_transmiter CAN0_transmiter; // CAN初始化
@@ -28,13 +28,14 @@ inline fmc_state_enum write_ADDRESS(u32 address, u32 data) {
/**
* @brief 设置OTA配置参数到Flash
*
*
* 此函数用于更新存储在Flash中的OTA相关标志位(如APP可用、启用、校验等)。
* GD32的Flash特性是:只能将1写为0,不能将0写为1。若要将0变为1,必须先擦除整个页面。
* 因此,本函数通过读取同一页内的所有参数,擦除该页,然后重新写入有效的参数来实现“写1”操作。
*
*
* @param addr: 要设置的Flash地址
* @param data: 要写入的数据 (通常为OTA_AVAL=0x00000000 或 OTA_NOT_AVAL=0xFFFFFFFF)
* @param data: 要写入的数据 (通常为OTA_AVAL=0x00000000 或
* OTA_NOT_AVAL=0xFFFFFFFF)
* @retval FLASH_EEPROM_OK (0) 表示成功, 其他值表示失败
*/
u8 OTA_SET(u32 addr, u32 data) {
@@ -59,7 +60,6 @@ u8 OTA_SET(u32 addr, u32 data) {
}
// 3. 对于需要将0改回1的操作,必须先擦除整个Flash页
// 首先读取同一页内所有相关配置参数的当前状态
flash_ptr = (volatile u32 *)n_APP_LATEST_AVAL_ADDR;
temp_val[0] = *flash_ptr;
flash_ptr = (volatile u32 *)n_APP_BACKUP_AVAL_ADDR;
@@ -74,11 +74,12 @@ u8 OTA_SET(u32 addr, u32 data) {
temp_val[5] = *flash_ptr;
#if EEP_DEBUG
printf("OTA_SET - Start updating configuration\r\n");
printf("OTA_prepare write%08x at %08x\r\n", data, addr);
// 修复:完整输出所有6个配置项的值,便于调试
printf("LatestAval:0x%x, BackupAval:0x%x, LatestEn:0x%x, "
"BackupEn:0x%x, LatestCheck:0x%x, BackupCheck:0x%x\r\n",
temp_val[0], temp_val[1], temp_val[2], temp_val[3], temp_val[4], temp_val[5]);
temp_val[0], temp_val[1], temp_val[2], temp_val[3], temp_val[4],
temp_val[5]);
#endif
// 4. 擦除包含所有配置参数的Flash页
@@ -90,35 +91,37 @@ u8 OTA_SET(u32 addr, u32 data) {
return FLASH_EEPROM_ERROR;
}
// 5. 重新写入所有之前为有效(OTA_AVAL)的配置项
// 注意:不包括当前正在设置的地址,因为它将在最后单独处理
// 5. 重新写入所有之前读取的配置项值,只有0改F需要写,所以最后不用写
for (int i = 0; i < OTA_CONFIG_NUM; i++) {
u32 current_addr = n_APP_LATEST_AVAL_ADDR + 4 * i;
if (temp_val[i] == OTA_AVAL && current_addr != addr) {
fmc_status = write_ADDRESS(current_addr, OTA_AVAL);
if (fmc_status != FMC_READY) {
#if EEP_DEBUG
printf("OTA_SET - Write backup value failed at 0x%08X!\r\n", current_addr);
#endif
return FLASH_EEPROM_ERROR;
}
if (current_addr != addr and temp_val[i] != OTA_NOT_AVAL) {
fmc_status = write_ADDRESS(current_addr, temp_val[i]);
}
}
// 6. 最后,写入本次调用的目标数据
// 即使addr为0(理论上无效),也检查一下以避免潜在问题
if (addr != 0) {
fmc_status = write_ADDRESS(addr, data);
if (fmc_status != FMC_READY) {
#if EEP_DEBUG
printf("OTA_SET - Final write to target address 0x%08X failed!\r\n", addr);
// 3. 对于需要将0改回1的操作,必须先擦除整个Flash页
flash_ptr = (volatile u32 *)n_APP_LATEST_AVAL_ADDR;
temp_val[0] = *flash_ptr;
flash_ptr = (volatile u32 *)n_APP_BACKUP_AVAL_ADDR;
temp_val[1] = *flash_ptr;
flash_ptr = (volatile u32 *)n_APP_LATEST_EN_ADDR;
temp_val[2] = *flash_ptr;
flash_ptr = (volatile u32 *)n_APP_BACKUP_EN_ADDR;
temp_val[3] = *flash_ptr;
flash_ptr = (volatile u32 *)n_APP_LATEST_CHECK_ADDR;
temp_val[4] = *flash_ptr;
flash_ptr = (volatile u32 *)n_APP_BACKUP_CHECK_ADDR;
temp_val[5] = *flash_ptr;
// 修复:完整输出所有6个配置项的值,便于调试
printf("LatestAval:0x%x, BackupAval:0x%x, LatestEn:0x%x, "
"BackupEn:0x%x, LatestCheck:0x%x, BackupCheck:0x%x\r\n",
temp_val[0], temp_val[1], temp_val[2], temp_val[3], temp_val[4],
temp_val[5]);
#endif
return FLASH_EEPROM_ERROR;
}
}
return FLASH_EEPROM_OK;
}
/**
* @brief 从4字节数组中提取一个32位无符号整数
* @param array: 4字节数组
@@ -208,12 +211,7 @@ void OTAHandler::jumpToApplication() {
#if DEBUG_OTA
printf("try jump to app\r\n");
if (!validateApplication()) {
printf("app valid failed\r\n");
return;
} else {
printf("valid result:successful\r\n");
u8 check_data[2] = {0x0A, 0xAC};
CAN0_transmiter.CANFD_AsyncSend(CANFD_OTA_WAIT_ID, 2, check_data);
}
printf("jumping1\r\n");
#endif
@@ -222,8 +220,6 @@ void OTAHandler::jumpToApplication() {
OTA_SET(n_APP_LATEST_EN_ADDR, OTA_AVAL); // 设置APP为激活
fmc_lock();
// 1. 关闭所有中断
__disable_irq();
for (int i = 0; i < 8; i++) {
NVIC->ICER[i] = 0xFFFFFFFF;
}
@@ -260,9 +256,7 @@ void OTAHandler::jumpToApplication() {
printf("jumping5, MSP:0x%08X, Reset Handler:0x%08X\r\n", msp_value,
reset_handler);
#endif
__set_MSP(msp_value);
// 在跳转前清除复位标志
rcu_all_reset_flag_clear();
// 7. 跳转
@@ -280,35 +274,39 @@ void OTAHandler::jumpToApplication() {
* @retval 无
*/
void OTAHandler::eraseApplicationArea() {
// 擦除APP区域
fmc_unlock();
OTA_SET(n_APP_LATEST_CHECK_ADDR, OTA_NOT_AVAL); // 设置APP为未确认
OTA_SET(n_APP_LATEST_EN_ADDR, OTA_NOT_AVAL); // 设置APP为未激活
OTA_SET(n_APP_LATEST_AVAL_ADDR, OTA_NOT_AVAL); // 设置APP为不可用
// 擦除前禁用中断,防止中断处理程序执行期间发生Flash操作导致问题
__disable_irq();
fmc_unlock();
fmc_state_enum fmc_status;
for (u32 addr = APPLATEST_START_ADDR;
addr < (APPLATEST_START_ADDR + APP_MAX_SIZE); addr += FMC_PAGE_SIZE) {
fmc_flag_clear(FMC_FLAG_PGERR | FMC_FLAG_PGAERR | FMC_FLAG_WPERR);
fmc_status = fmc_page_erase(addr);
if (fmc_status != FMC_READY) {
// 如果擦除失败,记录错误并退出
#if DEBUG_OTA
printf("Flash erase failed at address 0x%08X, status: %d\r\n", addr,
fmc_status);
delay_1ms(5000);
#endif
ota_error = OTA_ERROR_FLASH_ERROR;
send_error_frame(OTA_ERROR_FLASH_ERROR);
break;
} else {
#if DEBUG_OTA
printf("Flash erase SUCCESS\r\n");
#endif
}
}
// 重新启用中断
__enable_irq();
fmc_lock();
}
@@ -322,13 +320,17 @@ void OTAHandler::eraseApplicationArea() {
void OTAHandler::writeApplicationData(u32 offset, u8 *data, u32 size) {
fmc_unlock();
u32 write_addr = APPLATEST_START_ADDR + offset;
fmc_state_enum fmc_state;
u32 i = 0;
u8 *src = data;
// 32位对齐写入 - 处理完整的32位字
for (; i <= size - 4; i += 4) {
fmc_word_program(write_addr + i, *(u32 *)&src[i]);
fmc_state = fmc_word_program(write_addr + i, *(u32 *)&src[i]);
if (fmc_state != FMC_READY) {
printf("FMC_WRITE_ERROR\r\n");
}
}
// 处理剩余字节(如果有的话)
@@ -355,7 +357,16 @@ void OTAHandler::writeApplicationData(u32 offset, u8 *data, u32 size) {
* @retval 无
*/
void OTAHandler::handleOTAMessage(u32 id, u8 *data, u8 len) {
if (id == CANFD_OTA_DATA_ID) {
if (id == CANFD_OTA_CANCEL_ID) {
// 取消OTA过程
ota_state = OTA_STATE_IDLE;
ota_time = 0;
ota_error = OTA_ERROR_NONE;
#if DEBUG_OTA
printf("OTA process cancelled by CANFD_OTA_CANCEL_ID\r\n");
#endif
return;
} else if (id == CANFD_OTA_DATA_ID) {
ota_time = 0;
if (len == 64 and ota_state == OTA_STATE_RECEIVING_FIRMWARE) {
#if DEBUG_OTA
@@ -435,7 +446,6 @@ void OTAHandler::handleOTAMessage(u32 id, u8 *data, u8 len) {
}
u8 send_data[6] = {0xBA, 0xC0, 0x00,
0x00, 0x00, 0x00}; // 确认开始传输
eraseApplicationArea();
// 发送接收包0请求
CAN0_transmiter.CANFD_AsyncSend(CANFD_OTA_ACK_ID, 6, send_data);
@@ -444,10 +454,7 @@ void OTAHandler::handleOTAMessage(u32 id, u8 *data, u8 len) {
#if DEBUG_OTA
printf("stage--:OTA_STATE_FINISHED\r\n");
#endif
u8 send_data[2] = {0x0A, 0xAC}; // 确认开始传输
// 4. 验证成功 - 发送最终ACK
CAN0_transmiter.CANFD_AsyncSend(CANFD_OTA_ACK_ID, 2, send_data);
;
} else {
ota_error = OTA_ERROR_INVALID_PACKET;
ota_state = OTA_STATE_IDLE;
@@ -602,6 +609,7 @@ void getDeviceSerialNumberString(char *str) {
fmc_state_enum move_app_data() {
fmc_state_enum fmc_status = FMC_READY;
scanAppFlashContent();
// 关闭全局中断以防止Flash操作期间的中断干扰
__disable_irq();
fmc_unlock();
@@ -628,7 +636,7 @@ fmc_state_enum move_app_data() {
// 复制数据 - 按字(32位)进行复制以提高效率
uint32_t offset = 0;
uint32_t write_count = 0; // 记录实际写入的字数
const uint32_t *src_ptr = (const uint32_t *)APPBACK_START_ADDR; // 从备份区域读取
const uint32_t *src_ptr = (const uint32_t *)APPBACK_START_ADDR;
// 预计算源数据的CRC,避免重复访问内存
crc_deinit();
@@ -637,7 +645,7 @@ fmc_state_enum move_app_data() {
APP_MAX_SIZE / 4);
while (offset < APP_MAX_SIZE) {
uint32_t src_data = src_ptr[offset / 4]; // 从备份区域读取数据
uint32_t src_data = src_ptr[offset / 4];
// 检查源地址是否为有效的Flash数据(非0xFFFFFFFF表示有数据)
if (src_data != 0xFFFFFFFF) {
@@ -646,7 +654,7 @@ fmc_state_enum move_app_data() {
FMC_FLAG_PGERR);
fmc_status =
fmc_word_program(APPLATEST_START_ADDR + offset, src_data); // 写入到最新APP区域
fmc_word_program(APPLATEST_START_ADDR + offset, src_data);
// 检查写入操作是否成功
if (fmc_status != FMC_READY) {
@@ -763,4 +771,4 @@ void calculate_crc32_with_key(const uint8_t *key, const uint8_t *data,
output[1] = (uint8_t)(crc >> 8);
output[2] = (uint8_t)(crc >> 16);
output[3] = (uint8_t)(crc >> 24);
}
}