diff --git a/src/main/drivers/light_ws2811strip.c b/src/main/drivers/light_ws2811strip.c index 1735f37b18..6df190fbad 100644 --- a/src/main/drivers/light_ws2811strip.c +++ b/src/main/drivers/light_ws2811strip.c @@ -57,8 +57,9 @@ volatile uint8_t ws2811LedDataTransferInProgress = 0; uint16_t BIT_COMPARE_1 = 0; uint16_t BIT_COMPARE_0 = 0; -static hsvColor_t ledColorBuffer[WS2811_LED_STRIP_LENGTH]; +static hsvColor_t ledColorBuffer[WS2811_DATA_BUFFER_SIZE]; +#if !defined(USE_WS2811_SINGLE_COLOUR) void setLedHsv(uint16_t index, const hsvColor_t *color) { ledColorBuffer[index] = *color; @@ -78,19 +79,20 @@ void scaleLedValue(uint16_t index, const uint8_t scalePercent) { ledColorBuffer[index].v = ((uint16_t)ledColorBuffer[index].v * scalePercent / 100); } +#endif void setStripColor(const hsvColor_t *color) { uint16_t index; - for (index = 0; index < WS2811_LED_STRIP_LENGTH; index++) { - setLedHsv(index, color); + for (index = 0; index < WS2811_DATA_BUFFER_SIZE; index++) { + ledColorBuffer[index] = *color; } } void setStripColors(const hsvColor_t *colors) { uint16_t index; - for (index = 0; index < WS2811_LED_STRIP_LENGTH; index++) { + for (index = 0; index < WS2811_DATA_BUFFER_SIZE; index++) { setLedHsv(index, colors++); } } @@ -114,10 +116,7 @@ bool isWS2811LedStripReady(void) STATIC_UNIT_TESTED uint16_t dmaBufferOffset; static int16_t ledIndex; -#define USE_FAST_DMA_BUFFER_IMPL -#ifdef USE_FAST_DMA_BUFFER_IMPL - -STATIC_UNIT_TESTED void fastUpdateLEDDMABuffer(ledStripFormatRGB_e ledFormat, rgbColor24bpp_t *color) +STATIC_UNIT_TESTED void updateLEDDMABuffer(ledStripFormatRGB_e ledFormat, rgbColor24bpp_t *color) { uint32_t packed_colour; @@ -136,25 +135,6 @@ STATIC_UNIT_TESTED void fastUpdateLEDDMABuffer(ledStripFormatRGB_e ledFormat, rg ledStripDMABuffer[dmaBufferOffset++] = (packed_colour & (1 << index)) ? BIT_COMPARE_1 : BIT_COMPARE_0; } } -#else -STATIC_UNIT_TESTED void updateLEDDMABuffer(uint8_t componentValue) -{ - uint8_t bitIndex; - - for (bitIndex = 0; bitIndex < 8; bitIndex++) - { - if ((componentValue << bitIndex) & 0x80 ) // data sent MSB first, j = 0 is MSB j = 7 is LSB - { - ledStripDMABuffer[dmaBufferOffset] = BIT_COMPARE_1; - } - else - { - ledStripDMABuffer[dmaBufferOffset] = BIT_COMPARE_0; // compare value for logical 0 - } - dmaBufferOffset++; - } -} -#endif /* * This method is non-blocking unless an existing LED update is in progress. @@ -174,28 +154,11 @@ void ws2811UpdateStrip(ledStripFormatRGB_e ledFormat) // fill transmit buffer with correct compare values to achieve // correct pulse widths according to color values - while (ledIndex < WS2811_LED_STRIP_LENGTH) + while (ledIndex < WS2811_DATA_BUFFER_SIZE) { rgb24 = hsvToRgb24(&ledColorBuffer[ledIndex]); -#ifdef USE_FAST_DMA_BUFFER_IMPL - fastUpdateLEDDMABuffer(ledFormat, rgb24); -#else - switch (ledFormat) { - case LED_RGB: // WS2811 drivers use RGB format - updateLEDDMABuffer(rgb24->rgb.r); - updateLEDDMABuffer(rgb24->rgb.g); - break; - - case LED_GRB: // WS2812 drivers use GRB format - default: - updateLEDDMABuffer(rgb24->rgb.g); - updateLEDDMABuffer(rgb24->rgb.r); - break; - } - - updateLEDDMABuffer(rgb24->rgb.b); -#endif + updateLEDDMABuffer(ledFormat, rgb24); ledIndex++; } diff --git a/src/main/drivers/light_ws2811strip.h b/src/main/drivers/light_ws2811strip.h index 6dfc367749..77c15bca71 100644 --- a/src/main/drivers/light_ws2811strip.h +++ b/src/main/drivers/light_ws2811strip.h @@ -20,16 +20,26 @@ #pragma once +#include "platform.h" + #include "drivers/io_types.h" #define WS2811_LED_STRIP_LENGTH 32 + #define WS2811_BITS_PER_LED 24 + +#if defined(USE_WS2811_SINGLE_COLOUR) +#define WS2811_DATA_BUFFER_SIZE 1 +#define WS2811_DMA_BUFFER_SIZE (WS2811_DATA_BUFFER_SIZE * WS2811_BITS_PER_LED) +// Do 2 extra iterations of the DMA transfer with the ouptut set to low to generate the > 50us delay. +#define WS2811_DELAY_ITERATIONS 2 +#else +#define WS2811_DATA_BUFFER_SIZE WS2811_LED_STRIP_LENGTH // for 50us delay #define WS2811_DELAY_BUFFER_LENGTH 42 - -#define WS2811_DATA_BUFFER_SIZE (WS2811_BITS_PER_LED * WS2811_LED_STRIP_LENGTH) // number of bytes needed is #LEDs * 24 bytes + 42 trailing bytes) -#define WS2811_DMA_BUFFER_SIZE (WS2811_DATA_BUFFER_SIZE + WS2811_DELAY_BUFFER_LENGTH) +#define WS2811_DMA_BUFFER_SIZE (WS2811_DATA_BUFFER_SIZE * WS2811_BITS_PER_LED + WS2811_DELAY_BUFFER_LENGTH) +#endif #define WS2811_TIMER_MHZ 48 #define WS2811_CARRIER_HZ 800000 diff --git a/src/main/drivers/light_ws2811strip_stdperiph.c b/src/main/drivers/light_ws2811strip_stdperiph.c index 627aebefeb..6b180bd0ac 100644 --- a/src/main/drivers/light_ws2811strip_stdperiph.c +++ b/src/main/drivers/light_ws2811strip_stdperiph.c @@ -20,6 +20,7 @@ #include #include +#include #include "platform.h" @@ -50,9 +51,26 @@ static TIM_TypeDef *timer = NULL; static void WS2811_DMA_IRQHandler(dmaChannelDescriptor_t *descriptor) { +#if defined(USE_WS2811_SINGLE_COLOUR) + static uint32_t counter = 0; +#endif + if (DMA_GET_FLAG_STATUS(descriptor, DMA_IT_TCIF)) { +#if defined(USE_WS2811_SINGLE_COLOUR) + counter++; + if (counter == WS2811_LED_STRIP_LENGTH) { + // Output low for 50us delay + memset(ledStripDMABuffer, 0, sizeof(ledStripDMABuffer)); + } else if (counter == (WS2811_LED_STRIP_LENGTH + WS2811_DELAY_ITERATIONS)) { + counter = 0; + ws2811LedDataTransferInProgress = 0; + DMA_Cmd(descriptor->ref, DISABLE); + } +#else ws2811LedDataTransferInProgress = 0; DMA_Cmd(descriptor->ref, DISABLE); +#endif + DMA_CLEAR_FLAG(descriptor, DMA_IT_TCIF); } } @@ -162,7 +180,7 @@ void ws2811LedStripHardwareInit(ioTag_t ioTag) DMA_InitStructure.DMA_Priority = DMA_Priority_High; DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; #endif - DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; + DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; DMA_Init(dmaRef, &DMA_InitStructure); TIM_DMACmd(timer, timerDmaSource(timerHardware->channel), ENABLE); diff --git a/src/main/io/ledstrip.c b/src/main/io/ledstrip.c index 2edade98a0..5b61a72ced 100644 --- a/src/main/io/ledstrip.c +++ b/src/main/io/ledstrip.c @@ -94,10 +94,6 @@ static uint8_t previousProfileColorIndex = COLOR_UNDEFINED; #define BEACON_FAILSAFE_PERIOD_US 250 // 2Hz #define BEACON_FAILSAFE_ON_PERCENT 50 // 50% duty cycle -#if LED_MAX_STRIP_LENGTH > WS2811_LED_STRIP_LENGTH -# error "Led strip length must match driver" -#endif - const hsvColor_t hsv[] = { // H S V [COLOR_BLACK] = { 0, 0, 0}, @@ -140,6 +136,11 @@ void pgResetFn_ledStripConfig(ledStripConfig_t *ledStripConfig) } #ifdef USE_LED_STRIP_STATUS_MODE + +#if LED_MAX_STRIP_LENGTH > WS2811_LED_STRIP_LENGTH +# error "Led strip length must match driver" +#endif + const hsvColor_t *colors; const modeColorIndexes_t *modeColors; specialColorIndexes_t specialColors; diff --git a/src/main/target/common_post.h b/src/main/target/common_post.h index d2dad6b657..74683243cd 100644 --- a/src/main/target/common_post.h +++ b/src/main/target/common_post.h @@ -244,6 +244,10 @@ #undef USE_LED_STRIP_STATUS_MODE #endif +#if defined(USE_LED_STRIP) && !defined(USE_LED_STRIP_STATUS_MODE) +#define USE_WS2811_SINGLE_COLOUR +#endif + #if defined(SIMULATOR_BUILD) || defined(UNIT_TEST) // This feature uses 'arm_math.h', which does not exist for x86. #undef USE_GYRO_DATA_ANALYSE diff --git a/src/test/unit/ws2811_unittest.cc b/src/test/unit/ws2811_unittest.cc index b4b1f37fdd..75e6900120 100644 --- a/src/test/unit/ws2811_unittest.cc +++ b/src/test/unit/ws2811_unittest.cc @@ -33,8 +33,7 @@ extern "C" { extern "C" { STATIC_UNIT_TESTED extern uint16_t dmaBufferOffset; -STATIC_UNIT_TESTED void fastUpdateLEDDMABuffer(rgbColor24bpp_t *color); -STATIC_UNIT_TESTED void updateLEDDMABuffer(uint8_t componentValue); +STATIC_UNIT_TESTED void updateLEDDMABuffer(rgbColor24bpp_t *color); } TEST(WS2812, updateDMABuffer) { @@ -45,13 +44,7 @@ TEST(WS2812, updateDMABuffer) { dmaBufferOffset = 0; // when -#if 0 - updateLEDDMABuffer(color1.rgb.g); - updateLEDDMABuffer(color1.rgb.r); - updateLEDDMABuffer(color1.rgb.b); -#else - fastUpdateLEDDMABuffer(&color1); -#endif + updateLEDDMABuffer(&color1); // then EXPECT_EQ(24, dmaBufferOffset);