SPIFFS: flash access refactoring.
This commit is contained in:
parent
5d5f28a22f
commit
4b1568cbb9
6 changed files with 332 additions and 463 deletions
|
@ -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;
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
#ifndef __ESP_SPI_FLASH_H__
|
|
||||||
#define __ESP_SPI_FLASH_H__
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#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__
|
|
|
@ -11,7 +11,7 @@
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <esp/uart.h>
|
#include <esp/uart.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include "esp_spi_flash.h"
|
#include "esp_spiffs_flash.h"
|
||||||
|
|
||||||
spiffs fs;
|
spiffs fs;
|
||||||
|
|
||||||
|
@ -31,113 +31,19 @@ static fs_buf_t cache_buf = {0};
|
||||||
|
|
||||||
#define ESP_SPIFFS_CACHE_PAGES 5
|
#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)
|
static s32_t esp_spiffs_read(u32_t addr, u32_t size, u8_t *dst)
|
||||||
{
|
{
|
||||||
uint32_t result = SPIFFS_OK;
|
if (esp_spiffs_flash_read(addr, dst, size) == ESP_SPIFFS_FLASH_ERROR) {
|
||||||
uint32_t alignedBegin = (addr + 3) & (~3);
|
return SPIFFS_ERR_INTERNAL;
|
||||||
uint32_t alignedEnd = (addr + size) & (~3);
|
|
||||||
if (alignedEnd < alignedBegin) {
|
|
||||||
alignedEnd = alignedBegin;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (addr < alignedBegin) {
|
return SPIFFS_OK;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const int UNALIGNED_WRITE_BUFFER_SIZE = 512;
|
|
||||||
|
|
||||||
static s32_t esp_spiffs_write(u32_t addr, u32_t size, u8_t *src)
|
static s32_t esp_spiffs_write(u32_t addr, u32_t size, u8_t *src)
|
||||||
{
|
{
|
||||||
uint32_t alignedBegin = (addr + 3) & (~3);
|
if (esp_spiffs_flash_write(addr, src, size) == ESP_SPIFFS_FLASH_ERROR) {
|
||||||
uint32_t alignedEnd = (addr + size) & (~3);
|
return SPIFFS_ERR_INTERNAL;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return SPIFFS_OK;
|
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)
|
static s32_t esp_spiffs_erase(u32_t addr, u32_t size)
|
||||||
{
|
{
|
||||||
if (addr % SPI_FLASH_SEC_SIZE) {
|
uint32_t sectors = size / SPI_FLASH_SEC_SIZE;
|
||||||
printf("Unaligned erase addr=%x\n", addr);
|
|
||||||
}
|
for (uint32_t i = 0; i < sectors; i++) {
|
||||||
if (size % SPI_FLASH_SEC_SIZE) {
|
if (esp_spiffs_flash_erase_sector(addr + (SPI_FLASH_SEC_SIZE * i))
|
||||||
printf("Unaligned erase size=%d\n", size);
|
== 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;
|
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",
|
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);
|
work_buf.size, fds_buf.size, cache_buf.size);
|
||||||
|
|
||||||
int32_t err = SPIFFS_mount(&fs, &config, (uint8_t*)work_buf.buf,
|
int32_t err = SPIFFS_mount(&fs, &config, (uint8_t*)work_buf.buf,
|
||||||
(uint8_t*)fds_buf.buf, fds_buf.size,
|
(uint8_t*)fds_buf.buf, fds_buf.size,
|
||||||
cache_buf.buf, cache_buf.size, 0);
|
cache_buf.buf, cache_buf.size, 0);
|
||||||
|
|
||||||
if (err != SPIFFS_OK) {
|
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 )
|
long _write_r(struct _reent *r, int fd, const char *ptr, int len )
|
||||||
{
|
{
|
||||||
if(fd != r->_stdout->_file) {
|
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);
|
(char*)ptr, len);
|
||||||
return ret;
|
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)
|
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);
|
return SPIFFS_lseek(&fs, (spiffs_file)(fd - FD_OFFSET), offset, whence);
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ extern spiffs fs;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prepare for SPIFFS mount.
|
* Prepare for SPIFFS mount.
|
||||||
*
|
*
|
||||||
* The function allocates all the necessary buffers.
|
* The function allocates all the necessary buffers.
|
||||||
*/
|
*/
|
||||||
void esp_spiffs_init();
|
void esp_spiffs_init();
|
||||||
|
|
250
extras/spiffs/esp_spiffs_flash.c
Normal file
250
extras/spiffs/esp_spiffs_flash.c
Normal file
|
@ -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;
|
||||||
|
}
|
64
extras/spiffs/esp_spiffs_flash.h
Normal file
64
extras/spiffs/esp_spiffs_flash.h
Normal file
|
@ -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 <stdint.h>
|
||||||
|
#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__
|
Loading…
Reference in a new issue