180 lines
5.0 KiB
C
180 lines
5.0 KiB
C
/******************************************************************************
|
|
* Flash api for NodeMCU
|
|
* NodeMCU Team
|
|
* 2014-12-31
|
|
*******************************************************************************/
|
|
#include "flash_api.h"
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include "rom/spi_flash.h"
|
|
#include "platform_wdt.h"
|
|
#include "esp_image_format.h"
|
|
#include "esp_flash_partitions.h"
|
|
|
|
#define FLASH_HDR_ADDR 0x1000
|
|
|
|
static inline esp_image_header_t flash_load_rom_header (void)
|
|
{
|
|
esp_image_header_t hdr;
|
|
if (ESP_OK !=
|
|
spi_flash_read (FLASH_HDR_ADDR, (uint32_t *)&hdr, sizeof (hdr)))
|
|
{
|
|
NODE_ERR("Failed to load flash header block!\n");
|
|
abort();
|
|
}
|
|
return hdr;
|
|
}
|
|
|
|
#define IRAM_SECTION __attribute__((section(".iram1")))
|
|
static void IRAM_SECTION update_flash_chip_size (uint32_t sz)
|
|
{
|
|
esp_rom_spiflash_config_param (
|
|
g_rom_flashchip.device_id,
|
|
sz,
|
|
g_rom_flashchip.block_size,
|
|
g_rom_flashchip.sector_size,
|
|
g_rom_flashchip.page_size,
|
|
g_rom_flashchip.status_mask);
|
|
}
|
|
|
|
static uint32_t __attribute__((section(".iram1"))) flash_detect_size_byte(void)
|
|
{
|
|
#define DETECT_SZ 32
|
|
uint32_t detected_size = FLASH_SIZE_1MBYTE;
|
|
uint8_t data_orig[DETECT_SZ] PLATFORM_ALIGNMENT = {0};
|
|
uint8_t data_new[DETECT_SZ] PLATFORM_ALIGNMENT = {0};
|
|
// Ensure we read something which isn't just 0xff...
|
|
const uint32_t offs = ESP_PARTITION_TABLE_OFFSET;
|
|
// Detect read failure or wrap-around on flash read to find end of flash
|
|
if (ESP_OK == spi_flash_read (offs, (uint32_t *)data_orig, DETECT_SZ))
|
|
{
|
|
update_flash_chip_size (FLASH_SIZE_16MBYTE);
|
|
while ((detected_size < FLASH_SIZE_16MBYTE) &&
|
|
(ESP_OK == spi_flash_read (
|
|
detected_size + offs, (uint32_t *)data_new, DETECT_SZ)) &&
|
|
(0 != memcmp(data_orig, data_new, DETECT_SZ)))
|
|
{
|
|
detected_size *= 2;
|
|
}
|
|
|
|
update_flash_chip_size (detected_size);
|
|
};
|
|
return detected_size;
|
|
#undef FLASH_BUFFER_SIZE_DETECT
|
|
}
|
|
|
|
uint32_t flash_safe_get_size_byte(void)
|
|
{
|
|
static uint32_t flash_size = 0;
|
|
if (flash_size == 0)
|
|
{
|
|
flash_size = flash_detect_size_byte();
|
|
}
|
|
return flash_size;
|
|
}
|
|
|
|
|
|
uint16_t flash_safe_get_sec_num(void)
|
|
{
|
|
return (flash_safe_get_size_byte() / (SPI_FLASH_SEC_SIZE));
|
|
}
|
|
|
|
uint32_t flash_rom_get_size_byte(void)
|
|
{
|
|
static uint32_t flash_size = 0;
|
|
if (flash_size == 0)
|
|
{
|
|
switch (flash_load_rom_header ().spi_size)
|
|
{
|
|
default: // Unknown flash size, fall back mode.
|
|
case ESP_IMAGE_FLASH_SIZE_1MB: flash_size = FLASH_SIZE_1MBYTE; break;
|
|
case ESP_IMAGE_FLASH_SIZE_2MB: flash_size = FLASH_SIZE_2MBYTE; break;
|
|
case ESP_IMAGE_FLASH_SIZE_4MB: flash_size = FLASH_SIZE_4MBYTE; break;
|
|
case ESP_IMAGE_FLASH_SIZE_8MB: flash_size = FLASH_SIZE_8MBYTE; break;
|
|
case ESP_IMAGE_FLASH_SIZE_16MB: flash_size = FLASH_SIZE_16MBYTE; break;
|
|
}
|
|
}
|
|
return flash_size;
|
|
}
|
|
|
|
static bool flash_rom_set_size_type(uint8_t size_code)
|
|
{
|
|
// Dangerous, here are dinosaur infested!!!!!
|
|
// Reboot required!!!
|
|
// If you don't know what you're doing, your nodemcu may turn into stone ...
|
|
NODE_DBG("\nBEGIN SET FLASH HEADER\n");
|
|
esp_image_header_t *hdr = (esp_image_header_t *)malloc (SPI_FLASH_SEC_SIZE);
|
|
if (!hdr)
|
|
return false;
|
|
|
|
if (ESP_OK == spi_flash_read (FLASH_HDR_ADDR, (uint32_t *)hdr, SPI_FLASH_SEC_SIZE))
|
|
{
|
|
hdr->spi_size = size_code;
|
|
if (ESP_OK == spi_flash_erase_sector (FLASH_HDR_ADDR / SPI_FLASH_SEC_SIZE))
|
|
{
|
|
NODE_DBG("\nERASE SUCCESS\n");
|
|
}
|
|
if (ESP_OK == spi_flash_write(FLASH_HDR_ADDR, (uint32_t *)hdr, SPI_FLASH_SEC_SIZE))
|
|
{
|
|
NODE_DBG("\nWRITE SUCCESS, %u\n", size_code);
|
|
}
|
|
}
|
|
free (hdr);
|
|
NODE_DBG("\nEND SET FLASH HEADER\n");
|
|
return true;
|
|
}
|
|
|
|
|
|
bool flash_rom_set_size_byte(uint32_t size)
|
|
{
|
|
// Dangerous, here are dinosaur infested!!!!!
|
|
// Reboot required!!!
|
|
bool ok = true;
|
|
uint8_t size_code = 0;
|
|
switch (size)
|
|
{
|
|
case FLASH_SIZE_1MBYTE: size_code = ESP_IMAGE_FLASH_SIZE_1MB; break;
|
|
case FLASH_SIZE_2MBYTE: size_code = ESP_IMAGE_FLASH_SIZE_2MB; break;
|
|
case FLASH_SIZE_4MBYTE: size_code = ESP_IMAGE_FLASH_SIZE_4MB; break;
|
|
case FLASH_SIZE_8MBYTE: size_code = ESP_IMAGE_FLASH_SIZE_8MB; break;
|
|
case FLASH_SIZE_16MBYTE: size_code = ESP_IMAGE_FLASH_SIZE_16MB; break;
|
|
default: ok = false; break;
|
|
}
|
|
if (ok)
|
|
ok = flash_rom_set_size_type (size_code);
|
|
return ok;
|
|
}
|
|
|
|
|
|
uint16_t flash_rom_get_sec_num(void)
|
|
{
|
|
return ( flash_rom_get_size_byte() / (SPI_FLASH_SEC_SIZE) );
|
|
}
|
|
|
|
|
|
uint8_t flash_rom_get_mode(void)
|
|
{
|
|
return flash_load_rom_header ().spi_mode;
|
|
}
|
|
|
|
|
|
uint32_t flash_rom_get_speed(void)
|
|
{
|
|
switch (flash_load_rom_header ().spi_speed)
|
|
{
|
|
case ESP_IMAGE_SPI_SPEED_40M: return 40000000;
|
|
case ESP_IMAGE_SPI_SPEED_26M: return 26700000; // TODO: verify 26.7MHz
|
|
case ESP_IMAGE_SPI_SPEED_20M: return 20000000;
|
|
case ESP_IMAGE_SPI_SPEED_80M: return 80000000;
|
|
default: break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
esp_err_t flash_erase(size_t sector)
|
|
{
|
|
platform_wdt_feed();
|
|
return spi_flash_erase_sector(sector);
|
|
}
|