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 */