From 4b1568cbb90eaaa9fb138f5cac22ea60ed7e7136 Mon Sep 17 00:00:00 2001 From: sheinz Date: Mon, 18 Jul 2016 13:12:21 +0300 Subject: [PATCH] SPIFFS: flash access refactoring. --- extras/spiffs/esp_spi_flash.c | 336 ------------------------------- extras/spiffs/esp_spi_flash.h | 11 - extras/spiffs/esp_spiffs.c | 132 ++---------- extras/spiffs/esp_spiffs.h | 2 +- extras/spiffs/esp_spiffs_flash.c | 250 +++++++++++++++++++++++ extras/spiffs/esp_spiffs_flash.h | 64 ++++++ 6 files changed, 332 insertions(+), 463 deletions(-) delete mode 100644 extras/spiffs/esp_spi_flash.c delete mode 100644 extras/spiffs/esp_spi_flash.h create mode 100644 extras/spiffs/esp_spiffs_flash.c create mode 100644 extras/spiffs/esp_spiffs_flash.h diff --git a/extras/spiffs/esp_spi_flash.c b/extras/spiffs/esp_spi_flash.c deleted file mode 100644 index 74f8d98..0000000 --- a/extras/spiffs/esp_spi_flash.c +++ /dev/null @@ -1,336 +0,0 @@ -#include "esp_spi_flash.h" -#include "flashchip.h" -#include "espressif/spi_flash.h" -#include "FreeRTOS.h" -#include "esp/rom.h" -#include "esp/spi_regs.h" - - -static uint32_t IRAM read_status(sdk_flashchip_t *flashchip, uint32_t *status) -{ - uint32_t _status; - - do { - SPI(0).RSTATUS = 0; - SPI(0).CMD = SPI_CMD_READ_SR; - while (SPI(0).CMD) {} - _status = SPI(0).RSTATUS & flashchip->status_mask; - } while ( _status & 0b1); - - *status = _status; - - return 0; -} - -static uint32_t IRAM wait_idle(sdk_flashchip_t *flashchip) -{ - while (DPORT.SPI_READY & DPORT_SPI_READY_IDLE) {} - uint32_t a3; - return read_status(flashchip, &a3); -} - -static uint32_t IRAM write_enable(sdk_flashchip_t *flashchip) -{ - uint32_t local0 = 0; - - wait_idle(flashchip); - - SPI(0).CMD = SPI_CMD_WRITE_ENABLE; - while (SPI(0).CMD) {} - - if (!(local0 & 0b1)) { - do { - read_status(flashchip, &local0); - } while (!(local0 & (1<<1))); - } - return 0; -} - -static uint32_t IRAM page_program(sdk_flashchip_t *flashchip, uint32_t dest_addr, - uint32_t *buf, uint32_t size) -{ - if (size & 0b11) { - return 1; - } - - // check if block to write doesn't cross page boundary - if (flashchip->page_size < size + (dest_addr % flashchip->page_size)) { - return 1; - } - wait_idle(flashchip); - if (size < 1) { - return 0; - } - - // a12 = 0x60000200 - // a0 = 0x00FFFFFF - // a6 = (dest_addr & 0x00FFFFFF) | 0x20000000 - while (size >= 32) { - SPI(0).ADDR = (dest_addr & 0x00FFFFFF) | 0x20000000; - // a4 - loop variable += 4 - // a5 = buf[0] - for (uint8_t i = 0; i != 8; i++) { - SPI(0).W[i] = buf[i]; - } - size -= 32; - dest_addr += 32; - buf += 8; - if (write_enable(flashchip)) { - return 1; - } - SPI(0).CMD = SPI_CMD_PP; - while (SPI(0).CMD) {} // wait for reg->cmd to be 0 - wait_idle(flashchip); - // a0 = 0x00FFFFFF - if (size < 1) { - return 0; - } - } - // a7 = 0x00FFFFFF & dest_addr - // a4 = size << 24; - // a4 = a7 | a4 - SPI(0).ADDR = (size << 24) | (0x00FFFFFF & dest_addr); - // a6 = 0b11 & size - // a3 = size >> 2; - // a5 = a3 + 1 - uint32_t words = size >> 2; - if (0b11 & size) { - words += 1; - } - words = words & 0xFF; - if (words != 0) { - // a4 = 0 - uint8_t i = 0; - - if (words & 0b1) { // bit 0 is set in a3 - SPI(0).W[0] = buf[0]; - i++; - } - // a6 = a3 >> 1; - if (words >> 1) { - // a6 = 0x600000200 - // buff[0] - for (; i != words; i++) { - SPI(0).W[i] = buf[i]; - } - } - } - - if (write_enable(flashchip)) { - return 1; - } - SPI(0).CMD = SPI_CMD_PP; - while (SPI(0).CMD) {} // wait for reg->cmd to be 0 - wait_idle(flashchip); - // a0 = 0x00FFFFFF - return 0; -} - -static uint32_t IRAM read_data(sdk_flashchip_t *flashchip, uint32_t addr, - uint32_t *dst, uint32_t size) -{ - // a12 = dst - if ((addr + size) > flashchip->chip_size) { - return 1; - } - - // a14 = addr - // a13 = size - wait_idle(flashchip); - if (size < 1) { - return 0; - } - // SPI(0).CMD - while (size >= 32) { - // a8 = addr | 0x20000000; - SPI(0).ADDR = addr | 0x20000000; - SPI(0).CMD = SPI_CMD_READ; - while (SPI(0).CMD) {}; - for (uint32_t a2 = 0; a2 < 8; a2++) { - *dst = SPI(0).W[a2]; - dst++; - } - size -= 32; - addr += 32; - } - - if (size >= 1) { - // a7 = size << 24; - // a7 = addr | a7 - SPI(0).ADDR = addr | (size << 24); - SPI(0).CMD = SPI_CMD_READ; - while (SPI(0).CMD) {}; - // a10 = size & 0b11 - uint8_t a7 = size >> 2; - // a9 = a7 + 1 - if (size & 0b11) { - // a7 = a7 + 1 - a7++; - } - // a7 = a7 & 0xFF - if (!a7) { - return 0; - } - uint8_t a2 = 0; - if (a7 & 0b1) { - a2 = 1; - // a11 = SPI(0).W0 - *dst = SPI(0).W[0]; - dst += 1; - } - size = a7 >> 1; - if (!size) { - return 0; - } - for (; a2 != a7; a2++) { - *dst = SPI(0).W[a2]; - dst += 1; - } - } - - return 0; -} - -/** - * Reverse engineered implementation of spi_flash.o:sdk_SPIRead - */ -static uint32_t IRAM spi_read(uint32_t dest_addr, void *src, uint32_t size) -{ - if (read_data(&sdk_flashchip, dest_addr, (uint32_t*)src, size)) { - return 1; - } else { - return 0; - } -} - -/** - * Reverse engineered implementation of spi_flash.o:sdk_spi_flash_read - */ -uint32_t IRAM esp_spi_flash_read(uint32_t dest_addr, void *src, uint32_t size) -{ - if (src) { - vPortEnterCritical(); - Cache_Read_Disable(); - uint32_t result = spi_read(dest_addr, src, size); - Cache_Read_Enable(0, 0, 1); - vPortExitCritical(); - return result; - } else { - return 1; - } -} - -/** - * Reverse engineered implementation of spi_flash.o:sdk_SPIWrite - */ -static uint32_t IRAM spi_write(uint32_t dest_addr, void *dst, uint32_t size) -{ - if (sdk_flashchip.chip_size < (dest_addr + size)) { - return 1; - } - - uint32_t write_bytes_to_page = sdk_flashchip.page_size - - (dest_addr % sdk_flashchip.page_size); - - if (size < write_bytes_to_page) { - if (page_program(&sdk_flashchip, dest_addr, (uint32_t*)dst, size)) { - return 1; - } else { - return 0; - } - } - - if (page_program(&sdk_flashchip, dest_addr, (uint32_t*)dst, write_bytes_to_page)) { - return 1; - } - - uint32_t offset = write_bytes_to_page; - uint32_t pages_to_write = (size - offset) / sdk_flashchip.page_size; - for (uint8_t i = 0; i != pages_to_write; i++) { - if (page_program(&sdk_flashchip, dest_addr + offset, - dst + ((offset>>2)<<2), sdk_flashchip.page_size)) { - return 1; - } - offset += sdk_flashchip.page_size; - } - - if (page_program(&sdk_flashchip, dest_addr + offset, - dst + ((offset>>2)<<2), size - offset)) { - return 1; - } else { - return 0; - } -} - -/** - * Reverse engineered implementation of spi_flash.o:sdk_spi_flash_write - */ -uint32_t IRAM esp_spi_flash_write(uint32_t dest_addr, void *dst, uint32_t size) -{ - if (dst) { - if (size & 0b11) { // not 4-byte aligned - size = size >> 2; - size = (size << 2) + 1; - } - vPortEnterCritical(); - Cache_Read_Disable(); - uint32_t result = spi_write(dest_addr, dst, size); - Cache_Read_Enable(0, 0, 1); - vPortExitCritical(); - return result; - } else { - return 1; - } -} - -static uint32_t IRAM sector_erase(sdk_flashchip_t *chip, uint32_t addr) -{ - // a12 -> addr - // a0 = addr & 0xFFF - if (addr & 0xFFF) { - return 1; - } - - wait_idle(chip); - SPI(0).ADDR = addr & 0x00FFFFFF; - SPI(0).CMD = SPI_CMD_SE; - while (SPI(0).CMD) {}; - wait_idle(chip); - - return 0; -} - -/** - * Reverse engineered implementation of spi_flash.o:sdk_SPIEraseSector - */ -static uint32_t IRAM spi_erase_sector(uint32_t sector) -{ - if (sector >= (sdk_flashchip.chip_size / sdk_flashchip.sector_size)) { - return 1; - } - - if (write_enable(&sdk_flashchip)) { - return 1; - } - - if (sector_erase(&sdk_flashchip, sdk_flashchip.sector_size * sector)) { - return 1; - } - return 0; -} - -/** - * Reverse engineered implementation of spi_flash.o:sdk_spi_flash_erase_sector - */ -uint32_t IRAM esp_spi_flash_erase(uint32_t sector) -{ - vPortEnterCritical(); - Cache_Read_Disable(); - - uint32_t result = spi_erase_sector(sector); - - Cache_Read_Enable(0, 0, 1); - vPortExitCritical(); - - return result; -} diff --git a/extras/spiffs/esp_spi_flash.h b/extras/spiffs/esp_spi_flash.h deleted file mode 100644 index 6bf43e9..0000000 --- a/extras/spiffs/esp_spi_flash.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef __ESP_SPI_FLASH_H__ -#define __ESP_SPI_FLASH_H__ - -#include -#include "common_macros.h" - -uint32_t IRAM esp_spi_flash_read(uint32_t dest_addr, void *src, uint32_t size); -uint32_t IRAM esp_spi_flash_write(uint32_t dest_addr, void *dst, uint32_t size); -uint32_t IRAM esp_spi_flash_erase(uint32_t sector); - -#endif // __ESP_SPI_FLASH_H__ diff --git a/extras/spiffs/esp_spiffs.c b/extras/spiffs/esp_spiffs.c index a3c6b12..1574be2 100644 --- a/extras/spiffs/esp_spiffs.c +++ b/extras/spiffs/esp_spiffs.c @@ -11,7 +11,7 @@ #include #include #include -#include "esp_spi_flash.h" +#include "esp_spiffs_flash.h" spiffs fs; @@ -31,113 +31,19 @@ static fs_buf_t cache_buf = {0}; #define ESP_SPIFFS_CACHE_PAGES 5 - -/* - * Flash addresses and size alignment is a rip-off of Arduino implementation. - */ - static s32_t esp_spiffs_read(u32_t addr, u32_t size, u8_t *dst) { - uint32_t result = SPIFFS_OK; - uint32_t alignedBegin = (addr + 3) & (~3); - uint32_t alignedEnd = (addr + size) & (~3); - if (alignedEnd < alignedBegin) { - alignedEnd = alignedBegin; + if (esp_spiffs_flash_read(addr, dst, size) == ESP_SPIFFS_FLASH_ERROR) { + return SPIFFS_ERR_INTERNAL; } - if (addr < alignedBegin) { - uint32_t nb = alignedBegin - addr; - uint32_t tmp; - if (esp_spi_flash_read(alignedEnd - 4, &tmp, 4) != SPI_FLASH_RESULT_OK) { - printf("spi_flash_read failed\n"); - return SPIFFS_ERR_INTERNAL; - } - memcpy(dst, &tmp + 4 - nb, nb); - } - - if (alignedEnd != alignedBegin) { - if (esp_spi_flash_read(alignedBegin, - (uint32_t*) (dst + alignedBegin - addr), - alignedEnd - alignedBegin) != SPI_FLASH_RESULT_OK) { - printf("spi_flash_read failed\n"); - return SPIFFS_ERR_INTERNAL; - } - } - - if (addr + size > alignedEnd) { - uint32_t nb = addr + size - alignedEnd; - uint32_t tmp; - if (esp_spi_flash_read(alignedEnd, &tmp, 4) != SPI_FLASH_RESULT_OK) { - printf("spi_flash_read failed\n"); - return SPIFFS_ERR_INTERNAL; - } - - memcpy(dst + size - nb, &tmp, nb); - } - - return result; + return SPIFFS_OK; } -static const int UNALIGNED_WRITE_BUFFER_SIZE = 512; - static s32_t esp_spiffs_write(u32_t addr, u32_t size, u8_t *src) { - uint32_t alignedBegin = (addr + 3) & (~3); - uint32_t alignedEnd = (addr + size) & (~3); - if (alignedEnd < alignedBegin) { - alignedEnd = alignedBegin; - } - - if (addr < alignedBegin) { - uint32_t ofs = alignedBegin - addr; - uint32_t nb = (size < ofs) ? size : ofs; - uint8_t tmp[4] __attribute__((aligned(4))) = {0xff, 0xff, 0xff, 0xff}; - memcpy(tmp + 4 - ofs, src, nb); - if (esp_spi_flash_write(alignedBegin - 4, (uint32_t*) tmp, 4) - != SPI_FLASH_RESULT_OK) { - printf("spi_flash_write failed\n"); - return SPIFFS_ERR_INTERNAL; - } - } - - if (alignedEnd != alignedBegin) { - uint32_t* srcLeftover = (uint32_t*) (src + alignedBegin - addr); - uint32_t srcAlign = ((uint32_t) srcLeftover) & 3; - if (!srcAlign) { - if (esp_spi_flash_write(alignedBegin, (uint32_t*) srcLeftover, - alignedEnd - alignedBegin) != SPI_FLASH_RESULT_OK) { - printf("spi_flash_write failed\n"); - return SPIFFS_ERR_INTERNAL; - } - } - else { - uint8_t buf[UNALIGNED_WRITE_BUFFER_SIZE]; - for (uint32_t sizeLeft = alignedEnd - alignedBegin; sizeLeft; ) { - size_t willCopy = sizeLeft < sizeof(buf) ? sizeLeft : sizeof(buf); - memcpy(buf, srcLeftover, willCopy); - - if (esp_spi_flash_write(alignedBegin, (uint32_t*) buf, willCopy) - != SPI_FLASH_RESULT_OK) { - printf("spi_flash_write failed\n"); - return SPIFFS_ERR_INTERNAL; - } - - sizeLeft -= willCopy; - srcLeftover += willCopy; - alignedBegin += willCopy; - } - } - } - - if (addr + size > alignedEnd) { - uint32_t nb = addr + size - alignedEnd; - uint32_t tmp = 0xffffffff; - memcpy(&tmp, src + size - nb, nb); - - if (esp_spi_flash_write(alignedEnd, &tmp, 4) != SPI_FLASH_RESULT_OK) { - printf("spi_flash_write failed\n"); - return SPIFFS_ERR_INTERNAL; - } + if (esp_spiffs_flash_write(addr, src, size) == ESP_SPIFFS_FLASH_ERROR) { + return SPIFFS_ERR_INTERNAL; } return SPIFFS_OK; @@ -145,19 +51,15 @@ static s32_t esp_spiffs_write(u32_t addr, u32_t size, u8_t *src) static s32_t esp_spiffs_erase(u32_t addr, u32_t size) { - if (addr % SPI_FLASH_SEC_SIZE) { - printf("Unaligned erase addr=%x\n", addr); - } - if (size % SPI_FLASH_SEC_SIZE) { - printf("Unaligned erase size=%d\n", size); + uint32_t sectors = size / SPI_FLASH_SEC_SIZE; + + for (uint32_t i = 0; i < sectors; i++) { + if (esp_spiffs_flash_erase_sector(addr + (SPI_FLASH_SEC_SIZE * i)) + == ESP_SPIFFS_FLASH_ERROR) { + return SPIFFS_ERR_INTERNAL; + } } - const uint32_t sector = addr / SPI_FLASH_SEC_SIZE; - const uint32_t sectorCount = size / SPI_FLASH_SEC_SIZE; - - for (uint32_t i = 0; i < sectorCount; ++i) { - esp_spi_flash_erase(sector + i); - } return SPIFFS_OK; } @@ -196,8 +98,8 @@ int32_t esp_spiffs_mount() printf("SPIFFS memory, work_buf_size=%d, fds_buf_size=%d, cache_buf_size=%d\n", work_buf.size, fds_buf.size, cache_buf.size); - int32_t err = SPIFFS_mount(&fs, &config, (uint8_t*)work_buf.buf, - (uint8_t*)fds_buf.buf, fds_buf.size, + int32_t err = SPIFFS_mount(&fs, &config, (uint8_t*)work_buf.buf, + (uint8_t*)fds_buf.buf, fds_buf.size, cache_buf.buf, cache_buf.size, 0); if (err != SPIFFS_OK) { @@ -213,7 +115,7 @@ int32_t esp_spiffs_mount() long _write_r(struct _reent *r, int fd, const char *ptr, int len ) { if(fd != r->_stdout->_file) { - long ret = SPIFFS_write(&fs, (spiffs_file)(fd - FD_OFFSET), + long ret = SPIFFS_write(&fs, (spiffs_file)(fd - FD_OFFSET), (char*)ptr, len); return ret; } @@ -296,6 +198,6 @@ int _stat_r(struct _reent *r, const char *pathname, void *buf) } off_t _lseek_r(struct _reent *r, int fd, off_t offset, int whence) -{ +{ return SPIFFS_lseek(&fs, (spiffs_file)(fd - FD_OFFSET), offset, whence); } diff --git a/extras/spiffs/esp_spiffs.h b/extras/spiffs/esp_spiffs.h index f074017..60dc7f0 100644 --- a/extras/spiffs/esp_spiffs.h +++ b/extras/spiffs/esp_spiffs.h @@ -14,7 +14,7 @@ extern spiffs fs; /** * Prepare for SPIFFS mount. - * + * * The function allocates all the necessary buffers. */ void esp_spiffs_init(); diff --git a/extras/spiffs/esp_spiffs_flash.c b/extras/spiffs/esp_spiffs_flash.c new file mode 100644 index 0000000..1098551 --- /dev/null +++ b/extras/spiffs/esp_spiffs_flash.c @@ -0,0 +1,250 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2016 sheinz (https://github.com/sheinz) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "esp_spiffs_flash.h" +#include "flashchip.h" +#include "espressif/spi_flash.h" +#include "FreeRTOS.h" +#include "esp/rom.h" +#include "esp/spi_regs.h" + + +#define SPI_WRITE_MAX_SIZE 32 +#define SPI_READ_MAX_SIZE 32 + +/** + * Low level SPI flash write. Write block of data up to SPI_WRITE_MAX_SIZE. + */ +static inline uint32_t IRAM spi_write_data(sdk_flashchip_t *chip, uint32_t addr, + uint8_t *buf, uint32_t size) +{ + SPI(0).ADDR = (addr & 0x00FFFFFF) | (size << 24); + + uint32_t data = 0; + // Copy more than size, in order not to handle unaligned size. + // The exact size will be written to flash + for (uint32_t i = 0; i != SPI_WRITE_MAX_SIZE; i++) { data >>= 8; + data |= (uint32_t)buf[i] << 24; + + if (i & 0b11) { + SPI(0).W[i >> 2] = data; + } + } + + if (SPI_write_enable(chip)) { + return ESP_SPIFFS_FLASH_ERROR; + } + + SPI(0).CMD = SPI_CMD_PP; + while (SPI(0).CMD) {} + Wait_SPI_Idle(chip); + + return ESP_SPIFFS_FLASH_OK; +} + +/** + * Write a page of flash. Data block should bot cross page boundary. + */ +static uint32_t IRAM spi_write_page(sdk_flashchip_t *flashchip, uint32_t dest_addr, + uint8_t *buf, uint32_t size) +{ + // check if block to write doesn't cross page boundary + if (flashchip->page_size < size + (dest_addr % flashchip->page_size)) { + return ESP_SPIFFS_FLASH_ERROR; + } + + if (size < 1) { + return ESP_SPIFFS_FLASH_OK; + } + + Wait_SPI_Idle(flashchip); + + while (size >= SPI_WRITE_MAX_SIZE) { + if (spi_write_data(flashchip, dest_addr, buf, SPI_WRITE_MAX_SIZE)) { + return ESP_SPIFFS_FLASH_ERROR; + } + + size -= SPI_WRITE_MAX_SIZE; + dest_addr += SPI_WRITE_MAX_SIZE; + buf += SPI_WRITE_MAX_SIZE; + + if (size < 1) { + return ESP_SPIFFS_FLASH_OK; + } + } + + if (spi_write_data(flashchip, dest_addr, buf, size)) { + return ESP_SPIFFS_FLASH_ERROR; + } + return ESP_SPIFFS_FLASH_OK; +} + +/** + * Split block of data into pages and write pages. + */ +static uint32_t IRAM spi_write(uint32_t addr, uint8_t *dst, uint32_t size) +{ + if (sdk_flashchip.chip_size < (addr + size)) { + return ESP_SPIFFS_FLASH_ERROR; + } + + uint32_t write_bytes_to_page = sdk_flashchip.page_size - + (addr % sdk_flashchip.page_size); // TODO: place for optimization + + if (size < write_bytes_to_page) { + if (spi_write_page(&sdk_flashchip, addr, dst, size)) { + return ESP_SPIFFS_FLASH_ERROR; + } + return ESP_SPIFFS_FLASH_OK; + } + + if (spi_write_page(&sdk_flashchip, addr, dst, write_bytes_to_page)) { + return ESP_SPIFFS_FLASH_ERROR; + } + + uint32_t offset = write_bytes_to_page; + uint32_t pages_to_write = (size - offset) / sdk_flashchip.page_size; + for (uint8_t i = 0; i != pages_to_write; i++) { + if (spi_write_page(&sdk_flashchip, addr + offset, + dst + offset, sdk_flashchip.page_size)) { + return ESP_SPIFFS_FLASH_ERROR; + } + offset += sdk_flashchip.page_size; + } + + if (spi_write_page(&sdk_flashchip, addr + offset, + dst + offset, size - offset)) { + return ESP_SPIFFS_FLASH_ERROR; + } + return ESP_SPIFFS_FLASH_OK; +} + +uint32_t IRAM esp_spiffs_flash_write(uint32_t addr, uint8_t *buf, uint32_t size) +{ + uint32_t result = ESP_SPIFFS_FLASH_ERROR; + + if (buf) { + vPortEnterCritical(); + Cache_Read_Disable(); + + result = spi_write(addr, buf, size); + + Cache_Read_Enable(0, 0, 1); + vPortExitCritical(); + } + + return result; +} + +/** + * Read SPI flash up to SPI_READ_MAX_SIZE size. + */ +static inline void IRAM read_block(sdk_flashchip_t *chip, uint32_t addr, + uint8_t *buf, uint32_t size) +{ + SPI(0).ADDR = (addr & 0x00FFFFFF) | (size << 24); + SPI(0).CMD = SPI_CMD_READ; + while (SPI(0).CMD) {}; + uint32_t data = 0; + for (uint32_t i = 0; i < size; i++) { + if (!(i & 0b11)) { + data = SPI(0).W[i>>2]; + } + buf[i] = 0xFF & data; + data >>= 8; + } +} + +/** + * Read SPI flash data. Data region doesn't need to be page aligned. + */ +static inline uint32_t IRAM read_data(sdk_flashchip_t *flashchip, uint32_t addr, + uint8_t *dst, uint32_t size) +{ + if (size < 1) { + return ESP_SPIFFS_FLASH_OK; + } + + if ((addr + size) > flashchip->chip_size) { + return ESP_SPIFFS_FLASH_ERROR; + } + + Wait_SPI_Idle(flashchip); + + while (size >= SPI_READ_MAX_SIZE) { + read_block(flashchip, addr, dst, SPI_READ_MAX_SIZE); + dst += SPI_READ_MAX_SIZE; + size -= SPI_READ_MAX_SIZE; + addr += SPI_READ_MAX_SIZE; + } + + if (size > 0) { + read_block(flashchip, addr, dst, size); + } + + return ESP_SPIFFS_FLASH_OK; +} + +uint32_t IRAM esp_spiffs_flash_read(uint32_t dest_addr, uint8_t *buf, uint32_t size) +{ + uint32_t result = ESP_SPIFFS_FLASH_ERROR; + + if (buf) { + vPortEnterCritical(); + Cache_Read_Disable(); + + result = read_data(&sdk_flashchip, dest_addr, buf, size); + + Cache_Read_Enable(0, 0, 1); + vPortExitCritical(); + } + + return result; +} + +uint32_t IRAM esp_spiffs_flash_erase_sector(uint32_t addr) +{ + if ((addr + sdk_flashchip.sector_size) > sdk_flashchip.chip_size) { + return ESP_SPIFFS_FLASH_ERROR; + } + + if (addr & 0xFFF) { + return ESP_SPIFFS_FLASH_ERROR; + } + + vPortEnterCritical(); + Cache_Read_Disable(); + + SPI_write_enable(&sdk_flashchip); + + Wait_SPI_Idle(&sdk_flashchip); + SPI(0).ADDR = addr & 0x00FFFFFF; + SPI(0).CMD = SPI_CMD_SE; + while (SPI(0).CMD) {}; + Wait_SPI_Idle(&sdk_flashchip); + + Cache_Read_Enable(0, 0, 1); + vPortExitCritical(); + + return ESP_SPIFFS_FLASH_OK; +} diff --git a/extras/spiffs/esp_spiffs_flash.h b/extras/spiffs/esp_spiffs_flash.h new file mode 100644 index 0000000..abfe864 --- /dev/null +++ b/extras/spiffs/esp_spiffs_flash.h @@ -0,0 +1,64 @@ +/** + * The MIT License (MIT) + * + * Copyright (c) 2016 sheinz (https://github.com/sheinz) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef __ESP_SPIFFS_FLASH_H__ +#define __ESP_SPIFFS_FLASH_H__ + +#include +#include "common_macros.h" + +#define ESP_SPIFFS_FLASH_OK 0 +#define ESP_SPIFFS_FLASH_ERROR 1 + +/** + * Read data from SPI flash. + * + * @param addr Address to read from. Can be not aligned. + * @param buf Buffer to read to. Doesn't have to be aligned. + * @param size Size of data to read. Buffer size must be >= than data size. + * + * @return ESP_SPIFFS_FLASH_OK or ESP_SPIFFS_FLASH_ERROR + */ +uint32_t IRAM esp_spiffs_flash_read(uint32_t addr, uint8_t *buf, uint32_t size); + +/** + * Write data to SPI flash. + * + * @param addr Address to write to. Can be not aligned. + * @param buf Buffer of data to write to flash. Doesn't have to be aligned. + * @param size Size of data to write. Buffer size must be >= than data size. + * + * @return ESP_SPIFFS_FLASH_OK or ESP_SPIFFS_FLASH_ERROR + */ +uint32_t IRAM esp_spiffs_flash_write(uint32_t addr, uint8_t *buf, uint32_t size); + +/** + * Erase a sector. + * + * @param addr Address of sector to erase. Must be sector aligned. + * + * @return ESP_SPIFFS_FLASH_OK or ESP_SPIFFS_FLASH_ERROR + */ +uint32_t IRAM esp_spiffs_flash_erase_sector(uint32_t addr); + +#endif // __ESP_SPIFFS_FLASH_H__