spi_flash: fix spi_flash_read into buffer in external RAM, add test

This commit is contained in:
Ivan Grokhotkov
2017-10-18 12:21:19 +08:00
parent 099565635b
commit 8990549e89
2 changed files with 92 additions and 5 deletions

View File

@@ -230,9 +230,9 @@ esp_err_t IRAM_ATTR spi_flash_write(size_t dst, const void *srcv, size_t size)
/* If src buffer is 4-byte aligned as well and is not in a region that requires cache access to be enabled, we /* 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. */ * can write directly without buffering in RAM. */
#ifdef ESP_PLATFORM #ifdef ESP_PLATFORM
bool direct_write = ( (uintptr_t) srcc >= 0x3FFAE000 bool direct_write = esp_ptr_internal(srcc)
&& (uintptr_t) srcc < 0x40000000 && esp_ptr_byte_accessible(srcc)
&& ((uintptr_t) srcc + mid_off) % 4 == 0 ); && ((uintptr_t) srcc + mid_off) % 4 == 0;
#else #else
bool direct_write = true; bool direct_write = true;
#endif #endif
@@ -395,18 +395,38 @@ esp_err_t IRAM_ATTR spi_flash_read(size_t src, void *dstv, size_t size)
size_t pad_right_src = (src + pad_left_size + mid_size) & ~3U; size_t pad_right_src = (src + pad_left_size + mid_size) & ~3U;
size_t pad_right_off = (pad_right_src - src); size_t pad_right_off = (pad_right_src - src);
size_t pad_right_size = (size - pad_right_off); size_t pad_right_size = (size - pad_right_off);
#ifdef ESP_PLATFORM
bool direct_read = esp_ptr_internal(dstc)
&& esp_ptr_byte_accessible(dstc)
&& ((uintptr_t) dstc + dst_mid_off) % 4 == 0;
#else
bool direct_read = true;
#endif
if (mid_size > 0) { if (mid_size > 0) {
uint32_t mid_remaining = mid_size; uint32_t mid_remaining = mid_size;
uint32_t mid_read = 0; uint32_t mid_read = 0;
while (mid_remaining > 0) { while (mid_remaining > 0) {
uint32_t read_size = MIN(mid_remaining, MAX_READ_CHUNK); uint32_t read_size = MIN(mid_remaining, MAX_READ_CHUNK);
rc = esp_rom_spiflash_read(src + src_mid_off + mid_read, (uint32_t *) (dstc + dst_mid_off + mid_read), read_size); uint32_t read_buf[8];
uint8_t *read_dst_final = dstc + dst_mid_off + mid_read;
uint8_t *read_dst = read_dst_final;
if (!direct_read) {
read_size = MIN(read_size, sizeof(read_buf));
read_dst = (uint8_t *) read_buf;
}
rc = esp_rom_spiflash_read(src + src_mid_off + mid_read,
(uint32_t *) read_dst, read_size);
if (rc != ESP_ROM_SPIFLASH_RESULT_OK) { if (rc != ESP_ROM_SPIFLASH_RESULT_OK) {
goto out; goto out;
} }
mid_remaining -= read_size; mid_remaining -= read_size;
mid_read += read_size; mid_read += read_size;
if (mid_remaining > 0) { if (!direct_read) {
spi_flash_guard_end();
memcpy(read_dst_final, read_buf, read_size);
spi_flash_guard_start();
} else if (mid_remaining > 0) {
/* Drop guard momentarily, allows other tasks to preempt */ /* Drop guard momentarily, allows other tasks to preempt */
spi_flash_guard_end(); spi_flash_guard_end();
spi_flash_guard_start(); spi_flash_guard_start();
@@ -419,7 +439,13 @@ esp_err_t IRAM_ATTR spi_flash_read(size_t src, void *dstv, size_t size)
* Note that the shift can be left (src_mid_off < dst_mid_off) or right. * Note that the shift can be left (src_mid_off < dst_mid_off) or right.
*/ */
if (src_mid_off != dst_mid_off) { if (src_mid_off != dst_mid_off) {
if (!direct_read) {
spi_flash_guard_end();
}
memmove(dstc + src_mid_off, dstc + dst_mid_off, mid_size); memmove(dstc + src_mid_off, dstc + dst_mid_off, mid_size);
if (!direct_read) {
spi_flash_guard_start();
}
} }
} }
if (pad_left_size > 0) { if (pad_left_size > 0) {
@@ -429,7 +455,13 @@ esp_err_t IRAM_ATTR spi_flash_read(size_t src, void *dstv, size_t size)
goto out; goto out;
} }
COUNTER_ADD_BYTES(read, 4); COUNTER_ADD_BYTES(read, 4);
if (!direct_read) {
spi_flash_guard_end();
}
memcpy(dstc, ((uint8_t *) &t) + (4 - pad_left_size), pad_left_size); memcpy(dstc, ((uint8_t *) &t) + (4 - pad_left_size), pad_left_size);
if (!direct_read) {
spi_flash_guard_start();
}
} }
if (pad_right_size > 0) { if (pad_right_size > 0) {
uint32_t t[2]; uint32_t t[2];
@@ -439,7 +471,13 @@ esp_err_t IRAM_ATTR spi_flash_read(size_t src, void *dstv, size_t size)
goto out; goto out;
} }
COUNTER_ADD_BYTES(read, read_size); COUNTER_ADD_BYTES(read, read_size);
if (!direct_read) {
spi_flash_guard_end();
}
memcpy(dstc + pad_right_off, t, pad_right_size); memcpy(dstc + pad_right_off, t, pad_right_size);
if (!direct_read) {
spi_flash_guard_start();
}
} }
out: out:
spi_flash_guard_end(); spi_flash_guard_end();

