mirror of
https://github.com/iNavFlight/inav.git
synced 2025-07-25 09:16:01 +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/timer.h"
|
||||||
#include "drivers/light_ws2811strip.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 IO_t ws2811IO = IO_NONE;
|
||||||
static TCH_t * ws2811TCH = NULL;
|
static TCH_t * ws2811TCH = NULL;
|
||||||
static bool ws2811Initialised = false;
|
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];
|
static hsvColor_t ledColorBuffer[WS2811_LED_STRIP_LENGTH];
|
||||||
|
|
||||||
void setLedHsv(uint16_t index, const hsvColor_t *color)
|
void setLedHsv(uint16_t index, const hsvColor_t *color)
|
||||||
|
@ -103,10 +104,7 @@ void ws2811LedStripInit(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Compute the prescaler value */
|
/* Compute the prescaler value */
|
||||||
uint16_t period = WS2811_TIMER_HZ / WS2811_CARRIER_HZ;
|
uint8_t period = WS2811_TIMER_HZ / WS2811_CARRIER_HZ;
|
||||||
|
|
||||||
BIT_COMPARE_1 = period * 2 / 3;
|
|
||||||
BIT_COMPARE_0 = period / 3;
|
|
||||||
|
|
||||||
ws2811IO = IOGetByTag(IO_TAG(WS2811_PIN));
|
ws2811IO = IOGetByTag(IO_TAG(WS2811_PIN));
|
||||||
IOInit(ws2811IO, OWNER_LED_STRIP, RESOURCE_OUTPUT, 0);
|
IOInit(ws2811IO, OWNER_LED_STRIP, RESOURCE_OUTPUT, 0);
|
||||||
|
@ -116,7 +114,7 @@ void ws2811LedStripInit(void)
|
||||||
timerPWMConfigChannel(ws2811TCH, 0);
|
timerPWMConfigChannel(ws2811TCH, 0);
|
||||||
|
|
||||||
// If DMA failed - abort
|
// 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;
|
ws2811Initialised = false;
|
||||||
return;
|
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);
|
uint32_t grb = (color->rgb.g << 16) | (color->rgb.r << 8) | (color->rgb.b);
|
||||||
|
|
||||||
for (int8_t index = 23; index >= 0; index--) {
|
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
|
#ifdef USE_DSHOT
|
||||||
// DSHOT parameters
|
// DSHOT parameters
|
||||||
uint32_t dmaBuffer[DSHOT_DMA_BUFFER_SIZE] __attribute__ ((aligned (4)));
|
uint8_t dmaBuffer[DSHOT_DMA_BUFFER_SIZE];
|
||||||
#endif
|
#endif
|
||||||
} pwmOutputPort_t;
|
} pwmOutputPort_t;
|
||||||
|
|
||||||
|
@ -224,7 +224,7 @@ static pwmOutputPort_t * motorConfigDshot(const timerHardware_t * timerHardware,
|
||||||
dshotMotorUpdateIntervalUs = MAX(dshotMotorUpdateIntervalUs, motorIntervalUs);
|
dshotMotorUpdateIntervalUs = MAX(dshotMotorUpdateIntervalUs, motorIntervalUs);
|
||||||
|
|
||||||
// Configure timer DMA
|
// 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
|
// Only mark as DSHOT channel if DMA was set successfully
|
||||||
memset(port->dmaBuffer, 0, sizeof(port->dmaBuffer));
|
memset(port->dmaBuffer, 0, sizeof(port->dmaBuffer));
|
||||||
port->configured = true;
|
port->configured = true;
|
||||||
|
@ -239,7 +239,7 @@ static void pwmWriteDshot(uint8_t index, uint16_t value)
|
||||||
motors[index]->value = 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++) {
|
for (int i = 0; i < 16; i++) {
|
||||||
dmaBuffer[i] = (packet & 0x8000) ? DSHOT_MOTOR_BIT_1 : DSHOT_MOTOR_BIT_0; // MSB first
|
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);
|
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)
|
void timerPWMStartDMA(TCH_t * tch)
|
||||||
|
@ -256,4 +256,4 @@ void timerPWMStopDMA(TCH_t * tch)
|
||||||
bool timerPWMDMAInProgress(TCH_t * tch)
|
bool timerPWMDMAInProgress(TCH_t * tch)
|
||||||
{
|
{
|
||||||
return tch->dmaState != TCH_DMA_IDLE;
|
return tch->dmaState != TCH_DMA_IDLE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -190,8 +190,11 @@ void timerEnable(TCH_t * tch);
|
||||||
void timerPWMConfigChannel(TCH_t * tch, uint16_t value);
|
void timerPWMConfigChannel(TCH_t * tch, uint16_t value);
|
||||||
void timerPWMStart(TCH_t * tch);
|
void timerPWMStart(TCH_t * tch);
|
||||||
|
|
||||||
bool timerPWMConfigChannelDMA(TCH_t * tch, void * dmaBuffer, uint32_t dmaBufferSize);
|
// dmaBufferElementSize is the size in bytes of each element in the memory
|
||||||
void timerPWMPrepareDMA(TCH_t * tch, uint32_t dmaBufferSize);
|
// 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 timerPWMStartDMA(TCH_t * tch);
|
||||||
void timerPWMStopDMA(TCH_t * tch);
|
void timerPWMStopDMA(TCH_t * tch);
|
||||||
bool timerPWMDMAInProgress(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_timerPWMConfigChannel(TCH_t * tch, uint16_t value);
|
||||||
void impl_timerPWMStart(TCH_t * tch);
|
void impl_timerPWMStart(TCH_t * tch);
|
||||||
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);
|
||||||
void impl_timerPWMPrepareDMA(TCH_t * tch, uint32_t dmaBufferSize);
|
void impl_timerPWMPrepareDMA(TCH_t * tch, uint32_t dmaBufferElementCount);
|
||||||
void impl_timerPWMStartDMA(TCH_t * tch);
|
void impl_timerPWMStartDMA(TCH_t * tch);
|
||||||
void impl_timerPWMStopDMA(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->dma = dmaGetByTag(tch->timHw->dmaTag);
|
||||||
tch->dmaBuffer = dmaBuffer;
|
tch->dmaBuffer = dmaBuffer;
|
||||||
|
@ -346,11 +346,29 @@ bool impl_timerPWMConfigChannelDMA(TCH_t * tch, void * dmaBuffer, uint32_t dmaBu
|
||||||
init.Channel = channelLL;
|
init.Channel = channelLL;
|
||||||
init.PeriphOrM2MSrcAddress = (uint32_t)impl_timerCCR(tch);
|
init.PeriphOrM2MSrcAddress = (uint32_t)impl_timerCCR(tch);
|
||||||
init.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT;
|
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.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD;
|
||||||
init.MemoryOrM2MDstAddress = (uint32_t)dmaBuffer;
|
init.MemoryOrM2MDstAddress = (uint32_t)dmaBuffer;
|
||||||
init.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT;
|
init.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT;
|
||||||
init.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD;
|
init.MemoryOrM2MDstDataSize = memoryDataSize;
|
||||||
init.NbData = dmaBufferSize;
|
init.NbData = dmaBufferElementCount;
|
||||||
init.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH;
|
init.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH;
|
||||||
init.Mode = LL_DMA_MODE_NORMAL;
|
init.Mode = LL_DMA_MODE_NORMAL;
|
||||||
init.Priority = LL_DMA_PRIORITY_HIGH;
|
init.Priority = LL_DMA_PRIORITY_HIGH;
|
||||||
|
@ -375,10 +393,10 @@ bool impl_timerPWMConfigChannelDMA(TCH_t * tch, void * dmaBuffer, uint32_t dmaBu
|
||||||
return true;
|
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)];
|
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
|
// 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
|
// 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);
|
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_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_EnableIT_TC(dmaBase, streamLL);
|
||||||
LL_DMA_EnableStream(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;
|
DMA_InitTypeDef DMA_InitStructure;
|
||||||
TIM_TypeDef * timer = tch->timHw->tim;
|
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_StructInit(&DMA_InitStructure);
|
||||||
|
|
||||||
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)impl_timerCCR(tch);
|
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_PeripheralInc = DMA_PeripheralInc_Disable;
|
||||||
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
|
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;
|
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
|
||||||
|
|
||||||
|
|
||||||
#ifdef STM32F4
|
#ifdef STM32F4
|
||||||
DMA_InitStructure.DMA_Channel = dmaGetChannelByTag(tch->timHw->dmaTag);
|
DMA_InitStructure.DMA_Channel = dmaGetChannelByTag(tch->timHw->dmaTag);
|
||||||
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)dmaBuffer;
|
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)dmaBuffer;
|
||||||
|
@ -345,7 +363,7 @@ bool impl_timerPWMConfigChannelDMA(TCH_t * tch, void * dmaBuffer, uint32_t dmaBu
|
||||||
return true;
|
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
|
// 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
|
// 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_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);
|
DMA_Cmd(tch->dma->ref, ENABLE);
|
||||||
tch->dmaState = TCH_DMA_READY;
|
tch->dmaState = TCH_DMA_READY;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue