From a4e16cd7e91fd1c080f0700c9a2c200b7ca1f3a0 Mon Sep 17 00:00:00 2001 From: Alexandre Abadie Date: Tue, 23 May 2017 14:01:43 +0200 Subject: [PATCH] drivers/dsp0401: initial implementation --- drivers/Makefile.dep | 6 + drivers/Makefile.include | 3 + drivers/dsp0401/Makefile | 1 + drivers/dsp0401/dsp0401.c | 249 +++++++++++++++++++++++ drivers/dsp0401/include/dsp0401_params.h | 81 ++++++++ drivers/include/dsp0401.h | 109 ++++++++++ 6 files changed, 449 insertions(+) create mode 100644 drivers/dsp0401/Makefile create mode 100644 drivers/dsp0401/dsp0401.c create mode 100644 drivers/dsp0401/include/dsp0401_params.h create mode 100644 drivers/include/dsp0401.h diff --git a/drivers/Makefile.dep b/drivers/Makefile.dep index 4813af1e70..5fad444c99 100644 --- a/drivers/Makefile.dep +++ b/drivers/Makefile.dep @@ -83,6 +83,12 @@ ifneq (,$(filter dht,$(USEMODULE))) FEATURES_REQUIRED += periph_gpio endif +ifneq (,$(filter dsp0401,$(USEMODULE))) + USEMODULE += xtimer + FEATURES_REQUIRED += periph_gpio + FEATURES_REQUIRED += periph_pwm +endif + ifneq (,$(filter enc28j60,$(USEMODULE))) USEMODULE += netdev_eth USEMODULE += xtimer diff --git a/drivers/Makefile.include b/drivers/Makefile.include index 5ad17a4c32..cdfaa2acf3 100644 --- a/drivers/Makefile.include +++ b/drivers/Makefile.include @@ -121,3 +121,6 @@ endif ifneq (,$(filter lsm6dsl,$(USEMODULE))) USEMODULE_INCLUDES += $(RIOTBASE)/drivers/lsm6dsl/include endif +ifneq (,$(filter dsp0401,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/dsp0401/include +endif diff --git a/drivers/dsp0401/Makefile b/drivers/dsp0401/Makefile new file mode 100644 index 0000000000..48422e909a --- /dev/null +++ b/drivers/dsp0401/Makefile @@ -0,0 +1 @@ +include $(RIOTBASE)/Makefile.base diff --git a/drivers/dsp0401/dsp0401.c b/drivers/dsp0401/dsp0401.c new file mode 100644 index 0000000000..491e8a7e94 --- /dev/null +++ b/drivers/dsp0401/dsp0401.c @@ -0,0 +1,249 @@ +/* + * Copyright (C) 2017 Inria + * + * 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 drivers_dsp0401 + * @{ + * + * @file + * @brief Device driver implementation for dsp0401 alphanumeric display + * + * @author Alexandre Abadie + * + * @} + */ + +#include +#include + +#include "dsp0401.h" +#include "xtimer.h" +#include "periph/gpio.h" +#include "periph/pwm.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +#define LATCH_DELAY (50U) /* 50 us */ +#define SCK (dev->params.clk) +#define SDI (dev->params.sdi) +#define LAT (dev->params.lat) +#define PWM_PERIPH (dev->params.pwm) +#define PWM_CHAN (dev->params.pwm_channel) +#define BRIGHTNESS (dev->params.brightness) +#define PWM_FREQ (1000U) +#define PWM_STEPS (256U) +#define MOD_COUNT (dev->params.module_count) + +/* Internal Ascii char map */ +#define CHAR_MAP_MIN (30U) +#define CHAR_MAP_MAX (127U) + +static const uint8_t dsp0401_charmap[][2] = { + /* dec: char */ + { 0x00, 0x00 }, /* 30: */ + { 0x00, 0x00 }, /* 31: */ + { 0x00, 0x00 }, /* 32: ' ' */ + { 0x00, 0x00 }, /* 33: ! */ + { 0x00, 0x00 }, /* 34: " */ + { 0x00, 0x00 }, /* 35: # */ + { 0xB5, 0xB5 }, /* 36: $ */ + { 0xB3, 0xB3 }, /* 37: % */ + { 0x00, 0x00 }, /* 38: & */ + { 0x01, 0x00 }, /* 39: ` */ + { 0x81, 0x00 }, /* 40: ( */ + { 0x00, 0x42 }, /* 41: ) */ + { 0x53, 0x53 }, /* 42: * */ + { 0x11, 0x11 }, /* 43: + */ + { 0x00, 0x00 }, /* 44: , */ + { 0x10, 0x10 }, /* 45: - */ + { 0x00, 0x04 }, /* 46: . */ + { 0x02, 0x02 }, /* 47: / */ + { 0xAC, 0xAC }, /* 48: 0 */ + { 0x01, 0x01 }, /* 49: 1 */ + { 0x9C, 0x9C }, /* 50: 2 */ + { 0xBC, 0x84 }, /* 51: 3 */ + { 0x38, 0x30 }, /* 52: 4 */ + { 0xB4, 0xB4 }, /* 53: 5 */ + { 0xB4, 0xBC }, /* 54: 6 */ + { 0x16, 0x92 }, /* 55: 7 */ + { 0xBC, 0xBC }, /* 56: 8 */ + { 0xBC, 0xB4 }, /* 57: 9 */ + { 0x04, 0x04 }, /* 58: : */ + { 0x04, 0x02 }, /* 59: ; */ + { 0x00, 0x00 }, /* 60: < */ + { 0x90, 0x14 }, /* 61: = */ + { 0x00, 0x00 }, /* 62: > */ + { 0x00, 0x00 }, /* 63: ? */ + { 0xAC, 0x9D }, /* 64: @ */ + { 0x3C, 0xB8 }, /* 65: A */ + { 0xB1, 0xBC }, /* 66: B */ + { 0x84, 0xAC }, /* 67: C */ + { 0xAD, 0x85 }, /* 68: D */ + { 0x84, 0xBC }, /* 69: E */ + { 0x04, 0xB8 }, /* 70: F */ + { 0xB4, 0xAC }, /* 71: G */ + { 0x38, 0x38 }, /* 72: H */ + { 0x85, 0x85 }, /* 73: I */ + { 0xA8, 0x0C }, /* 74: J */ + { 0x42, 0x38 }, /* 75: K */ + { 0x80, 0x2C }, /* 76: L */ + { 0x2A, 0x68 }, /* 77: M */ + { 0x68, 0x68 }, /* 78: N */ + { 0xAC, 0xAC }, /* 79: 0 */ + { 0x1C, 0xB8 }, /* 80: P */ + { 0xEC, 0xAC }, /* 81: Q */ + { 0x5C, 0xB8 }, /* 82: R */ + { 0xB4, 0xB4 }, /* 83: S */ + { 0x05, 0x81 }, /* 84: T */ + { 0xA8, 0x2C }, /* 85: U */ + { 0x02, 0x2A }, /* 86: V */ + { 0x68, 0x2A }, /* 87: W */ + { 0x42, 0x42 }, /* 88: X */ + { 0x02, 0x42 }, /* 89: Y */ + { 0x86, 0x86 }, /* 90: Z */ + { 0x00, 0xAC }, /* 91: [ */ + { 0x40, 0x40 }, /* 92: \ */ + { 0xAC, 0x00 }, /* 93: ] */ + { 0x00, 0x00 }, /* 94: ^ */ + { 0x80, 0x04 }, /* 95: _ */ + { 0x00, 0x40 }, /* 96: ` */ + { 0x00, 0x00 }, /* 97: a */ + { 0x00, 0x00 }, /* 98: b */ + { 0x00, 0x00 }, /* 99: c */ + { 0x00, 0x00 }, /* 100: d */ + { 0x00, 0x00 }, /* 101: e */ + { 0x00, 0x00 }, /* 102: f */ + { 0x00, 0x00 }, /* 103: g */ + { 0x00, 0x00 }, /* 104: h */ + { 0x00, 0x00 }, /* 105: i */ + { 0x00, 0x00 }, /* 106: j */ + { 0x00, 0x00 }, /* 107: k */ + { 0x00, 0x00 }, /* 108: l */ + { 0x00, 0x00 }, /* 109: m */ + { 0x00, 0x00 }, /* 110: n */ + { 0x00, 0x00 }, /* 111: o */ + { 0x00, 0x00 }, /* 112: p */ + { 0x00, 0x00 }, /* 113: q */ + { 0x00, 0x00 }, /* 114: r */ + { 0x00, 0x00 }, /* 115: s */ + { 0x00, 0x00 }, /* 116: t */ + { 0x00, 0x00 }, /* 117: u */ + { 0x00, 0x00 }, /* 118: v */ + { 0x00, 0x00 }, /* 119: w */ + { 0x00, 0x00 }, /* 120: x */ + { 0x00, 0x00 }, /* 121: y */ + { 0x00, 0x00 }, /* 122: z */ + { 0x85, 0x11 }, /* 123: { */ + { 0x01, 0x01 }, /* 124: | */ + { 0x11, 0x85 }, /* 125: } */ + { 0x00, 0x00 }, /* 126: ~ */ + { 0x00, 0x00 }, /* 127: */ +}; + +static void _shift_char(dsp0401_t *dev, uint8_t c) +{ + /* Unsupported chars not displayed */ + if ((c < CHAR_MAP_MIN) || (c > CHAR_MAP_MAX)) { + c = ' '; + } + + for (unsigned p = 0 ; p < 2 ; ++p) { + for (unsigned i = 0; i < 8; ++i) { + gpio_write(SDI, !!(dsp0401_charmap[c - CHAR_MAP_MIN][p] & (1 << (7 - i)))); + gpio_set(SCK); + gpio_clear(SCK); + } + } +} + +static void _latch(dsp0401_t *dev) +{ + xtimer_usleep(LATCH_DELAY); + gpio_set(LAT); + xtimer_usleep(LATCH_DELAY); + gpio_clear(LAT); + xtimer_usleep(LATCH_DELAY); +} + +int dsp0401_init(dsp0401_t *dev, const dsp0401_params_t *params) +{ + dev->params = *params; + + /* Initialize clock pin and set it to low */ + if (gpio_init(SCK, GPIO_OUT) < 0) { + DEBUG("[ERROR] CLK GPIO initialization failed."); + return -DSP0401_ERR_CLK_GPIO; + } + gpio_clear(SCK); + + /* Initialize data pin */ + if (gpio_init(SDI, GPIO_OUT) < 0) { + DEBUG("[ERROR] SDI GPIO initialization failed."); + return -DSP0401_ERR_SDI_GPIO; + } + gpio_clear(SDI); + + /* Initialize latch pin and set it to low */ + if (gpio_init(LAT, GPIO_OUT) < 0) { + DEBUG("[ERROR] LAT GPIO initialization failed."); + return -DSP0401_ERR_LAT_GPIO; + } + gpio_clear(LAT); + + /* Initialize PWM used for LED brightness */ + if (!pwm_init(PWM_PERIPH, PWM_LEFT, PWM_FREQ, PWM_STEPS)) { + DEBUG("[ERROR] PWM initialization failed."); + return -DSP0401_ERR_PWM; + } + pwm_set(PWM_PERIPH, PWM_CHAN, BRIGHTNESS); + + dsp0401_clear_text(dev); + + return DSP0401_OK; +} + +void dsp0401_display_text(dsp0401_t *dev, char *text) +{ + unsigned text_len = strlen(text); + for (unsigned i = 0 ; i < MOD_COUNT * 4; ++i) { + if (i < text_len) { + _shift_char(dev, text[i]); + } else { + _shift_char(dev, ' '); + } + } + + _latch(dev); +} + +void dsp0401_clear_text(dsp0401_t *dev) +{ + /* each module has 4 alphanumeric displays */ + for (unsigned i = 0; i < MOD_COUNT * 4; ++i) { + _shift_char(dev, ' '); + } + _latch(dev); +} + +void dsp0401_scroll_text(dsp0401_t *dev, char *text, uint16_t delay) +{ + dsp0401_clear_text(dev); + + for (unsigned i = 0; i < strlen(text); ++i) { + _shift_char(dev, text[i]); + _latch(dev); + xtimer_usleep((uint32_t)(delay * US_PER_MS)); + } + + for (unsigned i = 0; i < MOD_COUNT * 4; ++i) { + _shift_char(dev, ' '); + _latch(dev); + xtimer_usleep((uint32_t)(delay * US_PER_MS)); + } +} diff --git a/drivers/dsp0401/include/dsp0401_params.h b/drivers/dsp0401/include/dsp0401_params.h new file mode 100644 index 0000000000..a2d2fee3c3 --- /dev/null +++ b/drivers/dsp0401/include/dsp0401_params.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2017 Inria + * + * 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 drivers_dsp0401 + * + * @{ + * @file + * @brief Default configuration for DSP0401 + * + * @author Alexandre Abadie + */ + +#ifndef DSP0401_PARAMS_H +#define DSP0401_PARAMS_H + +#include "board.h" +#include "dsp0401.h" +#include "periph/gpio.h" +#include "periph/pwm.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Set default configuration parameters for the DSP0401 (for Nucleo-F411) + * @{ + */ +#ifndef DSP0401_PARAM_SDI_PIN +#define DSP0401_PARAM_SDI_PIN GPIO_PIN(0, 10) /* D2 */ +#endif +#ifndef DSP0401_PARAM_CLK_PIN +#define DSP0401_PARAM_CLK_PIN GPIO_PIN(1, 3) /* D3 */ +#endif +#ifndef DSP0401_PARAM_LAT_PIN +#define DSP0401_PARAM_LAT_PIN GPIO_PIN(1, 5) /* D4 */ +#endif +#ifndef DSP0401_PARAM_PWM_DEV +#define DSP0401_PARAM_PWM_DEV PWM_DEV(1) +#endif +#ifndef DSP0401_PARAM_PWM_CHAN +#define DSP0401_PARAM_PWM_CHAN (0U) +#endif +#ifndef DSP0401_PARAM_BRIGHTNESS +#define DSP0401_PARAM_BRIGHTNESS (255U) +#endif +#ifndef DSP0401_PARAM_MODULE_COUNT +#define DSP0401_PARAM_MODULE_COUNT (1U) +#endif + + +#define DSP0401_PARAMS_DEFAULT { \ + .sdi = DSP0401_PARAM_SDI_PIN, \ + .clk = DSP0401_PARAM_CLK_PIN, \ + .lat = DSP0401_PARAM_LAT_PIN, \ + .pwm = DSP0401_PARAM_PWM_DEV, \ + .pwm_channel = DSP0401_PARAM_PWM_CHAN, \ + .brightness = DSP0401_PARAM_BRIGHTNESS, \ + .module_count = DSP0401_PARAM_MODULE_COUNT } +/**@}*/ + +/** + * @brief Configure DSP0401 + */ +static const dsp0401_params_t dsp0401_params[] = +{ + DSP0401_PARAMS_DEFAULT, +}; + +#ifdef __cplusplus +} +#endif + +#endif /* DSP0401_PARAMS_H */ +/** @} */ diff --git a/drivers/include/dsp0401.h b/drivers/include/dsp0401.h new file mode 100644 index 0000000000..344bcdd2b1 --- /dev/null +++ b/drivers/include/dsp0401.h @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2017 Inria + * + * 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 drivers_dsp0401 DSP0401 + * @ingroup drivers_actuators + * @brief Device driver interface for the DSP0401 alphanumeric display + * @{ + * + * @file + * @brief Device driver interface for the DSP0401 alphanumeric display + * + * @author Alexandre Abadie + */ + +#ifndef DSP0401_H +#define DSP0401_H + +#include +#include +#include "periph/gpio.h" +#include "periph/pwm.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @name Return codes + * @{ + */ +enum { + DSP0401_OK = 0, /**< All ok */ + DSP0401_ERR_CLK_GPIO, /**< Something went wrong with CLK GPIO */ + DSP0401_ERR_SDI_GPIO, /**< Something went wrong with SDI GPIO */ + DSP0401_ERR_LAT_GPIO, /**< Something went wrong with LAT GPIO */ + DSP0401_ERR_PWM, /**< Something went wrong with PWM */ +}; +/** @} */ + +/** + * @brief Device initialization parameters + */ +typedef struct { + gpio_t sdi; /**< Data input pin */ + gpio_t clk; /**< Clock pin */ + gpio_t lat; /**< Latch pin */ + pwm_t pwm; /**< PWM device */ + uint8_t pwm_channel; /**< PWM device channel */ + uint8_t brightness; /**< LED brightness */ + uint8_t module_count; /**< Number of connected modules */ +} dsp0401_params_t; + +/** + * @brief Device descriptor for the DSP0401 + */ +typedef struct { + dsp0401_params_t params; /**< Device parameters */ +} dsp0401_t; + +/** + * @brief Initialize the given DSP0401 + * + * @param[out] dev Initialized device descriptor of DSP0401 device + * @param[in] params Device parameters to use + * + * @return DSP0401_OK if everything is good + * @return -DSP0401_ERR_CLK_GPIO if an error occured during CLK GPIO initialization + * @return -DSP0401_ERR_SDI_GPIO if an error occured during SDI GPIO initialization + * @return -DSP0401_ERR_LAT_GPIO if an error occured during LAT GPIO initialization + * @return -DSP0401_ERR_PWM if an error occured during PWM initialization + */ +int dsp0401_init(dsp0401_t *dev, const dsp0401_params_t *params); + +/** + * @brief Display the given text on the DSP0401 + * + * @param[in] dev Device descriptor of the DSP0401 device + * @param[in] text The text to display + */ +void dsp0401_display_text(dsp0401_t *dev, char *text); + +/** + * @brief Clear the text displayed on the DSP0401 + * + * @param[in] dev Device descriptor of the DSP0401 device + */ +void dsp0401_clear_text(dsp0401_t *dev); + +/** + * @brief Scroll the given text on the DSP0401 + * + * @param[in] dev Device descriptor of the DSP0401 device + * @param[in] text The text to scroll on the display + * @param[in] delay Delay in ms between each horizontal move + */ +void dsp0401_scroll_text(dsp0401_t *dev, char *text, uint16_t delay); + +#ifdef __cplusplus +} +#endif + +#endif /* DSP0401_H */ +/** @} */