From c1c1706005b56e75ae1cb02c9b7a12fb3a26fc18 Mon Sep 17 00:00:00 2001 From: gdisirio Date: Sun, 28 Aug 2011 08:55:48 +0000 Subject: git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@3256 35acf78f-673a-0410-8e92-d51de3d6d3f4 --- os/hal/platforms/STM32/DMAv1/stm32_dma.c | 411 +++++++++++++++++-------------- os/hal/platforms/STM32/DMAv1/stm32_dma.h | 269 ++++++++++---------- 2 files changed, 354 insertions(+), 326 deletions(-) (limited to 'os/hal') diff --git a/os/hal/platforms/STM32/DMAv1/stm32_dma.c b/os/hal/platforms/STM32/DMAv1/stm32_dma.c index ae1a7170f..1df93bb2f 100644 --- a/os/hal/platforms/STM32/DMAv1/stm32_dma.c +++ b/os/hal/platforms/STM32/DMAv1/stm32_dma.c @@ -20,28 +20,78 @@ /** * @file DMAv1/stm32_dma.c - * @brief STM32 DMA helper driver code. + * @brief DMA helper driver code. * * @addtogroup STM32_DMA - * @details DMA sharing helper driver. In the STM32 the DMA channels are a + * @details DMA sharing helper driver. In the STM32 the DMA streams are a * shared resource, this driver allows to allocate and free DMA - * channels at runtime in order to allow all the other device + * streams at runtime in order to allow all the other device * drivers to coordinate the access to the resource. * @note The DMA ISR handlers are all declared into this module because * sharing, the various device drivers can associate a callback to - * IRSs when allocating channels. + * IRSs when allocating streams. * @{ */ #include "ch.h" #include "hal.h" +/* The following macro is only defined if some driver requiring DMA services + has been enabled.*/ #if defined(STM32_DMA_REQUIRED) || defined(__DOXYGEN__) +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/** + * @brief Mask of the DMA1 streams in @p dma_streams_mask. + */ +#define STM32_DMA1_STREAMS_MASK 0x0000007F + +/** + * @brief Mask of the DMA2 streams in @p dma_streams_mask. + */ +#define STM32_DMA2_STREAMS_MASK 0x00000F80 + +/** + * @brief Post-reset value of the stream CCR register. + */ +#define STM32_DMA_CCR_RESET_VALUE 0x00000000 + /*===========================================================================*/ /* Driver exported variables. */ /*===========================================================================*/ +/** + * @brief DMA streams descriptors. + * @details This table keeps the association between an unique stream + * identifier and the involved physical registers. + * @note Don't use this array directly, use the appropriate wrapper macros + * 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, 0, 0, DMA1_Channel1_IRQn}, + {DMA1_Channel2, &DMA1->IFCR, 4, 1, DMA1_Channel2_IRQn}, + {DMA1_Channel3, &DMA1->IFCR, 8, 2, DMA1_Channel3_IRQn}, + {DMA1_Channel4, &DMA1->IFCR, 12, 3, DMA1_Channel4_IRQn}, + {DMA1_Channel5, &DMA1->IFCR, 16, 4, DMA1_Channel5_IRQn}, + {DMA1_Channel6, &DMA1->IFCR, 20, 5, DMA1_Channel6_IRQn}, + {DMA1_Channel7, &DMA1->IFCR, 24, 6, DMA1_Channel7_IRQn}, +#if STM32_HAS_DMA2 || defined(__DOXYGEN__) + {DMA2_Channel1, &DMA2->IFCR, 0, 7, DMA2_Channel1_IRQn}, + {DMA2_Channel2, &DMA2->IFCR, 4, 8, DMA2_Channel2_IRQn}, + {DMA2_Channel3, &DMA2->IFCR, 8, 9, DMA2_Channel3_IRQn}, +#if defined(STM32F10X_CL) || defined(__DOXYGEN__) + {DMA2_Channel4, &DMA2->IFCR, 12, 10, DMA2_Channel4_IRQn}, + {DMA2_Channel5, &DMA2->IFCR, 16, 11, DMA2_Channel5_IRQn}, +#else /* !STM32F10X_CL */ + {DMA2_Channel4, &DMA2->IFCR, 12, 10, DMA2_Channel4_5_IRQn}, + {DMA2_Channel5, &DMA2->IFCR, 16, 11, DMA2_Channel4_5_IRQn}, +#endif /* !STM32F10X_CL */ +#endif /* STM32_HAS_DMA2 */ +}; + /*===========================================================================*/ /* Driver local variables and types. */ /*===========================================================================*/ @@ -50,17 +100,19 @@ * @brief DMA ISR redirector type. */ typedef struct { - stm32_dmaisr_t dmaisrfunc; - void *dmaisrparam; + stm32_dmaisr_t dma_func; + void *dma_param; } dma_isr_redir_t; -static uint32_t dmamsk1; -static dma_isr_redir_t dma1[7]; +/** + * @brief Mask of the allocated streams. + */ +static uint32_t dma_streams_mask; -#if STM32_HAS_DMA2 -static uint32_t dmamsk2; -static dma_isr_redir_t dma2[5]; -#endif +/** + * @brief DMA IRQ redirectors. + */ +static dma_isr_redir_t dma_isr_redir[STM32_DMA_STREAMS]; /*===========================================================================*/ /* Driver local functions. */ @@ -71,250 +123,249 @@ static dma_isr_redir_t dma2[5]; /*===========================================================================*/ /** - * @brief DMA1 channel 1 shared interrupt handler. + * @brief DMA1 stream 1 shared interrupt handler. * * @isr */ CH_IRQ_HANDLER(DMA1_Ch1_IRQHandler) { - uint32_t isr; + uint32_t flags; CH_IRQ_PROLOGUE(); - isr = STM32_DMA1->ISR >> (STM32_DMA_CHANNEL_1 * 4); - dmaClearChannel(STM32_DMA1, STM32_DMA_CHANNEL_1); - if (dma1[0].dmaisrfunc) - dma1[0].dmaisrfunc(dma1[0].dmaisrparam, isr); + flags = (DMA1->ISR >> 0) & STM32_DMA_ISR_MASK; + DMA1->IFCR = STM32_DMA_ISR_MASK << 0; + if (dma_isr_redir[0].dma_func) + dma_isr_redir[0].dma_func(dma_isr_redir[0].dma_param, flags); CH_IRQ_EPILOGUE(); } /** - * @brief DMA1 channel 2 shared interrupt handler. + * @brief DMA1 stream 2 shared interrupt handler. * * @isr */ CH_IRQ_HANDLER(DMA1_Ch2_IRQHandler) { - uint32_t isr; + uint32_t flags; CH_IRQ_PROLOGUE(); - isr = STM32_DMA1->ISR >> (STM32_DMA_CHANNEL_2 * 4); - dmaClearChannel(STM32_DMA1, STM32_DMA_CHANNEL_2); - if (dma1[1].dmaisrfunc) - dma1[1].dmaisrfunc(dma1[1].dmaisrparam, isr); + flags = (DMA1->ISR >> 4) & STM32_DMA_ISR_MASK; + DMA1->IFCR = STM32_DMA_ISR_MASK << 4; + if (dma_isr_redir[1].dma_func) + dma_isr_redir[1].dma_func(dma_isr_redir[1].dma_param, flags); CH_IRQ_EPILOGUE(); } /** - * @brief DMA1 channel 3 shared interrupt handler. + * @brief DMA1 stream 3 shared interrupt handler. * * @isr */ CH_IRQ_HANDLER(DMA1_Ch3_IRQHandler) { - uint32_t isr; + uint32_t flags; CH_IRQ_PROLOGUE(); - isr = STM32_DMA1->ISR >> (STM32_DMA_CHANNEL_3 * 4); - dmaClearChannel(STM32_DMA1, STM32_DMA_CHANNEL_3); - if (dma1[2].dmaisrfunc) - dma1[2].dmaisrfunc(dma1[2].dmaisrparam, isr); + flags = (DMA1->ISR >> 8) & STM32_DMA_ISR_MASK; + DMA1->IFCR = STM32_DMA_ISR_MASK << 8; + if (dma_isr_redir[2].dma_func) + dma_isr_redir[2].dma_func(dma_isr_redir[2].dma_param, flags); CH_IRQ_EPILOGUE(); } /** - * @brief DMA1 channel 4 shared interrupt handler. + * @brief DMA1 stream 4 shared interrupt handler. * * @isr */ CH_IRQ_HANDLER(DMA1_Ch4_IRQHandler) { - uint32_t isr; + uint32_t flags; CH_IRQ_PROLOGUE(); - isr = STM32_DMA1->ISR >> (STM32_DMA_CHANNEL_4 * 4); - dmaClearChannel(STM32_DMA1, STM32_DMA_CHANNEL_4); - if (dma1[3].dmaisrfunc) - dma1[3].dmaisrfunc(dma1[3].dmaisrparam, isr); + flags = (DMA1->ISR >> 12) & STM32_DMA_ISR_MASK; + DMA1->IFCR = STM32_DMA_ISR_MASK << 12; + if (dma_isr_redir[3].dma_func) + dma_isr_redir[3].dma_func(dma_isr_redir[3].dma_param, flags); CH_IRQ_EPILOGUE(); } /** - * @brief DMA1 channel 5 shared interrupt handler. + * @brief DMA1 stream 5 shared interrupt handler. * * @isr */ CH_IRQ_HANDLER(DMA1_Ch5_IRQHandler) { - uint32_t isr; + uint32_t flags; CH_IRQ_PROLOGUE(); - isr = STM32_DMA1->ISR >> (STM32_DMA_CHANNEL_5 * 4); - dmaClearChannel(STM32_DMA1, STM32_DMA_CHANNEL_5); - if (dma1[4].dmaisrfunc) - dma1[4].dmaisrfunc(dma1[4].dmaisrparam, isr); + flags = (DMA1->ISR >> 16) & STM32_DMA_ISR_MASK; + DMA1->IFCR = STM32_DMA_ISR_MASK << 16; + if (dma_isr_redir[4].dma_func) + dma_isr_redir[4].dma_func(dma_isr_redir[4].dma_param, flags); CH_IRQ_EPILOGUE(); } /** - * @brief DMA1 channel 6 shared interrupt handler. + * @brief DMA1 stream 6 shared interrupt handler. * * @isr */ CH_IRQ_HANDLER(DMA1_Ch6_IRQHandler) { - uint32_t isr; + uint32_t flags; CH_IRQ_PROLOGUE(); - isr = STM32_DMA1->ISR >> (STM32_DMA_CHANNEL_6 * 4); - dmaClearChannel(STM32_DMA1, STM32_DMA_CHANNEL_6); - if (dma1[5].dmaisrfunc) - dma1[5].dmaisrfunc(dma1[5].dmaisrparam, isr); + flags = (DMA1->ISR >> 20) & STM32_DMA_ISR_MASK; + DMA1->IFCR = STM32_DMA_ISR_MASK << 20; + if (dma_isr_redir[5].dma_func) + dma_isr_redir[5].dma_func(dma_isr_redir[5].dma_param, flags); CH_IRQ_EPILOGUE(); } /** - * @brief DMA1 channel 7 shared interrupt handler. + * @brief DMA1 stream 7 shared interrupt handler. * * @isr */ CH_IRQ_HANDLER(DMA1_Ch7_IRQHandler) { - uint32_t isr; + uint32_t flags; CH_IRQ_PROLOGUE(); - isr = STM32_DMA1->ISR >> (STM32_DMA_CHANNEL_7 * 4); - dmaClearChannel(STM32_DMA1, STM32_DMA_CHANNEL_7); - if (dma1[6].dmaisrfunc) - dma1[6].dmaisrfunc(dma1[6].dmaisrparam, isr); + flags = (DMA1->ISR >> 24) & STM32_DMA_ISR_MASK; + DMA1->IFCR = STM32_DMA_ISR_MASK << 24; + if (dma_isr_redir[6].dma_func) + dma_isr_redir[6].dma_func(dma_isr_redir[6].dma_param, flags); CH_IRQ_EPILOGUE(); } #if STM32_HAS_DMA2 || defined(__DOXYGEN__) /** - * @brief DMA2 channel 1 shared interrupt handler. + * @brief DMA2 stream 1 shared interrupt handler. * * @isr */ CH_IRQ_HANDLER(DMA2_Ch1_IRQHandler) { - uint32_t isr; + uint32_t flags; CH_IRQ_PROLOGUE(); - isr = STM32_DMA2->ISR >> (STM32_DMA_CHANNEL_1 * 4); - dmaClearChannel(STM32_DMA2, STM32_DMA_CHANNEL_1); - if (dma2[0].dmaisrfunc) - dma2[0].dmaisrfunc(dma2[0].dmaisrparam, isr); + flags = (DMA2->ISR >> 0) & STM32_DMA_ISR_MASK; + DMA2->IFCR = STM32_DMA_ISR_MASK << 0; + if (dma_isr_redir[7].dma_func) + dma_isr_redir[7].dma_func(dma_isr_redir[7].dma_param, flags); CH_IRQ_EPILOGUE(); } /** - * @brief DMA2 channel 2 shared interrupt handler. + * @brief DMA2 stream 2 shared interrupt handler. * * @isr */ CH_IRQ_HANDLER(DMA2_Ch2_IRQHandler) { - uint32_t isr; + uint32_t flags; CH_IRQ_PROLOGUE(); - isr = STM32_DMA2->ISR >> (STM32_DMA_CHANNEL_2 * 4); - dmaClearChannel(STM32_DMA2, STM32_DMA_CHANNEL_2); - if (dma2[1].dmaisrfunc) - dma2[1].dmaisrfunc(dma2[1].dmaisrparam, isr); + flags = (DMA2->ISR >> 4) & STM32_DMA_ISR_MASK; + DMA2->IFCR = STM32_DMA_ISR_MASK << 4; + if (dma_isr_redir[8].dma_func) + dma_isr_redir[8].dma_func(dma_isr_redir[8].dma_param, flags); CH_IRQ_EPILOGUE(); } /** - * @brief DMA2 channel 3 shared interrupt handler. + * @brief DMA2 stream 3 shared interrupt handler. * * @isr */ CH_IRQ_HANDLER(DMA2_Ch3_IRQHandler) { - uint32_t isr; + uint32_t flags; CH_IRQ_PROLOGUE(); - isr = STM32_DMA2->ISR >> (STM32_DMA_CHANNEL_3 * 4); - dmaClearChannel(STM32_DMA2, STM32_DMA_CHANNEL_3); - if (dma2[2].dmaisrfunc) - dma2[2].dmaisrfunc(dma2[2].dmaisrparam, isr); + flags = (DMA2->ISR >> 8) & STM32_DMA_ISR_MASK; + DMA2->IFCR = STM32_DMA_ISR_MASK << 8; + if (dma_isr_redir[9].dma_func) + dma_isr_redir[9].dma_func(dma_isr_redir[9].dma_param, flags); CH_IRQ_EPILOGUE(); } #if defined(STM32F10X_CL) || defined(__DOXYGEN__) /** - * @brief DMA2 channel 4 shared interrupt handler. + * @brief DMA2 stream 4 shared interrupt handler. * * @isr */ CH_IRQ_HANDLER(DMA2_Ch4_IRQHandler) { - uint32_t isr; + uint32_t flags; CH_IRQ_PROLOGUE(); - isr = STM32_DMA2->ISR >> (STM32_DMA_CHANNEL_4 * 4); - dmaClearChannel(STM32_DMA2, STM32_DMA_CHANNEL_4); - if (dma2[3].dmaisrfunc) - dma2[3].dmaisrfunc(dma2[3].dmaisrparam, isr); + flags = (DMA2->ISR >> 12) & STM32_DMA_ISR_MASK; + DMA2->IFCR = STM32_DMA_ISR_MASK << 12; + if (dma_isr_redir[10].dma_func) + dma_isr_redir[10].dma_func(dma_isr_redir[10].dma_param, flags); CH_IRQ_EPILOGUE(); } /** - * @brief DMA2 channel 5 shared interrupt handler. + * @brief DMA2 stream 5 shared interrupt handler. * * @isr */ CH_IRQ_HANDLER(DMA2_Ch5_IRQHandler) { - uint32_t isr; + uint32_t flags; CH_IRQ_PROLOGUE(); - isr = STM32_DMA2->ISR >> (STM32_DMA_CHANNEL_5 * 4); - dmaClearChannel(STM32_DMA2, STM32_DMA_CHANNEL_5); - if (dma2[4].dmaisrfunc) - dma2[4].dmaisrfunc(dma2[4].dmaisrparam, isr); + flags = (DMA2->ISR >> 16) & STM32_DMA_ISR_MASK; + DMA2->IFCR = STM32_DMA_ISR_MASK << 16; + if (dma_isr_redir[11].dma_func) + dma_isr_redir[11].dma_func(dma_isr_redir[11].dma_param, flags); CH_IRQ_EPILOGUE(); } - #else /* !STM32F10X_CL */ /** - * @brief DMA2 channels 4 and 5 shared interrupt handler. + * @brief DMA2 streams 4 and 5 shared interrupt handler. * @note This IRQ is shared between DMA2 channels 4 and 5 so it is a * bit less efficient because an extra check. * * @isr */ CH_IRQ_HANDLER(DMA2_Ch4_5_IRQHandler) { - uint32_t isr; + uint32_t flags; CH_IRQ_PROLOGUE(); /* Check on channel 4.*/ - isr = STM32_DMA2->ISR >> (STM32_DMA_CHANNEL_5 * 4); - if (isr & DMA_ISR_GIF1) { - dmaClearChannel(STM32_DMA2, STM32_DMA_CHANNEL_5); - if (dma2[3].dmaisrfunc) - dma2[3].dmaisrfunc(dma2[3].dmaisrparam, isr); + flags = (DMA2->ISR >> 12) & STM32_DMA_ISR_MASK; + if (flags & STM32_DMA_ISR_MASK) { + DMA2->IFCR = STM32_DMA_ISR_MASK << 12; + if (dma_isr_redir[10].dma_func) + dma_isr_redir[10].dma_func(dma_isr_redir[10].dma_param, flags); } /* Check on channel 5.*/ - isr = STM32_DMA2->ISR >> (STM32_DMA_CHANNEL_4 * 4); - if (isr & DMA_ISR_GIF1) { - dmaClearChannel(STM32_DMA2, STM32_DMA_CHANNEL_5); - if (dma2[4].dmaisrfunc) - dma2[4].dmaisrfunc(dma2[4].dmaisrparam, isr); + flags = (DMA2->ISR >> 16) & STM32_DMA_ISR_MASK; + if (flags & STM32_DMA_ISR_MASK) { + DMA2->IFCR = STM32_DMA_ISR_MASK << 16; + if (dma_isr_redir[11].dma_func) + dma_isr_redir[11].dma_func(dma_isr_redir[11].dma_param, flags); } CH_IRQ_EPILOGUE(); @@ -334,127 +385,109 @@ CH_IRQ_HANDLER(DMA2_Ch4_5_IRQHandler) { void dmaInit(void) { int i; - dmamsk1 = 0; - for (i = STM32_DMA_CHANNEL_7; i >= STM32_DMA_CHANNEL_1; i--) { - dmaDisableChannel(STM32_DMA1, i); - dma1[i].dmaisrfunc = NULL; + dma_streams_mask = 0; + for (i = 0; i < STM32_DMA_STREAMS; i++) { + _stm32_dma_streams[i].channel->CCR = 0; + dma_isr_redir[i].dma_func = NULL; } - STM32_DMA1->IFCR = 0xFFFFFFFF; + DMA1->IFCR = 0xFFFFFFFF; #if STM32_HAS_DMA2 - dmamsk2 = 0; - for (i = STM32_DMA_CHANNEL_5; i >= STM32_DMA_CHANNEL_1; i--) { - dmaDisableChannel(STM32_DMA2, i); - dma2[i].dmaisrfunc = NULL; - } - STM32_DMA1->IFCR = 0xFFFFFFFF; + DMA2->IFCR = 0xFFFFFFFF; #endif } /** - * @brief Allocates a DMA channel. - * @details The channel is allocated and, if required, the DMA clock enabled. - * Trying to allocate a channel already allocated is an illegal - * operation and is trapped if assertions are enabled. - * @pre The channel must not be already in use. - * @post The channel is allocated and the default ISR handler redirected + * @brief Allocates a DMA stream. + * @details The stream is allocated and, if required, the DMA clock enabled. + * The function also enables the IRQ vector associated to the stream + * and initializes its priority. + * @pre The stream must not be already in use or an error is returned. + * @post The stream is allocated and the default ISR handler redirected * to the specified function. - * @post The channel must be freed using @p dmaRelease() before it can + * @post The stream ISR vector is enabled and its priority configured. + * @post The stream must be freed using @p dmaStreamRelease() before it can * be reused with another peripheral. + * @post The stream is in its post-reset state. * @note This function can be invoked in both ISR or thread context. * - * @param[in] dma DMA controller id - * @param[in] channel requested channel id + * @param[in] dmastp pointer to a stm32_dma_stream_t structure * @param[in] func handling function pointer, can be @p NULL * @param[in] param a parameter to be passed to the handling function + * @return The operation status. + * @retval FALSE no error, stream taken. + * @retval TRUE error, stream already taken. * * @special */ -void dmaAllocate(uint32_t dma, uint32_t channel, - stm32_dmaisr_t func, void *param) { +bool_t dmaStreamAllocate(const stm32_dma_stream_t *dmastp, + uint32_t priority, + stm32_dmaisr_t func, + void *param) { + chDbgCheck(dmastp != NULL, "dmaAllocate"); + + /* Checks if the stream is already taken.*/ + if ((dma_streams_mask & (1 << dmastp->selfindex)) != 0) + return TRUE; + + /* Marks the stream as allocated.*/ + dma_isr_redir[dmastp->selfindex].dma_func = func; + dma_isr_redir[dmastp->selfindex].dma_param = param; + dma_streams_mask |= (1 << dmastp->selfindex); + + /* Enabling DMA clocks required by the current streams set.*/ + if ((dma_streams_mask & STM32_DMA1_STREAMS_MASK) != 0) + RCC->AHBENR |= RCC_AHBENR_DMA1EN; #if STM32_HAS_DMA2 - switch (dma) { - case STM32_DMA1_ID: -#else - (void)dma; -#endif - /* Check if the channel is already taken.*/ - chDbgAssert((dmamsk1 & (1 << channel)) == 0, - "dmaAllocate(), #1", "already allocated"); - - /* If the DMA unit was idle then the clock is enabled.*/ - if (dmamsk1 == 0) { - RCC->AHBENR |= RCC_AHBENR_DMA1EN; - DMA1->IFCR = 0x0FFFFFFF; - } - - dmamsk1 |= 1 << channel; - dma1[channel].dmaisrfunc = func; - dma1[channel].dmaisrparam = param; -#if STM32_HAS_DMA2 - break; - case STM32_DMA2_ID: - /* Check if the channel is already taken.*/ - chDbgAssert((dmamsk2 & (1 << channel)) == 0, - "dmaAllocate(), #2", "already allocated"); - - /* If the DMA unit was idle then the clock is enabled.*/ - if (dmamsk2 == 0) { - RCC->AHBENR |= RCC_AHBENR_DMA2EN; - DMA2->IFCR = 0x0FFFFFFF; - } - - dmamsk2 |= 1 << channel; - dma2[channel].dmaisrfunc = func; - dma2[channel].dmaisrparam = param; - break; - } + if ((dma_streams_mask & STM32_DMA2_STREAMS_MASK) != 0) + RCC->AHBENR |= RCC_AHBENR_DMA2EN; #endif + + /* Putting the stream in a safe state.*/ + dmaStreamDisable(dmastp); + dmaStreamClearInterrupt(dmastp); + dmastp->channel->CCR = STM32_DMA_CCR_RESET_VALUE; + + /* Enables the associated IRQ vector if a callback is defined.*/ + if (func != NULL) + NVICEnableVector(dmastp->vector, CORTEX_PRIORITY_MASK(priority)); + + return FALSE; } /** - * @brief Releases a DMA channel. - * @details The channel is freed and, if required, the DMA clock disabled. - * Trying to release a unallocated channel is an illegal operation + * @brief Releases a DMA stream. + * @details The stream is freed and, if required, the DMA clock disabled. + * Trying to release a unallocated stream is an illegal operation * and is trapped if assertions are enabled. - * @pre The channel must have been allocated using @p dmaRequest(). - * @post The channel is again available. + * @pre The stream must have been allocated using @p dmaStreamAllocate(). + * @post The stream is again available. * @note This function can be invoked in both ISR or thread context. * - * @param[in] dma DMA controller id - * @param[in] channel requested channel id + * @param[in] dmastp pointer to a stm32_dma_stream_t structure * * @special */ -void dmaRelease(uint32_t dma, uint32_t channel) { +void dmaStreamRelease(const stm32_dma_stream_t *dmastp) { + chDbgCheck(dmastp != NULL, "dmaRelease"); + + /* Check if the streams is not taken.*/ + chDbgAssert((dma_streams_mask & (1 << dmastp->selfindex)) != 0, + "dmaRelease(), #1", "not allocated"); + + /* Disables the associated IRQ vector.*/ + NVICDisableVector(dmastp->vector); + + /* Marks the stream as not allocated.*/ + dma_streams_mask &= ~(1 << dmastp->selfindex); + + /* Shutting down clocks that are no more required, if any.*/ + if ((dma_streams_mask & STM32_DMA1_STREAMS_MASK) == 0) + RCC->AHBENR &= ~RCC_AHBENR_DMA1EN; #if STM32_HAS_DMA2 - switch (dma) { - case STM32_DMA1_ID: -#else - (void)dma; -#endif - /* Check if the channel is not taken.*/ - chDbgAssert((dmamsk1 & (1 << channel)) != 0, - "dmaRelease(), #1", "not allocated"); - - dma1[channel].dmaisrfunc = NULL; - dmamsk1 &= ~(1 << channel); - if (dmamsk1 == 0) - RCC->AHBENR &= ~RCC_AHBENR_DMA1EN; -#if STM32_HAS_DMA2 - break; - case STM32_DMA2_ID: - /* Check if the channel is not taken.*/ - chDbgAssert((dmamsk2 & (1 << channel)) != 0, - "dmaRelease(), #2", "not allocated"); - - dma2[channel].dmaisrfunc = NULL; - dmamsk2 &= ~(1 << channel); - if (dmamsk2 == 0) - RCC->AHBENR &= ~RCC_AHBENR_DMA2EN; - break; - } + if ((dma_streams_mask & STM32_DMA2_STREAMS_MASK) == 0) + RCC->AHBENR &= ~RCC_AHBENR_DMA2EN; #endif } diff --git a/os/hal/platforms/STM32/DMAv1/stm32_dma.h b/os/hal/platforms/STM32/DMAv1/stm32_dma.h index 5ee06e939..0247c63cf 100644 --- a/os/hal/platforms/STM32/DMAv1/stm32_dma.h +++ b/os/hal/platforms/STM32/DMAv1/stm32_dma.h @@ -20,9 +20,11 @@ /** * @file DMAv1/stm32_dma.h - * @brief STM32 DMA helper driver header. - * @note This file requires definitions from the ST STM32 header file - * stm32f10x.h. + * @brief DMA helper driver header. + * @note This file requires definitions from the ST header files + * stm32f10x.h or stm32l1xx.h. + * @note This driver uses the new naming convention used for the STM32F2xx + * so the "DMA channels" are referred as "DMA streams". * * @addtogroup STM32_DMA * @{ @@ -35,14 +37,81 @@ /* Driver constants. */ /*===========================================================================*/ -/** @brief DMA1 identifier.*/ -#define STM32_DMA1_ID 0 - -/** @brief DMA2 identifier.*/ +/** + * @brief Total number of DMA streams. + * @note This is the total number of streams among all the DMA units. + */ #if STM32_HAS_DMA2 || defined(__DOXYGEN__) -#define STM32_DMA2_ID 1 +#define STM32_DMA_STREAMS 12 +#else +#define STM32_DMA_STREAMS 7 #endif +/** + * @brief Mask of the ISR bits passed to the DMA callback functions. + */ +#define STM32_DMA_ISR_MASK 0x0F + +/** + * @name DMA streams identifiers + * @{ + */ +#define STM32_DMA1_STREAM1 (&_stm32_dma_streams[0]) +#define STM32_DMA1_STREAM2 (&_stm32_dma_streams[1]) +#define STM32_DMA1_STREAM3 (&_stm32_dma_streams[2]) +#define STM32_DMA1_STREAM4 (&_stm32_dma_streams[3]) +#define STM32_DMA1_STREAM5 (&_stm32_dma_streams[4]) +#define STM32_DMA1_STREAM6 (&_stm32_dma_streams[5]) +#define STM32_DMA1_STREAM7 (&_stm32_dma_streams[6]) +#define STM32_DMA2_STREAM1 (&_stm32_dma_streams[8]) +#define STM32_DMA2_STREAM2 (&_stm32_dma_streams[9]) +#define STM32_DMA2_STREAM3 (&_stm32_dma_streams[10]) +#define STM32_DMA2_STREAM4 (&_stm32_dma_streams[11]) +#define STM32_DMA2_STREAM5 (&_stm32_dma_streams[12]) +/** @} */ + +/** + * @name CR register constants common to all DMA types + */ +#define STM32_DMA_CR_EN DMA_CCR1_EN +#define STM32_DMA_CR_TEIE DMA_CCR1_TEIE +#define STM32_DMA_CR_HTIE DMA_CCR1_HTIE +#define STM32_DMA_CR_TCIE DMA_CCR1_TCIE +#define STM32_DMA_CR_DIR_MASK (DMA_CCR1_DIR | DMA_CCR1_MEM2MEM) +#define STM32_DMA_CR_DIR_P2M 0 +#define STM32_DMA_CR_DIR_M2P DMA_CCR1_DIR +#define STM32_DMA_CR_DIR_M2M DMA_CCR1_MEM2MEM +#define STM32_DMA_CR_CIRC DMA_CCR1_CIRC +#define STM32_DMA_CR_PINC DMA_CCR1_PINC +#define STM32_DMA_CR_MINC DMA_CCR1_MINC +#define STM32_DMA_CR_PSIZE_MASK DMA_CCR1_PSIZE +#define STM32_DMA_CR_PSIZE_BYTE 0 +#define STM32_DMA_CR_PSIZE_HWORD DMA_CCR1_PSIZE_0 +#define STM32_DMA_CR_PSIZE_WORD DMA_CCR1_PSIZE_1 +#define STM32_DMA_CR_MSIZE_MASK DMA_CCR1_MSIZE +#define STM32_DMA_CR_MSIZE_BYTE 0 +#define STM32_DMA_CR_MSIZE_HWORD DMA_CCR1_MSIZE_0 +#define STM32_DMA_CR_MSIZE_WORD DMA_CCR1_MSIZE_1 +#define STM32_DMA_CR_PL_MASK DMA_CCR1_PL +#define STM32_DMA_CR_PL(n) ((n) << 12) +/** @} */ +/** + * @name CR register constants only found in enhanced DMA + */ +#define STM32_DMA_CR_CHSEL_MASK 0 /**< @brief Ignored by normal DMA. */ +#define STM32_DMA_CR_CHSEL(n) 0 /**< @brief Ignored by normal DMA. */ +/** @} */ + +/** + * @name Status flags passed to the ISR callbacks + */ +#define STM32_DMA_ISR_FEIF 0 +#define STM32_DMA_ISR_DMEIF 0 +#define STM32_DMA_ISR_TEIF DMA_ISR_TEIF1 +#define STM32_DMA_ISR_HTIF DMA_ISR_HTIF1 +#define STM32_DMA_ISR_TCIF DMA_ISR_TCIF1 +/** @} */ + /*===========================================================================*/ /* Driver pre-compile time settings. */ /*===========================================================================*/ @@ -56,33 +125,23 @@ /*===========================================================================*/ /** - * @brief STM32 DMA channel memory structure type. - */ -typedef struct { - volatile uint32_t CCR; - volatile uint32_t CNDTR; - volatile uint32_t CPAR; - volatile uint32_t CMAR; - volatile uint32_t dummy; -} stm32_dma_channel_t; - -/** - * @brief STM32 DMA subsystem memory structure type. - * @note This structure has been redefined here because it is convenient to - * have the channels organized as an array, the ST header does not - * do that. + * @brief STM32 DMA stream descriptor structure. */ typedef struct { - volatile uint32_t ISR; - volatile uint32_t IFCR; - stm32_dma_channel_t channels[7]; -} stm32_dma_t; + DMA_Channel_TypeDef *channel; /**< @brief Associated DMA channel. */ + volatile uint32_t *ifcr; /**< @brief Associated IFCR reg. */ + uint8_t ishift; /**< @brief Bits offset in xIFCR + register. */ + uint8_t selfindex; /**< @brief Index to self in array. */ + uint8_t vector; /**< @brief Associated IRQ vector. */ +} stm32_dma_stream_t; /** * @brief STM32 DMA ISR function type. * * @param[in] p parameter for the registered function - * @param[in] flags pre-shifted content of the ISR register + * @param[in] flags pre-shifted content of the ISR register, the bits + * are aligned to bit zero */ typedef void (*stm32_dmaisr_t)(void *p, uint32_t flags); @@ -90,186 +149,122 @@ typedef void (*stm32_dmaisr_t)(void *p, uint32_t flags); /* Driver macros. */ /*===========================================================================*/ -/** DMA1 registers block numeric address.*/ -#define STM32_DMA1_BASE (AHBPERIPH_BASE + 0x0000) -/** Pointer to the DMA1 registers block.*/ -#define STM32_DMA1 ((stm32_dma_t *)STM32_DMA1_BASE) -/** Pointer to the DMA1 channel 1 registers block.*/ -#define STM32_DMA1_CH1 (&STM32_DMA1->channels[0]) -/** Pointer to the DMA1 channel 2 registers block.*/ -#define STM32_DMA1_CH2 (&STM32_DMA1->channels[1]) -/** Pointer to the DMA1 channel 3 registers block.*/ -#define STM32_DMA1_CH3 (&STM32_DMA1->channels[2]) -/** Pointer to the DMA1 channel 4 registers block.*/ -#define STM32_DMA1_CH4 (&STM32_DMA1->channels[3]) -/** Pointer to the DMA1 channel 5 registers block.*/ -#define STM32_DMA1_CH5 (&STM32_DMA1->channels[4]) -/** Pointer to the DMA1 channel 6 registers block.*/ -#define STM32_DMA1_CH6 (&STM32_DMA1->channels[5]) -/** Pointer to the DMA1 channel 7 registers block.*/ -#define STM32_DMA1_CH7 (&STM32_DMA1->channels[6]) - -#if STM32_HAS_DMA2 || defined(__DOXYGEN__) -/** DMA2 registers block numeric address.*/ -#define STM32_DMA2_BASE (AHBPERIPH_BASE + 0x0400) -/** Pointer to the DMA2 registers block.*/ -#define STM32_DMA2 ((stm32_dma_t *)STM32_DMA2_BASE) -/** Pointer to the DMA2 channel 1 registers block.*/ -#define STM32_DMA2_CH1 (&STM32_DMA2->channels[0]) -/** Pointer to the DMA2 channel 2 registers block.*/ -#define STM32_DMA2_CH2 (&STM32_DMA2->channels[1]) -/** Pointer to the DMA2 channel 3 registers block.*/ -#define STM32_DMA2_CH3 (&STM32_DMA2->channels[2]) -/** Pointer to the DMA2 channel 4 registers block.*/ -#define STM32_DMA2_CH4 (&STM32_DMA2->channels[3]) -/** Pointer to the DMA2 channel 5 registers block.*/ -#define STM32_DMA2_CH5 (&STM32_DMA2->channels[4]) -#endif - -#define STM32_DMA_CHANNEL_1 0 /**< @brief DMA channel 1. */ -#define STM32_DMA_CHANNEL_2 1 /**< @brief DMA channel 2. */ -#define STM32_DMA_CHANNEL_3 2 /**< @brief DMA channel 3. */ -#define STM32_DMA_CHANNEL_4 3 /**< @brief DMA channel 4. */ -#define STM32_DMA_CHANNEL_5 4 /**< @brief DMA channel 5. */ -#define STM32_DMA_CHANNEL_6 5 /**< @brief DMA channel 6. */ -#define STM32_DMA_CHANNEL_7 6 /**< @brief DMA channel 7. */ - /** - * @brief Associates a peripheral data register to a DMA channel. + * @brief Associates a peripheral data register to a DMA stream. * @note This function can be invoked in both ISR or thread context. * - * @param[in] dmachp dmachp to a stm32_dma_channel_t structure - * @param[in] cpar value to be written in the CPAR register + * @param[in] dmastp pointer to a stm32_dma_stream_t structure + * @param[in] addr value to be written in the CPAR register * * @special */ -#define dmaChannelSetPeripheral(dmachp, cpar) { \ - (dmachp)->CPAR = (uint32_t)(cpar); \ +#define dmaStreamSetPeripheral(dmastp, addr) { \ + (dmastp)->channel->CPAR = (uint32_t)(addr); \ } /** - * @brief DMA channel setup by channel pointer. - * @note This macro does not change the CPAR register because that register - * value does not change frequently, it usually points to a peripheral - * data register. + * @brief Associates a memory destination to a DMA stream. * @note This function can be invoked in both ISR or thread context. * - * @param[in] dmachp pointer to a stm32_dma_channel_t structure - * @param[in] cndtr value to be written in the CNDTR register - * @param[in] cmar value to be written in the CMAR register - * @param[in] ccr value to be written in the CCR register + * @param[in] dmastp pointer to a stm32_dma_stream_t structure + * @param[in] addr value to be written in the CMAR register * * @special */ -#define dmaChannelSetup(dmachp, cndtr, cmar, ccr) { \ - (dmachp)->CNDTR = (uint32_t)(cndtr); \ - (dmachp)->CMAR = (uint32_t)(cmar); \ - (dmachp)->CCR = (uint32_t)(ccr); \ +#define dmaStreamSetMemory0(dmastp, addr) { \ + (dmastp)->channel->CMAR = (uint32_t)(addr); \ } /** - * @brief DMA channel enable by channel pointer. + * @brief Sets the number of transfers to be performed. * @note This function can be invoked in both ISR or thread context. * - * @param[in] dmachp pointer to a stm32_dma_channel_t structure + * @param[in] dmastp pointer to a stm32_dma_stream_t structure + * @param[in] size value to be written in the CNDTR register * * @special */ -#define dmaChannelEnable(dmachp) { \ - (dmachp)->CCR |= DMA_CCR1_EN; \ +#define dmaStreamSetTransactionSize(dmastp, size) { \ + (dmastp)->channel->CNDTR = (uint32_t)(size); \ } /** - * @brief DMA channel disable by channel pointer. + * @brief Returns the number of transfers to be performed. * @note This function can be invoked in both ISR or thread context. * - * @param[in] dmachp pointer to a stm32_dma_channel_t structure + * @param[in] dmastp pointer to a stm32_dma_stream_t structure + * @return The number of transfers to be performed. * * @special */ -#define dmaChannelDisable(dmachp) { \ - (dmachp)->CCR = 0; \ -} +#define dmaStreamGetTransactionSize(dmastp) ((size_t)((dmastp)->channel->CNDTR)) /** - * @brief DMA channel setup by channel ID. - * @note This macro does not change the CPAR register because that register - * value does not change frequently, it usually points to a peripheral - * data register. - * @note Channels are numbered from 0 to 6, use the appropriate macro - * as parameter. + * @brief Programs the stream mode settings. * @note This function can be invoked in both ISR or thread context. * - * @param[in] dmap pointer to a stm32_dma_t structure - * @param[in] ch channel number - * @param[in] cndtr value to be written in the CNDTR register - * @param[in] cmar value to be written in the CMAR register - * @param[in] ccr value to be written in the CCR register + * @param[in] dmastp pointer to a stm32_dma_stream_t structure + * @param[in] mode value to be written in the CCR register * * @special */ -#define dmaSetupChannel(dmap, ch, cndtr, cmar, ccr) { \ - dmaChannelSetup(&(dmap)->channels[ch], (cndtr), (cmar), (ccr)); \ +#define dmaStreamSetMode(dmastp, mode) { \ + (dmastp)->channel->CCR = (uint32_t)(mode); \ } /** - * @brief DMA channel enable by channel ID. - * @note Channels are numbered from 0 to 6, use the appropriate macro - * as parameter. + * @brief DMA stream enable. * @note This function can be invoked in both ISR or thread context. * - * @param[in] dmap pointer to a stm32_dma_t structure - * @param[in] ch channel number + * @param[in] dmachp pointer to a stm32_dma_stream_t structure * * @special */ -#define dmaEnableChannel(dmap, ch) { \ - dmaChannelEnable(&(dmap)->channels[ch]); \ +#define dmaStreamEnable(dmastp) { \ + (dmastp)->channel->CCR |= STM32_DMA_CR_EN; \ } /** - * @brief DMA channel disable by channel ID. - * @note Channels are numbered from 0 to 6, use the appropriate macro - * as parameter. + * @brief DMA stream disable. * @note This function can be invoked in both ISR or thread context. * - * @param[in] dmap pointer to a stm32_dma_t structure - * @param[in] ch channel number + * @param[in] dmastp pointer to a stm32_dma_stream_t structure * * @special */ -#define dmaDisableChannel(dmap, ch) { \ - dmaChannelDisable(&(dmap)->channels[ch]); \ +#define dmaStreamDisable(dmastp) { \ + (dmastp)->channel->CCR &= ~STM32_DMA_CR_EN; \ } /** - * @brief DMA channel interrupt sources clear. - * @details Sets the appropriate CGIF bit into the IFCR register in order to - * withdraw all the pending interrupt bits from the ISR register. - * @note Channels are numbered from 0 to 6, use the appropriate macro - * as parameter. + * @brief DMA stream interrupt sources clear. * @note This function can be invoked in both ISR or thread context. * - * @param[in] dmap pointer to a stm32_dma_t structure - * @param[in] ch channel number + * @param[in] dmastp pointer to a stm32_dma_stream_t structure * * @special */ -#define dmaClearChannel(dmap, ch) { \ - (dmap)->IFCR = 1 << ((ch) * 4); \ +#define dmaStreamClearInterrupt(dmastp) { \ + *(dmastp)->ifcr = STM32_DMA_ISR_MASK << (dmastp)->ishift; \ } /*===========================================================================*/ /* External declarations. */ /*===========================================================================*/ +#if !defined(__DOXYGEN__) +extern const stm32_dma_stream_t _stm32_dma_streams[STM32_DMA_STREAMS]; +#endif + #ifdef __cplusplus extern "C" { #endif void dmaInit(void); - void dmaAllocate(uint32_t dma, uint32_t channel, - stm32_dmaisr_t func, void *param); - void dmaRelease(uint32_t dma, uint32_t channel); + bool_t dmaStreamAllocate(const stm32_dma_stream_t *dmastp, + uint32_t priority, + stm32_dmaisr_t func, + void *param); + void dmaStreamRelease(const stm32_dma_stream_t *dmastp); #ifdef __cplusplus } #endif -- cgit v1.2.3