From df27ad28ce0406c1c190e063884d8e14e5750f50 Mon Sep 17 00:00:00 2001 From: Hauke Petersen Date: Mon, 21 Nov 2016 15:12:24 +0100 Subject: [PATCH] boards: added support for Calliope mini --- boards/calliope-mini/Makefile | 7 + boards/calliope-mini/Makefile.dep | 8 + boards/calliope-mini/Makefile.features | 14 ++ boards/calliope-mini/Makefile.include | 28 +++ boards/calliope-mini/board.c | 32 +++ boards/calliope-mini/dist/flash.sh | 65 ++++++ boards/calliope-mini/include/board.h | 93 +++++++++ boards/calliope-mini/include/gpio_params.h | 51 +++++ boards/calliope-mini/include/mini.h | 90 ++++++++ boards/calliope-mini/include/periph_conf.h | 123 +++++++++++ boards/calliope-mini/mini/Makefile | 1 + boards/calliope-mini/mini/mini.c | 227 +++++++++++++++++++++ 12 files changed, 739 insertions(+) create mode 100644 boards/calliope-mini/Makefile create mode 100644 boards/calliope-mini/Makefile.dep create mode 100644 boards/calliope-mini/Makefile.features create mode 100644 boards/calliope-mini/Makefile.include create mode 100644 boards/calliope-mini/board.c create mode 100755 boards/calliope-mini/dist/flash.sh create mode 100644 boards/calliope-mini/include/board.h create mode 100644 boards/calliope-mini/include/gpio_params.h create mode 100644 boards/calliope-mini/include/mini.h create mode 100644 boards/calliope-mini/include/periph_conf.h create mode 100644 boards/calliope-mini/mini/Makefile create mode 100644 boards/calliope-mini/mini/mini.c diff --git a/boards/calliope-mini/Makefile b/boards/calliope-mini/Makefile new file mode 100644 index 000000000000..ed5e3a66ac2e --- /dev/null +++ b/boards/calliope-mini/Makefile @@ -0,0 +1,7 @@ +MODULE = board + +ifneq (,$(filter mini,$(USEMODULE))) + DIRS += mini +endif + +include $(RIOTBASE)/Makefile.base diff --git a/boards/calliope-mini/Makefile.dep b/boards/calliope-mini/Makefile.dep new file mode 100644 index 000000000000..ea6d99073756 --- /dev/null +++ b/boards/calliope-mini/Makefile.dep @@ -0,0 +1,8 @@ +ifneq (,$(filter mini,$(USEMODULE))) + USEMODULE += xtimer + USEMODULE += mineplex +endif + +ifneq (,$(filter saul_default,$(USEMODULE))) + USEMODULE += saul_gpio +endif diff --git a/boards/calliope-mini/Makefile.features b/boards/calliope-mini/Makefile.features new file mode 100644 index 000000000000..5915575f8139 --- /dev/null +++ b/boards/calliope-mini/Makefile.features @@ -0,0 +1,14 @@ +# Put defined MCU peripherals here (in alphabetical order) +FEATURES_PROVIDED += periph_cpuid +FEATURES_PROVIDED += periph_gpio +FEATURES_PROVIDED += periph_hwrng +FEATURES_PROVIDED += periph_rtt +FEATURES_PROVIDED += periph_timer +FEATURES_PROVIDED += periph_uart + +# Various other features (if any) +FEATURES_PROVIDED += cpp +FEATURES_PROVIDED += radio_nrfmin + +# The board MPU family (used for grouping by the CI system) +FEATURES_MCU_GROUP = cortex_m0_1 diff --git a/boards/calliope-mini/Makefile.include b/boards/calliope-mini/Makefile.include new file mode 100644 index 000000000000..d9c05ab559bc --- /dev/null +++ b/boards/calliope-mini/Makefile.include @@ -0,0 +1,28 @@ +# define the used CPU +export CPU = nrf51 +export CPU_MODEL = nrf51x22xxab + +# define the default port depending on the host OS +PORT_LINUX ?= /dev/ttyACM0 +PORT_DARWIN ?= $(firstword $(sort $(wildcard /dev/tty.usbmodem*))) + +# setup serial terminal +include $(RIOTBOARD)/Makefile.include.serial + +# we support flashing through plain fscopy or using JLink +FLASHTOOL ?= fscopy +ifeq (fscopy,$(FLASHTOOL)) + export OFLAGS = -O ihex + export HEXFILE = $(ELFFILE:.elf=.hex) + export FFLAGS = + export DEBUGGER_FLAGS = + + export FLASHER = $(RIOTBOARD)/$(BOARD)/dist/flash.sh + export DEBUGGER = + export DEBUGSERVER = +else ifeq (jlink,$(FLASHTOOL)) + export JLINK_DEVICE := nrf51822 + include $(RIOTBOARD)/Makefile.include.jlink +else + $(info ERROR: invalid flash tool specified) +endif diff --git a/boards/calliope-mini/board.c b/boards/calliope-mini/board.c new file mode 100644 index 000000000000..c1460d791db2 --- /dev/null +++ b/boards/calliope-mini/board.c @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2016 Freie Universität Berlin + * + * 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 boards_calliope-mini + * @{ + * + * @file + * @brief Board initialization code for the Calliope mini + * + * @author Hauke Petersen + * + * @} + */ + +#include "board.h" +#include "periph/gpio.h" + +void board_init(void) +{ + /* initialize the CPU */ + cpu_init(); + + /* initialize the mini's buttons */ + gpio_init(BTN0_PIN, GPIO_IN); + gpio_init(BTN1_PIN, GPIO_IN); +} diff --git a/boards/calliope-mini/dist/flash.sh b/boards/calliope-mini/dist/flash.sh new file mode 100755 index 000000000000..9b4630f96652 --- /dev/null +++ b/boards/calliope-mini/dist/flash.sh @@ -0,0 +1,65 @@ +#!/bin/sh + +# Copyright (C) 2014 Freie Universität Berlin +# +# 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. + +# The Calliope mini can be flashed through accessing it as a mass storage +# device. To upload a new firmware, simply copy your binary onto this device. +# +# Under Ubuntu/Mint the default mount-point is /media/$(USER)/MINI +# +# @author Hauke Petersen +# @author Oliver Hahm + +OS=`uname` +DID_MOUNT=false +NAME="MINI" + +# set the mount path depending on the OS +if [ ${OS} = "Linux" ] +then + MOUNT=/media/${USER}/${NAME} +elif [ ${OS} = "Darwin" ] +then + MOUNT=/Volumes/${NAME} +else + echo "" + echo "ERROR: No mount point defined for your OS" + echo "Please copy the binary manually to your Calliope mini" + echo "" + exit +fi + +# check if device was mounted +mount | grep ${MOUNT} > /dev/null +if [ $? -eq 1 ] +then + mount ${MOUNT} + if [ $? -eq 1 ] + then + echo "" + echo "ERROR: could not mount your Calliope mini" + echo "" + exit + else + DID_MOUNT=true + fi +fi + +# copy new binary to device +cp ${HEXFILE} ${MOUNT} +# make sure hexfile was written +sync + +# unmount the device if we have manually mounted it before +if [ ${DID_MOUNT} = true ] +then + umount ${MOUNT} +fi + +echo "" +echo "UPLOAD SUCCESFUL" +echo "" diff --git a/boards/calliope-mini/include/board.h b/boards/calliope-mini/include/board.h new file mode 100644 index 000000000000..565d64b7750b --- /dev/null +++ b/boards/calliope-mini/include/board.h @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2016 Freie Universität Berlin + * + * 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 boards_mini Calliope mini + * @ingroup boards + * @brief Board specific files for the Calliope mini + * @{ + * + * @file + * @brief Board specific configuration for the Calliope mini + * + * @author Hauke Petersen + */ + +#ifndef BOARD_H +#define BOARD_H + +#include "cpu.h" +#include "periph_conf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Xtimer configuration + * @{ + */ +#define XTIMER_DEV (0) +#define XTIMER_CHAN (0) +#define XTIMER_WIDTH (24) +#define XTIMER_BACKOFF (40) +/** @} */ + +/** + * @brief LED matrix pin configuration + * @{ + */ +#define MINI_LED_COL1 GPIO_PIN(0, 4) +#define MINI_LED_COL2 GPIO_PIN(0, 5) +#define MINI_LED_COL3 GPIO_PIN(0, 6) +#define MINI_LED_COL4 GPIO_PIN(0, 7) +#define MINI_LED_COL5 GPIO_PIN(0, 8) +#define MINI_LED_COL6 GPIO_PIN(0, 9) +#define MINI_LED_COL7 GPIO_PIN(0, 10) +#define MINI_LED_COL8 GPIO_PIN(0, 11) +#define MINI_LED_COL9 GPIO_PIN(0, 12) +#define MINI_LED_ROW1 GPIO_PIN(0, 13) +#define MINI_LED_ROW2 GPIO_PIN(0, 14) +#define MINI_LED_ROW3 GPIO_PIN(0, 15) +/** @} */ + +/** + * @brief Button configuration + * @{ + */ +#define BTN0_PIN GPIO_PIN(0, 17) +#define BTN1_PIN GPIO_PIN(0, 26) +/** @} */ + +/** + * @brief MMA8653 accelerometer configuration + * @{ + */ +#define MMA8653_PARAM_I2C I2C_0, +#define MMA8653_PARAM_ADDR 0x1d +/** @} */ + +/** + * @brief MAG3110 magnetometer configuration + * @{ + */ +#define MAG3110_PARAM_I2C I2C_0, +#define MAG3110_PARAM_ADDR 0x0e +/** @} */ + +/** + * @brief Initialize the board, also triggers the CPU initialization + */ +void board_init(void); + +#ifdef __cplusplus +} +#endif + +#endif /** BOARD_H */ +/** @} */ diff --git a/boards/calliope-mini/include/gpio_params.h b/boards/calliope-mini/include/gpio_params.h new file mode 100644 index 000000000000..3446944a81ea --- /dev/null +++ b/boards/calliope-mini/include/gpio_params.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2016 Freie Universität Berlin + * + * 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 boards_calliope-mini + * @{ + * + * @file + * @brief Board specific configuration of direct mapped GPIOs + * + * @author Hauke Petersen + */ + +#ifndef GPIO_PARAMS_H +#define GPIO_PARAMS_H + +#include "board.h" +#include "saul/periph.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief GPIO pin configuration + */ +static const saul_gpio_params_t saul_gpio_params[] = +{ + { + .name = "Button A", + .pin = BTN0_PIN, + .mode = GPIO_IN + }, + { + .name = "Button B", + .pin = BTN1_PIN, + .mode = GPIO_IN + }, +}; + +#ifdef __cplusplus +} +#endif + +#endif /* GPIO_PARAMS_H */ +/** @} */ diff --git a/boards/calliope-mini/include/mini.h b/boards/calliope-mini/include/mini.h new file mode 100644 index 000000000000..1333bcaf10aa --- /dev/null +++ b/boards/calliope-mini/include/mini.h @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2016 Freie Universität Berlin + * + * 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 boards_calliope-mini + * @{ + * + * @file + * @brief Calliope mini specific LED handling + * + * @author Hauke Petersen + */ + +#ifndef MINI_H_ +#define MINI_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Number of rows of the LED matrix + */ +#define MINI_MATRIX_ROWS (5U) + +/** + * @brief Number of columns of the LED matrix + */ +#define MINI_MATRIX_COLS (5U) + +/** + * @brief Initialize the Calliope mini's LED matrix + */ +void mini_matrix_init(void); + +/** + * @brief Turn on a single LED in the LED matrix + * + * @param[in] row row of the LED + * @param[in] col column of the LED + */ +void mini_matrix_on(uint8_t row, uint8_t col); + +/** + * @brief Turn off a single LED in the LED matrix + * + * @param[in] row row of the LED + * @param[in] col column of the LED + */ +void mini_matrix_off(uint8_t row, uint8_t col); + +/** + * @brief Write the given 'image' to the LED matrix + * + * In the given buffer, each byte represents one LED in the matrix, hence the + * buffer MUST be at least 25 byte wide. A byte value of `0` turns an LED off, + * while any other value turns it on. + * + * @param[in] buf new data to display, MUST be at least 25 byte + */ +void mini_matrix_set_raw(const uint8_t *buf); + +/** + * @brief Write the given character to the matrix, using the Mineplex font + * + * @param[in] c character to display + */ +void mini_matrix_set_char(char c); + +/** + * @brief Shift the given string through the LED matrix + * + * @param[in] str string do display + * @param[in] delay delay between each step [in us] + */ +void mini_matrix_shift_str(const char *str, uint32_t delay); + +#ifdef __cplusplus +} +#endif + +#endif /* MINI_H_ */ +/** @} */ diff --git a/boards/calliope-mini/include/periph_conf.h b/boards/calliope-mini/include/periph_conf.h new file mode 100644 index 000000000000..031c6c5fb7d7 --- /dev/null +++ b/boards/calliope-mini/include/periph_conf.h @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2016 Freie Universität Berlin + * + * 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 boards_calliope-mini + * @{ + * + * @file + * @brief Peripheral configuration for the Calliope mini + * + * @author Hauke Petersen + */ + +#ifndef PERIPH_CONF_H +#define PERIPH_CONF_H + +#include "periph_cpu.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @name Clock configuration + * + * @note The radio will not work with the internal RC oscillator! + * + * @{ + */ +#define CLOCK_CORECLOCK (16000000U) /* fixed for all NRF51822 */ +#define CLOCK_CRYSTAL (16U) /* set to 0: internal RC oscillator + 16: 16MHz crystal + 32: 32MHz crystal */ +/** @} */ + +/** + * @name Timer configuration + * @{ + */ +static const timer_conf_t timer_config[] = { + { + .dev = NRF_TIMER0, + .channels = 3, + .bitmode = TIMER_BITMODE_BITMODE_24Bit, + .irqn = TIMER0_IRQn + }, + { + .dev = NRF_TIMER1, + .channels = 3, + .bitmode = TIMER_BITMODE_BITMODE_16Bit, + .irqn = TIMER1_IRQn + }, + { + .dev = NRF_TIMER2, + .channels = 3, + .bitmode = TIMER_BITMODE_BITMODE_16Bit, + .irqn = TIMER2_IRQn + } +}; + +#define TIMER_0_ISR isr_timer0 +#define TIMER_1_ISR isr_timer1 +#define TIMER_2_ISR isr_timer2 + +#define TIMER_NUMOF (sizeof(timer_config) / sizeof(timer_config[0])) +/** @} */ + +/** + * @name Real time counter configuration + * @{ + */ +#define RTT_NUMOF (1U) +#define RTT_IRQ_PRIO 1 + +#define RTT_DEV NRF_RTC1 +#define RTT_IRQ RTC1_IRQn +#define RTT_ISR isr_rtc1 +#define RTT_MAX_VALUE (0xffffff) +#define RTT_FREQUENCY (10) /* in Hz */ +#define RTT_PRESCALER (3275U) /* run with 10 Hz */ +/** @} */ + +/** + * @brief UART configuration + * @{ + */ +#define UART_NUMOF (1U) +/* UART pin configuration */ +#define UART_HWFLOWCTRL 0 +#define UART_PIN_RX 25 +#define UART_PIN_TX 24 +/** @} */ + +/** + * @brief ADC configuration + * + * The configuration consists simply of a list of channels that should be used + * @{ + */ +#define ADC_NUMOF (0) +/** @} */ + +/** + * @brief Radio device configuration + * + * The radio is not guarded by a NUMOF define, as the radio is selected by its + * own module in the build system. + * @{ + */ +#define RADIO_IRQ_PRIO 1 +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif /* PERIPH_CONF_H */ +/** @} */ diff --git a/boards/calliope-mini/mini/Makefile b/boards/calliope-mini/mini/Makefile new file mode 100644 index 000000000000..48422e909a47 --- /dev/null +++ b/boards/calliope-mini/mini/Makefile @@ -0,0 +1 @@ +include $(RIOTBASE)/Makefile.base diff --git a/boards/calliope-mini/mini/mini.c b/boards/calliope-mini/mini/mini.c new file mode 100644 index 000000000000..ee07ac9c719d --- /dev/null +++ b/boards/calliope-mini/mini/mini.c @@ -0,0 +1,227 @@ +/* + * Copyright (C) 2016 Freie Universität Berlin + * + * 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 boards_calliope-mini + * @{ + * + * @file + * @brief Calliope mini specific LED matrix handling + * + * @author Hauke Petersen + * + * @} + */ + +#include +#include "xtimer.h" + +#include "board.h" +#include "mini.h" +#include "mineplex.h" +#include "periph/gpio.h" +#include "periph/timer.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +/** + * @brief The visible number of rows and columns of the LED matrix + */ +#define ROWS MINI_MATRIX_ROWS +#define COLS MINI_MATRIX_COLS + +/** + * @brief The electrical number of rows and columns + */ +#define ROWS_HW (3) +#define COLS_HW (9) + +/** + * @brief The refresh rate used for drawing the contents + * + * We want a refresh rate of at least 50Hz (->20ms), so the LEDs do not flicker. + */ +#define REFRESH (6000) /* 6ms * 3 rows -> ~55Hz */ + +/** + * @brief GPIO pins driving the rows + */ +static const gpio_t rows[ROWS_HW] = { + MINI_LED_ROW1, + MINI_LED_ROW2, + MINI_LED_ROW3 +}; + +/** + * @brief GPIO pins driving the columns + */ +static const gpio_t cols[COLS_HW] = { + MINI_LED_COL1, + MINI_LED_COL2, + MINI_LED_COL3, + MINI_LED_COL4, + MINI_LED_COL5, + MINI_LED_COL6, + MINI_LED_COL7, + MINI_LED_COL8, + MINI_LED_COL9, +}; + +/** + * @brief Map electrical layout to visible layout + * + * The electrical layout of the matrix is different than the visible layout + * (3x9 -> 5x5). This array maps from the visible 5 by 5 layout to the actual + * 3 by 9 layout used by the hardware. + */ +static const uint8_t pixmap[5][5] = { + { 0, 12, 1, 13, 2 }, + { 21, 22, 23, 24, 25 }, + { 10, 8, 11, 26, 9 }, + { 7, 6, 5, 4, 3 }, + { 20, 15, 18, 14, 19 } +}; + +/** + * @brief Buffer holding the current 'image' that is displayed + */ +static uint8_t framebuf[ROWS_HW * COLS_HW] = { 0 }; + +/** + * @brief Internal counter to keep track of which row needs to be refreshed + * next + */ +static unsigned cur_row = 0; + +/** + * @brief Write a Mineplex encoded character into the given buffer + * + * @param[in] c character to write + * @param[out] buf buffer to write the encoded character into, MUST be able to + * hold 25 byte + */ +static void char2buf(char c, uint8_t *buf) +{ + const uint8_t *raw = mineplex_char(c); + + /* set each row */ + for (int row = 0; row < ROWS; row++) { + for (int col = 0; col < COLS; col++) { + buf[(row * COLS) + col] = (raw[row] & (1 << col)); + } + } +} + +/** + * @brief Shift out and replace an image with the next, column by column + * + * @param[in|out] cur current 'image', will be overwritten + * @param[in] next image to shift in + * @param[in] delay delay between each column + */ +static void shift_next(uint8_t *cur, const uint8_t *next, uint32_t delay) +{ + for (int i = 0; i < COLS; i++) { + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < (COLS - 1); c++) { + cur[(r * COLS) + c] = cur[(r * COLS) + c + 1]; + } + cur[(r * COLS) + COLS - 1] = next[(r * COLS) + i]; + } + mini_matrix_set_raw((uint8_t *)cur); + xtimer_usleep(delay); + } +} + +static void refresh(void *arg, int channel) +{ + (void)arg; + (void)channel; + + /* set next refresh */ + timer_set(TIMER_DEV(2), 0, REFRESH); + + /* disable current row */ + gpio_clear(rows[cur_row]); + /* goto next row */ + cur_row = ((++cur_row) < ROWS_HW) ? cur_row : 0; + /* setup columns */ + int base = (COLS_HW * cur_row); + for (int i = 0; i < COLS_HW; i++) { + gpio_write(cols[i], !(framebuf[base + i])); + } + /* and finally enable the new row */ + gpio_set(rows[cur_row]); +} + +void mini_matrix_init(void) +{ + /* initialize rows */ + for (int i = 0; i < ROWS_HW; i++) { + gpio_init(rows[i], GPIO_OUT); + gpio_clear(rows[i]); + } + /* initialize columns */ + for (int i = 0; i < COLS_HW; i++) { + gpio_init(cols[i], GPIO_OUT); + gpio_set(cols[i]); + } + /* and finally initialize and start the refresh timer */ + timer_init(TIMER_DEV(2), 1000000, refresh, NULL); + timer_set(TIMER_DEV(2), 0, REFRESH); +} + +void mini_matrix_on(uint8_t row, uint8_t col) +{ + if ((row >= 5) || (col >= 5)) { + return; + } + + framebuf[pixmap[row][col]] = 0x01; +} + +void mini_matrix_off(uint8_t row, uint8_t col) +{ + if ((row >= 5) || (col >= 5)) { + return; + } + + framebuf[pixmap[row][col]] = 0x00; +} + +void mini_matrix_set_raw(const uint8_t *buf) { + for (int row = 0; row < ROWS; row++) { + for (int col = 0; col < COLS; col++) { + framebuf[pixmap[row][col]] = buf[(row * COLS) + col]; + } + } +} + +void mini_matrix_set_char(char c) +{ + uint8_t buf[ROWS * COLS]; + + char2buf(c, buf); + mini_matrix_set_raw(buf); +} + +void mini_matrix_shift_str(const char *str, uint32_t delay) +{ + uint8_t curbuf[ROWS][COLS]; + uint8_t newbuf[ROWS][COLS]; + + char2buf(' ', (uint8_t *)curbuf); + mini_matrix_set_raw((uint8_t *)curbuf); + while (*str) { + char2buf(*str++, (uint8_t *)newbuf); + shift_next((uint8_t *)curbuf, (uint8_t *)newbuf, delay); + } + char2buf(' ', (uint8_t *)newbuf); + shift_next((uint8_t *)curbuf, (uint8_t *)newbuf, delay); +}