Files

190 lines
4.8 KiB
C

/**
* @file flash_upgrade.c
* @brief 外置 Flash 固件升级区读写(与 CCU601E_D / CCU621_IAP 布局一致)
*/
#include "flash_upgrade.h"
#include "app_init/app_init.h"
#include "wdt_task/wdt_task.h"
#include "exflash_spi4_gd25qxx.h"
#include <stdio.h>
#include <string.h>
extern U8_T s32_flash_dataflash_write(U32_T addr, U8_T *buf, U32_T len);
extern U8_T s32_flash_dataflash_read(U32_T addr, U8_T *buf, U32_T len);
extern U8_T s32_flash_dataflash_erase_sector(U32_T addr);
/* 0: 按包擦扇区;1: upgrade_erase_program_area 已整体擦除 */
static int g_upgrade_program_pre_erased = 0;
static uint8_t s_upgrade_header_buf[sizeof(upgrade_header_t)]
__attribute__((aligned(32)));
__attribute__((weak)) void upgrade_erase_yield(void)
{
}
int upgrade_init(void)
{
upgrade_header_t header;
if (upgrade_read_header(&header) == 0) {
if (header.upgrade_flag == UPGRADE_FLAG_NEED_UP) {
return 1;
}
if (header.upgrade_flag == UPGRADE_FLAG_DONE) {
return 2;
}
}
g_upgrade_program_pre_erased = 0;
return 0;
}
int upgrade_write_header(const upgrade_header_t *header)
{
if (header == NULL) {
return -1;
}
spi_flash_wait_for_write_end();
v_wdt_dog_toggle();
s32_flash_dataflash_erase_sector(HEADER_SECTOR_ADDR);
v_wdt_dog_toggle();
memcpy(s_upgrade_header_buf, header, sizeof(upgrade_header_t));
if (s32_flash_dataflash_write(HEADER_SECTOR_ADDR, s_upgrade_header_buf,
sizeof(upgrade_header_t)) != 0U) {
printf("[FW_UPGRADE] header write failed\r\n");
return -1;
}
spi_flash_wait_for_write_end();
v_wdt_dog_toggle();
return 0;
}
int upgrade_read_header(upgrade_header_t *header)
{
if (header == NULL) {
return -1;
}
if (s32_flash_dataflash_read(HEADER_SECTOR_ADDR, (U8_T *)header, sizeof(upgrade_header_t)) != 0U) {
return -1;
}
return 0;
}
int upgrade_success_update_header(upgrade_header_t *header)
{
return upgrade_write_header(header);
}
int upgrade_write_packet(uint32_t packet_index, const uint8_t *data, uint32_t data_len)
{
uint32_t packet_addr;
uint32_t sector_start;
if ((data == NULL) || (data_len == 0U) || (data_len > PACKET_SIZE)) {
return -1;
}
packet_addr = PROGRAM_START_ADDR + (packet_index * PACKET_SIZE);
if (packet_addr + data_len > UPGRADE_END_ADDR) {
return -1;
}
if (!g_upgrade_program_pre_erased) {
sector_start = (packet_addr / SECTOR_SIZE) * SECTOR_SIZE;
if ((packet_index * PACKET_SIZE) % SECTOR_SIZE == 0U) {
s32_flash_dataflash_erase_sector(sector_start);
v_wdt_dog_toggle();
mSleep(1);
}
}
if (s32_flash_dataflash_write(packet_addr, (U8_T *)data, data_len) != 0U) {
return -1;
}
return 0;
}
int upgrade_read_packet(uint32_t packet_index, uint8_t *data, uint32_t *data_len)
{
uint32_t packet_addr;
uint32_t max_read_size;
if ((data == NULL) || (data_len == NULL)) {
return -1;
}
packet_addr = PROGRAM_START_ADDR + (packet_index * PACKET_SIZE);
if (packet_addr > UPGRADE_END_ADDR) {
return -1;
}
if (s32_flash_dataflash_read(packet_addr, data, PACKET_SIZE) != 0U) {
return -1;
}
max_read_size = UPGRADE_END_ADDR - packet_addr + 1U;
if (max_read_size < PACKET_SIZE) {
*data_len = max_read_size;
} else {
*data_len = PACKET_SIZE;
}
return 0;
}
int upgrade_erase_program_area(void)
{
return upgrade_erase_program_area_for_size(PROGRAM_MAX_SIZE);
}
int upgrade_erase_program_area_for_size(uint32_t firmware_bytes)
{
uint32_t sector_addr;
uint32_t last_byte;
uint32_t last_sector;
if (firmware_bytes == 0U) {
return -1;
}
if (firmware_bytes > PROGRAM_MAX_SIZE) {
return -1;
}
last_byte = PROGRAM_START_ADDR + firmware_bytes - 1U;
if (last_byte > UPGRADE_END_ADDR) {
return -1;
}
last_sector = (last_byte / SECTOR_SIZE) * SECTOR_SIZE;
printf("[FW_UPGRADE] erase start size=%lu sectors=0x%08lX..0x%08lX\r\n",
(unsigned long)firmware_bytes,
(unsigned long)PROGRAM_START_ADDR,
(unsigned long)last_sector);
for (sector_addr = PROGRAM_START_ADDR; sector_addr <= last_sector; sector_addr += SECTOR_SIZE) {
s32_flash_dataflash_erase_sector(sector_addr);
v_wdt_dog_toggle();
mSleep(1);
upgrade_erase_yield();
if (((sector_addr - PROGRAM_START_ADDR) / SECTOR_SIZE) % 10U == 9U) {
printf("[FW_UPGRADE] erase progress at 0x%08lX\r\n",
(unsigned long)sector_addr);
}
}
printf("[FW_UPGRADE] erase done\r\n");
g_upgrade_program_pre_erased = 1;
return 0;
}