/* bytes erased by SPIEraseBlock() ROM function */
#define BLOCK_ERASE_SIZE 65536
+/* Limit number of bytes written/read in a single SPI operation,
+ as these operations disable all higher priority tasks from running.
+*/
+#define MAX_WRITE_CHUNK 8192
+#define MAX_READ_CHUNK 16384
+
#if CONFIG_SPI_FLASH_ENABLE_COUNTERS
static const char* TAG = "spi_flash";
static spi_flash_counters_t s_flash_stats;
return g_rom_flashchip.chip_size;
}
-static SpiFlashOpResult IRAM_ATTR spi_flash_unlock()
-{
- static bool unlocked = false;
- if (!unlocked) {
- SpiFlashOpResult rc = SPIUnlock();
- if (rc != SPI_FLASH_RESULT_OK) {
- return rc;
- }
- unlocked = true;
- }
- return SPI_FLASH_RESULT_OK;
-}
-
static inline void IRAM_ATTR spi_flash_guard_start()
{
if (s_flash_guard_ops && s_flash_guard_ops->start) {
}
}
+static SpiFlashOpResult IRAM_ATTR spi_flash_unlock()
+{
+ static bool unlocked = false;
+ if (!unlocked) {
+ spi_flash_guard_start();
+ SpiFlashOpResult rc = SPIUnlock();
+ spi_flash_guard_end();
+ if (rc != SPI_FLASH_RESULT_OK) {
+ return rc;
+ }
+ unlocked = true;
+ }
+ return SPI_FLASH_RESULT_OK;
+}
+
esp_err_t IRAM_ATTR spi_flash_erase_sector(size_t sec)
{
return spi_flash_erase_range(sec * SPI_FLASH_SEC_SIZE, SPI_FLASH_SEC_SIZE);
size_t end = start + size / SPI_FLASH_SEC_SIZE;
const size_t sectors_per_block = BLOCK_ERASE_SIZE / SPI_FLASH_SEC_SIZE;
COUNTER_START();
- spi_flash_guard_start();
- SpiFlashOpResult rc;
- rc = spi_flash_unlock();
+ SpiFlashOpResult rc = spi_flash_unlock();
if (rc == SPI_FLASH_RESULT_OK) {
for (size_t sector = start; sector != end && rc == SPI_FLASH_RESULT_OK; ) {
+ spi_flash_guard_start();
if (sector % sectors_per_block == 0 && end - sector > sectors_per_block) {
rc = SPIEraseBlock(sector / sectors_per_block);
sector += sectors_per_block;
++sector;
COUNTER_ADD_BYTES(erase, SPI_FLASH_SEC_SIZE);
}
+ spi_flash_guard_end();
}
}
- spi_flash_guard_end();
COUNTER_STOP(erase);
return spi_flash_translate_rc(rc);
}
size_t mid_size = (size - left_size) & ~3U;
size_t right_off = left_size + mid_size;
size_t right_size = size - mid_size - left_size;
- spi_flash_guard_start();
rc = spi_flash_unlock();
- spi_flash_guard_end();
if (rc != SPI_FLASH_RESULT_OK) {
goto out;
}
COUNTER_ADD_BYTES(write, 4);
}
if (mid_size > 0) {
- /* If src buffer is 4-byte aligned as well and is not in a region that
- * requires cache access to be enabled, we can write it all at once. */
+ /* If src buffer is 4-byte aligned as well and is not in a region that requires cache access to be enabled, we
+ * can write directly without buffering in RAM. */
#ifdef ESP_PLATFORM
- bool in_dram = ((uintptr_t) srcc >= 0x3FFAE000 &&
- (uintptr_t) srcc < 0x40000000);
+ bool direct_write = ( (uintptr_t) srcc >= 0x3FFAE000
+ && (uintptr_t) srcc < 0x40000000
+ && ((uintptr_t) srcc + mid_off) % 4 == 0 );
#else
- bool in_dram = true;
+ bool direct_write = true;
#endif
- if (in_dram && (((uintptr_t) srcc) + mid_off) % 4 == 0) {
+ while(mid_size > 0 && rc == SPI_FLASH_RESULT_OK) {
+ uint32_t write_buf[8];
+ uint32_t write_size;
+ const uint32_t *write_src = (const uint32_t *) (srcc + mid_off);
+ if (direct_write) {
+ write_size = MIN(mid_size, MAX_WRITE_CHUNK); /* Write in chunks, to avoid starving other CPU/tasks */
+ } else {
+ write_size = MIN(mid_size, sizeof(write_buf));
+ memcpy(write_buf, write_src, write_size);
+ write_src = write_buf;
+ }
spi_flash_guard_start();
- rc = SPIWrite(dst + mid_off, (const uint32_t *) (srcc + mid_off), mid_size);
+ rc = SPIWrite(dst + mid_off, write_src, write_size);
spi_flash_guard_end();
- if (rc != SPI_FLASH_RESULT_OK) {
- goto out;
- }
- COUNTER_ADD_BYTES(write, mid_size);
- } else {
- /*
- * Otherwise, unlike for read, we cannot manipulate data in the
- * user-provided buffer, so we write in 32 byte blocks.
- */
- while (mid_size > 0) {
- uint32_t t[8];
- uint32_t write_size = MIN(mid_size, sizeof(t));
- memcpy(t, srcc + mid_off, write_size);
- spi_flash_guard_start();
- rc = SPIWrite(dst + mid_off, t, write_size);
- spi_flash_guard_end();
- if (rc != SPI_FLASH_RESULT_OK) {
- goto out;
- }
- COUNTER_ADD_BYTES(write, write_size);
- mid_size -= write_size;
- mid_off += write_size;
- }
+ COUNTER_ADD_BYTES(write, write_size);
+ mid_size -= write_size;
+ mid_off += write_size;
+ }
+ if (rc != SPI_FLASH_RESULT_OK) {
+ goto out;
}
}
+
if (right_size > 0) {
uint32_t t = 0xffffffff;
memcpy(&t, srcc + right_off, right_size);
}
COUNTER_START();
- spi_flash_disable_interrupts_caches_and_other_cpu();
- SpiFlashOpResult rc;
- spi_flash_guard_start();
- rc = spi_flash_unlock();
- spi_flash_guard_end();
- spi_flash_enable_interrupts_caches_and_other_cpu();
+ SpiFlashOpResult rc = spi_flash_unlock();
if (rc == SPI_FLASH_RESULT_OK) {
/* SPI_Encrypt_Write encrypts data in RAM as it writes,
memcpy(encrypt_buf, ssrc + i, 32);
}
- spi_flash_disable_interrupts_caches_and_other_cpu();
+ spi_flash_guard_start();
rc = SPI_Encrypt_Write(row_addr, (uint32_t *)encrypt_buf, 32);
- spi_flash_enable_interrupts_caches_and_other_cpu();
+ spi_flash_guard_end();
if (rc != SPI_FLASH_RESULT_OK) {
break;
}
bzero(encrypt_buf, sizeof(encrypt_buf));
}
COUNTER_ADD_BYTES(write, size);
+ COUNTER_STOP(write);
spi_flash_guard_op_lock();
spi_flash_mark_modified_region(dest_addr, size);
size_t pad_right_off = (pad_right_src - src);
size_t pad_right_size = (size - pad_right_off);
if (mid_size > 0) {
- rc = SPIRead(src + src_mid_off, (uint32_t *) (dstc + dst_mid_off), mid_size);
- if (rc != SPI_FLASH_RESULT_OK) {
- goto out;
+ uint32_t mid_remaining = mid_size;
+ uint32_t mid_read = 0;
+ while (mid_remaining > 0) {
+ uint32_t read_size = MIN(mid_remaining, MAX_READ_CHUNK);
+ rc = SPIRead(src + src_mid_off + mid_read, (uint32_t *) (dstc + dst_mid_off + mid_read), read_size);
+ if (rc != SPI_FLASH_RESULT_OK) {
+ goto out;
+ }
+ mid_remaining -= read_size;
+ mid_read += read_size;
+ if (mid_remaining > 0) {
+ /* Drop guard momentarily, allows other tasks to preempt */
+ spi_flash_guard_end();
+ spi_flash_guard_start();
+ }
}
COUNTER_ADD_BYTES(read, mid_size);
/*
--- /dev/null
+// Copyright 2010-2016 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Test for spi_flash_{read,write}.
+
+#include <assert.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/param.h>
+
+#include <unity.h>
+#include <test_utils.h>
+#include <esp_partition.h>
+
+TEST_CASE("Test erase partition", "[spi_flash]")
+{
+ const esp_partition_t *part = get_test_data_partition();
+
+#if CONFIG_SPI_FLASH_ENABLE_COUNTERS
+ spi_flash_reset_counters();
+#endif
+
+ // erase whole partition
+ ESP_ERROR_CHECK( esp_partition_erase_range(part, 0, part->size) );
+
+#if CONFIG_SPI_FLASH_ENABLE_COUNTERS
+ spi_flash_dump_counters();
+#endif
+
+ // put some dummy data on sector boundaries
+ const char *some_data = "abcdefghijklmn";
+ for (int i = 0; i < part->size; i+= 4096) {
+ ESP_ERROR_CHECK( esp_partition_write(part, i, some_data, strlen(some_data)) );
+ }
+
+ // check it's there!
+ char buf[strlen(some_data)];
+ for (int i = 0; i < part->size; i+= 4096) {
+ memset(buf, 0x00, sizeof(buf));
+ ESP_ERROR_CHECK( esp_partition_read(part, i, buf, sizeof(buf)) );
+ TEST_ASSERT_EQUAL_INT(0, strncmp(buf, some_data, sizeof(buf)));
+ }
+
+ // erase the whole thing again
+ ESP_ERROR_CHECK( esp_partition_erase_range(part, 0, part->size) );
+
+ // check it's gone
+ for (int i = 0; i < part->size; i+= 4096) {
+ memset(buf, 0x00, sizeof(buf));
+ ESP_ERROR_CHECK( esp_partition_read(part, i, buf, sizeof(buf)) );
+ for (int i = 0; i < sizeof(buf); i++) {
+ TEST_ASSERT_EQUAL_HEX8(0xFF, buf[i]);
+ }
+ }
+
+}