diff --git a/drivers/include/nvram-spi.h b/drivers/include/nvram-spi.h new file mode 100644 index 0000000000000000000000000000000000000000..a945b3adb84fd6e9f26f4f4785630ea0253cfc28 --- /dev/null +++ b/drivers/include/nvram-spi.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2015 Eistec AB + * + * This file is subject to the terms and conditions of the GNU Lesser General + * Public License v2.1. See the file LICENSE in the top level directory for more + * details. + */ + +/** + * @ingroup nvram + * @{ + * + * @file + * + * @brief Device interface for various SPI connected NVRAM. + * + * Tested on: + * - Cypress/Ramtron FM25L04B. + * + * @author Joakim Gebart <joakim.gebart@eistec.se> + */ + +#ifndef DRIVERS_NVRAM_SPI_H_ +#define DRIVERS_NVRAM_SPI_H_ + +#include <stdint.h> +#include "nvram.h" +#include "periph/spi.h" +#include "periph/gpio.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Bus parameters for SPI NVRAM. + */ +typedef struct nvram_spi_params { + /** @brief RIOT SPI device */ + spi_t spi; + /** @brief Chip select pin */ + gpio_t cs; + /** @brief Number of address bytes following each read/write command. */ + uint8_t address_count; +} nvram_spi_params_t; + +/** + * @brief Initialize an nvram_t structure with SPI settings. + * + * This will also initialize the CS pin as a GPIO output, without pull resistors. + * + * @param[out] dev Pointer to NVRAM device descriptor + * @param[out] spi_params Pointer to SPI settings + * @param[in] size Device capacity + * + * @return 0 on success + * @return <0 on errors + */ +int nvram_spi_init(nvram_t *dev, nvram_spi_params_t *spi_params, size_t size); + +#ifdef __cplusplus +} +#endif + +#endif /* DRIVERS_NVRAM_SPI_H_ */ +/** @} */ diff --git a/drivers/include/nvram.h b/drivers/include/nvram.h new file mode 100644 index 0000000000000000000000000000000000000000..7ec41e953c220cd3aed1b77df9c1485af8a60900 --- /dev/null +++ b/drivers/include/nvram.h @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2015 Eistec AB + * + * This file is subject to the terms and conditions of the GNU Lesser General + * Public License v2.1. See the file LICENSE in the top level directory for more + * details. + */ + +/** + * @defgroup nvram Non-volatile RAM + * @ingroup drivers + * @brief Non-volatile RAM interface + * + * This API is designed around non-volatile memories which do not need blockwise + * erase, such as ferro-electric RAM (FRAM) or magneto-resistive RAM (MRAM). + * + * This interface is not suitable for flash memories. + * + * @{ + * + * @file + * + * @brief Generic non-volatile RAM driver interface + * @author Joakim Gebart <joakim.gebart@eistec.se> + */ + +#ifndef DRIVERS_NVRAM_H_ +#define DRIVERS_NVRAM_H_ + +#include <stdint.h> +#include <stddef.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* Forward declaration in order to declare function pointers which take this + * type as a parameter within the struct. */ +struct nvram; + +/** + * @brief Device descriptor for generic NVRAM devices. + */ +typedef struct nvram { + /** + * @brief Pointer to device-specific read function + * + * Copy data from system memory to NVRAM. + * + * @param[in] dev Pointer to NVRAM device descriptor + * @param[out] dst Pointer to the first byte in the system memory address space + * @param[in] src Starting address in the NVRAM device address space + * @param[in] len Number of bytes to copy + * + * @return Number of bytes read on success + * @return <0 on errors + */ + int (*read)(struct nvram *dev, uint8_t *dst, uint32_t src, size_t size); + + /** + * @brief Pointer to device-specific write function + * + * Copy data from NVRAM to system memory. + * + * @param[in] dev Pointer to NVRAM device descriptor + * @param[in] src Pointer to the first byte in the system memory address space + * @param[in] dst Starting address in the NVRAM device address space + * @param[in] len Number of bytes to copy + * + * @return Number of bytes written on success + * @return <0 on errors + */ + int (*write)(struct nvram *dev, uint8_t *src, uint32_t dst, size_t size); + + /** @brief Device capacity */ + size_t size; + + /** @brief Device-specific parameters, if any. */ + void *extra; +} nvram_t; + +#ifdef __cplusplus +} +#endif + +#endif /* DRIVERS_NVRAM_H_ */ +/** @} */ diff --git a/drivers/nvram_spi/Makefile b/drivers/nvram_spi/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..bc459313fce606ec33f7725b8e1855703ec3c55e --- /dev/null +++ b/drivers/nvram_spi/Makefile @@ -0,0 +1,3 @@ +MODULE = nvram_spi + +include $(RIOTBASE)/Makefile.base diff --git a/drivers/nvram_spi/nvram-spi.c b/drivers/nvram_spi/nvram-spi.c new file mode 100644 index 0000000000000000000000000000000000000000..4ae873b554fd54a1909e017b6fef06ec6c5b1c7e --- /dev/null +++ b/drivers/nvram_spi/nvram-spi.c @@ -0,0 +1,283 @@ +/* + * Copyright (C) 2015 Eistec AB + * + * This file is subject to the terms and conditions of the GNU Lesser General + * Public License v2.1. See the file LICENSE in the top level directory for more + * details. + */ + +#include <stdint.h> +#include <stddef.h> +#include "nvram.h" +#include "nvram-spi.h" +#include "byteorder.h" +#include "periph/spi.h" +#include "periph/gpio.h" +#include "hwtimer.h" + +/** + * @ingroup nvram + * @{ + * + * @file + * + * @brief Device interface for various SPI connected NVRAM. + * + * Tested on: + * - Cypress/Ramtron FM25L04B. + * + * @author Joakim Gebart <joakim.gebart@eistec.se> + */ + +typedef enum { + /** WRITE command byte, 0b0000 0010 */ + NVRAM_SPI_CMD_WRITE = 0x02, + /** READ command byte, 0b0000 0011 */ + NVRAM_SPI_CMD_READ = 0x03, + /** WREN command byte, 0b0000 0110 */ + NVRAM_SPI_CMD_WREN = 0x06, +} nvram_spi_commands_t; + +/** @brief Delay to wait between toggling CS pin, on most chips this can probably be + * removed. */ +#define NVRAM_SPI_CS_TOGGLE_TICKS 1 + +/** + * @brief Copy data from system memory to NVRAM. + * + * @param[in] dev Pointer to NVRAM device descriptor + * @param[in] src Pointer to the first byte in the system memory address space + * @param[in] dst Starting address in the NVRAM device address space + * @param[in] len Number of bytes to copy + * + * @return Number of bytes written on success + * @return <0 on errors + */ +static int nvram_spi_write(nvram_t *dev, uint8_t *src, uint32_t dst, size_t len); + +/** + * @brief Copy data from NVRAM to system memory. + * + * @param[in] dev Pointer to NVRAM device descriptor + * @param[out] dst Pointer to the first byte in the system memory address space + * @param[in] src Starting address in the NVRAM device address space + * @param[in] len Number of bytes to copy + * + * @return Number of bytes read on success + * @return <0 on errors + */ +static int nvram_spi_read(nvram_t *dev, uint8_t *dst, uint32_t src, size_t len); + +/** + * @brief Copy data from system memory to NVRAM. + * + * This is a special form of the WRITE command used by some Ramtron/Cypress + * 4Kbit FRAM devices which puts the 9th address bit inside the command byte to + * be able to use one byte for addressing instead of two. + * + * @param[in] dev Pointer to NVRAM device descriptor + * @param[in] src Pointer to the first byte in the system memory address space + * @param[in] dst Starting address in the NVRAM device address space + * @param[in] len Number of bytes to copy + * + * @return Number of bytes written on success + * @return <0 on errors + */ +static int nvram_spi_write_9bit_addr(nvram_t *dev, uint8_t *src, uint32_t dst, size_t len); + +/** + * @brief Copy data from NVRAM to system memory. + * + * This is a special form of the READ command used by some Ramtron/Cypress 4Kbit + * FRAM devices which puts the 9th address bit inside the command byte to be + * able to use one byte for addressing instead of two. + * + * @param[in] dev Pointer to NVRAM device descriptor + * @param[out] dst Pointer to the first byte in the system memory address space + * @param[in] src Starting address in the NVRAM device address space + * @param[in] len Number of bytes to copy + * + * @return Number of bytes read on success + * @return <0 on errors + */ +static int nvram_spi_read_9bit_addr(nvram_t *dev, uint8_t *dst, uint32_t src, size_t len); + +int nvram_spi_init(nvram_t *dev, nvram_spi_params_t *spi_params, size_t size) +{ + dev->size = size; + if (size > 0x100 && spi_params->address_count == 1) { + dev->write = nvram_spi_write_9bit_addr; + dev->read = nvram_spi_read_9bit_addr; + } else { + dev->write = nvram_spi_write; + dev->read = nvram_spi_read; + } + dev->extra = spi_params; + + gpio_init_out(spi_params->cs, GPIO_NOPULL); + gpio_set(spi_params->cs); + + return 0; +} + +static int nvram_spi_write(nvram_t *dev, uint8_t *src, uint32_t dst, size_t len) +{ + nvram_spi_params_t *spi_dev = (nvram_spi_params_t *) dev->extra; + int status; + union { + uint32_t u32; + char c[4]; + } addr; + /* Address is expected by the device as big-endian, i.e. network byte order, + * we utilize the network byte order macros here. */ + addr.u32 = HTONL(dst); + /* Acquire exclusive bus access */ + spi_acquire(spi_dev->spi); + /* Assert CS */ + gpio_clear(spi_dev->cs); + /* Enable writes */ + status = spi_transfer_byte(spi_dev->spi, NVRAM_SPI_CMD_WREN, NULL); + if (status < 0) + { + return status; + } + /* Release CS */ + gpio_set(spi_dev->cs); + hwtimer_spin(NVRAM_SPI_CS_TOGGLE_TICKS); + /* Re-assert CS */ + gpio_clear(spi_dev->cs); + /* Write command and address */ + status = spi_transfer_regs(spi_dev->spi, NVRAM_SPI_CMD_WRITE, + &addr.c[sizeof(addr.c) - spi_dev->address_count], NULL, + spi_dev->address_count); + if (status < 0) + { + return status; + } + /* Keep holding CS and write data */ + status = spi_transfer_bytes(spi_dev->spi, (char *)src, NULL, len); + if (status < 0) + { + return status; + } + /* Release CS */ + gpio_set(spi_dev->cs); + /* Release exclusive bus access */ + spi_release(spi_dev->spi); + return status; +} + +static int nvram_spi_read(nvram_t *dev, uint8_t *dst, uint32_t src, size_t len) +{ + nvram_spi_params_t *spi_dev = (nvram_spi_params_t *) dev->extra; + int status; + union { + uint32_t u32; + char c[4]; + } addr; + /* Address is expected by the device as big-endian, i.e. network byte order, + * we utilize the network byte order macros here. */ + addr.u32 = HTONL(src); + /* Acquire exclusive bus access */ + spi_acquire(spi_dev->spi); + /* Assert CS */ + gpio_clear(spi_dev->cs); + /* Write command and address */ + status = spi_transfer_regs(spi_dev->spi, NVRAM_SPI_CMD_READ, + &addr.c[sizeof(addr.c) - spi_dev->address_count], + NULL, spi_dev->address_count); + if (status < 0) + { + return status; + } + /* Keep holding CS and read data */ + status = spi_transfer_bytes(spi_dev->spi, NULL, (char *)dst, len); + if (status < 0) + { + return status; + } + /* Release CS */ + gpio_set(spi_dev->cs); + /* Release exclusive bus access */ + spi_release(spi_dev->spi); + /* status contains the number of bytes actually read from the SPI bus. */ + return status; +} + + +static int nvram_spi_write_9bit_addr(nvram_t *dev, uint8_t *src, uint32_t dst, size_t len) +{ + nvram_spi_params_t *spi_dev = (nvram_spi_params_t *) dev->extra; + int status; + uint8_t cmd; + uint8_t addr; + cmd = NVRAM_SPI_CMD_WRITE; + /* The upper address bit is mixed into the command byte on certain devices, + * probably just to save a byte in the SPI transfer protocol. */ + if (dst > 0xff) { + cmd |= 0x08; + } + /* LSB of address */ + addr = (dst & 0xff); + spi_acquire(spi_dev->spi); + gpio_clear(spi_dev->cs); + /* Enable writes */ + status = spi_transfer_byte(spi_dev->spi, NVRAM_SPI_CMD_WREN, NULL); + if (status < 0) + { + return status; + } + gpio_set(spi_dev->cs); + hwtimer_spin(NVRAM_SPI_CS_TOGGLE_TICKS); + gpio_clear(spi_dev->cs); + /* Write command and address */ + status = spi_transfer_reg(spi_dev->spi, cmd, addr, NULL); + if (status < 0) + { + return status; + } + /* Keep holding CS and write data */ + status = spi_transfer_bytes(spi_dev->spi, (char *)src, NULL, len); + if (status < 0) + { + return status; + } + gpio_set(spi_dev->cs); + spi_release(spi_dev->spi); + /* status contains the number of bytes actually written to the SPI bus. */ + return status; +} + +static int nvram_spi_read_9bit_addr(nvram_t *dev, uint8_t *dst, uint32_t src, size_t len) +{ + nvram_spi_params_t *spi_dev = (nvram_spi_params_t *) dev->extra; + int status; + uint8_t cmd; + uint8_t addr; + cmd = NVRAM_SPI_CMD_READ; + /* The upper address bit is mixed into the command byte on certain devices, + * probably just to save a byte in the SPI transfer protocol. */ + if (src > 0xff) { + cmd |= 0x08; + } + /* LSB of address */ + addr = (src & 0xff); + spi_acquire(spi_dev->spi); + gpio_clear(spi_dev->cs); + /* Write command and address */ + status = spi_transfer_reg(spi_dev->spi, (char)cmd, addr, NULL); + if (status < 0) + { + return status; + } + /* Keep holding CS and read data */ + status = spi_transfer_bytes(spi_dev->spi, NULL, (char *)dst, len); + if (status < 0) + { + return status; + } + gpio_set(spi_dev->cs); + spi_release(spi_dev->spi); + /* status contains the number of bytes actually read from the SPI bus. */ + return status; +} diff --git a/tests/driver_nvram_spi/Makefile b/tests/driver_nvram_spi/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..d764782ba9fe5ab1f05e7c906bd7a97d828a4f39 --- /dev/null +++ b/tests/driver_nvram_spi/Makefile @@ -0,0 +1,34 @@ +APPLICATION = driver_nvram_spi +include ../Makefile.tests_common + +FEATURES_REQUIRED = periph_spi periph_gpio + +USEMODULE += nvram_spi +USEMODULE += vtimer + +ifneq (,$(TEST_NVRAM_SPI_DEV)) + CFLAGS += -DTEST_NVRAM_SPI_DEV=$(TEST_NVRAM_SPI_DEV) +else + # set arbitrary default + CFLAGS += -DTEST_NVRAM_SPI_DEV=SPI_0 +endif +ifneq (,$(TEST_NVRAM_SPI_CS)) + CFLAGS += -DTEST_NVRAM_SPI_CS=$(TEST_NVRAM_SPI_CS) +else + # set arbitrary default + CFLAGS += -DTEST_NVRAM_SPI_CS=GPIO_0 +endif +ifneq (,$(TEST_NVRAM_SPI_SIZE)) + CFLAGS += -DTEST_NVRAM_SPI_SIZE=$(TEST_NVRAM_SPI_SIZE) +else + # set tiny arbitrary default + CFLAGS += -DTEST_NVRAM_SPI_SIZE=64 +endif +ifneq (,$(TEST_NVRAM_SPI_ADDRESS_COUNT)) + CFLAGS += -DTEST_NVRAM_SPI_ADDRESS_COUNT=$(TEST_NVRAM_SPI_ADDRESS_COUNT) +else + # set 1 address byte by default, increase if using a larger module for test. + CFLAGS += -DTEST_NVRAM_SPI_ADDRESS_COUNT=1 +endif + +include $(RIOTBASE)/Makefile.include diff --git a/tests/driver_nvram_spi/README.md b/tests/driver_nvram_spi/README.md new file mode 100644 index 0000000000000000000000000000000000000000..202200a24acbeb1e05b1d628d3dbf89ed6e2ea5d --- /dev/null +++ b/tests/driver_nvram_spi/README.md @@ -0,0 +1,12 @@ +# About +This is a manual test application for the SPI NVRAM driver. + +# Usage +This test application will initialize the SPI bus and NVRAM device with the +following parameters: + + - Baudrate: 10 MHz (overridable by setting TEST_NVRAM_SPI_SPEED) + - SPI config: SPI_CONF_FIRST_RISING (overridable by setting TEST_NVRAM_SPI_CONF) + +The memory will be overwritten by the test application. The original contents +will not be restored after the test. diff --git a/tests/driver_nvram_spi/main.c b/tests/driver_nvram_spi/main.c new file mode 100644 index 0000000000000000000000000000000000000000..8329046d54c7f86ddbe3c02016f038c71b09404f --- /dev/null +++ b/tests/driver_nvram_spi/main.c @@ -0,0 +1,257 @@ +/* + * Copyright (C) 2015 Eistec AB + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup tests + * @{ + * + * @file + * @brief Test application for the SPI NVRAM driver + * + * @author Joakim Gebart <joakim.gebart@eistec.se + * + * @} + */ + +#include <stdio.h> +#include <string.h> +#include <ctype.h> + +#include "board.h" +#include "vtimer.h" +#include "periph/spi.h" +#include "nvram-spi.h" + +#ifndef TEST_NVRAM_SPI_DEV +#error "TEST_NVRAM_SPI_DEV not defined" +#endif +#ifndef TEST_NVRAM_SPI_CS +#error "TEST_NVRAM_SPI_CS not defined" +#endif +#ifndef TEST_NVRAM_SPI_SIZE +#error "TEST_NVRAM_SPI_SIZE not defined" +#endif +#ifndef TEST_NVRAM_SPI_ADDRESS_COUNT +#error "TEST_NVRAM_SPI_ADDRESS_COUNT not defined" +#endif + +#ifdef TEST_NVRAM_SPI_CONF +#define SPI_CONF (TEST_NVRAM_SPI_CONF) +#else +#define SPI_CONF (SPI_CONF_FIRST_RISING) +#endif + +#ifdef TEST_NVRAM_SPI_SPEED +#define SPI_SPEED (TEST_NVRAM_SPI_SPEED) +#else +#define SPI_SPEED (SPI_SPEED_10MHZ) +#endif + +/* This will only work on small memories. Modify if you need to test NVRAM + * memories which do not fit inside free RAM */ +static uint8_t buf_out[TEST_NVRAM_SPI_SIZE]; +static uint8_t buf_in[TEST_NVRAM_SPI_SIZE]; + +/** + * @brief xxd-like printing of a binary buffer + */ +static void print_buffer(const uint8_t * buf, size_t length) { + static const unsigned int bytes_per_line = 16; + static const unsigned int bytes_per_group = 2; + unsigned long i = 0; + while (i < length) { + unsigned int col; + for (col = 0; col < bytes_per_line; ++col) { + /* Print hex data */ + if (col == 0) { + printf("\n%08lx: ", i); + } + else if ((col % bytes_per_group) == 0) { + putchar(' '); + } + if ((i + col) < length) { + printf("%02hhx", buf[i + col]); + } else { + putchar(' '); + putchar(' '); + } + } + putchar(' '); + for (col = 0; col < bytes_per_line; ++col) { + if ((i + col) < length) { + /* Echo only printable chars */ + if (isprint(buf[i + col])) { + putchar(buf[i + col]); + } else { + putchar('.'); + } + } else { + putchar(' '); + } + } + i += bytes_per_line; + } + /* end with a newline */ + puts(""); +} + +/* weak PRNG for generating "random" test data */ +static uint8_t lcg_rand8(void) { + static const uint32_t a = 1103515245; + static const uint32_t c = 12345; + static uint32_t val = 123456; /* seed value */ + val = val * a + c; + return (val >> 16) & 0xff; +} + +int main(void) +{ + uint32_t i; + nvram_spi_params_t spi_params = { + .spi = TEST_NVRAM_SPI_DEV, + .cs = TEST_NVRAM_SPI_CS, + .address_count = TEST_NVRAM_SPI_ADDRESS_COUNT, + }; + nvram_t dev; + timex_t start_delay = { + .seconds = 10, + .microseconds = 0, + }; + + puts("NVRAM SPI test application starting..."); + printf("Initializing SPI_%i... ", TEST_NVRAM_SPI_DEV); + if (spi_init_master(TEST_NVRAM_SPI_DEV, SPI_CONF, SPI_SPEED_10MHZ) == 0) { + puts("[OK]"); + } + else { + puts("[Failed]\n"); + return 1; + } + + puts("Initializing NVRAM SPI device descriptor... "); + if (nvram_spi_init(&dev, &spi_params, TEST_NVRAM_SPI_SIZE) == 0) { + puts("[OK]"); + } + else { + puts("[Failed]\n"); + return 1; + } + + puts("NVRAM SPI init done.\n"); + + puts("!!! This test will erase everything on the NVRAM !!!"); + puts("!!! Unplug/reset/halt device now if this is not acceptable !!!"); + puts("Waiting for 10 seconds before continuing..."); + vtimer_sleep(start_delay); + + puts("Reading current memory contents..."); + for (i = 0; i < TEST_NVRAM_SPI_SIZE; ++i) { + if (dev.read(&dev, &buf_in[i], i, 1) != 1) { + puts("[Failed]\n"); + return 1; + } + } + puts("[OK]"); + puts("NVRAM contents before test:"); + print_buffer(buf_in, sizeof(buf_in)); + + puts("Writing bytewise 0xFF to device"); + + memset(buf_out, 0xff, sizeof(buf_out)); + for (i = 0; i < TEST_NVRAM_SPI_SIZE; ++i) { + if (dev.write(&dev, &buf_out[i], i, 1) != 1) { + puts("[Failed]\n"); + return 1; + } + if (buf_out[i] != 0xff) { + puts("nvram_spi_write modified *src!"); + printf(" i = %08lx\n", (unsigned long) i); + puts("[Failed]\n"); + return 1; + } + } + + puts("Reading back blockwise"); + memset(buf_in, 0x00, sizeof(buf_in)); + if (dev.read(&dev, buf_in, 0, TEST_NVRAM_SPI_SIZE) != TEST_NVRAM_SPI_SIZE) { + puts("[Failed]\n"); + return 1; + } + puts("[OK]"); + puts("Verifying contents..."); + if (memcmp(buf_in, buf_out, TEST_NVRAM_SPI_SIZE) != 0) { + puts("[Failed]\n"); + return 1; + } + puts("[OK]"); + + puts("Writing blockwise address complement to device"); + for (i = 0; i < TEST_NVRAM_SPI_SIZE; ++i) { + buf_out[i] = (~(i)) & 0xff; + } + if (dev.write(&dev, buf_out, 0, TEST_NVRAM_SPI_SIZE) != TEST_NVRAM_SPI_SIZE) { + puts("[Failed]\n"); + return 1; + } + puts("[OK]"); + puts("buf_out:"); + print_buffer(buf_out, sizeof(buf_out)); + puts("Reading back blockwise"); + memset(buf_in, 0x00, sizeof(buf_in)); + if (dev.read(&dev, buf_in, 0, TEST_NVRAM_SPI_SIZE) != TEST_NVRAM_SPI_SIZE) { + puts("[Failed]\n"); + return 1; + } + puts("[OK]"); + puts("Verifying contents..."); + if (memcmp(buf_in, buf_out, TEST_NVRAM_SPI_SIZE) != 0) { + puts("buf_in:"); + print_buffer(buf_in, sizeof(buf_in)); + puts("[Failed]\n"); + return 1; + } + puts("[OK]"); + + puts("Generating pseudo-random test data..."); + + for (i = 0; i < TEST_NVRAM_SPI_SIZE; ++i) { + buf_out[i] = lcg_rand8(); + } + + puts("buf_out:"); + print_buffer(buf_out, sizeof(buf_out)); + + puts("Writing blockwise data to device"); + if (dev.write(&dev, buf_out, 0, TEST_NVRAM_SPI_SIZE) != TEST_NVRAM_SPI_SIZE) { + puts("[Failed]\n"); + return 1; + } + puts("[OK]"); + + puts("Reading back blockwise"); + memset(buf_in, 0x00, sizeof(buf_in)); + if (dev.read(&dev, buf_in, 0, TEST_NVRAM_SPI_SIZE) != TEST_NVRAM_SPI_SIZE) { + puts("[Failed]\n"); + return 1; + } + puts("[OK]"); + puts("Verifying contents..."); + if (memcmp(buf_in, buf_out, TEST_NVRAM_SPI_SIZE) != 0) { + puts("buf_in:"); + print_buffer(buf_in, sizeof(buf_in)); + puts("[Failed]\n"); + return 1; + } + puts("[OK]"); + + puts("All tests passed!"); + + while(1); + + return 0; +}