Merge pull request #7547 from mikeller/fix_led_extreme_cpu_load

Fixed initialisation problem with LED_STRIP.
This commit is contained in:
Michael Keller 2019-02-08 19:55:55 +13:00 committed by GitHub
commit 2c739346c6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 64 additions and 73 deletions

View File

@ -52,7 +52,9 @@ FAST_RAM_ZERO_INIT uint32_t ledStripDMABuffer[WS2811_DMA_BUFFER_SIZE];
uint32_t ledStripDMABuffer[WS2811_DMA_BUFFER_SIZE];
#endif
volatile uint8_t ws2811LedDataTransferInProgress = 0;
static ioTag_t ledStripIoTag;
static bool ws2811Initialised = false;
volatile bool ws2811LedDataTransferInProgress = false;
uint16_t BIT_COMPARE_1 = 0;
uint16_t BIT_COMPARE_0 = 0;
@ -83,16 +85,14 @@ void scaleLedValue(uint16_t index, const uint8_t scalePercent)
void setStripColor(const hsvColor_t *color)
{
uint16_t index;
for (index = 0; index < WS2811_DATA_BUFFER_SIZE; index++) {
for (unsigned 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_DATA_BUFFER_SIZE; index++) {
for (unsigned index = 0; index < WS2811_DATA_BUFFER_SIZE; index++) {
setLedHsv(index, colors++);
}
}
@ -100,23 +100,32 @@ void setStripColors(const hsvColor_t *colors)
void ws2811LedStripInit(ioTag_t ioTag)
{
memset(ledStripDMABuffer, 0, sizeof(ledStripDMABuffer));
ws2811LedStripHardwareInit(ioTag);
const hsvColor_t hsv_black = { 0, 0, 0 };
setStripColor(&hsv_black);
// RGB or GRB ordering doesn't matter for black
ws2811UpdateStrip(LED_RGB);
ledStripIoTag = ioTag;
}
void ws2811LedStripEnable(void)
{
if (!ws2811Initialised) {
if (!ws2811LedStripHardwareInit(ledStripIoTag)) {
return;
}
const hsvColor_t hsv_black = { 0, 0, 0 };
setStripColor(&hsv_black);
// RGB or GRB ordering doesn't matter for black
ws2811UpdateStrip(LED_RGB);
ws2811Initialised = true;
}
}
bool isWS2811LedStripReady(void)
{
return !ws2811LedDataTransferInProgress;
return ws2811Initialised && !ws2811LedDataTransferInProgress;
}
STATIC_UNIT_TESTED uint16_t dmaBufferOffset;
static int16_t ledIndex;
STATIC_UNIT_TESTED void updateLEDDMABuffer(ledStripFormatRGB_e ledFormat, rgbColor24bpp_t *color)
STATIC_UNIT_TESTED void updateLEDDMABuffer(ledStripFormatRGB_e ledFormat, rgbColor24bpp_t *color, unsigned ledIndex)
{
uint32_t packed_colour;
@ -131,8 +140,9 @@ STATIC_UNIT_TESTED void updateLEDDMABuffer(ledStripFormatRGB_e ledFormat, rgbCol
break;
}
for (int8_t index = 23; index >= 0; index--) {
ledStripDMABuffer[dmaBufferOffset++] = (packed_colour & (1 << index)) ? BIT_COMPARE_1 : BIT_COMPARE_0;
unsigned dmaBufferOffset = 0;
for (int index = 23; index >= 0; index--) {
ledStripDMABuffer[ledIndex * WS2811_BITS_PER_LED + dmaBufferOffset++] = (packed_colour & (1 << index)) ? BIT_COMPARE_1 : BIT_COMPARE_0;
}
}
@ -142,28 +152,22 @@ STATIC_UNIT_TESTED void updateLEDDMABuffer(ledStripFormatRGB_e ledFormat, rgbCol
*/
void ws2811UpdateStrip(ledStripFormatRGB_e ledFormat)
{
static rgbColor24bpp_t *rgb24;
// don't wait - risk of infinite block, just get an update next time round
if (ws2811LedDataTransferInProgress) {
if (!ws2811Initialised || ws2811LedDataTransferInProgress) {
return;
}
dmaBufferOffset = 0; // reset buffer memory index
ledIndex = 0; // reset led index
unsigned ledIndex = 0; // reset led index
// fill transmit buffer with correct compare values to achieve
// correct pulse widths according to color values
while (ledIndex < WS2811_DATA_BUFFER_SIZE)
{
rgb24 = hsvToRgb24(&ledColorBuffer[ledIndex]);
while (ledIndex < WS2811_DATA_BUFFER_SIZE) {
rgbColor24bpp_t *rgb24 = hsvToRgb24(&ledColorBuffer[ledIndex]);
updateLEDDMABuffer(ledFormat, rgb24);
ledIndex++;
updateLEDDMABuffer(ledFormat, rgb24, ledIndex++);
}
ws2811LedDataTransferInProgress = 1;
ws2811LedDataTransferInProgress = true;
ws2811LedStripDMAEnable();
}

View File

@ -51,8 +51,9 @@ typedef enum {
} ledStripFormatRGB_e;
void ws2811LedStripInit(ioTag_t ioTag);
void ws2811LedStripEnable(void);
void ws2811LedStripHardwareInit(ioTag_t ioTag);
bool ws2811LedStripHardwareInit(ioTag_t ioTag);
void ws2811LedStripDMAEnable(void);
void ws2811UpdateStrip(ledStripFormatRGB_e ledFormat);
@ -73,7 +74,7 @@ extern uint8_t ledStripDMABuffer[WS2811_DMA_BUFFER_SIZE];
#else
extern uint32_t ledStripDMABuffer[WS2811_DMA_BUFFER_SIZE];
#endif
extern volatile uint8_t ws2811LedDataTransferInProgress;
extern volatile bool ws2811LedDataTransferInProgress;
extern uint16_t BIT_COMPARE_1;
extern uint16_t BIT_COMPARE_0;

View File

@ -37,7 +37,6 @@
#include "light_ws2811strip.h"
static IO_t ws2811IO = IO_NONE;
bool ws2811Initialised = false;
static TIM_HandleTypeDef TimHandle;
static uint16_t timerChannel = 0;
@ -46,13 +45,13 @@ void WS2811_DMA_IRQHandler(dmaChannelDescriptor_t* descriptor)
{
HAL_DMA_IRQHandler(TimHandle.hdma[descriptor->userParam]);
TIM_DMACmd(&TimHandle, timerChannel, DISABLE);
ws2811LedDataTransferInProgress = 0;
ws2811LedDataTransferInProgress = false;
}
void ws2811LedStripHardwareInit(ioTag_t ioTag)
bool ws2811LedStripHardwareInit(ioTag_t ioTag)
{
if (!ioTag) {
return;
return false;
}
const timerHardware_t *timerHardware = timerGetByTag(ioTag);
@ -60,7 +59,7 @@ void ws2811LedStripHardwareInit(ioTag_t ioTag)
timerChannel = timerHardware->channel;
if (timerHardware->dmaRef == NULL) {
return;
return false;
}
TimHandle.Instance = timer;
@ -77,7 +76,7 @@ void ws2811LedStripHardwareInit(ioTag_t ioTag)
TimHandle.Init.CounterMode = TIM_COUNTERMODE_UP;
if (HAL_TIM_PWM_Init(&TimHandle) != HAL_OK) {
/* Initialization Error */
return;
return false;
}
static DMA_HandleTypeDef hdma_tim;
@ -116,7 +115,7 @@ void ws2811LedStripHardwareInit(ioTag_t ioTag)
/* Initialize TIMx DMA handle */
if (HAL_DMA_Init(TimHandle.hdma[dmaIndex]) != HAL_OK) {
/* Initialization Error */
return;
return false;
}
TIM_OC_InitTypeDef TIM_OCInitStructure;
@ -131,32 +130,28 @@ void ws2811LedStripHardwareInit(ioTag_t ioTag)
TIM_OCInitStructure.OCFastMode = TIM_OCFAST_DISABLE;
if (HAL_TIM_PWM_ConfigChannel(&TimHandle, &TIM_OCInitStructure, timerChannel) != HAL_OK) {
/* Configuration Error */
return;
return false;
}
if (timerHardware->output & TIMER_OUTPUT_N_CHANNEL) {
if (HAL_TIMEx_PWMN_Start(&TimHandle, timerChannel) != HAL_OK) {
/* Starting PWM generation Error */
return;
return false;
}
} else {
if (HAL_TIM_PWM_Start(&TimHandle, timerChannel) != HAL_OK) {
/* Starting PWM generation Error */
return;
return false;
}
}
ws2811Initialised = true;
return true;
}
void ws2811LedStripDMAEnable(void)
{
if (!ws2811Initialised) {
ws2811LedDataTransferInProgress = 0;
return;
}
if (DMA_SetCurrDataCounter(&TimHandle, timerChannel, ledStripDMABuffer, WS2811_DMA_BUFFER_SIZE) != HAL_OK) {
/* DMA set error */
ws2811LedDataTransferInProgress = 0;
ws2811LedDataTransferInProgress = false;
return;
}
/* Reset timer counter */

View File

@ -39,7 +39,6 @@
#include "light_ws2811strip.h"
static IO_t ws2811IO = IO_NONE;
bool ws2811Initialised = false;
#if defined(STM32F4)
static DMA_Stream_TypeDef *dmaRef = NULL;
#elif defined(STM32F3) || defined(STM32F1)
@ -63,11 +62,11 @@ static void WS2811_DMA_IRQHandler(dmaChannelDescriptor_t *descriptor)
memset(ledStripDMABuffer, 0, sizeof(ledStripDMABuffer));
} else if (counter == (WS2811_LED_STRIP_LENGTH + WS2811_DELAY_ITERATIONS)) {
counter = 0;
ws2811LedDataTransferInProgress = 0;
ws2811LedDataTransferInProgress = false;
DMA_Cmd(descriptor->ref, DISABLE);
}
#else
ws2811LedDataTransferInProgress = 0;
ws2811LedDataTransferInProgress = false;
DMA_Cmd(descriptor->ref, DISABLE);
#endif
@ -75,10 +74,10 @@ static void WS2811_DMA_IRQHandler(dmaChannelDescriptor_t *descriptor)
}
}
void ws2811LedStripHardwareInit(ioTag_t ioTag)
bool ws2811LedStripHardwareInit(ioTag_t ioTag)
{
if (!ioTag) {
return;
return false;
}
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
@ -89,7 +88,7 @@ void ws2811LedStripHardwareInit(ioTag_t ioTag)
timer = timerHardware->tim;
if (timerHardware->dmaRef == NULL) {
return;
return false;
}
ws2811IO = IOGetByTag(ioTag);
@ -185,18 +184,15 @@ void ws2811LedStripHardwareInit(ioTag_t ioTag)
DMA_Init(dmaRef, &DMA_InitStructure);
TIM_DMACmd(timer, timerDmaSource(timerHardware->channel), ENABLE);
DMA_ITConfig(dmaRef, DMA_IT_TC, ENABLE);
ws2811Initialised = true;
return true;
}
void ws2811LedStripDMAEnable(void)
{
if (!ws2811Initialised)
return;
DMA_SetCurrDataCounter(dmaRef, WS2811_DMA_BUFFER_SIZE); // load number of bytes to be transferred
TIM_SetCounter(timer, 0);
TIM_Cmd(timer, ENABLE);
DMA_Cmd(dmaRef, ENABLE);
}
#endif

View File

@ -652,8 +652,6 @@ void init(void)
#ifdef USE_LED_STRIP
ledStripInit();
delayMicroseconds(50);
if (featureIsEnabled(FEATURE_LED_STRIP)) {
ledStripEnable();
}

View File

@ -1150,6 +1150,8 @@ bool setModeColor(ledModeIndex_e modeIndex, int modeColorIndex, int colorIndex)
void ledStripEnable(void)
{
ws2811LedStripEnable();
ledStripEnabled = true;
}
@ -1157,8 +1159,8 @@ void ledStripDisable(void)
{
ledStripEnabled = false;
previousProfileColorIndex = COLOR_UNDEFINED;
setStripColor(&HSV(BLACK));
setStripColor(&HSV(BLACK));
ws2811UpdateStrip((ledStripFormatRGB_e)ledStripConfig()->ledstrip_grb_rgb);
}

View File

@ -393,4 +393,5 @@ uint8_t getRssiPercent(void) { return 0; }
bool isFlipOverAfterCrashActive(void) { return false; }
void ws2811LedStripEnable(void) { }
}

View File

@ -31,23 +31,15 @@ extern "C" {
#include "gtest/gtest.h"
extern "C" {
STATIC_UNIT_TESTED extern uint16_t dmaBufferOffset;
STATIC_UNIT_TESTED void updateLEDDMABuffer(rgbColor24bpp_t *color);
void updateLEDDMABuffer(ledStripFormatRGB_e ledFormat, rgbColor24bpp_t *color, unsigned ledIndex);
}
TEST(WS2812, updateDMABuffer) {
// given
rgbColor24bpp_t color1 = { .raw = {0xFF,0xAA,0x55} };
// and
dmaBufferOffset = 0;
// when
updateLEDDMABuffer(&color1);
// then
EXPECT_EQ(24, dmaBufferOffset);
updateLEDDMABuffer(LED_GRB, &color1, 0);
// and
uint8_t byteIndex = 0;
@ -89,8 +81,10 @@ rgbColor24bpp_t* hsvToRgb24(const hsvColor_t *c) {
return NULL;
}
void ws2811LedStripHardwareInit(ioTag_t ioTag) {
bool ws2811LedStripHardwareInit(ioTag_t ioTag) {
UNUSED(ioTag);
return true;
}
void ws2811LedStripDMAEnable(void) {}