diff --git a/src/main/cli/cli.c b/src/main/cli/cli.c index 8ebf10de0e..b0fa256d10 100644 --- a/src/main/cli/cli.c +++ b/src/main/cli/cli.c @@ -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) { diff --git a/src/main/drivers/dma.h b/src/main/drivers/dma.h index a865907248..afa9b64d3d 100644 --- a/src/main/drivers/dma.h +++ b/src/main/drivers/dma.h @@ -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 ... diff --git a/src/main/drivers/dma_reqmap.c b/src/main/drivers/dma_reqmap.c index 5b94b44d84..6e53a61a28 100644 --- a/src/main/drivers/dma_reqmap.c +++ b/src/main/drivers/dma_reqmap.c @@ -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) { diff --git a/src/main/drivers/dma_reqmap.h b/src/main/drivers/dma_reqmap.h index 1ce9d9ef8b..a904618bfc 100644 --- a/src/main/drivers/dma_reqmap.h +++ b/src/main/drivers/dma_reqmap.h @@ -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 diff --git a/src/main/drivers/dma_stm32g4xx.c b/src/main/drivers/dma_stm32g4xx.c new file mode 100644 index 0000000000..d06db079bf --- /dev/null +++ b/src/main/drivers/dma_stm32g4xx.c @@ -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 . + */ + +#include +#include +#include + +#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 diff --git a/src/main/pg/timerup.c b/src/main/pg/timerup.c index 2fb92efec8..e0e820009a 100644 --- a/src/main/pg/timerup.c +++ b/src/main/pg/timerup.c @@ -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"