From 4c04c63c2a7773ac92b0860735d62e79a66b83bb Mon Sep 17 00:00:00 2001 From: Gijs Noorlander Date: Wed, 19 Dec 2018 04:59:25 +0100 Subject: [PATCH] Rewrite PUYA patch to be more universal and mem friendly. (#5504) * [PUYA] Applied ESPeasy puya_v3.patch Applied the patch to get the starting point as described in https://github.com/esp8266/Arduino/issues/5493 * [PUYA] Only allocate memory when PUYA detected core 2.5.0 PUYA patch, no puya: Description Function #calls call/sec min (ms) Avg (ms) max (ms) Save File 4 0.25 34.755 45.264 67.620 Free Mem: 16168 core 2.5.0 PUYA patch, Faked Puya detect: Description Function #calls call/sec min (ms) Avg (ms) max (ms) Save File 2 0.04 41.332 57.544 73.756 Free Mem: 11560 * [PUYA] Check for PUYA chip as soon as possible at boot Check for PUYA chip in call for `getFlashChipId()` This will only be done once and the result of the get function is also cached. * [PUYA] Use limited buffer (512 byte) allocated at first write No need to allocate a buffer when not writing to flash. The default buffer size is 512 bytes, which is 2 pages in the flash chip. * [PUYA] Lower PUYA flash buffer to 1 page (256 B) As discussed here: https://github.com/esp8266/Arduino/issues/5493#issuecomment-447543279 * [PUYA] Fix indents naming and return conditions * [PUYA] Move Puya write code to spi_flash_write_puya * [PUYA] Make spi_flash_write_puya static and define PUYA_SUPPORT * [PUYA] Add some SPI flash vendor IDs As requested by @igrr https://github.com/esp8266/Arduino/pull/5504#discussion_r242016184 * [PUYA] All suggested changes. See: https://github.com/esp8266/Arduino/pull/5504#pullrequestreview-186145820 --- cores/esp8266/Esp.cpp | 77 ++++++++++++++++++++++++++++++++++++++----- cores/esp8266/Esp.h | 48 +++++++++++++++++++++++++++ 2 files changed, 117 insertions(+), 8 deletions(-) diff --git a/cores/esp8266/Esp.cpp b/cores/esp8266/Esp.cpp index 8dc37ff2a..d95c94516 100644 --- a/cores/esp8266/Esp.cpp +++ b/cores/esp8266/Esp.cpp @@ -132,18 +132,18 @@ uint64_t EspClass::deepSleepMax() } -/* +/* Layout of RTC Memory is as follows: Ref: Espressif doc 2C-ESP8266_Non_OS_SDK_API_Reference, section 3.3.23 (system_rtc_mem_write) |<------system data (256 bytes)------->|<-----------------user data (512 bytes)--------------->| -SDK function signature: +SDK function signature: bool system_rtc_mem_read ( - uint32 des_addr, - void * src_addr, + uint32 des_addr, + void * src_addr, uint32 save_size -) +) The system data section can't be used by the user, so: des_addr must be >=64 (i.e.: 256/4) and <192 (i.e.: 768/4) @@ -160,7 +160,7 @@ Same for write Note: If the Updater class is in play, e.g.: the application uses OTA, the eboot command will be stored into the first 128 bytes of user data, then it will be retrieved by eboot on boot. That means that user data present there will be lost. -Ref: +Ref: - discussion in PR #5330. - https://github.com/esp8266/esp8266-wiki/wiki/Memory-Map#memmory-mapped-io-registers - Arduino/bootloaders/eboot/eboot_command.h RTC_MEM definition @@ -266,7 +266,16 @@ uint8_t EspClass::getCpuFreqMHz(void) uint32_t EspClass::getFlashChipId(void) { - return spi_flash_get_id(); + static uint32_t flash_chip_id = 0; + if (flash_chip_id == 0) { + flash_chip_id = spi_flash_get_id(); + } + return flash_chip_id; +} + +uint8_t EspClass::getFlashChipVendorId(void) +{ + return (getFlashChipId() & 0x000000ff); } uint32_t EspClass::getFlashChipRealSize(void) @@ -569,9 +578,61 @@ bool EspClass::flashEraseSector(uint32_t sector) { return rc == 0; } +#if PUYA_SUPPORT +static int spi_flash_write_puya(uint32_t offset, uint32_t *data, size_t size) { + if (data == nullptr) { + return 1; // SPI_FLASH_RESULT_ERR + } + // PUYA flash chips need to read existing data, update in memory and write modified data again. + static uint32_t *flash_write_puya_buf = nullptr; + int rc = 0; + uint32_t* ptr = data; + + if (flash_write_puya_buf == nullptr) { + flash_write_puya_buf = (uint32_t*) malloc(PUYA_BUFFER_SIZE); + // No need to ever free this, since the flash chip will never change at runtime. + if (flash_write_puya_buf == nullptr) { + // Memory could not be allocated. + return 1; // SPI_FLASH_RESULT_ERR + } + } + size_t bytesLeft = size; + uint32_t pos = offset; + while (bytesLeft > 0 && rc == 0) { + size_t bytesNow = bytesLeft; + if (bytesNow > PUYA_BUFFER_SIZE) { + bytesNow = PUYA_BUFFER_SIZE; + bytesLeft -= PUYA_BUFFER_SIZE; + } else { + bytesLeft = 0; + } + rc = spi_flash_read(pos, flash_write_puya_buf, bytesNow); + if (rc != 0) { + return rc; + } + for (size_t i = 0; i < bytesNow / 4; ++i) { + flash_write_puya_buf[i] &= *ptr; + ++ptr; + } + rc = spi_flash_write(pos, flash_write_puya_buf, bytesNow); + pos += bytesNow; + } + return rc; +} +#endif + bool EspClass::flashWrite(uint32_t offset, uint32_t *data, size_t size) { ets_isr_mask(FLASH_INT_MASK); - int rc = spi_flash_write(offset, (uint32_t*) data, size); + int rc = 0; +#if PUYA_SUPPORT + if (getFlashChipVendorId() == SPI_FLASH_VENDOR_PUYA) { + rc = spi_flash_write_puya(offset, data, size); + } + else +#endif + { + rc = spi_flash_write(offset, data, size); + } ets_isr_unmask(FLASH_INT_MASK); return rc == 0; } diff --git a/cores/esp8266/Esp.h b/cores/esp8266/Esp.h index b2ee09144..21dff0852 100644 --- a/cores/esp8266/Esp.h +++ b/cores/esp8266/Esp.h @@ -23,6 +23,52 @@ #include +#ifndef PUYA_SUPPORT + #define PUYA_SUPPORT 0 +#endif +#ifndef PUYA_BUFFER_SIZE + // Good alternative for buffer size is: SPI_FLASH_SEC_SIZE (= 4k) + // Always use a multiple of flash page size (256 bytes) + #define PUYA_BUFFER_SIZE 256 +#endif + +// Vendor IDs taken from Flashrom project +// https://review.coreboot.org/cgit/flashrom.git/tree/flashchips.h?h=1.0.x +typedef enum { + SPI_FLASH_VENDOR_ALLIANCE = 0x52, /* Alliance Semiconductor */ + SPI_FLASH_VENDOR_AMD = 0x01, /* AMD */ + SPI_FLASH_VENDOR_AMIC = 0x37, /* AMIC */ + SPI_FLASH_VENDOR_ATMEL = 0x1F, /* Atmel (now used by Adesto) */ + SPI_FLASH_VENDOR_BRIGHT = 0xAD, /* Bright Microelectronics */ + SPI_FLASH_VENDOR_CATALYST = 0x31, /* Catalyst */ + SPI_FLASH_VENDOR_EON = 0x1C, /* EON Silicon Devices, missing 0x7F prefix */ + SPI_FLASH_VENDOR_ESMT = 0x8C, /* Elite Semiconductor Memory Technology (ESMT) / EFST Elite Flash Storage */ + SPI_FLASH_VENDOR_EXCEL = 0x4A, /* ESI, missing 0x7F prefix */ + SPI_FLASH_VENDOR_FIDELIX = 0xF8, /* Fidelix */ + SPI_FLASH_VENDOR_FUJITSU = 0x04, /* Fujitsu */ + SPI_FLASH_VENDOR_GIGADEVICE = 0xC8, /* GigaDevice */ + SPI_FLASH_VENDOR_HYUNDAI = 0xAD, /* Hyundai */ + SPI_FLASH_VENDOR_INTEL = 0x89, /* Intel */ + SPI_FLASH_VENDOR_ISSI = 0xD5, /* ISSI Integrated Silicon Solutions, see also PMC. */ + SPI_FLASH_VENDOR_MACRONIX = 0xC2, /* Macronix (MX) */ + SPI_FLASH_VENDOR_NANTRONICS = 0xD5, /* Nantronics, missing prefix */ + SPI_FLASH_VENDOR_PMC = 0x9D, /* PMC, missing 0x7F prefix */ + SPI_FLASH_VENDOR_PUYA = 0x85, /* Puya semiconductor (shanghai) co. ltd */ + SPI_FLASH_VENDOR_SANYO = 0x62, /* Sanyo */ + SPI_FLASH_VENDOR_SHARP = 0xB0, /* Sharp */ + SPI_FLASH_VENDOR_SPANSION = 0x01, /* Spansion, same ID as AMD */ + SPI_FLASH_VENDOR_SST = 0xBF, /* SST */ + SPI_FLASH_VENDOR_ST = 0x20, /* ST / SGS/Thomson / Numonyx (later acquired by Micron) */ + SPI_FLASH_VENDOR_SYNCMOS_MVC = 0x40, /* SyncMOS (SM) and Mosel Vitelic Corporation (MVC) */ + SPI_FLASH_VENDOR_TENX = 0x5E, /* Tenx Technologies */ + SPI_FLASH_VENDOR_TI = 0x97, /* Texas Instruments */ + SPI_FLASH_VENDOR_TI_OLD = 0x01, /* TI chips from last century */ + SPI_FLASH_VENDOR_WINBOND = 0xDA, /* Winbond */ + SPI_FLASH_VENDOR_WINBOND_NEX = 0xEF, /* Winbond (ex Nexcom) serial flashes */ + + SPI_FLASH_VENDOR_UNKNOWN = 0xFF +} SPI_FLASH_VENDOR_t; + /** * AVR macros for WDT managment */ @@ -123,6 +169,8 @@ class EspClass { uint8_t getCpuFreqMHz(); uint32_t getFlashChipId(); + uint8_t getFlashChipVendorId(); + //gets the actual chip size based on the flash id uint32_t getFlashChipRealSize(); //gets the size of the flash as set by the compiler