411 lines
11 KiB
C
411 lines
11 KiB
C
/*
|
|
* INCLUDE FILES
|
|
****************************************************************************************
|
|
*/
|
|
|
|
#include "Includes.h"
|
|
//#include "xinc_reg.h"
|
|
// #include "spi_flash.h"
|
|
#include "xc_drv_spi.h"
|
|
|
|
#define FLASH_PAGE_WORDS 64
|
|
#define FLASH_PAGE_SIZE 256
|
|
#define FLASH_BLOCK_SIZE 65536
|
|
#define FLASH_SECTOR_SIZE 4096
|
|
#define PAGES_SIZE 1024
|
|
|
|
|
|
volatile uint32_t param_backup_addr = ((8*1024)-256);
|
|
sboot_message *pms;
|
|
uint8_t burn_ser=0;
|
|
//sboot_message parambuffa1;
|
|
//sboot_message parambuffa2;
|
|
static uint8_t ALIGN(4) parambuffa[FLASH_PAGE_SIZE];
|
|
static uint8_t ALIGN(4) parambuffb[FLASH_PAGE_SIZE];
|
|
static uint8_t ALIGN(4) rwbuff[FLASH_PAGE_SIZE];
|
|
uint8_t spi_idx = SPI0_IDX;
|
|
uint8_t single_ota_flag=0;
|
|
|
|
|
|
typedef void (*iapfun)(void); // 定义一个函数类型的参数.
|
|
static iapfun jump2app;
|
|
//__RAM_CODE __asm void MSR_MSP(uint32_t addr) // 设置栈顶地址 addr:栈顶地址
|
|
//{
|
|
// MSR MSP, r0 // set Main Stack value
|
|
// BX r14
|
|
//}
|
|
|
|
void flash_init()
|
|
{
|
|
|
|
SPI_InitCfg_t spi_cfg = {0};
|
|
|
|
spi_cfg.Mode = SPI_MODE_MASTER;
|
|
spi_cfg.DataSize = SSI_CTRL0_DFS_LEN_8BIT;
|
|
spi_cfg.Direction = SSI_CTRL0_TMOD_WR;
|
|
spi_cfg.BaudRatePrescaler = SSI_BAUD_DIV_2;
|
|
spi_cfg.CLKPolarity = SSI_CTRL0_SCPOL_LOW;
|
|
spi_cfg.CLKPhase = SSI_CTRL0_SCPHA_LEAD;
|
|
spi_cfg.FirstBit = SPI_FirstBit_MSB;
|
|
|
|
xc_spi_init(spi_idx, &spi_cfg);
|
|
xc_spi_flash_wake_up(spi_idx);
|
|
}
|
|
|
|
static void param_overwrite(uint8_t to, uint8_t *buff,uint8_t flag)
|
|
{
|
|
uint8_t data[256];
|
|
if(flag)
|
|
{
|
|
for(int i=0; i<256; i+=2){
|
|
data[i] = buff[i+1];
|
|
data[i+1] = buff[i];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for(int i=0; i<256; i++){
|
|
data[i] = buff[i];
|
|
|
|
}
|
|
}
|
|
uint32_t addr = (to == TO_B) ? param_backup_addr : PARAM_ADDR;
|
|
xc_wdt_reload();
|
|
// SPI_WRITE_ENABLE();
|
|
FLASH_PAGE_ERASE(spi_idx, addr); // spi_flash_page_erase(addr);
|
|
FLASH_WAIT_READY;
|
|
/*write a page*/
|
|
// SPI_WRITE_ENABLE();
|
|
FLASH_WRITE_PAGE(spi_idx, addr, data);
|
|
FLASH_WAIT_READY;
|
|
}
|
|
|
|
/**
|
|
* Copyright (c) 2022 - 2025, XinChip
|
|
* All rights reserved.
|
|
* Author : D
|
|
*/
|
|
__RAM_CODE void bootapp(param_unit *bparam)
|
|
{
|
|
uart_printf("boot app=%x\n", bparam->aloadaddr);
|
|
if (bparam->aloadaddr < FLASH_VIR_AADDR)
|
|
{
|
|
// 4096 0 16 pagecnt=16
|
|
uint32_t words;
|
|
uint32_t remain = bparam->alen % FLASH_PAGE_SIZE;
|
|
uint32_t pagecnt = bparam->alen / FLASH_PAGE_SIZE;
|
|
pagecnt = (remain == 0) ? pagecnt : (pagecnt + 1);
|
|
|
|
for (uint32_t pageser = 0, buffser = 0, pdesser = 0; pageser < pagecnt; pageser++)
|
|
{
|
|
FLASH_READ_PAGE(spi_idx, bparam->aaddr + pageser * FLASH_PAGE_SIZE, rwbuff);
|
|
// i= (pageser==0) ? (CODES_OFFSET/4):0;
|
|
|
|
words = ((pagecnt - 1) == pageser) ? (((remain % 4) == 0) ? (remain / 4) : ((remain / 4) + 1)) : FLASH_PAGE_WORDS;
|
|
|
|
for (buffser = 0; buffser < words; buffser++, pdesser++)
|
|
{
|
|
*(((uint32_t *)bparam->aloadaddr) + pdesser) = *(((uint32_t *)rwbuff) + buffser);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#ifdef QUAD_ENABLE
|
|
init_xip(QUAD_MODE);
|
|
#else
|
|
init_xip(DUAL_MODE);
|
|
#endif
|
|
}
|
|
|
|
jump2app = (iapfun) * (uint32_t *)(bparam->aloadaddr + 4); // 用户代码区第二个字为程序开始地址(复位地址)
|
|
MSR_MSP(*(uint32_t *)(bparam->aloadaddr)); // 设置栈顶地址 addr:栈顶地址 (用户代码区第一个字为程序的栈顶地址)
|
|
jump2app();
|
|
while (1)
|
|
;
|
|
}
|
|
/**
|
|
* Copyright (c) 2022 - 2025, XinChip
|
|
* All rights reserved.
|
|
* Author : D
|
|
*/
|
|
static void boot_backup(param_unit *bParam)
|
|
{
|
|
/*reserved*/
|
|
}
|
|
/**
|
|
* Copyright (c) 2022 - 2025, XinChip
|
|
* All rights reserved.
|
|
* Author : D
|
|
*/
|
|
static uint8_t eraseapp(param_unit *eparam)
|
|
{
|
|
uint32_t addrB = eparam->baddr;
|
|
uint32_t addr=0;
|
|
//set Loading_addr=0x11015000 //app bin startup address, The app bin is stored in the A region of the flash memory. //aaddr=Loading_addr-0x11000000
|
|
//set Back_addr=0x15000, // The address of the backup area corresponds to the address of Flash's B area. //baddr=Back_addr
|
|
//Loading_addr and Back_addr can be modified via parameters in the ge_ota.bat file.
|
|
|
|
//Zone A and Zone B share the same address for single-zone OTA wireless upgrades.
|
|
if(eparam->baddr==eparam->aaddr)
|
|
{
|
|
single_ota_flag=1;
|
|
}
|
|
uart_printf("ota_flag=%x ,%x, %x\n", single_ota_flag, eparam->baddr, eparam->aaddr);
|
|
|
|
if(!single_ota_flag)
|
|
{
|
|
addr = eparam->aaddr;
|
|
}
|
|
|
|
uint32_t era_sectorcnt = (eparam->blen) / FLASH_SECTOR_SIZE;
|
|
era_sectorcnt = (((eparam->blen) % FLASH_SECTOR_SIZE) == 0) ? era_sectorcnt : (era_sectorcnt + 1);
|
|
|
|
uint32_t crc = CRC32_INITIAL;
|
|
uint32_t remain = 0;
|
|
uint32_t pagecnt = (eparam->blen) / FLASH_PAGE_SIZE;
|
|
|
|
pagecnt = (((eparam->blen) % FLASH_PAGE_SIZE) == 0) ? pagecnt : (pagecnt + 1);
|
|
remain = ((eparam->blen) % FLASH_PAGE_SIZE);
|
|
|
|
if (remain == 0)
|
|
remain = FLASH_PAGE_SIZE;
|
|
for (uint32_t i = 0; i < pagecnt; i++)
|
|
{
|
|
|
|
FLASH_READ_PAGE(spi_idx, addrB + i * FLASH_PAGE_SIZE, rwbuff);
|
|
|
|
crc = ((pagecnt - 1) == i) ? (get_crc32(crc, rwbuff, FLASH_PAGE_SIZE)) : (get_crc32(crc, rwbuff, FLASH_PAGE_SIZE));
|
|
}
|
|
|
|
if (crc != (eparam->bcheck))
|
|
{
|
|
static uint8_t ErrCrcCNT = 0;
|
|
ErrCrcCNT++;
|
|
return 0;
|
|
}
|
|
for (uint32_t i = 0; i < era_sectorcnt; i++)
|
|
{
|
|
if(!single_ota_flag)
|
|
{
|
|
xc_wdt_reload();
|
|
FLASH_SECTOR_ERASE(spi_idx, addr + i * FLASH_SECTOR_SIZE); // spi_flash_page_erase(addr);
|
|
FLASH_WAIT_READY;
|
|
}
|
|
}
|
|
|
|
eparam->status = OVERWRITEASTAT;
|
|
return 1;
|
|
}
|
|
/**
|
|
* Copyright (c) 2022 - 2025, XinChip
|
|
* All rights reserved.
|
|
* Author : D
|
|
*/
|
|
static void erase_backup(param_unit *eparam)
|
|
{
|
|
uint32_t addr=0;
|
|
|
|
if(!single_ota_flag)
|
|
{
|
|
addr = eparam->baddr;
|
|
}
|
|
|
|
uint16_t era_sectorcnt = (eparam->blen) / FLASH_SECTOR_SIZE;
|
|
era_sectorcnt = (((eparam->blen) % FLASH_SECTOR_SIZE) == 0) ? era_sectorcnt : (era_sectorcnt + 1);
|
|
|
|
for (uint32_t i = 0; i < era_sectorcnt; i++)
|
|
{
|
|
if(!single_ota_flag){
|
|
FLASH_SECTOR_ERASE(spi_idx, addr + i * FLASH_SECTOR_SIZE); // spi_flash_page_erase(addr);
|
|
FLASH_WAIT_READY;
|
|
}
|
|
}
|
|
|
|
eparam->status = ACTIVEASTAT;
|
|
pms->paramcrc32 = get_crc32(CRC32_INITIAL, (uint8_t *)pms, PARAM_LENGTH);
|
|
param_overwrite(TO_A, (uint8_t *)pms,0);
|
|
param_overwrite(TO_B, (uint8_t *)pms,0);
|
|
}
|
|
/**
|
|
* Copyright (c) 2022 - 2025, XinChip
|
|
* All rights reserved.
|
|
* Author : D
|
|
*/
|
|
// void reverse_bytes(uint8_t *data, size_t length) {
|
|
// if (length % 2 != 0) {
|
|
// // printf("Error: Length of data must be even.\n");
|
|
// return;
|
|
// }
|
|
|
|
// for (size_t i = 0; i < length; i += 2) {
|
|
// // 交换每两个字节
|
|
// uint8_t temp = data[i];
|
|
// data[i] = data[i + 1];
|
|
// data[i + 1] = temp;
|
|
// }
|
|
//}
|
|
static void overwriteapp(param_unit *oparam)
|
|
{
|
|
if(!single_ota_flag)
|
|
{
|
|
uart_printf("overwriteapp\n");
|
|
uint32_t addrA = oparam->aaddr;
|
|
uint32_t addrB = oparam->baddr;
|
|
|
|
uint32_t remain = 0;
|
|
uint32_t pagecnt = (oparam->blen) / FLASH_PAGE_SIZE;
|
|
pagecnt = (((oparam->blen) % FLASH_PAGE_SIZE) == 0) ? pagecnt : (pagecnt + 1);
|
|
remain = ((oparam->blen) % FLASH_PAGE_SIZE);
|
|
|
|
if (remain == 0)
|
|
remain = FLASH_PAGE_SIZE;
|
|
for (uint32_t i = 0; i < pagecnt; i++)
|
|
{
|
|
xc_wdt_reload();
|
|
FLASH_READ_PAGE(spi_idx, addrB + i * FLASH_PAGE_SIZE, rwbuff);
|
|
FLASH_WAIT_READY;
|
|
// reverse_bytes(rwbuff,256);
|
|
FLASH_WRITE_PAGE(spi_idx, addrA + i * FLASH_PAGE_SIZE, rwbuff);
|
|
FLASH_WAIT_READY;
|
|
}
|
|
}
|
|
oparam->alen = oparam->blen;
|
|
oparam->acheck = oparam->bcheck;
|
|
oparam->status = ERASEBSTAT;
|
|
pms->paramcrc32 = get_crc32(CRC32_INITIAL, (uint8_t *)pms, PARAM_LENGTH);
|
|
param_overwrite(TO_A, (uint8_t *)pms,0);
|
|
}
|
|
/**
|
|
* Copyright (c) 2022 - 2025, XinChip
|
|
* All rights reserved.
|
|
* Author : D
|
|
*/
|
|
void overwrite_backup(param_unit *oparam)
|
|
{
|
|
/*reserved*/
|
|
}
|
|
/**
|
|
* Copyright (c) 2022 - 2025, XinChip
|
|
* All rights reserved.
|
|
* Author : D
|
|
*/
|
|
void param_analy(param_unit *sparam)
|
|
{
|
|
uart_printf("param_analy\n");
|
|
if(sparam->status==ERASEASTAT)
|
|
{
|
|
xc_wdt_reload();
|
|
uart_printf("eraseapp\n");
|
|
if(!eraseapp(sparam))
|
|
{
|
|
uart_printf("crc err\n");
|
|
param_overwrite(TO_A, parambuffb,0);
|
|
bootapp((param_unit *)parambuffa);
|
|
}
|
|
|
|
overwriteapp(sparam);
|
|
erase_backup(sparam);
|
|
xc_wdt_reload();
|
|
bootapp(sparam);
|
|
}
|
|
else if(sparam->status==ACTIVEBSTAT)
|
|
{
|
|
boot_backup(sparam);
|
|
}
|
|
else
|
|
{
|
|
uart_printf("status error:%d",sparam->status);
|
|
}
|
|
}
|
|
|
|
void param_backup_addr_set()
|
|
{
|
|
// uint8_t flash_sizeid = (uint8_t)spi_flash_read_identific();
|
|
uint8_t flash_sizeid = FLASH_SIZE_2M;
|
|
|
|
switch (flash_sizeid)
|
|
{
|
|
case FLASH_SIZE_4M: // 4M size
|
|
param_backup_addr = FLASH_4M_BACKUPADDR; // 4096 * 128 - 3 * 4096;
|
|
break;
|
|
case FLASH_SIZE_2M: // 2M
|
|
param_backup_addr = FLASH_2M_BACKUPADDR; // 4096 * 64 - 3 * 4096;
|
|
break;
|
|
case FLASH_SIZE_1M: // 1M
|
|
param_backup_addr = FLASH_1M_BACKUPADDR; // 4096 * 32 - 3 * 4096;
|
|
break;
|
|
default: // 4M
|
|
param_backup_addr = FLASH_4M_BACKUPADDR; // 4096 * 128 - 3 * 4096;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
int boot_get_status()
|
|
{
|
|
uint32_t crc32a, crc32b;
|
|
sboot_message *ptr_area = (sboot_message *)(¶mbuffa[0]);
|
|
sboot_message *ptr_brea = (sboot_message *)(¶mbuffb[0]);
|
|
|
|
FLASH_READ_PAGE(spi_idx, PARAM_ADDR, parambuffa);
|
|
FLASH_READ_PAGE(spi_idx, param_backup_addr, parambuffb);
|
|
|
|
crc32a = get_crc32(CRC32_INITIAL, parambuffa, PARAM_LENGTH);
|
|
crc32b = get_crc32(CRC32_INITIAL, parambuffb, PARAM_LENGTH);
|
|
|
|
if(ptr_area->paramcrc32==crc32a)
|
|
{
|
|
|
|
pms = ptr_area;
|
|
for(int param_no=0;param_no<PARAM_CNT;param_no++)
|
|
{
|
|
if(ptr_area->paramunit[param_no].status==ERASEASTAT)//OTA begin,select whitch app need updata
|
|
{
|
|
burn_ser=param_no;
|
|
return STATUS_APPUPDATA;
|
|
}
|
|
else if(ptr_area->paramunit[param_no].status==ACTIVEASTAT)//OTA begin
|
|
{
|
|
if(crc32a!=crc32b)
|
|
{
|
|
param_overwrite(TO_B, parambuffa,0);
|
|
}
|
|
burn_ser=param_no;
|
|
return STATUS_APPBOOT;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(ptr_brea->paramcrc32==crc32b)
|
|
{
|
|
param_overwrite(TO_A, parambuffb,0);
|
|
}
|
|
}
|
|
return STATUS_APPERROR;
|
|
}
|
|
|
|
void boot_run_sec()
|
|
{
|
|
|
|
uint8_t status = boot_get_status();
|
|
|
|
switch (status)
|
|
{
|
|
case STATUS_APPBOOT:
|
|
bootapp(&(pms->paramunit[burn_ser]));
|
|
break;
|
|
case STATUS_APPUPDATA:
|
|
while (1)
|
|
{
|
|
param_analy(&(pms->paramunit[burn_ser]));
|
|
}
|
|
case STATUS_APPERROR:
|
|
uart_printf(" error_status\r\n");
|
|
boot_run_sec();
|
|
break;
|
|
}
|
|
}
|