/* * 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_noparamunit[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; } }