aboutsummaryrefslogtreecommitdiff
path: root/projects
diff options
context:
space:
mode:
Diffstat (limited to 'projects')
-rw-r--r--projects/board-test/Makefile2
-rw-r--r--projects/board-test/spiflash-perf.c238
2 files changed, 239 insertions, 1 deletions
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;
+}