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

Improve speed of LED STRIP code.

Shaved about 150us each strip update.

This commit leaves in some timing trace code for the CC3D target, the
results of which can be seen in the debug variables for the sections
being timed.

A later commit will remove/disable the timing code.
This commit is contained in:
Dominic Clifton 2014-09-20 01:00:13 +01:00
parent 36dac872b8
commit e847a6347d
9 changed files with 189 additions and 15 deletions

View file

@ -20,9 +20,40 @@
#define UNUSED(x) (void)(x) #define UNUSED(x) (void)(x)
#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)])) #define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
#ifdef UNIT_TEST
#define STATIC_UNIT_TESTED // make visible to unit test
#define UNIT_TESTED
#else
#define STATIC_UNIT_TESTED static
#define UNIT_TESTED
#endif
//#define SOFT_I2C // enable to test software i2c //#define SOFT_I2C // enable to test software i2c
#ifndef __CC_ARM #ifndef __CC_ARM
#define REQUIRE_CC_ARM_PRINTF_SUPPORT #define REQUIRE_CC_ARM_PRINTF_SUPPORT
#define REQUIRE_PRINTF_LONG_SUPPORT #define REQUIRE_PRINTF_LONG_SUPPORT
#endif #endif
extern int16_t debug[4];
#ifdef DEBUG_SECTION_TIMES
extern uint32_t sectionTimes[2][4];
#define TIME_SECTION_BEGIN(index) { \
extern uint32_t sectionTimes[2][4]; \
sectionTimes[0][index] = micros(); \
}
#define TIME_SECTION_END(index) { \
extern uint32_t sectionTimes[2][4]; \
sectionTimes[1][index] = micros(); \
debug[index] = sectionTimes[1][index] - sectionTimes[0][index]; \
}
#else
#define TIME_SECTION_BEGIN(index) {}
#define TIME_SECTION_END(index) {}
#endif

View file

