Skip to content

Commit

Permalink
[module] WS2812 led module (#2435)
Browse files Browse the repository at this point in the history
Using the ChibiOS DMA driver
  • Loading branch information
gautierhattenberger committed Jun 19, 2019
1 parent 17b185d commit 208c37b
Show file tree
Hide file tree
Showing 7 changed files with 334 additions and 1 deletion.
25 changes: 25 additions & 0 deletions conf/modules/light_scheduler.xml
@@ -0,0 +1,25 @@
<!DOCTYPE module SYSTEM "module.dtd">

<module name="light_scheduler" dir="light">
<doc>
<description>
Basic light scheduler using WS2812 driver

WS2812 are small RGB leds controlled with a 1-wire protocol.
This module is an example of controlling several leds with the color changing continuously.
Implementation for ChibiOS using DMA.
</description>
<define name="WS2812_NB_LEDS" value="8" description="Number of leds"/>
</doc>
<header>
<file name="light_scheduler.h"/>
</header>
<init fun="light_scheduler_init()"/>
<periodic fun="light_scheduler_periodic()" freq="8"/>
<makefile target="ap">
<file name="light_scheduler.c"/>
<file_arch name="light_ws2812_arch.c"/>
<file_arch name="hal_stm32_dma.c" dir="mcu_periph" cond="ifeq ($(RTOS),chibios)"/>
<define name="STM32_PWM_USE_TIM1" value="TRUE" cond="ifeq ($(RTOS),chibios)"/>
</makefile>
</module>
162 changes: 162 additions & 0 deletions sw/airborne/arch/chibios/modules/light/light_ws2812_arch.c
@@ -0,0 +1,162 @@
/*
* Copyright (C) 2019 Xavier Paris <xavier.paris@enac.fr>
*
* This file is part of paparazzi
*
* paparazzi is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* paparazzi is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with paparazzi; see the file COPYING. If not, see
* <http://www.gnu.org/licenses/>.
*/

/**
* @file light_ws2812i_arch.c
* @brief WS2812 driver based on ChibiOS
*
* @author Xavier Paris
* @maintainer Gautier Hattenberger <gautier.hattenberger@enac.fr>
*/

/****************************************************************************************
https://github.com/joewa/WS2812-LED-Driver_ChibiOS/
****************************************************************************************/

#include <hal.h>
#include "modules/light/light_ws2812_arch.h"
#include "mcu_periph/hal_stm32_dma.h"

#define WS2812_SERVO_HZ 800000
#define WS2812_PWM_FREQUENCY (STM32_SYSCLK/2)

#define WS2812_DUTYCYCLE_0 (WS2812_PWM_FREQUENCY/(1000000000/350))
#define WS2812_DUTYCYCLE_1 (WS2812_PWM_FREQUENCY/(1000000000/800))

#define WS2812_RESET_BIT_N (50)
#define WS2812_COLOR_BIT_N (WS2812_NB_LEDS * 24)
#define WS2812_BIT_N (WS2812_COLOR_BIT_N + WS2812_RESET_BIT_N)

// Use driver 1 by default
#ifndef WS2812_CFG_DEF
#define WS2812_CFG_DEF WS2812D1_CFG_DEF
#endif

#define WS2812_DMA_IRQ_PRIORITY 6

/**
* Configuration structure
*/
typedef struct {
uint32_t dma_stream;
uint8_t dma_channel;
uint8_t pwm_channel;
uint8_t dma_priority;
PWMDriver *pwmp;
} WS2812Config;

// Config from board conf
static WS2812Config WS2812CFG = WS2812_CFG_DEF;

/**
* Driver structure
*/
typedef struct {
const WS2812Config *config;
DMAConfig dma_conf;
PWMConfig pwm_conf;
DMADriver dmap;
uint32_t buf[WS2812_BIT_N + 1];
} WS2812Driver;

// Driver
static WS2812Driver WS2812D;

void light_ws2812_arch_init(void)
{
uint32_t i;
for (i = 0; i < WS2812_COLOR_BIT_N; i++) {
WS2812D.buf[i] = WS2812_DUTYCYCLE_0;
}
for (i = 0; i < WS2812_RESET_BIT_N; i++) {
WS2812D.buf[i + WS2812_COLOR_BIT_N] = 0;
}

WS2812D.config = &WS2812CFG;

WS2812D.dma_conf = (DMAConfig) {
.stream = WS2812CFG.dma_stream,
.channel = WS2812CFG.dma_channel,
.dma_priority = WS2812CFG.dma_priority,
.irq_priority = WS2812_DMA_IRQ_PRIORITY,
.direction = DMA_DIR_M2P,
.psize = 4,
.msize = 4,
.inc_peripheral_addr = false,
.inc_memory_addr = true,
.circular = true,
.error_cb = NULL,
.end_cb = NULL,
.pburst = 0,
.mburst = 0,
.fifo = 0
};

WS2812D.pwm_conf = (PWMConfig) {
.frequency = WS2812_PWM_FREQUENCY,
.period = WS2812_PWM_FREQUENCY / WS2812_SERVO_HZ,
.callback = NULL,
.channels = {
{
.mode = PWM_OUTPUT_DISABLED,
.callback = NULL
},
{
.mode = PWM_OUTPUT_DISABLED,
.callback = NULL
},
{
.mode = PWM_OUTPUT_DISABLED,
.callback = NULL
},
{
.mode = PWM_OUTPUT_DISABLED,
.callback = NULL
},
},
.cr2 = 0,
.dier = STM32_TIM_DIER_UDE
};

dmaObjectInit(&WS2812D.dmap);
dmaStart(&WS2812D.dmap, &WS2812D.dma_conf);
dmaStartTransfert(&WS2812D.dmap, &(WS2812D.config->pwmp->tim->CCR[WS2812D.config->pwm_channel]), &WS2812D.buf, WS2812_BIT_N);

WS2812D.pwm_conf.channels[WS2812D.config->pwm_channel].mode = PWM_OUTPUT_ACTIVE_HIGH;
pwmStart(WS2812D.config->pwmp, &WS2812D.pwm_conf);
pwmEnableChannel(WS2812D.config->pwmp, WS2812D.config->pwm_channel, 0);
}

#define WS2812_BIT(led, byte, bit) (24*(led) + 8*(byte) + (7 - (bit)))
#define WS2812_RED_BIT(led, bit) WS2812_BIT((led), 1, (bit))
#define WS2812_GREEN_BIT(led, bit) WS2812_BIT((led), 0, (bit))
#define WS2812_BLUE_BIT(led, bit) WS2812_BIT((led), 2, (bit))

void light_ws2812_arch_set(uint32_t led_number, uint8_t r, uint8_t g, uint8_t b)
{
uint32_t bit;
if (led_number < WS2812_NB_LEDS) {
for (bit = 0; bit < 8; bit++) {
WS2812D.buf[WS2812_RED_BIT(led_number, bit)] = ((r >> bit) & 0x01) ? WS2812_DUTYCYCLE_1 : WS2812_DUTYCYCLE_0;
WS2812D.buf[WS2812_GREEN_BIT(led_number, bit)] = ((g >> bit) & 0x01) ? WS2812_DUTYCYCLE_1 : WS2812_DUTYCYCLE_0;
WS2812D.buf[WS2812_BLUE_BIT(led_number, bit)] = ((b >> bit) & 0x01) ? WS2812_DUTYCYCLE_1 : WS2812_DUTYCYCLE_0;
}
}
}
44 changes: 44 additions & 0 deletions sw/airborne/arch/chibios/modules/light/light_ws2812_arch.h
@@ -0,0 +1,44 @@
/*
* Copyright (C) 2019 Xavier Paris <xavier.paris@enac.fr>
*
* This file is part of paparazzi
*
* paparazzi is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* paparazzi is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with paparazzi; see the file COPYING. If not, see
* <http://www.gnu.org/licenses/>.
*/

/**
* @file arch/chibios/modules/light/light_ws2812_arch.h
* @brief ws2812 driver based on ChibiOS
*
* @author Xavier Paris
* @maintainer Gautier Hattenberger <gautier.hattenberger@enac.fr>
*/

#pragma once

#include "std.h"

/** Number of LEDs
*/
#ifndef WS2812_NB_LEDS
#define WS2812_NB_LEDS 8
#endif

extern void light_ws2812_arch_init(void);

/** set color RGB color of one led
*/
extern void light_ws2812_arch_set(uint32_t led_number, uint8_t r, uint8_t g, uint8_t b);

10 changes: 10 additions & 0 deletions sw/airborne/boards/apogee/chibios/v1.0/board.h
Expand Up @@ -576,6 +576,16 @@
#define SDLOG_USB_VBUS_PIN GPIO9


/**
* For WS2812
*/
#define WS2812D1_CFG_DEF { \
.dma_stream = STM32_PWM1_UP_DMA_STREAM, \
.dma_channel = STM32_PWM1_UP_DMA_CHANNEL, \
.dma_priority = STM32_PWM1_UP_DMA_PRIORITY, \
.pwm_channel = 0, \
.pwmp = &PWMD1 \
}


/*
Expand Down
9 changes: 8 additions & 1 deletion sw/airborne/boards/apogee/chibios/v1.0/mcuconf.h
Expand Up @@ -223,7 +223,9 @@
* PWM driver system settings.
*/
#define STM32_PWM_USE_ADVANCED FALSE
#define STM32_PWM_USE_TIM1 FALSE
#ifndef STM32_PWM_USE_TIM1
#define STM32_PWM_USE_TIM1 FALSE // enable for WS2812
#endif
#ifndef STM32_PWM_USE_TIM2
#define STM32_PWM_USE_TIM2 TRUE
#endif
Expand All @@ -242,6 +244,11 @@
#define STM32_PWM_TIM8_IRQ_PRIORITY 7
#define STM32_PWM_TIM9_IRQ_PRIORITY 7

#define STM32_PWM1_UP_DMA_STREAM STM32_DMA_STREAM_ID(2, 5) // incompatible with SPI1_TX
#define STM32_PWM1_UP_DMA_CHANNEL 6
#define STM32_PWM1_UP_DMA_IRQ_PRIORITY 6
#define STM32_PWM1_UP_DMA_PRIORITY 2

#define STM32_PWM2_UP_DMA_STREAM STM32_DMA_STREAM_ID(1, 1)
#define STM32_PWM2_UP_DMA_CHANNEL 3
#define STM32_PWM2_UP_DMA_IRQ_PRIORITY 6
Expand Down
49 changes: 49 additions & 0 deletions sw/airborne/modules/light/light_scheduler.c
@@ -0,0 +1,49 @@
/*
* Copyright (C) 2019 Xavier Paris
*
* This file is part of paparazzi.
*
* paparazzi is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* paparazzi is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with paparazzi; see the file COPYING. If not, see
* <http://www.gnu.org/licenses/>.
*
*/

