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:
parent
7393d5fdac
commit
37d0d402c8
6 changed files with 52 additions and 63 deletions
|
@ -57,8 +57,9 @@ volatile uint8_t ws2811LedDataTransferInProgress = 0;
|
||||||
uint16_t BIT_COMPARE_1 = 0;
|
uint16_t BIT_COMPARE_1 = 0;
|
||||||
uint16_t BIT_COMPARE_0 = 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)
|
void setLedHsv(uint16_t index, const hsvColor_t *color)
|
||||||
{
|
{
|
||||||
ledColorBuffer[index] = *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);
|
ledColorBuffer[index].v = ((uint16_t)ledColorBuffer[index].v * scalePercent / 100);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void setStripColor(const hsvColor_t *color)
|
void setStripColor(const hsvColor_t *color)
|
||||||
{
|
{
|
||||||
uint16_t index;
|
uint16_t index;
|
||||||
for (index = 0; index < WS2811_LED_STRIP_LENGTH; index++) {
|
for (index = 0; index < WS2811_DATA_BUFFER_SIZE; index++) {
|
||||||
setLedHsv(index, color);
|
ledColorBuffer[index] = *color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void setStripColors(const hsvColor_t *colors)
|
void setStripColors(const hsvColor_t *colors)
|
||||||
{
|
{
|
||||||
uint16_t index;
|
uint16_t index;
|
||||||
for (index = 0; index < WS2811_LED_STRIP_LENGTH; index++) {
|
for (index = 0; index < WS2811_DATA_BUFFER_SIZE; index++) {
|
||||||
setLedHsv(index, colors++);
|
setLedHsv(index, colors++);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -114,10 +116,7 @@ bool isWS2811LedStripReady(void)
|
||||||
STATIC_UNIT_TESTED uint16_t dmaBufferOffset;
|
STATIC_UNIT_TESTED uint16_t dmaBufferOffset;
|
||||||
static int16_t ledIndex;
|
static int16_t ledIndex;
|
||||||
|
|
||||||
#define USE_FAST_DMA_BUFFER_IMPL
|
STATIC_UNIT_TESTED void updateLEDDMABuffer(ledStripFormatRGB_e ledFormat, rgbColor24bpp_t *color)
|
||||||
#ifdef USE_FAST_DMA_BUFFER_IMPL
|
|
||||||
|
|
||||||
STATIC_UNIT_TESTED void fastUpdateLEDDMABuffer(ledStripFormatRGB_e ledFormat, rgbColor24bpp_t *color)
|
|
||||||
{
|
{
|
||||||
uint32_t packed_colour;
|
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;
|
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.
|
* 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
|
// fill transmit buffer with correct compare values to achieve
|
||||||
// correct pulse widths according to color values
|
// correct pulse widths according to color values
|
||||||
while (ledIndex < WS2811_LED_STRIP_LENGTH)
|
while (ledIndex < WS2811_DATA_BUFFER_SIZE)
|
||||||
{
|
{
|
||||||
rgb24 = hsvToRgb24(&ledColorBuffer[ledIndex]);
|
rgb24 = hsvToRgb24(&ledColorBuffer[ledIndex]);
|
||||||
|
|
||||||
#ifdef USE_FAST_DMA_BUFFER_IMPL
|
updateLEDDMABuffer(ledFormat, rgb24);
|
||||||
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
|
|
||||||
|
|
||||||
ledIndex++;
|
ledIndex++;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,16 +20,26 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "platform.h"
|
||||||
|
|
||||||
#include "drivers/io_types.h"
|
#include "drivers/io_types.h"
|
||||||
|
|
||||||
#define WS2811_LED_STRIP_LENGTH 32
|
#define WS2811_LED_STRIP_LENGTH 32
|
||||||
|
|
||||||
#define WS2811_BITS_PER_LED 24
|
#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
|
// for 50us delay
|
||||||
#define WS2811_DELAY_BUFFER_LENGTH 42
|
#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)
|
// 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_TIMER_MHZ 48
|
||||||
#define WS2811_CARRIER_HZ 800000
|
#define WS2811_CARRIER_HZ 800000
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
|
|
||||||
|
@ -50,9 +51,26 @@ static TIM_TypeDef *timer = NULL;
|
||||||
|
|
||||||
static void WS2811_DMA_IRQHandler(dmaChannelDescriptor_t *descriptor)
|
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 (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;
|
ws2811LedDataTransferInProgress = 0;
|
||||||
DMA_Cmd(descriptor->ref, DISABLE);
|
DMA_Cmd(descriptor->ref, DISABLE);
|
||||||
|
#endif
|
||||||
|
|
||||||
DMA_CLEAR_FLAG(descriptor, DMA_IT_TCIF);
|
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_Priority = DMA_Priority_High;
|
||||||
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
|
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
|
||||||
#endif
|
#endif
|
||||||
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
|
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
|
||||||
|
|
||||||
DMA_Init(dmaRef, &DMA_InitStructure);
|
DMA_Init(dmaRef, &DMA_InitStructure);
|
||||||
TIM_DMACmd(timer, timerDmaSource(timerHardware->channel), ENABLE);
|
TIM_DMACmd(timer, timerDmaSource(timerHardware->channel), ENABLE);
|
||||||
|
|
|
@ -94,10 +94,6 @@ static uint8_t previousProfileColorIndex = COLOR_UNDEFINED;
|
||||||
#define BEACON_FAILSAFE_PERIOD_US 250 // 2Hz
|
#define BEACON_FAILSAFE_PERIOD_US 250 // 2Hz
|
||||||
#define BEACON_FAILSAFE_ON_PERCENT 50 // 50% duty cycle
|
#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[] = {
|
const hsvColor_t hsv[] = {
|
||||||
// H S V
|
// H S V
|
||||||
[COLOR_BLACK] = { 0, 0, 0},
|
[COLOR_BLACK] = { 0, 0, 0},
|
||||||
|
@ -140,6 +136,11 @@ void pgResetFn_ledStripConfig(ledStripConfig_t *ledStripConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef USE_LED_STRIP_STATUS_MODE
|
#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 hsvColor_t *colors;
|
||||||
const modeColorIndexes_t *modeColors;
|
const modeColorIndexes_t *modeColors;
|
||||||
specialColorIndexes_t specialColors;
|
specialColorIndexes_t specialColors;
|
||||||
|
|
|
@ -244,6 +244,10 @@
|
||||||
#undef USE_LED_STRIP_STATUS_MODE
|
#undef USE_LED_STRIP_STATUS_MODE
|
||||||
#endif
|
#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)
|
#if defined(SIMULATOR_BUILD) || defined(UNIT_TEST)
|
||||||
// This feature uses 'arm_math.h', which does not exist for x86.
|
// This feature uses 'arm_math.h', which does not exist for x86.
|
||||||
#undef USE_GYRO_DATA_ANALYSE
|
#undef USE_GYRO_DATA_ANALYSE
|
||||||
|
|
|
@ -33,8 +33,7 @@ extern "C" {
|
||||||
extern "C" {
|
extern "C" {
|
||||||
STATIC_UNIT_TESTED extern uint16_t dmaBufferOffset;
|
STATIC_UNIT_TESTED extern uint16_t dmaBufferOffset;
|
||||||
|
|
||||||
STATIC_UNIT_TESTED void fastUpdateLEDDMABuffer(rgbColor24bpp_t *color);
|
STATIC_UNIT_TESTED void updateLEDDMABuffer(rgbColor24bpp_t *color);
|
||||||
STATIC_UNIT_TESTED void updateLEDDMABuffer(uint8_t componentValue);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(WS2812, updateDMABuffer) {
|
TEST(WS2812, updateDMABuffer) {
|
||||||
|
@ -45,13 +44,7 @@ TEST(WS2812, updateDMABuffer) {
|
||||||
dmaBufferOffset = 0;
|
dmaBufferOffset = 0;
|
||||||
|
|
||||||
// when
|
// when
|
||||||
#if 0
|
updateLEDDMABuffer(&color1);
|
||||||
updateLEDDMABuffer(color1.rgb.g);
|
|
||||||
updateLEDDMABuffer(color1.rgb.r);
|
|
||||||
updateLEDDMABuffer(color1.rgb.b);
|
|
||||||
#else
|
|
||||||
fastUpdateLEDDMABuffer(&color1);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// then
|
// then
|
||||||
EXPECT_EQ(24, dmaBufferOffset);
|
EXPECT_EQ(24, dmaBufferOffset);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue