diff --git a/os/hal/ports/STM32/LLD/DMAv1/notes.txt b/os/hal/ports/STM32/LLD/DMAv1/notes.txt new file mode 100644 index 000000000..889365852 --- /dev/null +++ b/os/hal/ports/STM32/LLD/DMAv1/notes.txt @@ -0,0 +1,29 @@ +STM32 DMAv1 driver. + +Driver capability: + +- The driver supports the STM32 traditional DMA controller in the following + configurations: 5ch, 7ch, 7ch+5ch. +- Support for automatic the channel selection through the CSELR register. +- For devices without CSELR register it is possible to select channels but + the SYSCFG CFGR register is not configured, the user has to configure it + before starting the DMA driver. +- The driver supports shared ISR handlers with a quirk: the IRQ priority is + established by the first allocated channel among the channels sharing the + ISR. + +The file registry must export: + +STM32_ADVANCED_DMA - TRUE if CSELR is present. +STM32_DMAn_NUM_CHANNELS - Number of channels in DMA1. +STM32_DMAn_CHx_HANDLER - Vector name for IRQ "x". +STM32_DMAn_CHxyz_HANDLER - Vector name for shared IRQs "x", "y" and "z". +STM32_DMAn_CHx_NUMBER - Vector number for IRQ "x". +STM32_DMAn_CHxyz_NUMBER - Vector number for shared IRQs "x", "y" and "z". + +Currently supported shared combinations are: + +STM32_DMA1_CH23_HANDLER +STM32_DMA1_CH23_NUMBER +STM32_DMA1_CH4567_HANDLER +STM32_DMA1_CH4567_NUMBER diff --git a/os/hal/ports/STM32/LLD/DMAv1/stm32_dma.c b/os/hal/ports/STM32/LLD/DMAv1/stm32_dma.c index 57a325c61..74db011d1 100644 --- a/os/hal/ports/STM32/LLD/DMAv1/stm32_dma.c +++ b/os/hal/ports/STM32/LLD/DMAv1/stm32_dma.c @@ -78,6 +78,34 @@ #define ADDR_DMA2_CSELR NULL #endif +/* + * ISR collision masks. + */ +#define DMA1_CH1_CMASK 0x00000001U +#if !defined(STM32_DMA1_CH23_NUMBER) +#define DMA1_CH2_CMASK 0x00000002U +#define DMA1_CH3_CMASK 0x00000004U +#else +#define DMA1_CH2_CMASK 0x00000006U +#define DMA1_CH3_CMASK 0x00000006U +#endif +#if !defined(STM32_DMA1_CH4567_NUMBER) +#define DMA1_CH4_CMASK 0x00000008U +#define DMA1_CH5_CMASK 0x00000010U +#define DMA1_CH6_CMASK 0x00000020U +#define DMA1_CH7_CMASK 0x00000040U +#else +#define DMA1_CH4_CMASK 0x00000078U +#define DMA1_CH5_CMASK 0x00000078U +#define DMA1_CH6_CMASK 0x00000078U +#define DMA1_CH7_CMASK 0x00000078U +#endif +#define DMA2_CH1_CMASK 0x00000080U +#define DMA3_CH2_CMASK 0x00000100U +#define DMA3_CH3_CMASK 0x00000200U +#define DMA4_CH4_CMASK 0x00000400U +#define DMA5_CH5_CMASK 0x00000800U + /*===========================================================================*/ /* Driver exported variables. */ /*===========================================================================*/ @@ -90,23 +118,23 @@ * instead: @p STM32_DMA1_STREAM1, @p STM32_DMA1_STREAM2 etc. */ const stm32_dma_stream_t _stm32_dma_streams[STM32_DMA_STREAMS] = { - {DMA1_Channel1, &DMA1->IFCR, ADDR_DMA1_CSELR, 0, 0, STM32_DMA1_CH1_NUMBER}, - {DMA1_Channel2, &DMA1->IFCR, ADDR_DMA1_CSELR, 4, 1, STM32_DMA1_CH2_NUMBER}, - {DMA1_Channel3, &DMA1->IFCR, ADDR_DMA1_CSELR, 8, 2, STM32_DMA1_CH3_NUMBER}, - {DMA1_Channel4, &DMA1->IFCR, ADDR_DMA1_CSELR, 12, 3, STM32_DMA1_CH4_NUMBER}, - {DMA1_Channel5, &DMA1->IFCR, ADDR_DMA1_CSELR, 16, 4, STM32_DMA1_CH5_NUMBER}, + {DMA1_Channel1, DMA1_CH1_CMASK, &DMA1->IFCR, ADDR_DMA1_CSELR, 0, 0, STM32_DMA1_CH1_NUMBER}, + {DMA1_Channel2, DMA1_CH2_CMASK, &DMA1->IFCR, ADDR_DMA1_CSELR, 4, 1, STM32_DMA1_CH2_NUMBER}, + {DMA1_Channel3, DMA1_CH3_CMASK, &DMA1->IFCR, ADDR_DMA1_CSELR, 8, 2, STM32_DMA1_CH3_NUMBER}, + {DMA1_Channel4, DMA1_CH4_CMASK, &DMA1->IFCR, ADDR_DMA1_CSELR, 12, 3, STM32_DMA1_CH4_NUMBER}, + {DMA1_Channel5, DMA1_CH5_CMASK, &DMA1->IFCR, ADDR_DMA1_CSELR, 16, 4, STM32_DMA1_CH5_NUMBER}, #if STM32_DMA1_NUM_CHANNELS > 5 - {DMA1_Channel6, &DMA1->IFCR, ADDR_DMA1_CSELR, 20, 5, STM32_DMA1_CH6_NUMBER}, + {DMA1_Channel6, DMA1_CH6_CMASK, &DMA1->IFCR, ADDR_DMA1_CSELR, 20, 5, STM32_DMA1_CH6_NUMBER}, #endif #if STM32_DMA1_NUM_CHANNELS > 6 - {DMA1_Channel7, &DMA1->IFCR, ADDR_DMA1_CSELR, 24, 6, STM32_DMA1_CH7_NUMBER}, + {DMA1_Channel7, DMA1_CH7_CMASK, &DMA1->IFCR, ADDR_DMA1_CSELR, 24, 6, STM32_DMA1_CH7_NUMBER}, #endif #if STM32_DMA2_NUM_CHANNELS > 0 - {DMA2_Channel1, &DMA2->IFCR, ADDR_DMA2_CSELR, 0, 8, STM32_DMA2_CH1_NUMBER}, - {DMA2_Channel2, &DMA2->IFCR, ADDR_DMA2_CSELR, 4, 9, STM32_DMA2_CH2_NUMBER}, - {DMA2_Channel3, &DMA2->IFCR, ADDR_DMA2_CSELR, 8, 10, STM32_DMA2_CH3_NUMBER}, - {DMA2_Channel4, &DMA2->IFCR, ADDR_DMA2_CSELR, 12, 11, STM32_DMA2_CH4_NUMBER}, - {DMA2_Channel5, &DMA2->IFCR, ADDR_DMA2_CSELR, 16, 13, STM32_DMA2_CH5_NUMBER}, + {DMA2_Channel1, DMA2_CH1_CMASK, &DMA2->IFCR, ADDR_DMA2_CSELR, 0, 8, STM32_DMA2_CH1_NUMBER}, + {DMA2_Channel2, DMA2_CH2_CMASK, &DMA2->IFCR, ADDR_DMA2_CSELR, 4, 9, STM32_DMA2_CH2_NUMBER}, + {DMA2_Channel3, DMA2_CH3_CMASK, &DMA2->IFCR, ADDR_DMA2_CSELR, 8, 10, STM32_DMA2_CH3_NUMBER}, + {DMA2_Channel4, DMA2_CH4_CMASK, &DMA2->IFCR, ADDR_DMA2_CSELR, 12, 11, STM32_DMA2_CH4_NUMBER}, + {DMA2_Channel5, DMA2_CH5_CMASK, &DMA2->IFCR, ADDR_DMA2_CSELR, 16, 13, STM32_DMA2_CH5_NUMBER}, #endif }; @@ -505,10 +533,9 @@ bool dmaStreamAllocate(const stm32_dma_stream_t *dmastp, if ((dma_streams_mask & (1U << dmastp->selfindex)) != 0U) return true; - /* Marks the stream as allocated.*/ + /* Installs the DMA handler.*/ dma_isr_redir[dmastp->selfindex].dma_func = func; dma_isr_redir[dmastp->selfindex].dma_param = param; - dma_streams_mask |= (1U << dmastp->selfindex); /* Enabling DMA clocks required by the current streams set.*/ if ((dma_streams_mask & STM32_DMA1_STREAMS_MASK) != 0U) @@ -522,9 +549,15 @@ bool dmaStreamAllocate(const stm32_dma_stream_t *dmastp, dmaStreamDisable(dmastp); dmastp->channel->CCR = STM32_DMA_CCR_RESET_VALUE; - /* Enables the associated IRQ vector if a callback is defined.*/ - if (func != NULL) + /* Enables the associated IRQ vector if not alread enabled and if a + callback is defined.*/ + if (((dma_streams_mask & dmastp->cmask) != 0U) && + (func != NULL)) { nvicEnableVector(dmastp->vector, priority); + } + + /* Marks the stream as allocated.*/ + dma_streams_mask |= (1U << dmastp->selfindex); return false; } @@ -550,12 +583,18 @@ void dmaStreamRelease(const stm32_dma_stream_t *dmastp) { osalDbgAssert((dma_streams_mask & (1 << dmastp->selfindex)) != 0U, "not allocated"); - /* Disables the associated IRQ vector.*/ - nvicDisableVector(dmastp->vector); - /* Marks the stream as not allocated.*/ dma_streams_mask &= ~(1 << dmastp->selfindex); + /* Disables the associated IRQ vector if it is no more in use.*/ + if ((dma_streams_mask & dmastp->cmask) == 0U) { + nvicDisableVector(dmastp->vector); + } + + /* Removes the DMA handler.*/ + dma_isr_redir[dmastp->selfindex].dma_func = NULL; + dma_isr_redir[dmastp->selfindex].dma_param = NULL; + /* Shutting down clocks that are no more required, if any.*/ if ((dma_streams_mask & STM32_DMA1_STREAMS_MASK) == 0U) rccDisableDMA1(false); diff --git a/os/hal/ports/STM32/LLD/DMAv1/stm32_dma.h b/os/hal/ports/STM32/LLD/DMAv1/stm32_dma.h index f8cf56dda..63e0c5cfc 100644 --- a/os/hal/ports/STM32/LLD/DMAv1/stm32_dma.h +++ b/os/hal/ports/STM32/LLD/DMAv1/stm32_dma.h @@ -201,6 +201,8 @@ */ typedef struct { DMA_Channel_TypeDef *channel; /**< @brief Associated DMA channel. */ + uint32_t cmask; /**< @brief Mask of streams sharing + the same ISR. */ volatile uint32_t *ifcr; /**< @brief Associated IFCR reg. */ volatile uint32_t *cselr; /**< @brief Associated CSELR reg. */ uint8_t shift; /**< @brief Bit offset in IFCR and diff --git a/readme.txt b/readme.txt index 77ca21930..ad689a3f7 100644 --- a/readme.txt +++ b/readme.txt @@ -74,7 +74,12 @@ ***************************************************************************** *** 3.1.0 *** +- HAL: STM32F0xx and STM32L0xx devices now share the same ADCv1 and DMAv1 + drivers. - HAL: Introduced preliminary support for STM32L0xx devices. +- HAL: New STM32 DMAv1 driver supporting channel selection and fixing the + behavior with shared IRQs. +- HAL: New STM32 ADCv1 driver supporting small STM32 devices. - HAL: Introduced support for TIM21 and TIM22 in STM32 ST driver. - HAL: Updated STM32F0xx headers to STM32CubeF0 version 1.3.0. Added support for STM32F030xC, STM32F070x6, STM32F070xB devices.