refactor(build): 支持A/B分区逻辑

移除sys/flash.h、sys/flash.cpp、sys/initial.h和sys/OTA相关文件的
引用,清理cproject.yml和cbuild.yml中的未使用组件和文件配置。

BREAKING CHANGE: 移除了FlashEEPROM相关功能和接口。
This commit is contained in:
cbb
2026-01-05 00:52:20 +08:00
parent 2f482554f0
commit c7c4451d57
28 changed files with 1676 additions and 1569 deletions
+211 -41
View File
@@ -7,22 +7,96 @@
#include "systick.h"
#include <cstdio>
#include <cstring>
#include <flash.h>
#include <stdint.h>
extern CAN_transmiter CAN0_transmiter; // CAN初始化
extern FlashEEPROM flashEEP;
OTAHandler ota;
extern "C" {
void canfd_rx_irq_handler(void);
}
inline fmc_state_enum write_ADDRESS(u32 address, u32 data) {
fmc_unlock();
fmc_flag_clear(FMC_FLAG_PGERR | FMC_FLAG_PGAERR | FMC_FLAG_WPERR);
// 确保使用对齐地址
fmc_state_enum fmc_status = fmc_word_program(address, data);
fmc_lock();
return fmc_status;
}
u8 OTA_SET(u32 addr, u32 data) {
fmc_state_enum fmc_status;
u32 temp_val[OTA_CONFIG_NUM];
volatile u32 *flash_ptr = (volatile u32 *)addr;
temp_val[0] = *flash_ptr;
if (temp_val[0] == data) { // 如果相同
return FLASH_EEPROM_OK; // 成功
}
fmc_unlock();
// 如果不同,且要写0,直接写
if (data == OTA_AVAL) {
fmc_status = write_ADDRESS(addr, data);
fmc_lock();
if (fmc_status == FMC_READY) {
return FLASH_EEPROM_OK; // 成功可以直接退出
}
}
// 如果不同或写入出错,要写1,需要重置,然后再写
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;
#if EEP_DEBUG
printf("OTA_SET\r\n");
printf("0x%x_0x%x_0x%x_0x%x\r\n", temp_val[0], temp_val[1], temp_val[2],
temp_val[3]);
#endif
fmc_status = fmc_page_erase(n_APP_LATEST_AVAL_ADDR); // 擦除页
if (fmc_status != FMC_READY) {
return FLASH_EEPROM_ERROR; // 擦除错误退出
}
for (int i = 0; i < OTA_CONFIG_NUM; i++) {
if (temp_val[i] == OTA_AVAL and
n_APP_LATEST_AVAL_ADDR + 4 * i != addr) {
fmc_status = write_ADDRESS(n_APP_LATEST_AVAL_ADDR + 4 * i,
OTA_AVAL); // 把需要写入0的写入0
if (fmc_status != FMC_READY) {
fmc_lock();
return FLASH_EEPROM_ERROR; // 写入错误退出
}
}
}
fmc_lock();
return FLASH_EEPROM_OK;
}
/**
* @brief 从4字节数组中提取一个32位无符号整数
* @param array: 4字节数组
* @retval 32位无符号整数
*/
static inline uint32_t extract_u32_from_4bytes(const uint8_t *array) {
return ((uint32_t)array[3] << 24) | ((uint32_t)array[2] << 16) |
((uint32_t)array[1] << 8) | (uint32_t)array[0];
}
void OTAHandler::init() {}
/**
* @brief OTA处理函数
* @param 无
* @retval 无
*/
void OTAHandler::process() {
if (ota_state == OTA_STATE_IDLE) {
ota_time = 0; // 重置计时器
@@ -43,27 +117,36 @@ void OTAHandler::process() {
ota_time = 0;
ota_state = OTA_STATE_IDLE;
ota_error = OTA_ERROR_TIMEOUT;
send_error_frame(OTA_ERROR_TIMEOUT); // 验证失败
volatile u32 *flash_ptr =
(volatile u32 *)n_APP_LATEST_CHECK_ADDR; // 如果是实际可以运行
u32 if_checked = *flash_ptr;
flash_ptr = (volatile u32 *)n_APP_LATEST_AVAL_ADDR; // 如果是实际已刷入
u32 if_aval = *flash_ptr;
send_error_frame(OTA_ERROR_TIMEOUT); // OTA超时
if (if_checked == OTA_AVAL and if_aval == OTA_AVAL) {
OTA_SET(n_APP_LATEST_AVAL_ADDR,
OTA_AVAL); // 实际可用,设置APP为启用
}
jumpToApplication();
}
}
bool validateApplication() {
u32 *app_vector = (u32 *)APP_START_ADDR;
u32 *app_vector = (u32 *)APPLATEST_START_ADDR;
u32 stack_ptr = app_vector[0];
u32 reset_handler = app_vector[1];
#if DEBUG_OTA
printf("APP_START_ADDR: 0x%08X\r\n", APP_START_ADDR);
printf("APPLATEST_START_ADDR: 0x%08X\r\n", APPLATEST_START_ADDR);
printf("Stack Pointer: 0x%08X\r\n", stack_ptr);
printf("Reset Handler: 0x%08X\r\n", reset_handler);
printf("APP Range: 0x%08X - 0x%08X\r\n", APP_START_ADDR,
APP_START_ADDR + APP_MAX_SIZE);
printf("APP Range: 0x%08X - 0x%08X\r\n", APPLATEST_START_ADDR,
APPLATEST_START_ADDR + APP_MAX_SIZE);
#endif
// 简单验证:检查栈指针是否在SRAM范围内
bool stack_valid = (stack_ptr >= 0x20000000 && stack_ptr < 0x20008000);
bool reset_valid = (reset_handler >= APP_START_ADDR &&
reset_handler < (APP_START_ADDR + APP_MAX_SIZE));
bool reset_valid = (reset_handler >= APPLATEST_START_ADDR &&
reset_handler < (APPLATEST_START_ADDR + APP_MAX_SIZE));
#if DEBUG_OTA
if (!stack_valid) {
@@ -77,6 +160,11 @@ bool validateApplication() {
return stack_valid && reset_valid;
}
/**
* @brief 跳转应用处理模块
* @param 无
* @retval 无
*/
void OTAHandler::jumpToApplication() {
#if DEBUG_OTA
printf("try jump to app\r\n");
@@ -90,6 +178,8 @@ void OTAHandler::jumpToApplication() {
}
printf("jumping1\r\n");
#endif
OTA_SET(n_APP_LATEST_AVAL_ADDR, OTA_AVAL); // 设置APP为可用
OTA_SET(n_APP_LATEST_EN_ADDR, OTA_AVAL); // 设置APP为激活
// 1. 关闭所有中断
__disable_irq();
for (int i = 0; i < 8; i++) {
@@ -117,11 +207,11 @@ void OTAHandler::jumpToApplication() {
printf("jumping3\r\n");
#endif
// 5. 设置中断向量表偏移到应用程序起始地址
SCB->VTOR = APP_START_ADDR;
SCB->VTOR = APPLATEST_START_ADDR;
// 6. 设置MSP并跳转
uint32_t msp_value = *(__IO uint32_t *)APP_START_ADDR;
uint32_t reset_handler = *(__IO uint32_t *)(APP_START_ADDR + 4);
uint32_t msp_value = *(__IO uint32_t *)APPLATEST_START_ADDR;
uint32_t reset_handler = *(__IO uint32_t *)(APPLATEST_START_ADDR + 4);
typedef void (*AppEntryFunc)(void);
AppEntryFunc app_entry = (AppEntryFunc)reset_handler;
#if DEBUG_OTA
@@ -151,8 +241,8 @@ void OTAHandler::eraseApplicationArea() {
__disable_irq();
fmc_state_enum fmc_status;
for (u32 addr = APP_START_ADDR; addr < (APP_START_ADDR + APP_MAX_SIZE);
addr += FMC_PAGE_SIZE) {
for (u32 addr = APPLATEST_START_ADDR;
addr < (APPLATEST_START_ADDR + APP_MAX_SIZE); addr += FMC_PAGE_SIZE) {
fmc_status = fmc_page_erase(addr);
if (fmc_status != FMC_READY) {
// 如果擦除失败,记录错误并退出
@@ -181,7 +271,7 @@ void OTAHandler::eraseApplicationArea() {
*/
void OTAHandler::writeApplicationData(u32 offset, u8 *data, u32 size) {
fmc_unlock();
u32 write_addr = APP_START_ADDR + offset;
u32 write_addr = APPLATEST_START_ADDR + offset;
u32 i = 0;
u8 *src = data;
@@ -207,29 +297,6 @@ void OTAHandler::writeApplicationData(u32 offset, u8 *data, u32 size) {
fmc_lock();
}
/**
* @brief 验证应用程序数据
* @param offset: 写入偏移量
* @param data: 原始数据指针
* @param size: 数据大小
* @retval true if verification passes, false otherwise
*/
bool OTAHandler::verifyApplicationData(u32 offset, u8 *data, u32 size) {
u32 verify_addr = APP_START_ADDR + offset;
for (u32 i = 0; i < size; i++) {
if (((u8 *)verify_addr)[i] != data[i]) {
#if DEBUG_OTA
printf("Data verification failed at offset %d, expected 0x%02X, "
"got 0x%02X\r\n",
i, data[i], ((u8 *)verify_addr)[i]);
#endif
return false;
}
}
return true;
}
/**
* @brief 处理OTA数据包
* @param id: CAN帧ID
@@ -318,7 +385,7 @@ void OTAHandler::handleOTAMessage(u32 id, u8 *data, u8 len) {
ota_state = OTA_STATE_RECEIVING_FIRMWARE;
} else if (len == 2 and ota_state == OTA_STATE_FINISHED) {
#if DEBUG_OTA
printf("stage8:OTA_STATE_FINISHED\r\n");
printf("stage--:OTA_STATE_FINISHED\r\n");
#endif
u8 send_data[2] = {0x0A, 0xAC}; // 确认开始传输
// 4. 验证成功 - 发送最终ACK
@@ -423,6 +490,12 @@ void OTAHandler::handleOTAMessage(u32 id, u8 *data, u8 len) {
}
}
/**
* @brief 发送错误帧
* @param error: 错误码
* @retval 无
*/
void send_error_frame(u8 error) {
u8 error_frame[1] = {error};
CAN0_transmiter.CANFD_AsyncSend(CANFD_OTA_ACK_ID, 1, error_frame);
@@ -462,6 +535,103 @@ void getDeviceSerialNumberString(char *str) {
str[24] = '\0'; // 确保字符串结束
}
/**
* @brief 将0x08010500地址后0xC000大小区域内的数据搬运到0x08011000地址
* @param None
* @retval fmc_state_enum: 操作状态
*/
fmc_state_enum move_app_data() {
fmc_state_enum fmc_status = FMC_READY;
// 关闭全局中断以防止Flash操作期间的中断干扰
__disable_irq();
fmc_unlock();
// 首先擦除目标地址的Flash页面
uint32_t num_pages =
(APP_MAX_SIZE + FMC_PAGE_SIZE - 1) / FMC_PAGE_SIZE; // 向上取整
for (uint32_t i = 0; i < num_pages; i++) {
uint32_t page_addr = APPLATEST_START_ADDR + i * FMC_PAGE_SIZE;
// 擦除页面
fmc_status = fmc_page_erase(page_addr);
if (fmc_status != FMC_READY) {
fmc_lock();
#if OTA_DEBUG
printf("move_app_data erase error\r\n");
#endif
__enable_irq(); // 重新开启中断
return fmc_status;
}
}
// 复制数据 - 按字(32位)进行复制以提高效率
uint32_t offset = 0;
uint32_t write_count = 0; // 记录实际写入的字数
const uint32_t *src_ptr = (const uint32_t *)APPLATEST_START_ADDR;
uint32_t *dst_ptr = (uint32_t *)APPLATEST_START_ADDR;
// 预计算源数据的CRC,避免重复访问内存
crc_deinit();
crc_data_register_reset();
uint32_t src_crc = crc_block_data_calculate(
(uint32_t *)APPBACK_START_ADDR, APP_MAX_SIZE / 4);
while (offset < APP_MAX_SIZE) {
uint32_t src_data = src_ptr[offset / 4];
// 检查源地址是否为有效的Flash数据(非0xFFFFFFFF表示有数据)
if (src_data != 0xFFFFFFFF) {
// 清除之前的标志位
fmc_flag_clear(FMC_FLAG_END | FMC_FLAG_WPERR | FMC_FLAG_PGAERR |
FMC_FLAG_PGERR);
fmc_status =
fmc_word_program(APPLATEST_START_ADDR + offset, src_data);
// 检查写入操作是否成功
if (fmc_status != FMC_READY) {
#if OTA_DEBUG
printf(
"Flash write failed at offset 0x%08X with status: %d\r\n",
offset, fmc_status);
#endif
fmc_lock();
__enable_irq(); // 重新开启中断
return fmc_status;
}
write_count++;
}
offset += 4;
// 每写入一定数量的数据后,喂狗一次
if ((offset % 4096) == 0) { // 每4KB喂狗一次
fwdgt_counter_reload();
}
}
fmc_lock();
// 重新开启全局中断
__enable_irq();
crc_data_register_reset(); // 确保CRC计算从初始状态开始
// 计算目标数据的CRC值
uint32_t dst_crc = crc_block_data_calculate(
(uint32_t *)APPLATEST_START_ADDR, APP_MAX_SIZE / 4);
// 比较CRC值,确保数据完整性
if (src_crc != dst_crc) {
#if OTA_DEBUG
printf("CRC mismatch: src_crc=0x%08X, dst_crc=0x%08X\r\n", src_crc,
dst_crc);
#endif
return (fmc_state_enum)0xFF; // CRC校验失败
}
return fmc_status;
}
/**
* 带密钥的CRC32校验函数
*