Skip to content
Snippets Groups Projects
Commit a8678aea authored by Hauke Petersen's avatar Hauke Petersen Committed by GitHub
Browse files

Merge pull request #6753 from haukepetersen/add_apa102

drivers: add driver for apa102 RGB LEDs
parents 1809a1df ca4ee668
No related branches found
No related tags found
No related merge requests found
...@@ -4,6 +4,10 @@ ifneq (,$(filter adxl345,$(USEMODULE))) ...@@ -4,6 +4,10 @@ ifneq (,$(filter adxl345,$(USEMODULE)))
FEATURES_REQUIRED += periph_i2c FEATURES_REQUIRED += periph_i2c
endif endif
ifneq (,$(filter apa102,$(USEMODULE)))
FEATURES_REQUIRED += periph_gpio
endif
ifneq (,$(filter at30tse75x,$(USEMODULE))) ifneq (,$(filter at30tse75x,$(USEMODULE)))
USEMODULE += xtimer USEMODULE += xtimer
FEATURES_REQUIRED += periph_i2c FEATURES_REQUIRED += periph_i2c
......
...@@ -142,3 +142,6 @@ endif ...@@ -142,3 +142,6 @@ endif
ifneq (,$(filter sx127%,$(USEMODULE))) ifneq (,$(filter sx127%,$(USEMODULE)))
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/sx127x/include USEMODULE_INCLUDES += $(RIOTBASE)/drivers/sx127x/include
endif endif
ifneq (,$(filter apa102,$(USEMODULE)))
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/apa102/include
endif
include $(RIOTBASE)/Makefile.base
/*
* Copyright (C) 2017 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 drivers_apa102
* @{
*
* @file
* @brief APA 102 RGB LED driver implementation
*
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
*
* @}
*/
#include <string.h>
#include "assert.h"
#include "apa102.h"
#define START (0x00000000)
#define END (0xffffffff)
#define HEAD (0xe0000000)
#define BRIGHT (0x1f000000)
#define BLUE (0x00ff0000)
#define GREEN (0x0000ff00)
#define RED (0x000000ff)
#define BRIGHT_SHIFT (21U)
#define BLUE_SHIFT (16U)
#define GREEN_SHIFT (8U)
static inline void shift(const apa102_t *dev, uint32_t data)
{
for (int i = 31; i >= 0; i--) {
gpio_write(dev->data_pin, ((data >> i) & 0x01));
gpio_set(dev->clk_pin);
gpio_clear(dev->clk_pin);
}
}
void apa102_init(apa102_t *dev, const apa102_params_t *params)
{
assert(dev && params);
memcpy(dev, params, sizeof(apa102_params_t));
gpio_init(dev->data_pin, GPIO_OUT);
gpio_init(dev->clk_pin, GPIO_OUT);
gpio_clear(dev->data_pin);
gpio_clear(dev->clk_pin);
}
void apa102_load_rgba(const apa102_t *dev, const color_rgba_t vals[])
{
assert(dev && vals);
shift(dev, START);
for (int i = 0; i < dev->led_numof; i++) {
uint32_t data = HEAD;
/* we scale the 8-bit alpha value to a 5-bit value by cutting off the
* 3 leas significant bits */
data |= (((uint32_t)vals[i].alpha << BRIGHT_SHIFT) & BRIGHT);
data |= ((uint32_t)vals[i].color.b << BLUE_SHIFT);
data |= ((uint32_t)vals[i].color.g << GREEN_SHIFT);
data |= vals[i].color.r;
shift(dev, data);
}
shift(dev, END);
}
/*
* Copyright (C) 2017 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 drivers_apa102
* @{
*
* @file
* @brief APA102 board specific configuration
*
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
*/
#ifndef APA102_PARAMS_H
#define APA102_PARAMS_H
#include "board.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Set default configuration parameters for the APA102 driver
* @{
*/
#ifndef APA102_PARAM_LED_NUMOF
#define APA102_PARAM_LED_NUMOF (64) /* many have 64 per meter... */
#endif
#ifndef APA102_PARAM_DATA_PIN
#define APA102_PARAM_DATA_PIN (GPIO_PIN(0, 0))
#endif
#ifndef APA102_PARAM_CLK_PIN
#define APA102_PARAM_CLK_PIN (GPIO_PIN(0, 1))
#endif
#define APA102_PARAMS_DEFAULT { .led_numof = APA102_PARAM_LED_NUMOF, \
.data_pin = APA102_PARAM_DATA_PIN, \
.clk_pin = APA102_PARAM_CLK_PIN }
/**@}*/
/**
* @brief APA102 configuration
*/
static const apa102_params_t apa102_params[] =
{
#ifdef APA102_PARAMS_BOARD
APA102_PARAMS_BOARD,
#else
APA102_PARAMS_DEFAULT,
#endif
};
#ifdef __cplusplus
}
#endif
#endif /* APA102_PARAMS_H */
/** @} */
/*
* Copyright (C) 2017 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 drivers_apa102 APA102 RGB LED
* @ingroup drivers_actuators
* @brief Driver for chained APA102 RGB LEDs
* @{
*
* @file
* @brief Interface for controlling APA102 LEDs
*
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
*/
#ifndef APA102_H
#define APA102_H
#include "color.h"
#include "periph/gpio.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Configuration parameters for (chained) APA102 LEDs
*/
typedef struct {
int led_numof; /**< number of chained LEDs */
gpio_t data_pin; /**< data pin */
gpio_t clk_pin; /**< clock pin */
} apa102_params_t;
/**
* @brief Device descriptor definition for APA102 LEDs
*/
typedef apa102_params_t apa102_t;
/**
* @brief Initialize (chained) APA102 LEDs
*
* @param[out] dev device descriptor
* @param[in] params device configuration
*
* @pre @p dev != NULL
* @pre @p params != NULL
*/
void apa102_init(apa102_t *dev, const apa102_params_t *params);
/**
* @brief Apply the given color values to the connected LED(s)
*
* @param[in] dev device descriptor
* @param[in] vals color values, MUST be of size `dev->led_numof`
*
* @pre @p dev != NULL
* @pre @p vals != NULL
*/
void apa102_load_rgba(const apa102_t *dev, const color_rgba_t vals[]);
#ifdef __cplusplus
}
#endif
#endif /* APA102_H */
/** @} */
...@@ -38,6 +38,14 @@ typedef struct { ...@@ -38,6 +38,14 @@ typedef struct {
uint8_t b; /**< blue value [0 - 255] */ uint8_t b; /**< blue value [0 - 255] */
} color_rgb_t; } color_rgb_t;
/**
* @brief RGBA color value
*/
typedef struct {
color_rgb_t color; /**< RGB value */
uint8_t alpha; /**< alpha value [0 - 255] */
} color_rgba_t;
/** /**
* @brief Data-structure for holding HSV colors * @brief Data-structure for holding HSV colors
*/ */
...@@ -47,7 +55,6 @@ typedef struct { ...@@ -47,7 +55,6 @@ typedef struct {
float v; /**< value [0.0 - 1.0] */ float v; /**< value [0.0 - 1.0] */
} color_hsv_t; } color_hsv_t;
/** /**
* @brief Convert RGB color to HSV color * @brief Convert RGB color to HSV color
* *
......
APPLICATION = driver_apa102
include ../Makefile.tests_common
USEMODULE += apa102
USEMODULE += color
USEMODULE += xtimer
include $(RIOTBASE)/Makefile.include
# About
This test application is made for verification of the APA102 LED strip driver.
# Usage
Connect a APA102 based LED strip to a board of your choice, build, and flash
this application. When run, you should see the strip changing its brightness
while lighting in red, then green, and then blue. After this sequence, you
should see a light moving up and down the strip, changing its color.
You might need to adjust the default parameters (number of LEDs on the strip and
pin configuration). You can do this simply by pre-setting the `CFLAGS`
environment variable, e.g.:
```
$ CFLAGS="-DAPA102_PARAM_LED_NUMOF=78"" make all
```
To change the default pins, simply override the default parameters, e.g.:
```
$ CFLAGS="-DAPA102_PARAM_DATA_PIN=GPIO_PIN\(2,3\) -DAPA102_PARAM_CLK_PIN=GPIO_PIN\(1,17\)" make all
```
/*
* Copyright (C) 2017 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 tests
* @{
*
* @file
* @brief Test application for the APA102 LED strip driver
*
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
*
* @}
*/
#include <string.h>
#include <stdio.h>
#include <stdint.h>
#include "xtimer.h"
#include "color.h"
#include "apa102.h"
#include "apa102_params.h"
/**
* @brief Switch to the next LED every 10ms
*/
#define STEP (200 * US_PER_MS)
/**
* @brief Interval for dimming colors
*/
#define DIM (100 * US_PER_MS)
/**
* @brief Step through brightness levels (0-255) in 32 steps
*/
#define BSTEP (8U)
/**
* @brief Allocate the device descriptor
*/
static apa102_t dev;
/**
* @brief Allocate a color_rgb_t struct for each LED on the strip
*/
static color_rgba_t leds[APA102_PARAM_LED_NUMOF];
static void setcolor(int color, uint8_t alpha)
{
for (int i = 0; i < (int)APA102_PARAM_LED_NUMOF; i++) {
leds[i].alpha = alpha;
memset(&leds[i].color, 0, sizeof(color_rgb_t));
switch (color) {
case 0:
leds[i].color.r = 255;
break;
case 1:
leds[i].color.g = 255;
break;
case 2:
leds[i].color.b = 255;
break;
}
}
}
int main(void)
{
int pos = 0;
int step = 1;
color_hsv_t col = { 0.0, 1.0, 1.0 };
puts("APA102 Test App");
/* initialize all LED color values to black (off) */
memset(leds, 0, sizeof(color_rgba_t) * APA102_PARAM_LED_NUMOF);
/* initialize the driver */
apa102_init(&dev, &apa102_params[0]);
puts("Initialization done.");
/* set to each red, green, and blue, and fade each color in and out */
for (int col = 0; col <= 2; col++) {
int i = 0;
for (; i <= (int)UINT8_MAX; i += BSTEP) {
setcolor(col, (uint8_t)i);
apa102_load_rgba(&dev, leds);
xtimer_usleep(DIM);
}
i -= BSTEP;
for (; i >= 0; i -= BSTEP) {
setcolor(col, (uint8_t)i);
apa102_load_rgba(&dev, leds);
xtimer_usleep(DIM);
}
}
puts("Color Fading done");
/* reset color values */
setcolor(-1, 255);
apa102_load_rgba(&dev, leds);
xtimer_ticks32_t now = xtimer_now();
while (1) {
/* change the active color by running around the hue circle */
col.h += 1.0;
if (col.h > 360.0) {
col.h = 0.0;
}
/* set the active LED to the active color value */
memset(&leds[pos].color, 0, sizeof(color_rgb_t));
pos += step;
color_hsv2rgb(&col, &leds[pos].color);
/* apply the values to the LED strip */
apa102_load_rgba(&dev, leds);
/* switch direction once reaching an end of the strip */
if ((pos == (APA102_PARAM_LED_NUMOF - 1)) || (pos == 0)) {
step *= -1;
}
xtimer_periodic_wakeup(&now, STEP);
}
return 0;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment