aboutsummaryrefslogblamecommitdiff
path: root/projects/board-test/spiflash-perf.c
blob: 726509836803be364c1fdc84b53f922a0aaf7733 (plain) (tree)













































































































































































































































                                                                                   
/*
 * 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;
}