From 1dc664a90471f165855c737c5ae649d01897b2d6 Mon Sep 17 00:00:00 2001 From: Paul Selkirk Date: Wed, 15 Feb 2017 11:39:10 -0500 Subject: Add performance tests for spiflash_n25q128.c --- projects/board-test/Makefile | 2 +- projects/board-test/spiflash-perf.c | 238 ++++++++++++++++++++++++++++++++++++ 2 files changed, 239 insertions(+), 1 deletion(-) create mode 100644 projects/board-test/spiflash-perf.c diff --git a/projects/board-test/Makefile b/projects/board-test/Makefile index 9b1812f..0e60229 100644 --- a/projects/board-test/Makefile +++ b/projects/board-test/Makefile @@ -1,4 +1,4 @@ -TEST = led-test short-test uart-test fmc-test fmc-perf fmc-probe rtc-test +TEST = led-test short-test uart-test fmc-test fmc-perf fmc-probe rtc-test spiflash-perf all: $(TEST:=.elf) diff --git a/projects/board-test/spiflash-perf.c b/projects/board-test/spiflash-perf.c new file mode 100644 index 0000000..7265098 --- /dev/null +++ b/projects/board-test/spiflash-perf.c @@ -0,0 +1,238 @@ +/* + * Test read/write/erase performance of the N25Q128 SPI flash chip. + */ + +#include "string.h" + +#include "stm-init.h" +#include "stm-led.h" +#include "stm-uart.h" +#include "stm-keystore.h" +#include "spiflash_n25q128.h" + +/* + * Use the keystore memory for testing, because it's less involved than + * using the FPGA configuration memory, and less work to restore it to a + * useful configuration. + * + * However, rather than using the stm-keystore abstractions, this version + * goes straight to the low-level API. + */ + +extern struct spiflash_ctx keystore_ctx; +static struct spiflash_ctx *ctx = &keystore_ctx; + +/* + * Based on _wait_while_wip in spiflash_n25q128.c, but can be more + * aggressive about re-checking. + */ +static inline void _wait_while_wip(uint32_t delay) +{ + while (n25q128_get_wip_flag(ctx) != HAL_OK) { + if (delay != 0) + HAL_Delay(delay); + } +} + +/* + * 1. Read the entire flash by pages, ignoring data. + */ +static void test_read_page(void) +{ + uint8_t read_buf[N25Q128_PAGE_SIZE]; + uint32_t i; + int err; + + for (i = 0; i < N25Q128_NUM_PAGES; ++i) { + err = n25q128_read_page(ctx, i, read_buf); + if (err != 1) { + uart_send_string("ERROR: n25q128_read_page returned "); + uart_send_integer(err, 0); + uart_send_string("\r\n"); + break; + } + } +} + +/* + * Read the flash data and verify it against a known pattern. + * It turns out that verification doesn't slow us down in any measurable + * way, because memcmp on 256 bytes is pretty inconsequential. + */ +static void _read_verify(uint8_t *vrfy_buf) +{ + uint8_t read_buf[N25Q128_PAGE_SIZE]; + uint32_t i; + int err; + + for (i = 0; i < N25Q128_NUM_PAGES; ++i) { + err = n25q128_read_page(ctx, i, read_buf); + if (err != 1) { + uart_send_string("ERROR: n25q128_read_page returned "); + uart_send_integer(err, 0); + uart_send_string("\r\n"); + break; + } + if (memcmp(read_buf, vrfy_buf, N25Q128_PAGE_SIZE) != 0) { + uart_send_string("ERROR: verify failed in page "); + uart_send_integer(i, 0); + uart_send_string("\r\n"); + break; + } + } +} + +/* + * 2a. Erase the entire flash by sectors. + */ +static void test_erase_sector(void) +{ + uint32_t i; + int err; + + for (i = 0; i < N25Q128_NUM_SECTORS; ++i) { + err = n25q128_erase_sector(ctx, i); + if (err != 1) { + uart_send_string("ERROR: n25q128_erase_sector returned "); + uart_send_integer(err, 0); + uart_send_string("\r\n"); + break; + } + } +} + +/* + * 2b. Erase the entire flash by subsectors. + */ +static void test_erase_subsector(void) +{ + uint32_t i; + int err; + + for (i = 0; i < N25Q128_NUM_SUBSECTORS; ++i) { + err = n25q128_erase_subsector(ctx, i); + if (err != 1) { + uart_send_string("ERROR: n25q128_erase_subsector returned "); + uart_send_integer(err, 0); + uart_send_string("\r\n"); + break; + } + } +} + +/* + * 2c. Erase the entire flash in bulk. + */ +static void test_erase_bulk(void) +{ + int err; + + err = n25q128_erase_bulk(ctx); + if (err != 1) { + uart_send_string("ERROR: n25q128_erase_bulk returned "); + uart_send_integer(err, 0); + uart_send_string("\r\n"); + } +} + +/* + * 2d. Read the entire flash, verify erasure. + */ +static void test_verify_erase(void) +{ + uint8_t vrfy_buf[N25Q128_PAGE_SIZE]; + uint32_t i; + + for (i = 0; i < sizeof(vrfy_buf); ++i) + vrfy_buf[i] = 0xFF; + + _read_verify(vrfy_buf); +} + +/* + * 3a. Write the entire flash with a pattern. + */ +static void test_write_page(uint32_t delay) +{ + uint8_t write_buf[N25Q128_PAGE_SIZE]; + uint32_t i; + int err; + + for (i = 0; i < sizeof(write_buf); ++i) + write_buf[i] = i & 0xFF; + + for (i = 0; i < N25Q128_NUM_PAGES; ++i) { + err = n25q128_write_page(ctx, i, write_buf); + if (err != 1) { + uart_send_string("ERROR: n25q128_write_page returned "); + uart_send_integer(err, 0); + uart_send_string(" for page "); + uart_send_integer(i, 0); + uart_send_string("\r\n"); + break; + } + _wait_while_wip(delay); + } +} + +/* + * 3b. Read the entire flash, verify data. + */ +static void test_verify_write(void) +{ + uint8_t vrfy_buf[N25Q128_PAGE_SIZE]; + uint32_t i; + + for (i = 0; i < sizeof(vrfy_buf); ++i) + vrfy_buf[i] = i & 0xFF; + + _read_verify(vrfy_buf); +} + +static void _time_check(char *label, const uint32_t t0, uint32_t n_rounds) +{ + uint32_t t = HAL_GetTick() - t0; + + uart_send_string(label); + uart_send_integer(t / 1000, 0); + uart_send_char('.'); + uart_send_integer(t % 1000, 3); + uart_send_string(" sec for "); + uart_send_integer(n_rounds, 0); + uart_send_string(" rounds, "); + uart_send_integer((t + n_rounds/2) / n_rounds, 0); + uart_send_string(" ms each\r\n"); +} + +#define time_check(_label_, _expr_, _n_) \ + do { \ + uint32_t _t = HAL_GetTick(); \ + (_expr_); \ + _time_check(_label_, _t, _n_); \ + } while (0) + +int main(void) +{ + stm_init(); + uart_set_default(STM_UART_MGMT); + + if (n25q128_check_id(ctx) != 1) { + uart_send_string("ERROR: n25q128_check_id failed\r\n"); + return 0; + } + + uart_send_string("Starting...\r\n\r\n"); + + time_check("read_page ", test_read_page(), N25Q128_NUM_PAGES); + time_check("erase_sector ", test_erase_sector(), N25Q128_NUM_SECTORS); + time_check("erase_subsector ", test_erase_subsector(), N25Q128_NUM_SUBSECTORS); + time_check("erase_bulk ", test_erase_bulk(), 1); + time_check("verify_erase ", test_verify_erase(), N25Q128_NUM_PAGES); + time_check("write_page 0ms ", test_write_page(0), N25Q128_NUM_PAGES); + time_check("write_page 1ms ", test_write_page(1), N25Q128_NUM_PAGES); + time_check("write_page 10ms ", test_write_page(10), N25Q128_NUM_PAGES); + time_check("verify_write ", test_verify_write(), N25Q128_NUM_PAGES); + + uart_send_string("Done.\r\n\r\n"); + return 0; +} -- cgit v1.2.3