/* * 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; /* * 1a. 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 != HAL_OK) { uart_send_string("ERROR: n25q128_read_page returned "); uart_send_integer(err, 1); uart_send_string("\r\n"); break; } } } /* * 1b. Read the entire flash by subsectors, ignoring data. */ static void test_read_subsector(void) { uint8_t read_buf[N25Q128_SUBSECTOR_SIZE]; uint32_t i; int err; for (i = 0; i < N25Q128_NUM_SUBSECTORS; ++i) { err = n25q128_read_subsector(ctx, i, read_buf); if (err != HAL_OK) { uart_send_string("ERROR: n25q128_read_subsector returned "); uart_send_integer(err, 1); 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 != HAL_OK) { uart_send_string("ERROR: n25q128_read_page returned "); uart_send_integer(err, 1); 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, 1); 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 != HAL_OK) { uart_send_string("ERROR: n25q128_erase_sector returned "); uart_send_integer(err, 1); 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 != HAL_OK) { uart_send_string("ERROR: n25q128_erase_subsector returned "); uart_send_integer(err, 1); 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 != HAL_OK) { uart_send_string("ERROR: n25q128_erase_bulk returned "); uart_send_integer(err, 1); 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(void) { 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 != HAL_OK) { uart_send_string("ERROR: n25q128_write_page returned "); uart_send_integer(err, 1); uart_send_string(" for page "); uart_send_integer(i, 1); uart_send_string("\r\n"); break; } } } /* * 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, 1); uart_send_char('.'); uart_send_integer(t % 1000, 3); uart_send_string(" sec"); if (n_rounds > 1) { uart_send_string(" for "); uart_send_integer(n_rounds, 1); uart_send_string(" rounds, "); uart_send_integer(t / n_rounds, 1); uart_send_char('.'); uart_send_integer(((t % n_rounds) * 100) / n_rounds, 2); uart_send_string(" ms each"); } uart_send_string("\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(); if (n25q128_check_id(ctx) != HAL_OK) { uart_send_string("ERROR: n25q128_check_id failed\r\n"); return 0; } uart_send_string("Starting...\r\n"); time_check("read page ", test_read_page(), N25Q128_NUM_PAGES); time_check("read subsector ", test_read_subsector(), N25Q128_NUM_SUBSECTORS); time_check("erase subsector ", test_erase_subsector(), N25Q128_NUM_SUBSECTORS); time_check("erase sector ", test_erase_sector(), N25Q128_NUM_SECTORS); time_check("erase bulk ", test_erase_bulk(), 1); time_check("verify erase ", test_verify_erase(), N25Q128_NUM_PAGES); time_check("write page ", test_write_page(), N25Q128_NUM_PAGES); time_check("verify write ", test_verify_write(), N25Q128_NUM_PAGES); uart_send_string("Done.\r\n\r\n"); return 0; } .ge { font-style: italic } /* Generic.Emph */ .highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */ .highlight .gr { color: #aa0000 } /* Generic.Error */ .highlight .gh { color: #333333 } /* Generic.Heading */ .highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ .highlight .go { color: #888888 } /* Generic.Output */ .highlight .gp { color: #555555 } /* Generic.Prompt */ .highlight .gs { font-weight: bold } /* Generic.Strong */ .highlight .gu { color: #666666 } /* Generic.Subheading */ .highlight .gt { color: #aa0000 } /* Generic.Traceback */ .highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */ .highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */ .highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */ .highlight .kp { color: #008800 } /* Keyword.Pseudo */ .highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */ .highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */ .highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */ .highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */ .highlight .na { color: #336699 } /* Name.Attribute */ .highlight .nb { color: #003388 } /* Name.Builtin */ .highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */ .highlight .no { color: #003366; font-weight: bold } /* Name.Constant */ .highlight .nd { color: #555555 } /* Name.Decorator */ .highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */ .highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */ .highlight .nl { color: #336699; font-style: italic } /* Name.Label */ .highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */ .highlight .py { color: #336699; font-weight: bold } /* Name.Property */ .highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */ .highlight .nv { color: #336699 } /* Name.Variable */ .highlight .ow { color: #008800 } /* Operator.Word */ .highlight .w { color: #bbbbbb } /* Text.Whitespace */ .highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */ .highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */ .highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */ .highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */ .highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */ .highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
/*
 * errorstrings.c
 * --------------
 * Translate HAL error codes to strings.
 *
 * Authors: Rob Austein
 * Copyright (c) 2015, NORDUnet A/S
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 * - Redistributions of source code must retain the above copyright notice,
 *   this list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 *
 * - Neither the name of the NORDUnet nor the names of its contributors may
 *   be used to endorse or promote products derived from this software
 *   without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "hal.h"

#define DEFINE_HAL_ERROR(_code_,_text_) \
  case _code_: return _text_;

const char *hal_error_string(const hal_error_t code)
{
  switch (code) {
    HAL_ERROR_LIST;
  default:
    return "Unknown HAL error code";
  }
}

#undef DEFINE_HAL_ERROR

/*
 * Local variables:
 * indent-tabs-mode: nil
 * End:
 */