From ecaca83b0bf1368e6b3c3c7cce7d7e93e176396d Mon Sep 17 00:00:00 2001 From: smlng Date: Mon, 12 Jun 2017 22:28:55 +0200 Subject: [PATCH] drivers: add my9221 led controller --- drivers/Makefile.dep | 9 +- drivers/Makefile.include | 3 + drivers/include/my9221.h | 129 +++++++++++++++++++++ drivers/my9221/Makefile | 1 + drivers/my9221/include/my9221_internal.h | 48 ++++++++ drivers/my9221/my9221.c | 137 +++++++++++++++++++++++ 6 files changed, 325 insertions(+), 2 deletions(-) create mode 100644 drivers/include/my9221.h create mode 100644 drivers/my9221/Makefile create mode 100644 drivers/my9221/include/my9221_internal.h create mode 100644 drivers/my9221/my9221.c diff --git a/drivers/Makefile.dep b/drivers/Makefile.dep index ddc5541d76..923d8072ef 100644 --- a/drivers/Makefile.dep +++ b/drivers/Makefile.dep @@ -164,8 +164,13 @@ ifneq (,$(filter mpu9150,$(USEMODULE))) endif ifneq (,$(filter mtd_sdcard,$(USEMODULE))) - USEMODULE += mtd - USEMODULE += sdcard_spi + USEMODULE += mtd + USEMODULE += sdcard_spi +endif + +ifneq (,$(filter my9221,$(USEMODULE))) + FEATURES_REQUIRED += periph_gpio + USEMODULE += xtimer endif ifneq (,$(filter nrfmin,$(USEMODULE))) diff --git a/drivers/Makefile.include b/drivers/Makefile.include index 2ce48e8c87..6ed1123fcb 100644 --- a/drivers/Makefile.include +++ b/drivers/Makefile.include @@ -52,6 +52,9 @@ endif ifneq (,$(filter mpu9150,$(USEMODULE))) USEMODULE_INCLUDES += $(RIOTBASE)/drivers/mpu9150/include endif +ifneq (,$(filter my9221,$(USEMODULE))) + USEMODULE_INCLUDES += $(RIOTBASE)/drivers/my9221/include +endif ifneq (,$(filter ina220,$(USEMODULE))) USEMODULE_INCLUDES += $(RIOTBASE)/drivers/ina220/include endif diff --git a/drivers/include/my9221.h b/drivers/include/my9221.h new file mode 100644 index 0000000000..1cf72ca035 --- /dev/null +++ b/drivers/include/my9221.h @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2017 HAW Hamburg + * + * 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_my9221 MY9221 LED controller + * @ingroup drivers_actuators + * @brief Driver for the MY-Semi MY9221 LED controller + * + * @{ + * @file + * @brief Interface for the MY9221 LED controller driver + * + * @author Sebastian Meiling + */ + +#ifndef MY9221_H +#define MY9221_H + +#include + +#include "periph/gpio.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Maximum number of distinct LEDs the controller can operate + */ +#define MY9221_LED_MAX (12U) + +/** + * @brief Max brightness value to turn LED full on + */ +#define MY9221_LED_ON (0xFF) + +/** + * @brief Min brightness value to turn LED off + */ +#define MY9221_LED_OFF (0x00) + +/** + * @name Direction the controller accesses LEDs + * @{ + */ +enum { + MY9221_DIR_FWD, /**< forward */ + MY9221_DIR_REV, /**< backward */ +}; +/** @} */ + +/** + * @name Driver specific return codes + * @{ + */ +enum { + MY9221_OK, /**< success */ + MY9221_ERR, /**< failure */ +}; +/** @} */ + +/** + * @brief Parameters needed for device initialization + */ +typedef struct { + uint8_t leds; /**< number of LEDs */ + uint8_t dir; /**< led direction */ + gpio_t clk; /**< clock gpio pin */ + gpio_t dat; /**< data gpio pin */ +} my9221_params_t; + +/** + * @brief Device descriptor for MY9221 LED controller + */ +typedef struct { + my9221_params_t params; /**< config parameters */ + uint8_t state[MY9221_LED_MAX]; /**< state of individual leds */ +} my9221_t; + +/** + * @brief Initialize the given driver + * + * @param[out] dev device descriptor of MY9221 LED controller + * @param[in] params configuration parameters + * + * @return 0 on success, otherwise error + */ +int my9221_init(my9221_t *dev, const my9221_params_t *params); + +/** + * @brief Set device state + * + * @note If @p state is NULL or @p len is 0, current device state is set + * otherwise, current state is overwritten by @p state. + * + * @param[in] dev device descriptor of MY9221 LED controller + * @param[in] state new device state array + * @param[in] len length of state array + */ +void my9221_set_state(my9221_t *dev, const uint8_t *state, uint8_t len); + +/** + * @brief Set brightness of distinct LED + * + * @param[in] dev device descriptor of MY9221 LED controller + * @param[in] led led number, start with 0 + * @param[in] alpha brightness level for led + */ +void my9221_set_led(my9221_t *dev, const uint8_t led, const uint8_t alpha); + +/** + * @brief Toggle a distinct LED + * + * @param[in] dev device descriptor of MY9221 LED controller + * @param[in] led led number, start with 0 + */ +void my9221_toggle_led(my9221_t *dev, const uint8_t led); + +#ifdef __cplusplus +} +#endif + +#endif /* MY9221_H */ +/** @} */ diff --git a/drivers/my9221/Makefile b/drivers/my9221/Makefile new file mode 100644 index 0000000000..48422e909a --- /dev/null +++ b/drivers/my9221/Makefile @@ -0,0 +1 @@ +include $(RIOTBASE)/Makefile.base diff --git a/drivers/my9221/include/my9221_internal.h b/drivers/my9221/include/my9221_internal.h new file mode 100644 index 0000000000..ecc895faea --- /dev/null +++ b/drivers/my9221/include/my9221_internal.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2017 HAW Hamburg + * + * 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_my9221 + * + * @{ + * @file + * @brief Internal config and parameters for the MY9221 LED controller + * + * @author Sebastian Meiling + */ + +#ifndef MY9221_INTERNAL_H +#define MY9221_INTERNAL_H + +#include "xtimer.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Time to wait until latch register is processed + */ +#define MY9221_LATCH_WAIT (10U * US_PER_MS) + +/** + * @brief Number of write loops for latch register + */ +#define MY9221_LATCH_LOOP (4U) + +/** + * @brief Enable command mode on LED controller + */ +#define MY9221_CMDMODE (0x00) + +#ifdef __cplusplus +} +#endif + +#endif /* MY9221_INTERNAL_H */ +/** @} */ diff --git a/drivers/my9221/my9221.c b/drivers/my9221/my9221.c new file mode 100644 index 0000000000..797cb8a0af --- /dev/null +++ b/drivers/my9221/my9221.c @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2017 HAW Hamburg + * + * 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_my9221 + * + * @{ + * @file + * @brief Driver for the MY9221 LED controller + * + * @author Sebastian Meiling + * + * @} + */ + +#include +#include +#include + +#include "log.h" +#include "periph/gpio.h" +#include "xtimer.h" + +#include "my9221.h" +#include "my9221_internal.h" + +#define DEV_DIR (dev->params.dir) +#define DEV_LEDS (dev->params.leds) +#define DEV_STATE(x) (dev->state[x]) +#define PIN_CLK (dev->params.clk) +#define PIN_DAT (dev->params.dat) + +/** + * @brief Write a single data to the LED controller + */ +void _write(my9221_t *dev, uint16_t data) +{ + assert(dev); + + for (unsigned i = 0; i < 16; ++i) { + (data & 0x8000) ? gpio_set(PIN_DAT) : gpio_clear(PIN_DAT); + gpio_toggle(PIN_CLK); + data <<= 1; + } +} + +/** + * @brief Load data into the latch register of the LED controller + */ +void _latch(my9221_t *dev) +{ + assert(dev); + + gpio_clear(PIN_DAT); + xtimer_usleep(MY9221_LATCH_WAIT); + + for (unsigned i = 0; i < MY9221_LATCH_LOOP; ++i) { + gpio_set(PIN_DAT); + gpio_clear(PIN_DAT); + } +} + +/** + * @brief Write state data of all LEDs to the controller + */ +void _set_state(my9221_t *dev) +{ + assert(dev); + + _write(dev, MY9221_CMDMODE); + for (unsigned i = 0; i < DEV_LEDS; ++i) { + if (DEV_DIR == MY9221_DIR_REV) { + /* Write LED state in reverse order */ + _write(dev, DEV_STATE(DEV_LEDS-i-1)); + } + else { + /* Write LED state in forward order */ + _write(dev, DEV_STATE(i)); + } + } + /* set unused LED pins to off */ + for (unsigned j = DEV_LEDS; j < MY9221_LED_MAX; ++j) { + _write(dev, MY9221_LED_OFF); + } + + _latch(dev); +} + +int my9221_init(my9221_t *dev, const my9221_params_t *params) +{ + assert(dev); + assert(params); + /* write config params to device descriptor */ + memcpy(&dev->params, params, sizeof(my9221_params_t)); + /* init clock and data pins as output */ + gpio_init(PIN_CLK, GPIO_OUT); + gpio_init(PIN_DAT, GPIO_OUT); + /* reset state, i.e., all LEDs off */ + memset(dev->state, 0, sizeof(dev->state)); + _set_state(dev); + + return MY9221_OK; +} + +void my9221_set_state(my9221_t *dev, const uint8_t *state, uint8_t len) +{ + if ((state != NULL) && (len > 0)) { + if (len > MY9221_LED_MAX) { + len = MY9221_LED_MAX; + } + memcpy(dev->state, state, len); + } + _set_state(dev); +} + +void my9221_set_led(my9221_t *dev, const uint8_t led, const uint8_t alpha) +{ + assert(dev); + assert(led < DEV_LEDS); + + DEV_STATE(led) = ~(MY9221_LED_ON << ((uint16_t)(alpha << 3) >> 8)); + _set_state(dev); +} + +void my9221_toggle_led(my9221_t *dev, const uint8_t led) +{ + assert(dev); + assert(led < DEV_LEDS); + + DEV_STATE(led) = DEV_STATE(led) ? MY9221_LED_OFF : MY9221_LED_ON; + _set_state(dev); +}