diff --git a/conf/modules/light_scheduler.xml b/conf/modules/light_scheduler.xml
new file mode 100644
index 00000000000..c36df0eb0d0
--- /dev/null
+++ b/conf/modules/light_scheduler.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+ 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.
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sw/airborne/arch/chibios/modules/light/light_ws2812_arch.c b/sw/airborne/arch/chibios/modules/light/light_ws2812_arch.c
new file mode 100644
index 00000000000..f855707ca6a
--- /dev/null
+++ b/sw/airborne/arch/chibios/modules/light/light_ws2812_arch.c
@@ -0,0 +1,162 @@
+/*
+ * 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
+ * .
+ */
+
+/**
+ * @file light_ws2812i_arch.c
+ * @brief WS2812 driver based on ChibiOS
+ *
+ * @author Xavier Paris
+ * @maintainer Gautier Hattenberger
+ */
+
+/****************************************************************************************
+https://github.com/joewa/WS2812-LED-Driver_ChibiOS/
+****************************************************************************************/
+
+#include
+#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;
+ }
+ }
+}
diff --git a/sw/airborne/arch/chibios/modules/light/light_ws2812_arch.h b/sw/airborne/arch/chibios/modules/light/light_ws2812_arch.h
new file mode 100644
index 00000000000..5922fa88a2f
--- /dev/null
+++ b/sw/airborne/arch/chibios/modules/light/light_ws2812_arch.h
@@ -0,0 +1,44 @@
+/*
+ * 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
+ * .
+ */
+
+/**
+ * @file arch/chibios/modules/light/light_ws2812_arch.h
+ * @brief ws2812 driver based on ChibiOS
+ *
+ * @author Xavier Paris
+ * @maintainer Gautier Hattenberger
+ */
+
+#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);
+
diff --git a/sw/airborne/boards/apogee/chibios/v1.0/board.h b/sw/airborne/boards/apogee/chibios/v1.0/board.h
index ad41d32b29f..d77b687614f 100644
--- a/sw/airborne/boards/apogee/chibios/v1.0/board.h
+++ b/sw/airborne/boards/apogee/chibios/v1.0/board.h
@@ -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 \
+}
/*
diff --git a/sw/airborne/boards/apogee/chibios/v1.0/mcuconf.h b/sw/airborne/boards/apogee/chibios/v1.0/mcuconf.h
index 70ce9cf4150..35887d152c2 100644
--- a/sw/airborne/boards/apogee/chibios/v1.0/mcuconf.h
+++ b/sw/airborne/boards/apogee/chibios/v1.0/mcuconf.h
@@ -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
@@ -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
diff --git a/sw/airborne/modules/light/light_scheduler.c b/sw/airborne/modules/light/light_scheduler.c
new file mode 100644
index 00000000000..d81cf428929
--- /dev/null
+++ b/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
+ * .
+ *
+ */
+
+/**
+ * @file modules/light/light_scheduler.c
+ * @brief basic LED scheduler based on WS2812 RGB led driver
+ *
+ * @author Xavier Paris
+ * @maintainer Gautier Hattenberger
+ */
+
+#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;
+}
+
diff --git a/sw/airborne/modules/light/light_scheduler.h b/sw/airborne/modules/light/light_scheduler.h
new file mode 100644
index 00000000000..cb6e60f7e6c
--- /dev/null
+++ b/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
+ * .
+ *
+ */
+
+/**
+ * @file modules/light/light_scheduler.h
+ * @brief basic LED scheduler based on WS2812 RGB led driver
+ *
+ * @author Xavier Paris
+ * @maintainer Gautier Hattenberger
+ */
+
+#ifndef LIGHT_SCHEDULER_H
+#define LIGHT_SCHEDULER_H
+
+extern void light_scheduler_init(void);
+extern void light_scheduler_periodic(void);
+
+#endif /* LIGHT_SCHEDULER_H */