1
0
Fork 0
mirror of https://github.com/betaflight/betaflight.git synced 2025-07-19 22:35:23 +03:00

Added single colour mode to WS2811 driver for RAM savings.

This commit is contained in:
mikeller 2019-02-06 12:04:34 +13:00
parent 7393d5fdac
commit 37d0d402c8
6 changed files with 52 additions and 63 deletions

View file

@ -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++;
}

View file

@ -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

View file

@ -20,6 +20,7 @@
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#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);

View file

@ -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;

View file

@ -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

View file

@ -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);