/**
* @file modules/light/light_scheduler.c
* @brief basic LED scheduler based on WS2812 RGB led driver
*
* @author Xavier Paris
* @maintainer Gautier Hattenberger <gautier.hattenberger@enac.fr>
*/

#include "modules/light/light_scheduler.h"
#include "modules/light/light_ws2812_arch.h"

static uint32_t s = 0;

void light_scheduler_init(void)
{
light_ws2812_arch_init();
}

void light_scheduler_periodic(void)
{
uint32_t n, s0;
for (n = 0; n < WS2812_NB_LEDS; n++) {
s0 = s + 10 * n;
light_ws2812_arch_set(n, s0 % 255, (s0 + 85) % 255, (s0 + 170) % 255);
}
s += 10;
}

36 changes: 36 additions & 0 deletions sw/airborne/modules/light/light_scheduler.h
@@ -0,0 +1,36 @@
/*
* Copyright (C) 2019 Xavier Paris
*
* This file is part of paparazzi.
*
* paparazzi is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* paparazzi is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with paparazzi; see the file COPYING. If not, see
* <http://www.gnu.org/licenses/>.
*
*/

/**
* @file modules/light/light_scheduler.h
* @brief basic LED scheduler based on WS2812 RGB led driver
*
* @author Xavier Paris
* @maintainer Gautier Hattenberger <gautier.hattenberger@enac.fr>
*/

#ifndef LIGHT_SCHEDULER_H
#define LIGHT_SCHEDULER_H

extern void light_scheduler_init(void);
extern void light_scheduler_periodic(void);

#endif /* LIGHT_SCHEDULER_H */

0 comments on commit 208c37b

Please sign in to comment.