@ -25,9 +25,12 @@
*/ */
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <string.h>
#include "platform.h" #include "platform.h"
#include "build_config.h"
#include "common/color.h" #include "common/color.h"
#include "common/colorconversion.h" #include "common/colorconversion.h"
#include "drivers/light_ws2811strip.h" #include "drivers/light_ws2811strip.h"
@ -75,6 +78,7 @@ void setStripColors(const hsvColor_t *colors)
void ws2811LedStripInit(void) void ws2811LedStripInit(void)
{ {
memset(&ledStripDMABuffer, 0, WS2811_DMA_BUFFER_SIZE);
ws2811LedStripHardwareInit(); ws2811LedStripHardwareInit();
ws2811UpdateStrip(); ws2811UpdateStrip();
} }
@ -84,10 +88,22 @@ bool isWS2811LedStripReady(void)
return !ws2811LedDataTransferInProgress; return !ws2811LedDataTransferInProgress;
} }
static uint16_t dmaBufferOffset; STATIC_UNIT_TESTED uint16_t dmaBufferOffset;
static int16_t ledIndex; static int16_t ledIndex;
void updateLEDDMABuffer(uint8_t componentValue) #define USE_FAST_DMA_BUFFER_IMPL
#ifdef USE_FAST_DMA_BUFFER_IMPL
STATIC_UNIT_TESTED void fastUpdateLEDDMABuffer(rgbColor24bpp_t *color)
{
uint32_t grb = (color->rgb.g << 16) | (color->rgb.r << 8) | (color->rgb.b);
for (int8_t index = 23; index >= 0; index--) {
ledStripDMABuffer[dmaBufferOffset++] = (grb & (1 << index)) ? BIT_COMPARE_1 : BIT_COMPARE_0;
}
}
#else
STATIC_UNIT_TESTED void updateLEDDMABuffer(uint8_t componentValue)
{ {
uint8_t bitIndex; uint8_t bitIndex;
@ -95,15 +111,16 @@ void updateLEDDMABuffer(uint8_t componentValue)
{ {
if ((componentValue << bitIndex) & 0x80 ) // data sent MSB first, j = 0 is MSB j = 7 is LSB if ((componentValue << bitIndex) & 0x80 ) // data sent MSB first, j = 0 is MSB j = 7 is LSB
{ {
ledStripDMABuffer[dmaBufferOffset] = 17; // compare value for logical 1 ledStripDMABuffer[dmaBufferOffset] = BIT_COMPARE_1;
} }
else else
{ {
ledStripDMABuffer[dmaBufferOffset] = 9; // compare value for logical 0 ledStripDMABuffer[dmaBufferOffset] = BIT_COMPARE_0; // compare value for logical 0
} }
dmaBufferOffset++; 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.
@ -128,20 +145,17 @@ void ws2811UpdateStrip(void)
{ {
rgb24 = hsvToRgb24(&ledColorBuffer[ledIndex]); rgb24 = hsvToRgb24(&ledColorBuffer[ledIndex]);
#ifdef USE_FAST_DMA_BUFFER_IMPL
fastUpdateLEDDMABuffer(rgb24);
#else
updateLEDDMABuffer(rgb24->rgb.g); updateLEDDMABuffer(rgb24->rgb.g);
updateLEDDMABuffer(rgb24->rgb.r); updateLEDDMABuffer(rgb24->rgb.r);
updateLEDDMABuffer(rgb24->rgb.b); updateLEDDMABuffer(rgb24->rgb.b);
#endif
ledIndex++; ledIndex++;
} }
// add needed delay at end of byte cycle, pulsewidth = 0
while(dmaBufferOffset < WS2811_DMA_BUFFER_SIZE)
{
ledStripDMABuffer[dmaBufferOffset] = 0;
dmaBufferOffset++;
}
ws2811LedDataTransferInProgress = 1; ws2811LedDataTransferInProgress = 1;
ws2811LedStripDMAEnable(); ws2811LedStripDMAEnable();
} }

View file

@ -21,7 +21,12 @@
#define WS2811_BITS_PER_LED 24 #define WS2811_BITS_PER_LED 24
#define WS2811_DELAY_BUFFER_LENGTH 42 // for 50us delay #define WS2811_DELAY_BUFFER_LENGTH 42 // for 50us delay
#define WS2811_DMA_BUFFER_SIZE (WS2811_BITS_PER_LED * WS2811_LED_STRIP_LENGTH + WS2811_DELAY_BUFFER_LENGTH) // number of bytes needed is #LEDs * 24 bytes + 42 trailing bytes) #define WS2811_DATA_BUFFER_SIZE (WS2811_BITS_PER_LED * WS2811_LED_STRIP_LENGTH)
#define WS2811_DMA_BUFFER_SIZE (WS2811_DATA_BUFFER_SIZE + WS2811_DELAY_BUFFER_LENGTH) // number of bytes needed is #LEDs * 24 bytes + 42 trailing bytes)
#define BIT_COMPARE_1 17 // timer compare value for logical 1
#define BIT_COMPARE_0 9 // timer compare value for logical 0
void ws2811LedStripInit(void); void ws2811LedStripInit(void);

View file

@ -216,7 +216,6 @@ static void ppmEdgeCallback(uint8_t port, captureCompare_t capture)
#define MAX_MISSED_PWM_EVENTS 10 #define MAX_MISSED_PWM_EVENTS 10
extern uint16_t debug[4];
static void pwmOverflowCallback(uint8_t port, captureCompare_t capture) static void pwmOverflowCallback(uint8_t port, captureCompare_t capture)
{ {
UNUSED(capture); UNUSED(capture);

View file

@ -725,8 +725,11 @@ void updateLedStrip(void)
static uint8_t warningState = 0; static uint8_t warningState = 0;
static uint8_t warningFlags; static uint8_t warningFlags;
TIME_SECTION_BEGIN(3);
// LAYER 1 // LAYER 1
TIME_SECTION_BEGIN(0);
applyLedModeLayer(); applyLedModeLayer();
applyLedThrottleLayer(); applyLedThrottleLayer();
@ -781,7 +784,14 @@ void updateLedStrip(void)
#ifdef USE_LED_ANIMATION #ifdef USE_LED_ANIMATION
applyLedAnimationLayer(); applyLedAnimationLayer();
#endif #endif
TIME_SECTION_END(0);
TIME_SECTION_BEGIN(2);
ws2811UpdateStrip(); ws2811UpdateStrip();
TIME_SECTION_END(2);
TIME_SECTION_END(3);
} }
bool parseColor(uint8_t index, char *colorConfig) bool parseColor(uint8_t index, char *colorConfig)

View file

@ -68,6 +68,9 @@
#include "build_config.h" #include "build_config.h"
#ifdef DEBUG_SECTION_TIMES
uint32_t sectionTimes[2][4];
#endif
extern uint32_t previousTime; extern uint32_t previousTime;
#ifdef SOFTSERIAL_LOOPBACK #ifdef SOFTSERIAL_LOOPBACK

View file

@ -15,6 +15,8 @@
* along with Cleanflight. If not, see <http://www.gnu.org/licenses/>. * along with Cleanflight. If not, see <http://www.gnu.org/licenses/>.
*/ */
#define DEBUG_SECTION_TIMES
#define LED0_GPIO GPIOB #define LED0_GPIO GPIOB
#define LED0_PIN Pin_3 // PB3 (LED) #define LED0_PIN Pin_3 // PB3 (LED)
#define LED0_PERIPHERAL RCC_APB2Periph_GPIOB #define LED0_PERIPHERAL RCC_APB2Periph_GPIOB

View file

@ -29,7 +29,7 @@ OBJECT_DIR = ../../obj/test
CPPFLAGS += -isystem $(GTEST_DIR)/inc CPPFLAGS += -isystem $(GTEST_DIR)/inc
# Flags passed to the C++ compiler. # Flags passed to the C++ compiler.
CXXFLAGS += -g -Wall -Wextra -pthread -ggdb -O0 CXXFLAGS += -g -Wall -Wextra -pthread -ggdb -O0 -DUNIT_TEST
# All tests produced by this Makefile. Remember to add new tests you # All tests produced by this Makefile. Remember to add new tests you
# created to the list. # created to the list.
@ -39,7 +39,8 @@ TESTS = \
gps_conversion_unittest \ gps_conversion_unittest \
telemetry_hott_unittest \ telemetry_hott_unittest \
rc_controls_unittest \ rc_controls_unittest \
ledstrip_unittest ledstrip_unittest \
ws2811_unittest
# All Google Test headers. Usually you shouldn't change this # All Google Test headers. Usually you shouldn't change this
# definition. # definition.
@ -172,3 +173,17 @@ ledstrip_unittest :$(OBJECT_DIR)/io/ledstrip.o $(OBJECT_DIR)/ledstrip_unittest.o
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $(OBJECT_DIR)/$@ $(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $(OBJECT_DIR)/$@
$(OBJECT_DIR)/drivers/light_ws2811strip.o : $(USER_DIR)/drivers/light_ws2811strip.c $(USER_DIR)/drivers/light_ws2811strip.h $(GTEST_HEADERS)
@mkdir -p $(dir $@)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(TEST_CFLAGS) -c $(USER_DIR)/drivers/light_ws2811strip.c -o $@
$(OBJECT_DIR)/ws2811_unittest.o : $(TEST_DIR)/ws2811_unittest.cc \
$(USER_DIR)/drivers/light_ws2811strip.h $(GTEST_HEADERS)
@mkdir -p $(dir $@)
$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(TEST_CFLAGS) -c $(TEST_DIR)/ws2811_unittest.cc -o $@
ws2811_unittest :$(OBJECT_DIR)/drivers/light_ws2811strip.o $(OBJECT_DIR)/ws2811_unittest.o $(OBJECT_DIR)/gtest_main.a
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -lpthread $^ -o $(OBJECT_DIR)/$@

View file

@ -0,0 +1,95 @@
/*
* This file is part of Cleanflight.
*
* Cleanflight 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 3 of the License, or
* (at your option) any later version.
*
* Cleanflight 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 Cleanflight. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdint.h>
#include <stdlib.h>
#include <limits.h>
#include "build_config.h"
#include "common/color.h"
#include "drivers/light_ws2811strip.h"
#include "unittest_macros.h"
#include "gtest/gtest.h"
STATIC_UNIT_TESTED extern uint16_t dmaBufferOffset;
STATIC_UNIT_TESTED void fastUpdateLEDDMABuffer(rgbColor24bpp_t *color);
STATIC_UNIT_TESTED void updateLEDDMABuffer(uint8_t componentValue);
TEST(WS2812, updateDMABuffer) {
// given
rgbColor24bpp_t color1 = {0xFF,0xAA,0x55};
// and
dmaBufferOffset = 0;
// when
#if 0
updateLEDDMABuffer(color1.rgb.g);
updateLEDDMABuffer(color1.rgb.r);
updateLEDDMABuffer(color1.rgb.b);
#else
fastUpdateLEDDMABuffer(&color1);
#endif
// then
EXPECT_EQ(24, dmaBufferOffset);
// and
uint8_t byteIndex = 0;
EXPECT_EQ(BIT_COMPARE_1, ledStripDMABuffer[(byteIndex * 8) + 0]);
EXPECT_EQ(BIT_COMPARE_0, ledStripDMABuffer[(byteIndex * 8) + 1]);
EXPECT_EQ(BIT_COMPARE_1, ledStripDMABuffer[(byteIndex * 8) + 2]);
EXPECT_EQ(BIT_COMPARE_0, ledStripDMABuffer[(byteIndex * 8) + 3]);
EXPECT_EQ(BIT_COMPARE_1, ledStripDMABuffer[(byteIndex * 8) + 4]);
EXPECT_EQ(BIT_COMPARE_0, ledStripDMABuffer[(byteIndex * 8) + 5]);
EXPECT_EQ(BIT_COMPARE_1, ledStripDMABuffer[(byteIndex * 8) + 6]);
EXPECT_EQ(BIT_COMPARE_0, ledStripDMABuffer[(byteIndex * 8) + 7]);
byteIndex++;
EXPECT_EQ(BIT_COMPARE_1, ledStripDMABuffer[(byteIndex * 8) + 0]);
EXPECT_EQ(BIT_COMPARE_1, ledStripDMABuffer[(byteIndex * 8) + 1]);
EXPECT_EQ(BIT_COMPARE_1, ledStripDMABuffer[(byteIndex * 8) + 2]);
EXPECT_EQ(BIT_COMPARE_1, ledStripDMABuffer[(byteIndex * 8) + 3]);
EXPECT_EQ(BIT_COMPARE_1, ledStripDMABuffer[(byteIndex * 8) + 4]);
EXPECT_EQ(BIT_COMPARE_1, ledStripDMABuffer[(byteIndex * 8) + 5]);
EXPECT_EQ(BIT_COMPARE_1, ledStripDMABuffer[(byteIndex * 8) + 6]);
EXPECT_EQ(BIT_COMPARE_1, ledStripDMABuffer[(byteIndex * 8) + 7]);
byteIndex++;
EXPECT_EQ(BIT_COMPARE_0, ledStripDMABuffer[(byteIndex * 8) + 0]);
EXPECT_EQ(BIT_COMPARE_1, ledStripDMABuffer[(byteIndex * 8) + 1]);
EXPECT_EQ(BIT_COMPARE_0, ledStripDMABuffer[(byteIndex * 8) + 2]);
EXPECT_EQ(BIT_COMPARE_1, ledStripDMABuffer[(byteIndex * 8) + 3]);
EXPECT_EQ(BIT_COMPARE_0, ledStripDMABuffer[(byteIndex * 8) + 4]);
EXPECT_EQ(BIT_COMPARE_1, ledStripDMABuffer[(byteIndex * 8) + 5]);
EXPECT_EQ(BIT_COMPARE_0, ledStripDMABuffer[(byteIndex * 8) + 6]);
EXPECT_EQ(BIT_COMPARE_1, ledStripDMABuffer[(byteIndex * 8) + 7]);
byteIndex++;
}
rgbColor24bpp_t* hsvToRgb24(const hsvColor_t *c) {
UNUSED(c);
return NULL;
}
void ws2811LedStripHardwareInit(void) {}
void ws2811LedStripDMAEnable(void) {}