View File

@@ -27,6 +27,7 @@
#include "../cache_utils.h" #include "../cache_utils.h"
#include "soc/timer_group_struct.h" #include "soc/timer_group_struct.h"
#include "soc/timer_group_reg.h" #include "soc/timer_group_reg.h"
#include "esp_heap_caps.h"
/* Base offset in flash for tests. */ /* Base offset in flash for tests. */
static size_t start; static size_t start;
@@ -217,3 +218,51 @@ TEST_CASE("Test spi_flash_write", "[spi_flash]")
ESP_ERROR_CHECK(spi_flash_write(start, (char *) 0x40078000, 16)); ESP_ERROR_CHECK(spi_flash_write(start, (char *) 0x40078000, 16));
ESP_ERROR_CHECK(spi_flash_write(start, (char *) 0x40080000, 16)); ESP_ERROR_CHECK(spi_flash_write(start, (char *) 0x40080000, 16));
} }
#ifdef CONFIG_SPIRAM_SUPPORT
TEST_CASE("spi_flash_read can read into buffer in external RAM", "[spi_flash]")
{
uint8_t* buf_ext = (uint8_t*) heap_caps_malloc(SPI_FLASH_SEC_SIZE, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
TEST_ASSERT_NOT_NULL(buf_ext);
uint8_t* buf_int = (uint8_t*) heap_caps_malloc(SPI_FLASH_SEC_SIZE, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
TEST_ASSERT_NOT_NULL(buf_int);
TEST_ESP_OK(spi_flash_read(0x1000, buf_int, SPI_FLASH_SEC_SIZE));
TEST_ESP_OK(spi_flash_read(0x1000, buf_ext, SPI_FLASH_SEC_SIZE));
TEST_ASSERT_EQUAL(0, memcmp(buf_ext, buf_int, SPI_FLASH_SEC_SIZE));
free(buf_ext);
free(buf_int);
}
TEST_CASE("spi_flash_write can write from external RAM buffer", "[spi_flash]")
{
uint32_t* buf_ext = (uint32_t*) heap_caps_malloc(SPI_FLASH_SEC_SIZE, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
TEST_ASSERT_NOT_NULL(buf_ext);
srand(0);
for (size_t i = 0; i < SPI_FLASH_SEC_SIZE / sizeof(uint32_t); i++)
{
uint32_t val = rand();
buf_ext[i] = val;
}
uint8_t* buf_int = (uint8_t*) heap_caps_malloc(SPI_FLASH_SEC_SIZE, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
TEST_ASSERT_NOT_NULL(buf_int);
/* Write to flash from buf_ext */
const esp_partition_t *part = get_test_data_partition();
TEST_ESP_OK(spi_flash_erase_range(part->address, SPI_FLASH_SEC_SIZE));
TEST_ESP_OK(spi_flash_write(part->address, buf_ext, SPI_FLASH_SEC_SIZE));
/* Read back to buf_int and compare */
TEST_ESP_OK(spi_flash_read(part->address, buf_int, SPI_FLASH_SEC_SIZE));
TEST_ASSERT_EQUAL(0, memcmp(buf_ext, buf_int, SPI_FLASH_SEC_SIZE));
free(buf_ext);
free(buf_int);
}
#endif // CONFIG_SPIRAM_SUPPORT