int do_flash_erase(uint32_t addr, uint32_t len) { if (addr % FLASH_SECTOR_SIZE != 0) return 0x32; if (len % FLASH_SECTOR_SIZE != 0) return 0x33; if (SPIUnlock() != 0) return 0x34; while (len > 0 && (addr % FLASH_BLOCK_SIZE != 0)) { if (SPIEraseSector(addr / FLASH_SECTOR_SIZE) != 0) return 0x35; len -= FLASH_SECTOR_SIZE; addr += FLASH_SECTOR_SIZE; } while (len > FLASH_BLOCK_SIZE) { if (SPIEraseBlock(addr / FLASH_BLOCK_SIZE) != 0) return 0x36; len -= FLASH_BLOCK_SIZE; addr += FLASH_BLOCK_SIZE; } while (len > 0) { if (SPIEraseSector(addr / FLASH_SECTOR_SIZE) != 0) return 0x37; len -= FLASH_SECTOR_SIZE; addr += FLASH_SECTOR_SIZE; } return 0; }
//extern char _text_end; //============================================================================= // IRAM code //============================================================================= // call_user_start() - вызов из заголовка, загрузчиком // ENTRY(call_user_start) in eagle.app.v6.ld //----------------------------------------------------------------------------- void __attribute__ ((noreturn)) call_user_start(void) { // Cache_Read_Disable(); IO_RTC_4 = 0; // Отключить блок WiFi (уменьшение потребления на время загрузки) GPIO0_MUX_alt = VAL_MUX_GPIO0_SDK_DEF; // Отключить вывод CLK на GPIO0 SPI0_USER |= SPI_CS_SETUP; // +1 такт перед CS = 0x80000064 #if FQSPI == 80 // xSPI на 80 MHz GPIO_MUX_CFG_alt |= BIT(MUX_SPI0_CLK_BIT); // QSPI = 80 MHz SPI0_CTRL = (SPI0_CTRL & SPI_CTRL_F_MASK) | SPI_CTRL_F80MHZ; #else // xSPI на 40 MHz GPIO_MUX_CFG_alt &= ~(1<< MUX_SPI0_CLK_BIT); SPI0_CTRL = (SPI0_CTRL & SPI_CTRL_F_MASK) | SPI_CTRL_F40MHZ; #endif // OTA #if DEBUGSOO > 1 p_printf("\nStart OTA loader.\n"); #endif uint32_t buffer[SPI_FLASH_SEC_SIZE/4]; SPIRead(esp_init_data_default_addr + MAX_SYS_CONST_BLOCK, buffer, (sizeof(OTA_flash_struct)+3)&~3); OTA_flash_struct *OTA = (OTA_flash_struct *)buffer; if(OTA->id == OTA_flash_struct_id) { uint32 image_start = OTA->image_addr; uint32 sectors = OTA->image_sectors; SPIRead(image_start, buffer, 4); if(*(uint8 *)buffer == firmware_start_magic) { #if DEBUGSOO > 0 p_printf("Update firmware from 0x%x, %u sectors: ", image_start, sectors); #endif ets_delay_us(1000000); // 1 sec uint32 write_to = 0; for(uint32 i = 0; i < sectors; i++) { SPIRead(image_start + i * SPI_FLASH_SEC_SIZE, buffer, SPI_FLASH_SEC_SIZE); SPIEraseSector(i); SPIWrite(write_to, buffer, SPI_FLASH_SEC_SIZE); write_to += SPI_FLASH_SEC_SIZE; #if DEBUGSOO > 0 p_printf("x"); #endif } #if DEBUGSOO > 0 p_printf("\nOk."); #endif if(image_start >= write_to) SPIEraseSector(image_start / SPI_FLASH_SEC_SIZE); _ResetVector(); } } #if DEBUGSOO > 1 p_printf("\nGoto next loader.\n"); #endif // Всё, включаем кеширование, далее можно вызывать процедуры из flash Cache_Read_Enable(0, 0, 0); // Переход в область кеширования flash, // Запускаем загрузку SDK с указателем на заголовок SPIFlashHeader (находится за данным загручиком по адресу с align 16) // ((loader_call)((uint32)(&loader_flash_boot) + FLASH_BASE - IRAM_BASE + 0x10))((struct SPIFlashHeader *)(((uint32)(&_text_end) + FLASH_BASE - IRAM_BASE + 0x17) & (~15))); ((loader_call)(loader_flash_boot_addr))((struct SPIFlashHeader *)(next_flash_header_addr)); }
int copy_raw(const uint32_t src_addr, const uint32_t dst_addr, const uint32_t size) { // require regions to be aligned if (src_addr & 0xfff != 0 || dst_addr & 0xfff != 0) { return 1; } const uint32_t buffer_size = FLASH_SECTOR_SIZE; uint8_t buffer[buffer_size]; uint32_t left = ((size+buffer_size-1) & ~(buffer_size-1)); uint32_t saddr = src_addr; uint32_t daddr = dst_addr; while (left) { if (SPIEraseSector(daddr/buffer_size)) { return 2; } if (SPIRead(saddr, buffer, buffer_size)) { return 3; } if (SPIWrite(daddr, buffer, buffer_size)) { return 4; } saddr += buffer_size; daddr += buffer_size; left -= buffer_size; } return 0; }
void load_app(uint32 from_addr, uint32 to_addr, uint32 total_size) { uint8 buffer[SECTOR_SIZE]; uint32 readpos, writepos, sector = to_addr/SECTOR_SIZE; readpos = from_addr; writepos = to_addr; while(total_size > 0) { INFO("."); SPIEraseSector(sector); if (SPIRead(readpos, buffer, SECTOR_SIZE) != 0) { return; } //INFO("ESPBOOT: Write at 0x%X ...\r\n", writepos); if (SPIWrite(writepos, buffer, SECTOR_SIZE) != 0) { return; } writepos += SECTOR_SIZE; readpos += SECTOR_SIZE; if(total_size > SECTOR_SIZE) total_size -= SECTOR_SIZE; else total_size = 0; sector ++; } INFO(".\r\n"); }
int do_flash_write(uint32_t addr, uint32_t len, uint32_t erase) { struct uart_buf ub; uint8_t digest[16]; uint32_t num_written = 0, num_erased = 0; struct MD5Context ctx; MD5Init(&ctx); if (addr % FLASH_SECTOR_SIZE != 0) return 0x32; if (len % FLASH_SECTOR_SIZE != 0) return 0x33; if (SPIUnlock() != 0) return 0x34; ub.nr = 0; ub.pr = ub.pw = ub.data; ets_isr_attach(ETS_UART_INUM, uart_isr, &ub); SET_PERI_REG_MASK(UART_INT_ENA(0), UART_RX_INTS); ets_isr_unmask(1 << ETS_UART_INUM); SLIP_send(&num_written, 4); while (num_written < len) { volatile uint32_t *nr = &ub.nr; /* Prepare the space ahead. */ while (erase && num_erased < num_written + SPI_WRITE_SIZE) { const uint32_t num_left = (len - num_erased); if (num_left > FLASH_BLOCK_SIZE && addr % FLASH_BLOCK_SIZE == 0) { if (SPIEraseBlock(addr / FLASH_BLOCK_SIZE) != 0) return 0x35; num_erased += FLASH_BLOCK_SIZE; } else { /* len % FLASH_SECTOR_SIZE == 0 is enforced, no further checks needed */ if (SPIEraseSector(addr / FLASH_SECTOR_SIZE) != 0) return 0x36; num_erased += FLASH_SECTOR_SIZE; } } /* Wait for data to arrive. */ while (*nr < SPI_WRITE_SIZE) { } MD5Update(&ctx, ub.pr, SPI_WRITE_SIZE); if (SPIWrite(addr, ub.pr, SPI_WRITE_SIZE) != 0) return 0x37; ets_intr_lock(); *nr -= SPI_WRITE_SIZE; ets_intr_unlock(); num_written += SPI_WRITE_SIZE; addr += SPI_WRITE_SIZE; ub.pr += SPI_WRITE_SIZE; if (ub.pr >= ub.data + UART_BUF_SIZE) ub.pr = ub.data; SLIP_send(&num_written, 4); } ets_isr_mask(1 << ETS_UART_INUM); MD5Final(digest, &ctx); SLIP_send(digest, 16); return 0; }
void save_boot_cfg(espboot_cfg *cfg) { cfg->chksum = calc_chksum((uint8*)cfg, (uint8*)&cfg->chksum); if (SPIEraseSector(BOOT_CONFIG_SECTOR) != 0) { ERROR("Can not erase boot configuration sector\r\n"); } if (SPIWrite(BOOT_CONFIG_SECTOR * SECTOR_SIZE, cfg, sizeof(espboot_cfg)) != 0) { ERROR("Can not save boot configurations\r\n"); } }
SpiFlashOpResult IRAM spi_flash_erase_sector(uint16_t sec) { CHECK_PARAM_RET (sec < flashchip->chip_size / flashchip->sector_size, SPI_FLASH_RESULT_ERR); critical_enter (); Cache_Read_Disable(); SpiFlashOpResult ret = SPIEraseSector (sec); Cache_Read_Enable(0, 0, 1); critical_exit (); return ret; }
void TWLCard::eraseSaveData(void (*cb)(u32, u32)) const { u32 pos; u32 sz = SPIGetCapacity(cardType_); Result res; cb(0, sz); for(pos = 0; pos < sz; pos += 0x10000) { res = SPIEraseSector(cardType_, pos); if(res != 0) throw Error(res, __FILE__, __LINE__); cb((sz < pos + 0x10000) ? sz : pos + 0x10000, sz); } }
// prevent this function being placed inline with main // to keep main's stack size as small as possible static uint32 NOINLINE find_image() { uint8 flag; uint32 runAddr; uint32 flashsize; int32 romToBoot; uint8 gpio_boot = FALSE; uint8 updateConfig = TRUE; uint8 buffer[SECTOR_SIZE]; rboot_config *romconf = (rboot_config*)buffer; rom_header *header = (rom_header*)buffer; ets_delay_us(2000000); ets_printf("\r\nrBoot v1.0.0 - [email protected]\r\n"); // read rom header SPIRead(0, header, sizeof(rom_header)); // print and get flash size ets_printf("Flash Size: "); flag = header->flags2 >> 4; if (flag == 0) { ets_printf("4 Mbit\r\n"); flashsize = 0x80000; } else if (flag == 1) { ets_printf("2 Mbit\r\n"); flashsize = 0x40000; } else if (flag == 2) { ets_printf("8 Mbit\r\n"); flashsize = 0x100000; } else if (flag == 3) { ets_printf("16 Mbit\r\n"); flashsize = 0x200000; } else if (flag == 4) { ets_printf("32 Mbit\r\n"); flashsize = 0x400000; } else { ets_printf("unknown\r\n"); // assume at least 4mbit flashsize = 0x80000; } // print spi mode ets_printf("Flash Mode: "); if (header->flags1 == 0) { ets_printf("QIO\r\n"); } else if (header->flags1 == 1) { ets_printf("QOUT\r\n"); } else if (header->flags1 == 2) { ets_printf("DIO\r\n"); } else if (header->flags1 == 3) { ets_printf("DOUT\r\n"); } else { ets_printf("unknown\r\n"); } // print spi speed ets_printf("Flash Speed: "); flag = header->flags2 & 0x0f; if (flag == 0) ets_printf("40 MHz\r\n"); else if (flag == 1) ets_printf("26.7 MHz\r\n"); else if (flag == 2) ets_printf("20 MHz\r\n"); else if (flag == 0x0f) ets_printf("80 MHz\r\n"); else ets_printf("unknown\r\n"); // read boot config SPIRead(BOOT_CONFIG_SECTOR * SECTOR_SIZE, buffer, SECTOR_SIZE); // fresh install or old version? if (romconf->magic != BOOT_CONFIG_MAGIC || romconf->version != BOOT_CONFIG_VERSION) { // create a default config for a standard 2 rom setup ets_printf("Writing default boot config.\r\n"); ets_memset(romconf, 0x00, sizeof(rboot_config)); romconf->magic = BOOT_CONFIG_MAGIC; romconf->version = BOOT_CONFIG_VERSION; romconf->mode = MODE_STANDARD; romconf->current_rom = 0; romconf->count = 2; romconf->current_rom = 0; romconf->roms[0] = SECTOR_SIZE * 2; romconf->roms[1] = (flashsize / 2) + (SECTOR_SIZE * 2); // write new config sector SPIEraseSector(BOOT_CONFIG_SECTOR); SPIWrite(BOOT_CONFIG_SECTOR * SECTOR_SIZE, buffer, SECTOR_SIZE); } // if gpio mode enabled check status of the gpio if ((romconf->mode & MODE_GPIO_ROM) && (get_gpio16() == 0)) { ets_printf("Booting GPIO-selected.\r\n"); romToBoot = romconf->gpio_rom; gpio_boot = TRUE; } else if (romconf->current_rom >= romconf->count) { // if invalid rom selected try rom 0 ets_printf("Invalid rom selected, defaulting.\r\n"); romToBoot = 0; romconf->current_rom = 0; updateConfig = TRUE; } else { // try rom selected in the config romToBoot = romconf->current_rom; } // try to find a good rom do { runAddr = check_image(romconf->roms[romToBoot]); if (runAddr == 0) { ets_printf("Rom %d is bad.\r\n", romToBoot); if (gpio_boot) { // don't switch to backup for gpio-selected rom ets_printf("GPIO boot failed.\r\n"); return 0; } else { // for normal mode try each previous rom // until we find a good one or run out updateConfig = TRUE; romToBoot--; if (romToBoot < 0) romToBoot = romconf->count - 1; if (romToBoot == romconf->current_rom) { // tried them all and all are bad! ets_printf("No good rom available.\r\n"); return 0; } } } } while (runAddr == 0); // re-write config, if required if (updateConfig) { romconf->current_rom = romToBoot; SPIEraseSector(BOOT_CONFIG_SECTOR); SPIWrite(BOOT_CONFIG_SECTOR * SECTOR_SIZE, buffer, SECTOR_SIZE); } ets_printf("Booting rom %d.\r\n", romToBoot); // copy the loader to top of iram ets_memcpy((void*)_text_addr, _text_data, _text_len); // return address to load from return runAddr; }
// prevent this function being placed inline with main // to keep main's stack size as small as possible // don't mark as static or it'll be optimised out when // using the assembler stub uint32 NOINLINE find_image() { uint8 flag; uint32 runAddr; uint32 flashsize; int32 romToBoot; uint8 gpio_boot = FALSE; uint8 updateConfig = TRUE; uint8 buffer[SECTOR_SIZE]; rboot_config *romconf = (rboot_config*)buffer; rom_header *header = (rom_header*)buffer; // delay to slow boot (help see messages when debugging) //ets_delay_us(2000000); ets_printf("\r\nrBoot v1.2.1 - [email protected]\r\n"); // read rom header SPIRead(0, header, sizeof(rom_header)); // print and get flash size ets_printf("Flash Size: "); flag = header->flags2 >> 4; if (flag == 0) { ets_printf("4 Mbit\r\n"); flashsize = 0x80000; } else if (flag == 1) { ets_printf("2 Mbit\r\n"); flashsize = 0x40000; } else if (flag == 2) { ets_printf("8 Mbit\r\n"); flashsize = 0x100000; } else if (flag == 3) { ets_printf("16 Mbit\r\n"); #ifdef BOOT_BIG_FLASH flashsize = 0x200000; #else flashsize = 0x100000; // limit to 8Mbit #endif } else if (flag == 4) { ets_printf("32 Mbit\r\n"); #ifdef BOOT_BIG_FLASH flashsize = 0x400000; #else flashsize = 0x100000; // limit to 8Mbit #endif } else { ets_printf("unknown\r\n"); // assume at least 4mbit flashsize = 0x80000; } // print spi mode ets_printf("Flash Mode: "); if (header->flags1 == 0) { ets_printf("QIO\r\n"); } else if (header->flags1 == 1) { ets_printf("QOUT\r\n"); } else if (header->flags1 == 2) { ets_printf("DIO\r\n"); } else if (header->flags1 == 3) { ets_printf("DOUT\r\n"); } else { ets_printf("unknown\r\n"); } // print spi speed ets_printf("Flash Speed: "); flag = header->flags2 & 0x0f; if (flag == 0) ets_printf("40 MHz\r\n"); else if (flag == 1) ets_printf("26.7 MHz\r\n"); else if (flag == 2) ets_printf("20 MHz\r\n"); else if (flag == 0x0f) ets_printf("80 MHz\r\n"); else ets_printf("unknown\r\n"); // print enabled options #ifdef BOOT_BIG_FLASH ets_printf("rBoot Option: Big flash\r\n"); #endif #ifdef BOOT_CONFIG_CHKSUM ets_printf("rBoot Option: Config chksum\r\n"); #endif #ifdef BOOT_IROM_CHKSUM ets_printf("rBoot Option: irom chksum\r\n"); #endif ets_printf("\r\n"); // read boot config SPIRead(BOOT_CONFIG_SECTOR * SECTOR_SIZE, buffer, SECTOR_SIZE); // fresh install or old version? if (romconf->magic != BOOT_CONFIG_MAGIC || romconf->version != BOOT_CONFIG_VERSION #ifdef BOOT_CONFIG_CHKSUM || romconf->chksum != calc_chksum((uint8*)romconf, (uint8*)&romconf->chksum) #endif ) { /* Modified by Cesanta */ ets_printf("Writing default boot config.\r\n"); ets_memset(romconf, 0x00, sizeof(rboot_config)); romconf->magic = BOOT_CONFIG_MAGIC; romconf->version = BOOT_CONFIG_VERSION; romconf->count = 2; romconf->mode = MODE_STANDARD; /* FWx_ADDR, FWx_FS_ADDR and FS_SIZE, FW_SIZE must be defined by -D */ romconf->roms[0] = FW1_ADDR; romconf->roms[1] = FW2_ADDR; romconf->fs_addresses[0] = FW1_FS_ADDR; romconf->fs_addresses[1] = FW2_FS_ADDR; romconf->fs_sizes[0] = romconf->fs_sizes[1] = FS_SIZE; romconf->roms_sizes[0] = romconf->roms_sizes[1] = FW_SIZE; #ifdef BOOT_CONFIG_CHKSUM romconf->chksum = calc_chksum((uint8*)romconf, (uint8*)&romconf->chksum); #endif // write new config sector SPIEraseSector(BOOT_CONFIG_SECTOR); SPIWrite(BOOT_CONFIG_SECTOR * SECTOR_SIZE, buffer, SECTOR_SIZE); } // if gpio mode enabled check status of the gpio if ((romconf->mode & MODE_GPIO_ROM) && (get_gpio16() == 0)) { ets_printf("Booting GPIO-selected.\r\n"); romToBoot = romconf->previous_rom; /* * Modified by Cesanta * Make FD current */ updateConfig = TRUE; romconf->fw_updated = 0; romconf->is_first_boot = 0; gpio_boot = TRUE; } else if (romconf->current_rom >= romconf->count) { // if invalid rom selected try rom 0 ets_printf("Invalid rom selected, defaulting.\r\n"); romToBoot = 0; romconf->current_rom = 0; romconf->fw_updated = 0; romconf->is_first_boot = 0; updateConfig = TRUE; } else { /* Modified by Cesanta */ if (romconf->is_first_boot != 0) { ets_printf("First boot, attempt %d\n", romconf->boot_attempts); /* boot is unconfirmed */ if (romconf->boot_attempts == 0) { /* haven't try to load yes */ ets_printf("Boot is unconfirmed\r\n"); romconf->boot_attempts++; } else { ets_printf("Boot failed, fallback to fw #%d\r\n", romconf->previous_rom); romconf->current_rom = romconf->previous_rom; /* clear fw update flag, to avoid post-update acttions */ romconf->fw_updated = 0; romconf->boot_attempts = 0; } updateConfig = TRUE; } /* End of Cesanta modifications */ // try rom selected in the config romToBoot = romconf->current_rom; } // try to find a good rom do { runAddr = check_image(romconf->roms[romToBoot]); if (runAddr == 0) { ets_printf("Rom %d is bad.\r\n", romToBoot); if (gpio_boot) { // don't switch to backup for gpio-selected rom ets_printf("GPIO boot failed.\r\n"); return 0; } else { // for normal mode try each previous rom // until we find a good one or run out updateConfig = TRUE; romToBoot--; if (romToBoot < 0) romToBoot = romconf->count - 1; if (romToBoot == romconf->current_rom) { // tried them all and all are bad! ets_printf("No good rom available.\r\n"); return 0; } } } } while (runAddr == 0); // re-write config, if required if (updateConfig) { romconf->current_rom = romToBoot; #ifdef BOOT_CONFIG_CHKSUM romconf->chksum = calc_chksum((uint8*)romconf, (uint8*)&romconf->chksum); #endif SPIEraseSector(BOOT_CONFIG_SECTOR); SPIWrite(BOOT_CONFIG_SECTOR * SECTOR_SIZE, buffer, SECTOR_SIZE); } ets_printf("Booting rom %d.\r\n", romToBoot); // copy the loader to top of iram ets_memcpy((void*)_text_addr, _text_data, _text_len); // return address to load from return runAddr; }
//============================================================================= // call_user_start //----------------------------------------------------------------------------- void call_user_start(void) { struct SPIFlashHead sfh; // заголовок flash struct StoreWifiHdr wifihdr; // заголовок из последнего сектора flash с индексом на сохранение последней конфигурации WiFi struct BootConfig bootcfg; // начало блока сохранения последней конфигурации WiFi, часть с boot параметрами ets_printf("\n2nd boot version : 1.2\n"); SPIRead(0, &sfh, sizeof(sfh)); ets_printf(" SPI Speed : "); switch (sfh.hsz.spi_freg) { case SPEED_40MHZ: ets_printf("40MHz\n"); break; case SPEED_26MHZ: ets_printf("26.7MHz\n"); break; case SPEED_20MHZ: ets_printf("20MHz\n"); break; case SPEED_80MHZ: ets_printf("80MHz\n"); break; } ets_printf(" SPI Mode : "); switch (sfh.spi_interface) { case MODE_QIO: ets_printf("QIO\n"); break; case MODE_QOUT: ets_printf("QOUT\n"); break; case MODE_DIO: ets_printf("DIO\n"); break; case MODE_DOUT: ets_printf("DOUT\n"); break; } ets_printf(" SPI Flash Size : "); uint32 sector; switch (sfh.hsz.flash_size) { case SIZE_4MBIT: ets_printf("4Mbit\n"); sector = 128-4; break; case SIZE_2MBIT: ets_printf("2Mbit\n"); sector = 64-4; break; case SIZE_8MBIT: ets_printf("8Mbit\n"); sector = 256-4; break; case SIZE_16MBIT: ets_printf("16Mbit\n"); sector = 512-4; break; case SIZE_32MBIT: ets_printf("32Mbit\n"); sector = 1024-4; break; default: ets_printf("4Mbit\n"); sector = 128-4; break; } uint32 addr = sector * FSECTOR_SIZE; SPIRead(addr + 3 * FSECTOR_SIZE, &wifihdr.bank, sizeof(wifihdr)); if(wifihdr.bank == 0) { SPIRead(addr + FSECTOR_SIZE, &bootcfg, sizeof(bootcfg)); } else { SPIRead(addr + 2 * FSECTOR_SIZE, &bootcfg, sizeof(bootcfg)); } if(bootcfg.boot_version == 0xff) { bootcfg.boot_number = 0; } if(bootcfg.boot_version != 2) { bootcfg.boot_version = 2; if(wifihdr.bank == 0) wifihdr.bank = 1; else wifihdr.bank = 0; SPIEraseSector(sector+wifihdr.bank+1); SPIWrite((sector+wifihdr.bank+1) * FSECTOR_SIZE, &bootcfg, sizeof(bootcfg)); SPIEraseSector(sector+3); SPIWrite(addr + 3 * FSECTOR_SIZE, &wifihdr.bank, sizeof(wifihdr)); } ets_memcpy((void *)0x4010800, &code_blk, size_code_blk); // загрузчик не прикреплен! ets_printf("jump to run user"); switch(bootcfg.boot_number & 0x0f) { case 0: ets_printf("1\n\n"); uint32 seg_size = get_seg_size(FSECTOR_SIZE); if(seg_size == 0xffffffff) return; if(seg_size == 0) { 0x4010800C(FSECTOR_SIZE); } else { 0x4010800C(seg_size + 0x1010); } break; case 1: ets_printf("2\n\n"); if(sector == 512 - 4 || sector == 1024 - 4) sector = 256 - 4; get_seg_size(((sector + 4)>>1)*FSECTOR_SIZE + FSECTOR_SIZE); if(seg_size == 0xffffffff) return; if(seg_size == 0) { 0x4010800C(FSECTOR_SIZE); } else { 0x4010800C(seg_size + 0x1010); } break; default: ets_printf("error user bin flag, flag = %x\n", bootcfg.boot_number & 0x0f); } }
/** Checks the boot config sector to see if there's a new image to write and if so, erases old and copies in new * @note Must be NOINLINE and not static to call from ASM without generating a stack which will be left in memory */ void NOINLINE copyNewImage(void) { BootloaderConfig config; SPIRead(BOOT_CONFIG_SECTOR * SECTOR_SIZE, &config, sizeof(BootloaderConfig)); if (config.header != BOOT_CONFIG_HEADER) { ets_printf("No boot config header, %08x != %08x, skipping\r\n", config.header, BOOT_CONFIG_HEADER); return; } else if (calc_chksum((uint8*)&config, (uint8*)&config.chksum) != config.chksum) { ets_printf("ERROR: boot config has bad checksum, %02x, expecting %02x\r\n", config.chksum, calc_chksum((uint8*)&config, (uint8*)&config.chksum)); return; } else if (config.newImageStart == 0 || config.newImageSize == 0) { ets_printf("No new firmware, continuing\r\n"); return; } else { uint32 buffer[SECTOR_SIZE/4]; // Buffer to copy from one sector to another uint32 sector; SpiFlashOpResult rslt; ets_printf("Found new image: %x[%d]\r\n", config.newImageStart, config.newImageSize); ets_printf("\tErasing old firmware\r\n"); for (sector = FIRMWARE_START_SECTOR; sector < FIRMWARE_START_SECTOR + config.newImageSize; sector++) { rslt = SPIEraseSector(sector); if (rslt != SPI_FLASH_RESULT_OK) { ets_printf("\tError erasing sector %x: %d\r\n", sector, rslt); sector--; // Try this sector again } else { ets_printf("_"); } } ets_printf("\tCopying in new firmware\r\n"); for (sector = 0; sector < config.newImageSize; sector++) { rslt = SPIRead((sector + config.newImageStart)*SECTOR_SIZE + IMAGE_READ_OFFSET, buffer, SECTOR_SIZE); if (rslt != SPI_FLASH_RESULT_OK) { ets_printf("\tError reading sector %x: %d\r\n", sector + config.newImageStart, rslt); sector--; // Retry the same sector } else { rslt = SPIWrite((sector + FIRMWARE_START_SECTOR)*SECTOR_SIZE, buffer, SECTOR_SIZE); if (rslt != SPI_FLASH_RESULT_OK) { ets_printf("\tError writing sector %x: %d\r\n", sector + FIRMWARE_START_SECTOR, rslt); sector--; // Retry the same sector } else { ets_printf("."); } } } ets_printf("Done copying new image, %d sectors\r\n", sector); } }