Merge pull request #9397 from jflyper/bfdev-g4-dma

[G4] DMA support
This commit is contained in:
Michael Keller 2020-01-24 12:53:10 +13:00 committed by GitHub
commit 2cc6554f9d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 336 additions and 15 deletions

View File

@ -5180,7 +5180,7 @@ dmaoptEntry_t dmaoptEntryTable[] = {
DEFS("SDIO", DMA_PERIPH_SDIO, PG_SDIO_CONFIG, sdioConfig_t, dmaopt),
DEFW("UART_TX", DMA_PERIPH_UART_TX, PG_SERIAL_UART_CONFIG, serialUartConfig_t, txDmaopt, UARTDEV_CONFIG_MAX, MASK_IGNORED),
DEFW("UART_RX", DMA_PERIPH_UART_RX, PG_SERIAL_UART_CONFIG, serialUartConfig_t, rxDmaopt, UARTDEV_CONFIG_MAX, MASK_IGNORED),
#ifdef STM32H7
#if defined(STM32H7) || defined(STM32G4)
DEFW("TIMUP", DMA_PERIPH_TIMUP, PG_TIMER_UP_CONFIG, timerUpConfig_t, dmaopt, HARDWARE_TIMER_DEFINITION_COUNT, TIMUP_TIMERS),
#endif
};
@ -5192,13 +5192,19 @@ dmaoptEntry_t dmaoptEntryTable[] = {
#define DMA_OPT_UI_INDEX(i) ((i) + 1)
#define DMA_OPT_STRING_BUFSIZE 5
#ifdef STM32H7
#if defined(STM32H7) || defined(STM32G4)
#define DMA_CHANREQ_STRING "Request"
#else
#define DMA_CHANREQ_STRING "Channel"
#endif
#define DMASPEC_FORMAT_STRING "DMA%d Stream %d " DMA_CHANREQ_STRING " %d"
#if defined(STM32F4) || defined(STM32F7) || defined(STM32H7)
#define DMA_STCH_STRING "Stream"
#else
#define DMA_STCH_STRING "Channel"
#endif
#define DMASPEC_FORMAT_STRING "DMA%d " DMA_STCH_STRING " %d " DMA_CHANREQ_STRING " %d"
static void optToString(int optval, char *buf)
{

View File

@ -45,7 +45,7 @@ typedef void (*dmaCallbackHandlerFuncPtr)(struct dmaChannelDescriptor_s *channel
typedef struct dmaChannelDescriptor_s {
DMA_TypeDef* dma;
dmaResource_t *ref;
#if defined(STM32F4) || defined(STM32F7) || defined(STM32H7)
#if defined(STM32F4) || defined(STM32F7) || defined(STM32H7) || defined(STM32G4)
uint8_t stream;
#endif
dmaCallbackHandlerFuncPtr irqHandlerCallback;
@ -130,6 +130,34 @@ uint32_t dmaGetChannel(const uint8_t channel);
#else
#if defined(STM32G4)
typedef enum {
DMA_NONE = 0,
DMA1_CH1_HANDLER = 1,
DMA1_CH2_HANDLER,
DMA1_CH3_HANDLER,
DMA1_CH4_HANDLER,
DMA1_CH5_HANDLER,
DMA1_CH6_HANDLER,
DMA1_CH7_HANDLER,
DMA1_CH8_HANDLER,
DMA2_CH1_HANDLER,
DMA2_CH2_HANDLER,
DMA2_CH3_HANDLER,
DMA2_CH4_HANDLER,
DMA2_CH5_HANDLER,
DMA2_CH6_HANDLER,
DMA2_CH7_HANDLER,
DMA2_CH8_HANDLER,
DMA_LAST_HANDLER = DMA2_CH8_HANDLER
} dmaIdentifier_e;
#define DMA_DEVICE_NO(x) ((((x)-1) / 8) + 1)
#define DMA_DEVICE_INDEX(x) ((((x)-1) % 8) + 1)
#else // !STM32G4
typedef enum {
DMA_NONE = 0,
DMA1_CH1_HANDLER = 1,
@ -153,6 +181,9 @@ typedef enum {
#define DMA_DEVICE_NO(x) ((((x)-1) / 7) + 1)
#define DMA_DEVICE_INDEX(x) ((((x)-1) % 7) + 1)
#endif // STM32G4
#define DMA_OUTPUT_INDEX 0
#define DMA_OUTPUT_STRING "DMA%d Channel %d:"
#define DMA_INPUT_STRING "DMA%d_CH%d"
@ -209,6 +240,10 @@ dmaResource_t* dmaGetRefByIdentifier(const dmaIdentifier_e identifier);
((uint32_t)(reg) < D3_AHB1PERIPH_BASE) ? \
(((DMA_Stream_TypeDef *)(reg))->CR & DMA_SxCR_EN) : \
(((BDMA_Channel_TypeDef *)(reg))->CCR & BDMA_CCR_EN)
#elif defined(STM32G4)
#define IS_DMA_ENABLED(reg) (((DMA_ARCH_TYPE *)(reg))->CCR & DMA_CCR_EN)
// Missing __HAL_DMA_SET_COUNTER in FW library V1.0.0
#define __HAL_DMA_SET_COUNTER(__HANDLE__, __COUNTER__) ((__HANDLE__)->Instance->CNDTR = (uint16_t)(__COUNTER__))
#else
#if defined(STM32F1)
#define DMA_CCR_EN 1 // Not defined anywhere ...

View File

@ -37,7 +37,7 @@
typedef struct dmaPeripheralMapping_s {
dmaPeripheral_e device;
uint8_t index;
#if defined(STM32H7)
#if defined(STM32H7) || defined(STM32G4)
uint8_t dmaRequest;
#else
dmaChannelSpec_t channelSpec[MAX_PERIPHERAL_DMA_OPTIONS];
@ -47,14 +47,152 @@ typedef struct dmaPeripheralMapping_s {
typedef struct dmaTimerMapping_s {
TIM_TypeDef *tim;
uint8_t channel;
#if defined(STM32H7)
#if defined(STM32H7) || defined(STM32G4)
uint8_t dmaRequest;
#else
dmaChannelSpec_t channelSpec[MAX_TIMER_DMA_OPTIONS];
#endif
} dmaTimerMapping_t;
#if defined(STM32H7)
#if defined(STM32G4)
#define REQMAP_SGL(periph) { DMA_PERIPH_ ## periph, 0, DMA_REQUEST_ ## periph }
#define REQMAP(periph, device) { DMA_PERIPH_ ## periph, periph ## DEV_ ## device, DMA_REQUEST_ ## periph ## device }
#define REQMAP_DIR(periph, device, dir) { DMA_PERIPH_ ## periph ## _ ## dir, periph ## DEV_ ## device, DMA_REQUEST_ ## periph ## device ## _ ## dir }
#define REQMAP_TIMUP(periph, timno) { DMA_PERIPH_TIMUP, timno - 1, DMA_REQUEST_ ## TIM ## timno ## _UP }
// Resolve UART/USART mess, also map UART6 requests to LPUART1 requests
#define DMA_REQUEST_UART1_RX DMA_REQUEST_USART1_RX
#define DMA_REQUEST_UART1_TX DMA_REQUEST_USART1_TX
#define DMA_REQUEST_UART2_RX DMA_REQUEST_USART2_RX
#define DMA_REQUEST_UART2_TX DMA_REQUEST_USART2_TX
#define DMA_REQUEST_UART3_RX DMA_REQUEST_USART3_RX
#define DMA_REQUEST_UART3_TX DMA_REQUEST_USART3_TX
#define DMA_REQUEST_UART6_RX DMA_REQUEST_LPUART1_RX
#define DMA_REQUEST_UART6_TX DMA_REQUEST_LPUART1_TX
static const dmaPeripheralMapping_t dmaPeripheralMapping[] = {
#ifdef USE_SPI
REQMAP_DIR(SPI, 1, TX),
REQMAP_DIR(SPI, 1, RX),
REQMAP_DIR(SPI, 2, TX),
REQMAP_DIR(SPI, 2, RX),
REQMAP_DIR(SPI, 3, TX),
REQMAP_DIR(SPI, 3, RX),
REQMAP_DIR(SPI, 4, TX),
REQMAP_DIR(SPI, 4, RX),
#endif // USE_SPI
#ifdef USE_ADC
REQMAP(ADC, 1),
REQMAP(ADC, 2),
REQMAP(ADC, 3),
REQMAP(ADC, 4),
REQMAP(ADC, 5),
#endif
#ifdef USE_UART
REQMAP_DIR(UART, 1, TX),
REQMAP_DIR(UART, 1, RX),
REQMAP_DIR(UART, 2, TX),
REQMAP_DIR(UART, 2, RX),
REQMAP_DIR(UART, 3, TX),
REQMAP_DIR(UART, 3, RX),
REQMAP_DIR(UART, 4, TX),
REQMAP_DIR(UART, 4, RX),
REQMAP_DIR(UART, 5, TX),
REQMAP_DIR(UART, 5, RX),
REQMAP_DIR(UART, 6, TX),
REQMAP_DIR(UART, 6, RX),
#endif
#ifdef USE_TIMER
// Pseudo peripheral for TIMx_UP channel
REQMAP_TIMUP(TIMUP, 1),
REQMAP_TIMUP(TIMUP, 2),
REQMAP_TIMUP(TIMUP, 3),
REQMAP_TIMUP(TIMUP, 4),
REQMAP_TIMUP(TIMUP, 5),
REQMAP_TIMUP(TIMUP, 6),
REQMAP_TIMUP(TIMUP, 7),
REQMAP_TIMUP(TIMUP, 8),
REQMAP_TIMUP(TIMUP, 15),
REQMAP_TIMUP(TIMUP, 16),
REQMAP_TIMUP(TIMUP, 17),
REQMAP_TIMUP(TIMUP, 20),
#endif
};
#undef REQMAP_TIMUP
#undef REQMAP
#undef REQMAP_SGL
#undef REQMAP_DIR
#define TC(chan) DEF_TIM_CHANNEL(CH_ ## chan)
#define REQMAP_TIM(tim, chan) { tim, TC(chan), DMA_REQUEST_ ## tim ## _ ## chan }
static const dmaTimerMapping_t dmaTimerMapping[] = {
REQMAP_TIM(TIM1, CH1),
REQMAP_TIM(TIM1, CH2),
REQMAP_TIM(TIM1, CH3),
REQMAP_TIM(TIM1, CH4),
REQMAP_TIM(TIM2, CH1),
REQMAP_TIM(TIM2, CH2),
REQMAP_TIM(TIM2, CH3),
REQMAP_TIM(TIM2, CH4),
REQMAP_TIM(TIM3, CH1),
REQMAP_TIM(TIM3, CH2),
REQMAP_TIM(TIM3, CH3),
REQMAP_TIM(TIM3, CH4),
REQMAP_TIM(TIM4, CH1),
REQMAP_TIM(TIM4, CH2),
REQMAP_TIM(TIM4, CH3),
REQMAP_TIM(TIM5, CH1),
REQMAP_TIM(TIM5, CH2),
REQMAP_TIM(TIM5, CH3),
REQMAP_TIM(TIM5, CH4),
REQMAP_TIM(TIM8, CH1),
REQMAP_TIM(TIM8, CH2),
REQMAP_TIM(TIM8, CH3),
REQMAP_TIM(TIM8, CH4),
REQMAP_TIM(TIM15, CH1),
REQMAP_TIM(TIM16, CH1),
REQMAP_TIM(TIM17, CH1),
REQMAP_TIM(TIM20, CH1),
REQMAP_TIM(TIM20, CH2),
REQMAP_TIM(TIM20, CH3),
REQMAP_TIM(TIM20, CH4),
// XXX Check non-CH1 for TIM15,16,17 and 20
};
#undef TC
#undef REQMAP_TIM
#define DMA(d, c) { DMA_CODE(d, c, 0), (dmaResource_t *)DMA ## d ## _Channel ## c, 0 }
static dmaChannelSpec_t dmaChannelSpec[MAX_PERIPHERAL_DMA_OPTIONS] = {
DMA(1, 1),
DMA(1, 2),
DMA(1, 3),
DMA(1, 4),
DMA(1, 5),
DMA(1, 6),
DMA(1, 7),
DMA(1, 8),
DMA(2, 1),
DMA(2, 2),
DMA(2, 3),
DMA(2, 4),
DMA(2, 5),
DMA(2, 6),
DMA(2, 7),
DMA(2, 8),
};
#undef DMA
#elif defined(STM32H7)
#define REQMAP_SGL(periph) { DMA_PERIPH_ ## periph, 0, DMA_REQUEST_ ## periph }
#define REQMAP(periph, device) { DMA_PERIPH_ ## periph, periph ## DEV_ ## device, DMA_REQUEST_ ## periph ## device }
@ -376,7 +514,7 @@ static const dmaTimerMapping_t dmaTimerMapping[] = {
#undef DMA
#endif
#if defined(STM32H7)
#if defined(STM32H7) || defined(STM32G4)
static void dmaSetupRequest(dmaChannelSpec_t *dmaSpec, uint8_t request)
{
// Setup request as channel
@ -396,7 +534,7 @@ const dmaChannelSpec_t *dmaGetChannelSpecByPeripheral(dmaPeripheral_e device, ui
for (unsigned i = 0 ; i < ARRAYLEN(dmaPeripheralMapping) ; i++) {
const dmaPeripheralMapping_t *periph = &dmaPeripheralMapping[i];
#if defined(STM32H7)
#if defined(STM32H7) || defined(STM32G4)
if (periph->device == device && periph->index == index) {
dmaChannelSpec_t *dmaSpec = &dmaChannelSpec[opt];
dmaSetupRequest(dmaSpec, periph->dmaRequest);
@ -435,7 +573,7 @@ const dmaChannelSpec_t *dmaGetChannelSpecByTimerValue(TIM_TypeDef *tim, uint8_t
for (unsigned i = 0 ; i < ARRAYLEN(dmaTimerMapping) ; i++) {
const dmaTimerMapping_t *timerMapping = &dmaTimerMapping[i];
#if defined(STM32H7)
#if defined(STM32H7) || defined(STM32G4)
if (timerMapping->tim == tim && timerMapping->channel == channel) {
dmaChannelSpec_t *dmaSpec = &dmaChannelSpec[dmaopt];
dmaSetupRequest(dmaSpec, timerMapping->dmaRequest);
@ -465,7 +603,7 @@ const dmaChannelSpec_t *dmaGetChannelSpecByTimer(const timerHardware_t *timer)
dmaoptValue_t dmaGetOptionByTimer(const timerHardware_t *timer)
{
#if defined(STM32H7)
#if defined(STM32H7) || defined(STM32G4)
for (unsigned opt = 0; opt < ARRAYLEN(dmaChannelSpec); opt++) {
if (timer->dmaRefConfigured == dmaChannelSpec[opt].ref) {
return (dmaoptValue_t)opt;
@ -492,7 +630,7 @@ dmaoptValue_t dmaGetOptionByTimer(const timerHardware_t *timer)
return DMA_OPT_UNUSED;
}
#if defined(STM32H7)
#if defined(STM32H7) || defined(STM32G4)
// A variant of dmaGetOptionByTimer that looks for matching dmaTimUPRef
dmaoptValue_t dmaGetUpOptionByTimer(const timerHardware_t *timer)
{

View File

@ -30,7 +30,7 @@ typedef uint16_t dmaCode_t;
typedef struct dmaChannelSpec_s {
dmaCode_t code;
dmaResource_t *ref;
#if defined(STM32F4) || defined(STM32F7) || defined(STM32H7)
#if defined(STM32F4) || defined(STM32F7) || defined(STM32H7) || defined(STM32G4)
uint32_t channel;
#endif
} dmaChannelSpec_t;
@ -55,7 +55,7 @@ typedef int8_t dmaoptValue_t;
#define DMA_OPT_UNUSED (-1)
#if defined(STM32H7)
#if defined(STM32H7) || defined(STM32G4)
#define MAX_PERIPHERAL_DMA_OPTIONS 16
#define MAX_TIMER_DMA_OPTIONS 16
#else

View File

@ -0,0 +1,142 @@
/*
* This file is part of Cleanflight and Betaflight.
*
* Cleanflight and Betaflight are free software. You can redistribute
* this software and/or modify this software under the terms of the
* GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option)
* any later version.
*
* Cleanflight and Betaflight are distributed in the hope that they
* will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software.
*
* If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include "platform.h"
#ifdef USE_DMA
#include "drivers/nvic.h"
#include "drivers/dma.h"
#include "resource.h"
/*
* DMA descriptors.
*/
static dmaChannelDescriptor_t dmaDescriptors[DMA_LAST_HANDLER] = {
DEFINE_DMA_CHANNEL(DMA1, 1, 0),
DEFINE_DMA_CHANNEL(DMA1, 2, 4),
DEFINE_DMA_CHANNEL(DMA1, 3, 8),
DEFINE_DMA_CHANNEL(DMA1, 4, 12),
DEFINE_DMA_CHANNEL(DMA1, 5, 16),
DEFINE_DMA_CHANNEL(DMA1, 6, 20),
DEFINE_DMA_CHANNEL(DMA1, 7, 24),
DEFINE_DMA_CHANNEL(DMA1, 8, 28),
DEFINE_DMA_CHANNEL(DMA2, 1, 0),
DEFINE_DMA_CHANNEL(DMA2, 2, 4),
DEFINE_DMA_CHANNEL(DMA2, 3, 8),
DEFINE_DMA_CHANNEL(DMA2, 4, 12),
DEFINE_DMA_CHANNEL(DMA2, 5, 16),
DEFINE_DMA_CHANNEL(DMA2, 6, 20),
DEFINE_DMA_CHANNEL(DMA2, 7, 24),
DEFINE_DMA_CHANNEL(DMA2, 8, 28),
};
/*
* DMA IRQ Handlers
*/
DEFINE_DMA_IRQ_HANDLER(1, 1, DMA1_CH1_HANDLER)
DEFINE_DMA_IRQ_HANDLER(1, 2, DMA1_CH2_HANDLER)
DEFINE_DMA_IRQ_HANDLER(1, 3, DMA1_CH3_HANDLER)
DEFINE_DMA_IRQ_HANDLER(1, 4, DMA1_CH4_HANDLER)
DEFINE_DMA_IRQ_HANDLER(1, 5, DMA1_CH5_HANDLER)
DEFINE_DMA_IRQ_HANDLER(1, 6, DMA1_CH6_HANDLER)
DEFINE_DMA_IRQ_HANDLER(1, 7, DMA1_CH7_HANDLER)
DEFINE_DMA_IRQ_HANDLER(1, 8, DMA1_CH8_HANDLER)
DEFINE_DMA_IRQ_HANDLER(2, 1, DMA2_CH1_HANDLER)
DEFINE_DMA_IRQ_HANDLER(2, 2, DMA2_CH2_HANDLER)
DEFINE_DMA_IRQ_HANDLER(2, 3, DMA2_CH3_HANDLER)
DEFINE_DMA_IRQ_HANDLER(2, 4, DMA2_CH4_HANDLER)
DEFINE_DMA_IRQ_HANDLER(2, 5, DMA2_CH5_HANDLER)
DEFINE_DMA_IRQ_HANDLER(2, 6, DMA2_CH6_HANDLER)
DEFINE_DMA_IRQ_HANDLER(2, 7, DMA2_CH7_HANDLER)
DEFINE_DMA_IRQ_HANDLER(2, 8, DMA2_CH8_HANDLER)
static void enableDmaClock(int index)
{
// This is essentially copies of __HAL_RCC_DMA{1,2}_CLK_ENABLE macros
// squashed into one.
const uint32_t rcc = dmaDescriptors[index].dma == DMA1 ? RCC_AHB1ENR_DMA1EN : RCC_AHB1ENR_DMA2EN;
do {
__IO uint32_t tmpreg;
SET_BIT(RCC->AHB1ENR, rcc);
/* Delay after an RCC peripheral clock enabling */
tmpreg = READ_BIT(RCC->AHB1ENR, rcc);
UNUSED(tmpreg);
} while (0);
}
void dmaInit(dmaIdentifier_e identifier, resourceOwner_e owner, uint8_t resourceIndex)
{
const int index = DMA_IDENTIFIER_TO_INDEX(identifier);
enableDmaClock(index);
dmaDescriptors[index].owner.owner = owner;
dmaDescriptors[index].owner.resourceIndex = resourceIndex;
}
void dmaSetHandler(dmaIdentifier_e identifier, dmaCallbackHandlerFuncPtr callback, uint32_t priority, uint32_t userParam)
{
const int index = DMA_IDENTIFIER_TO_INDEX(identifier);
enableDmaClock(index);
dmaDescriptors[index].irqHandlerCallback = callback;
dmaDescriptors[index].userParam = userParam;
HAL_NVIC_SetPriority(dmaDescriptors[index].irqN, NVIC_PRIORITY_BASE(priority), NVIC_PRIORITY_SUB(priority));
HAL_NVIC_EnableIRQ(dmaDescriptors[index].irqN);
}
const resourceOwner_t *dmaGetOwner(dmaIdentifier_e identifier)
{
return &dmaDescriptors[DMA_IDENTIFIER_TO_INDEX(identifier)].owner;
}
dmaIdentifier_e dmaGetIdentifier(const dmaResource_t* stream)
{
for (int i = 0; i < DMA_LAST_HANDLER; i++) {
if (dmaDescriptors[i].ref == stream) {
return i + 1;
}
}
return 0;
}
dmaResource_t* dmaGetRefByIdentifier(const dmaIdentifier_e identifier)
{
return dmaDescriptors[DMA_IDENTIFIER_TO_INDEX(identifier)].ref;
}
dmaChannelDescriptor_t* dmaGetDescriptorByIdentifier(const dmaIdentifier_e identifier)
{
return &dmaDescriptors[DMA_IDENTIFIER_TO_INDEX(identifier)];
}
uint32_t dmaGetChannel(const uint8_t channel)
{
return ((uint32_t)channel*2)<<24;
}
#endif

View File

@ -22,7 +22,7 @@
#include "platform.h"
#if defined(USE_TIMER_MGMT) && defined(STM32H7)
#if defined(USE_TIMER_MGMT) && (defined(STM32H7) || defined(STM32G4))
#include "drivers/dma_reqmap.h"
#include "drivers/timer.h"