mirror of
https://github.com/iNavFlight/inav.git
synced 2025-07-23 08:15:26 +03:00
Merge pull request #4529 from iNavFlight/agh_dmabuffer_memsize
Allow configurable DMA memory buffer element sizes
This commit is contained in:
commit
45aa5138bd
7 changed files with 70 additions and 33 deletions
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue