diff --git a/boards/mulle/Makefile.dep b/boards/mulle/Makefile.dep index 6309c1ec49..d83b5bf3be 100644 --- a/boards/mulle/Makefile.dep +++ b/boards/mulle/Makefile.dep @@ -6,6 +6,9 @@ endif # The RTT clock drives the core clock in the default configuration FEATURES_REQUIRED += periph_rtt +# The RTT clock drives the core clock in the default configuration +FEATURES_REQUIRED += periph_rtt + # The Mulle uses NVRAM to store persistent variables, such as boot count. -#~ USEMODULE += nvram_spi -# Uncomment above when #2353 is merged. +USEMODULE += nvram_spi +FEATURES_REQUIRED += periph_spi diff --git a/boards/mulle/board.c b/boards/mulle/board.c index 358ce39a2d..d989a7b0a0 100644 --- a/boards/mulle/board.c +++ b/boards/mulle/board.c @@ -26,6 +26,16 @@ #include "periph/gpio.h" #include "periph/uart.h" #include "periph/rtt.h" +#include "periph/spi.h" +#include "nvram-spi.h" + +static nvram_t mulle_nvram_dev; +nvram_t *mulle_nvram = &mulle_nvram_dev; +static nvram_spi_params_t nvram_spi_params = { + .spi = MULLE_NVRAM_SPI_DEV, + .cs = MULLE_NVRAM_SPI_CS, + .address_count = MULLE_NVRAM_SPI_ADDRESS_COUNT, +}; /** * @brief Initialize the boards on-board LEDs @@ -50,9 +60,12 @@ static inline void set_safe_clock_dividers(void); /** @brief Set the FLL source clock to RTC32k */ static inline void set_fll_source(void); +static void increase_boot_count(void); +static int mulle_nvram_init(void); void board_init(void) { + int status; /* initialize the boards LEDs, this is done first for debugging purposes */ leds_init(); @@ -60,6 +73,12 @@ void board_init(void) power_pins_init(); /* Turn on Vperiph for peripherals */ + /* + * By turning on Vperiph first, and before waiting for the clocks to + * stabilize, we will have used enough time to have let the FRAM start up + * properly when we want to access it later without having to add any extra + * delays. + */ gpio_set(MULLE_POWER_VPERIPH); /* Turn on AVDD for reading voltages */ @@ -98,6 +117,17 @@ void board_init(void) /* initialize the CPU */ cpu_init(); + + LED_YELLOW_ON; + + /* Initialize NVRAM */ + status = mulle_nvram_init(); + if (status == 0) { + /* Increment boot counter */ + increase_boot_count(); + } + + LED_GREEN_ON; } /** @@ -168,3 +198,57 @@ static inline void set_fll_source(void) #error Unknown K60 CPU revision #endif } + +static int mulle_nvram_init(void) +{ + union { + uint32_t u32; + uint8_t u8[sizeof(uint32_t)]; + } rec; + rec.u32 = 0; + + if (spi_init_master(MULLE_NVRAM_SPI_DEV, SPI_CONF_FIRST_RISING, SPI_SPEED_5MHZ) != 0) { + return -1; + } + + if (nvram_spi_init(mulle_nvram, &nvram_spi_params, MULLE_NVRAM_CAPACITY) != 0) { + return -2; + } + + if (mulle_nvram->read(mulle_nvram, &rec.u8[0], MULLE_NVRAM_MAGIC, sizeof(rec.u32)) != sizeof(rec.u32)) { + return -3; + } + + if (rec.u32 != MULLE_NVRAM_MAGIC_EXPECTED) { + int i; + union { + uint64_t u64; + uint8_t u8[sizeof(uint64_t)]; + } zero; + zero.u64 = 0; + for (i = 0; i < MULLE_NVRAM_CAPACITY; i += sizeof(zero)) { + if (mulle_nvram->write(mulle_nvram, &zero.u8[0], i, sizeof(zero.u64)) != sizeof(zero.u64)) { + return -4; + } + } + rec.u32 = MULLE_NVRAM_MAGIC_EXPECTED; + if (mulle_nvram->write(mulle_nvram, &rec.u8[0], MULLE_NVRAM_MAGIC, sizeof(rec.u32)) != sizeof(rec.u32)) { + return -5; + } + } + return 0; +} + +static void increase_boot_count(void) +{ + union { + uint32_t u32; + uint8_t u8[sizeof(uint32_t)]; + } rec; + rec.u32 = 0; + if (mulle_nvram->read(mulle_nvram, &rec.u8[0], MULLE_NVRAM_BOOT_COUNT, sizeof(rec.u32)) != sizeof(rec.u32)) { + return; + } + ++rec.u32; + mulle_nvram->write(mulle_nvram, &rec.u8[0], MULLE_NVRAM_BOOT_COUNT, sizeof(rec.u32)); +} diff --git a/boards/mulle/include/board.h b/boards/mulle/include/board.h index 33362b810a..ed93949379 100644 --- a/boards/mulle/include/board.h +++ b/boards/mulle/include/board.h @@ -23,6 +23,7 @@ #include "cpu.h" #include "periph_conf.h" +#include "mulle-nvram.h" /* Use the on board RTC 32kHz clock for LPTMR clocking. */ #undef LPTIMER_CLKSRC @@ -120,6 +121,17 @@ void board_init(void); #define MULLE_POWER_VSEC GPIO_5 /**< VSEC enable pin */ /** @} */ +/** + * @name Mulle NVRAM hardware configuration + */ +/** @{ */ +/** FRAM SPI bus, SPI_2 in RIOT is mapped to hardware bus SPI0, see periph_conf.h */ +#define MULLE_NVRAM_SPI_DEV SPI_2 +#define MULLE_NVRAM_SPI_CS GPIO_16 /**< FRAM CS pin */ +#define MULLE_NVRAM_CAPACITY 512 /**< FRAM size, in bytes */ +#define MULLE_NVRAM_SPI_ADDRESS_COUNT 1 /**< FRAM addressing size, in bytes */ +/** @} */ + /** * @name K60 clock dividers */ diff --git a/boards/mulle/include/mulle-nvram.h b/boards/mulle/include/mulle-nvram.h new file mode 100644 index 0000000000..36efba21d5 --- /dev/null +++ b/boards/mulle/include/mulle-nvram.h @@ -0,0 +1,45 @@ +/* + * 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. + */ + +#ifndef MULLE_NVRAM_H_ +#define MULLE_NVRAM_H_ + +#include "nvram.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @ingroup board_mulle + * @{ + * + * @file + * @brief NVRAM offsets for the Eistec Mulle IoT board + * + * @author Joakim Gebart + */ + +typedef enum mulle_nvram_address { + /** @brief NVRAM magic number, used to identify an initialized FRAM device. */ + MULLE_NVRAM_MAGIC = 0x0000, + /** @brief Reboot counter */ + MULLE_NVRAM_BOOT_COUNT = 0x0004, +} mulle_nvram_address_t; + +#define MULLE_NVRAM_MAGIC_EXPECTED (0x4c4c554dul) /* == "MULL" in ASCII */ + +extern nvram_t *mulle_nvram; + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* MULLE_NVRAM_H_ */