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:
+211
-41
@@ -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校验函数
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user