1
0
Fork 0
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:
Konstantin Sharlaimov 2019-03-27 19:55:47 +01:00 committed by GitHub
commit 45aa5138bd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 70 additions and 33 deletions

View file

@ -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;
}
}

View file

@ -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

View file

@ -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;
}
}

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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;
}