diff --git a/src/main/drivers/light_ws2811strip.c b/src/main/drivers/light_ws2811strip.c index d91d5d5bc5..1eac8f5ab5 100644 --- a/src/main/drivers/light_ws2811strip.c +++ b/src/main/drivers/light_ws2811strip.c @@ -43,14 +43,15 @@ #include "drivers/timer.h" #include "drivers/light_ws2811strip.h" -static uint32_t ledStripDMABuffer[WS2811_DMA_BUFFER_SIZE]; +#define WS2811_PERIOD (WS2811_TIMER_HZ / WS2811_CARRIER_HZ) +#define WS2811_BIT_COMPARE_1 ((WS2811_PERIOD * 2) / 3) +#define WS2811_BIT_COMPARE_0 (WS2811_PERIOD / 3) + +static uint8_t ledStripDMABuffer[WS2811_DMA_BUFFER_SIZE]; static IO_t ws2811IO = IO_NONE; static TCH_t * ws2811TCH = NULL; static bool ws2811Initialised = false; -static uint16_t BIT_COMPARE_1 = 0; -static uint16_t BIT_COMPARE_0 = 0; - static hsvColor_t ledColorBuffer[WS2811_LED_STRIP_LENGTH]; void setLedHsv(uint16_t index, const hsvColor_t *color) @@ -103,10 +104,7 @@ void ws2811LedStripInit(void) } /* Compute the prescaler value */ - uint16_t period = WS2811_TIMER_HZ / WS2811_CARRIER_HZ; - - BIT_COMPARE_1 = period * 2 / 3; - BIT_COMPARE_0 = period / 3; + uint8_t period = WS2811_TIMER_HZ / WS2811_CARRIER_HZ; ws2811IO = IOGetByTag(IO_TAG(WS2811_PIN)); IOInit(ws2811IO, OWNER_LED_STRIP, RESOURCE_OUTPUT, 0); @@ -116,7 +114,7 @@ void ws2811LedStripInit(void) timerPWMConfigChannel(ws2811TCH, 0); // If DMA failed - abort - if (!timerPWMConfigChannelDMA(ws2811TCH, ledStripDMABuffer, WS2811_DMA_BUFFER_SIZE)) { + if (!timerPWMConfigChannelDMA(ws2811TCH, ledStripDMABuffer, sizeof(uint8_t), WS2811_DMA_BUFFER_SIZE)) { ws2811Initialised = false; return; } @@ -141,7 +139,7 @@ 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; + ledStripDMABuffer[dmaBufferOffset++] = (grb & (1 << index)) ? WS2811_BIT_COMPARE_1 : WS2811_BIT_COMPARE_0; } } diff --git a/src/main/drivers/pwm_output.c b/src/main/drivers/pwm_output.c index 5413f51d0f..5a0f2a2913 100644 --- a/src/main/drivers/pwm_output.c +++ b/src/main/drivers/pwm_output.c @@ -70,7 +70,7 @@ typedef struct { #ifdef USE_DSHOT // DSHOT parameters - uint32_t dmaBuffer[DSHOT_DMA_BUFFER_SIZE] __attribute__ ((aligned (4))); + uint8_t dmaBuffer[DSHOT_DMA_BUFFER_SIZE]; #endif } pwmOutputPort_t; @@ -224,7 +224,7 @@ static pwmOutputPort_t * motorConfigDshot(const timerHardware_t * timerHardware, dshotMotorUpdateIntervalUs = MAX(dshotMotorUpdateIntervalUs, motorIntervalUs); // Configure timer DMA - if (timerPWMConfigChannelDMA(port->tch, port->dmaBuffer, DSHOT_DMA_BUFFER_SIZE)) { + if (timerPWMConfigChannelDMA(port->tch, port->dmaBuffer, sizeof(uint8_t), DSHOT_DMA_BUFFER_SIZE)) { // Only mark as DSHOT channel if DMA was set successfully memset(port->dmaBuffer, 0, sizeof(port->dmaBuffer)); port->configured = true; @@ -239,7 +239,7 @@ static void pwmWriteDshot(uint8_t index, uint16_t value) motors[index]->value = value; } -static void loadDmaBufferDshot(uint32_t * dmaBuffer, uint16_t packet) +static void loadDmaBufferDshot(uint8_t *dmaBuffer, uint16_t packet) { for (int i = 0; i < 16; i++) { dmaBuffer[i] = (packet & 0x8000) ? DSHOT_MOTOR_BIT_1 : DSHOT_MOTOR_BIT_0; // MSB first diff --git a/src/main/drivers/timer.c b/src/main/drivers/timer.c index b60e087e39..89084b3d87 100755 --- a/src/main/drivers/timer.c +++ b/src/main/drivers/timer.c @@ -233,14 +233,14 @@ uint32_t timerGetBaseClockHW(const timerHardware_t * timHw) return SystemCoreClock / timerClockDivisor(timHw->tim); } -bool timerPWMConfigChannelDMA(TCH_t * tch, void * dmaBuffer, uint32_t dmaBufferSize) +bool timerPWMConfigChannelDMA(TCH_t * tch, void * dmaBuffer, uint8_t dmaBufferElementSize, uint32_t dmaBufferElementCount) { - return impl_timerPWMConfigChannelDMA(tch, dmaBuffer, dmaBufferSize); + return impl_timerPWMConfigChannelDMA(tch, dmaBuffer, dmaBufferElementSize, dmaBufferElementCount); } -void timerPWMPrepareDMA(TCH_t * tch, uint32_t dmaBufferSize) +void timerPWMPrepareDMA(TCH_t * tch, uint32_t dmaBufferElementCount) { - impl_timerPWMPrepareDMA(tch, dmaBufferSize); + impl_timerPWMPrepareDMA(tch, dmaBufferElementCount); } void timerPWMStartDMA(TCH_t * tch) @@ -256,4 +256,4 @@ void timerPWMStopDMA(TCH_t * tch) bool timerPWMDMAInProgress(TCH_t * tch) { return tch->dmaState != TCH_DMA_IDLE; -} \ No newline at end of file +} diff --git a/src/main/drivers/timer.h b/src/main/drivers/timer.h index 2fe3c39e3f..27e3e93fc2 100644 --- a/src/main/drivers/timer.h +++ b/src/main/drivers/timer.h @@ -190,8 +190,11 @@ void timerEnable(TCH_t * tch); void timerPWMConfigChannel(TCH_t * tch, uint16_t value); void timerPWMStart(TCH_t * tch); -bool timerPWMConfigChannelDMA(TCH_t * tch, void * dmaBuffer, uint32_t dmaBufferSize); -void timerPWMPrepareDMA(TCH_t * tch, uint32_t dmaBufferSize); +// dmaBufferElementSize is the size in bytes of each element in the memory +// buffer. 1, 2 or 4 are the only valid values. +// dmaBufferElementCount is the number of elements in the buffer +bool timerPWMConfigChannelDMA(TCH_t * tch, void * dmaBuffer, uint8_t dmaBufferElementSize, uint32_t dmaBufferElementCount); +void timerPWMPrepareDMA(TCH_t * tch, uint32_t dmaBufferElementCount); void timerPWMStartDMA(TCH_t * tch); void timerPWMStopDMA(TCH_t * tch); bool timerPWMDMAInProgress(TCH_t * tch); diff --git a/src/main/drivers/timer_impl.h b/src/main/drivers/timer_impl.h index aa9b7fee27..bb9d55af98 100644 --- a/src/main/drivers/timer_impl.h +++ b/src/main/drivers/timer_impl.h @@ -55,7 +55,7 @@ void impl_timerChCaptureCompareEnable(TCH_t * tch, bool enable); void impl_timerPWMConfigChannel(TCH_t * tch, uint16_t value); void impl_timerPWMStart(TCH_t * tch); -bool impl_timerPWMConfigChannelDMA(TCH_t * tch, void * dmaBuffer, uint32_t dmaBufferSize); -void impl_timerPWMPrepareDMA(TCH_t * tch, uint32_t dmaBufferSize); +bool impl_timerPWMConfigChannelDMA(TCH_t * tch, void * dmaBuffer, uint8_t dmaBufferElementSize, uint32_t dmaBufferElementCount); +void impl_timerPWMPrepareDMA(TCH_t * tch, uint32_t dmaBufferElementCount); void impl_timerPWMStartDMA(TCH_t * tch); void impl_timerPWMStopDMA(TCH_t * tch); diff --git a/src/main/drivers/timer_impl_hal.c b/src/main/drivers/timer_impl_hal.c index 1834d84c74..34099abd05 100644 --- a/src/main/drivers/timer_impl_hal.c +++ b/src/main/drivers/timer_impl_hal.c @@ -319,7 +319,7 @@ static void impl_timerDMA_IRQHandler(DMA_t descriptor) } } -bool impl_timerPWMConfigChannelDMA(TCH_t * tch, void * dmaBuffer, uint32_t dmaBufferSize) +bool impl_timerPWMConfigChannelDMA(TCH_t * tch, void * dmaBuffer, uint8_t dmaBufferElementSize, uint32_t dmaBufferElementCount) { tch->dma = dmaGetByTag(tch->timHw->dmaTag); tch->dmaBuffer = dmaBuffer; @@ -346,11 +346,29 @@ bool impl_timerPWMConfigChannelDMA(TCH_t * tch, void * dmaBuffer, uint32_t dmaBu init.Channel = channelLL; init.PeriphOrM2MSrcAddress = (uint32_t)impl_timerCCR(tch); init.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT; + uint32_t memoryDataSize; + switch (dmaBufferElementSize) { + case 1: + memoryDataSize = LL_DMA_MDATAALIGN_BYTE; + break; + case 2: + memoryDataSize = LL_DMA_MDATAALIGN_HALFWORD; + break; + case 4: + memoryDataSize = LL_DMA_MDATAALIGN_WORD; + break; + default: + // Programmer error + while(1) { + + } + } + init.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD; init.MemoryOrM2MDstAddress = (uint32_t)dmaBuffer; init.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT; - init.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD; - init.NbData = dmaBufferSize; + init.MemoryOrM2MDstDataSize = memoryDataSize; + init.NbData = dmaBufferElementCount; init.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH; init.Mode = LL_DMA_MODE_NORMAL; init.Priority = LL_DMA_PRIORITY_HIGH; @@ -375,10 +393,10 @@ bool impl_timerPWMConfigChannelDMA(TCH_t * tch, void * dmaBuffer, uint32_t dmaBu return true; } -void impl_timerPWMPrepareDMA(TCH_t * tch, uint32_t dmaBufferSize) +void impl_timerPWMPrepareDMA(TCH_t * tch, uint32_t dmaBufferElementCount) { const uint32_t streamLL = lookupDMALLStreamTable[DMATAG_GET_STREAM(tch->timHw->dmaTag)]; - DMA_TypeDef * dmaBase = tch->dma->dma; + DMA_TypeDef *dmaBase = tch->dma->dma; // Make sure we terminate any DMA transaction currently in progress // Clear the flag as well, so even if DMA transfer finishes while within ATOMIC_BLOCK @@ -389,7 +407,7 @@ void impl_timerPWMPrepareDMA(TCH_t * tch, uint32_t dmaBufferSize) DMA_CLEAR_FLAG(tch->dma, DMA_IT_TCIF); } - LL_DMA_SetDataLength(dmaBase, streamLL, dmaBufferSize); + LL_DMA_SetDataLength(dmaBase, streamLL, dmaBufferElementCount); LL_DMA_ConfigAddresses(dmaBase, streamLL, (uint32_t)tch->dmaBuffer, (uint32_t)impl_timerCCR(tch), LL_DMA_DIRECTION_MEMORY_TO_PERIPH); LL_DMA_EnableIT_TC(dmaBase, streamLL); LL_DMA_EnableStream(dmaBase, streamLL); diff --git a/src/main/drivers/timer_impl_stdperiph.c b/src/main/drivers/timer_impl_stdperiph.c index 17ccae91c2..047ff262ac 100644 --- a/src/main/drivers/timer_impl_stdperiph.c +++ b/src/main/drivers/timer_impl_stdperiph.c @@ -284,7 +284,7 @@ static void impl_timerDMA_IRQHandler(DMA_t descriptor) } } -bool impl_timerPWMConfigChannelDMA(TCH_t * tch, void * dmaBuffer, uint32_t dmaBufferSize) +bool impl_timerPWMConfigChannelDMA(TCH_t * tch, void * dmaBuffer, uint8_t dmaBufferElementSize, uint32_t dmaBufferElementCount) { DMA_InitTypeDef DMA_InitStructure; TIM_TypeDef * timer = tch->timHw->tim; @@ -319,12 +319,30 @@ bool impl_timerPWMConfigChannelDMA(TCH_t * tch, void * dmaBuffer, uint32_t dmaBu DMA_StructInit(&DMA_InitStructure); DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)impl_timerCCR(tch); - DMA_InitStructure.DMA_BufferSize = dmaBufferSize; + DMA_InitStructure.DMA_BufferSize = dmaBufferElementCount; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; - DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word; + uint32_t DMA_MemoryDataSize; + switch (dmaBufferElementSize) { + case 1: + DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; + break; + case 2: + DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; + break; + case 4: + DMA_MemoryDataSize = DMA_MemoryDataSize_Word; + break; + default: + // Programmer error + while(1) { + + } + } + DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize; DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; + #ifdef STM32F4 DMA_InitStructure.DMA_Channel = dmaGetChannelByTag(tch->timHw->dmaTag); DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)dmaBuffer; @@ -345,7 +363,7 @@ bool impl_timerPWMConfigChannelDMA(TCH_t * tch, void * dmaBuffer, uint32_t dmaBu return true; } -void impl_timerPWMPrepareDMA(TCH_t * tch, uint32_t dmaBufferSize) +void impl_timerPWMPrepareDMA(TCH_t * tch, uint32_t dmaBufferElementCount) { // Make sure we terminate any DMA transaction currently in progress // Clear the flag as well, so even if DMA transfer finishes while within ATOMIC_BLOCK @@ -356,7 +374,7 @@ void impl_timerPWMPrepareDMA(TCH_t * tch, uint32_t dmaBufferSize) DMA_CLEAR_FLAG(tch->dma, DMA_IT_TCIF); } - DMA_SetCurrDataCounter(tch->dma->ref, dmaBufferSize); + DMA_SetCurrDataCounter(tch->dma->ref, dmaBufferElementCount); DMA_Cmd(tch->dma->ref, ENABLE); tch->dmaState = TCH_DMA_READY; }