From e7e79a6ccb4f3e320b2b8b7bad1b14d65218641d Mon Sep 17 00:00:00 2001 From: gdisirio Date: Fri, 18 Mar 2011 18:38:08 +0000 Subject: License updated. git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@2827 35acf78f-673a-0410-8e92-d51de3d6d3f4 --- os/hal/platforms/STM32/stm32_dma.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'os/hal/platforms/STM32/stm32_dma.c') diff --git a/os/hal/platforms/STM32/stm32_dma.c b/os/hal/platforms/STM32/stm32_dma.c index e25e05ad1..be7833777 100644 --- a/os/hal/platforms/STM32/stm32_dma.c +++ b/os/hal/platforms/STM32/stm32_dma.c @@ -1,5 +1,6 @@ /* - ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010 Giovanni Di Sirio. + ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010, + 2011 Giovanni Di Sirio. This file is part of ChibiOS/RT. -- cgit v1.2.3 From 618a978da8f1b570236914e034fb91aa980b9ffc Mon Sep 17 00:00:00 2001 From: gdisirio Date: Sun, 10 Apr 2011 16:45:41 +0000 Subject: Added DMA sharing in the STM32 HAL. git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@2874 35acf78f-673a-0410-8e92-d51de3d6d3f4 --- os/hal/platforms/STM32/stm32_dma.c | 361 ++++++++++++++++++++++++++++++++++--- 1 file changed, 334 insertions(+), 27 deletions(-) (limited to 'os/hal/platforms/STM32/stm32_dma.c') diff --git a/os/hal/platforms/STM32/stm32_dma.c b/os/hal/platforms/STM32/stm32_dma.c index be7833777..023f2fdd3 100644 --- a/os/hal/platforms/STM32/stm32_dma.c +++ b/os/hal/platforms/STM32/stm32_dma.c @@ -23,23 +23,43 @@ * @brief STM32 DMA helper driver code. * * @addtogroup STM32_DMA + * @details DMA sharing helper driver. In the STM32 the DMA channels are a + * shared resource, this driver allows to allocate and free DMA + * channels 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. * @{ */ #include "ch.h" #include "hal.h" +#if defined(STM32_DMA_REQUIRED) || defined(__DOXYGEN__) + /*===========================================================================*/ /* Driver exported variables. */ /*===========================================================================*/ /*===========================================================================*/ -/* Driver local variables. */ +/* Driver local variables and types. */ /*===========================================================================*/ -static cnt_t dmacnt1; +/** + * @brief DMA ISR redirector type. + */ +typedef struct { + stm32_dmaisr_t dmaisrfunc; + void *dmaisrparam; +} dma_isr_redir_t; + +static uint32_t dmamsk1; +static dma_isr_redir_t dma1[7]; + #if STM32_HAS_DMA2 -static cnt_t dmacnt2; +static uint32_t dmamsk2; +static dma_isr_redir_t dma2[5]; #endif /*===========================================================================*/ @@ -50,6 +70,224 @@ static cnt_t dmacnt2; /* Driver interrupt handlers. */ /*===========================================================================*/ +/** + * @brief DMA1 channel 1 shared interrupt handler. + * + * @isr + */ +CH_IRQ_HANDLER(DMA1_Ch1_IRQHandler) { + uint32_t isr; + + 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); + + CH_IRQ_EPILOGUE(); +} + +/** + * @brief DMA1 channel 2 shared interrupt handler. + * + * @isr + */ +CH_IRQ_HANDLER(DMA1_Ch2_IRQHandler) { + uint32_t isr; + + 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); + + CH_IRQ_EPILOGUE(); +} + +/** + * @brief DMA1 channel 3 shared interrupt handler. + * + * @isr + */ +CH_IRQ_HANDLER(DMA1_Ch3_IRQHandler) { + uint32_t isr; + + 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); + + CH_IRQ_EPILOGUE(); +} + +/** + * @brief DMA1 channel 4 shared interrupt handler. + * + * @isr + */ +CH_IRQ_HANDLER(DMA1_Ch4_IRQHandler) { + uint32_t isr; + + 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); + + CH_IRQ_EPILOGUE(); +} + +/** + * @brief DMA1 channel 5 shared interrupt handler. + * + * @isr + */ +CH_IRQ_HANDLER(DMA1_Ch5_IRQHandler) { + uint32_t isr; + + 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); + + CH_IRQ_EPILOGUE(); +} + +/** + * @brief DMA1 channel 6 shared interrupt handler. + * + * @isr + */ +CH_IRQ_HANDLER(DMA1_Ch6_IRQHandler) { + uint32_t isr; + + 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); + + CH_IRQ_EPILOGUE(); +} + +/** + * @brief DMA1 channel 7 shared interrupt handler. + * + * @isr + */ +CH_IRQ_HANDLER(DMA1_Ch7_IRQHandler) { + uint32_t isr; + + 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); + + CH_IRQ_EPILOGUE(); +} + +#if STM32_HAS_DMA2 || defined(__DOXYGEN__) +/** + * @brief DMA2 channel 1 shared interrupt handler. + * + * @isr + */ +CH_IRQ_HANDLER(DMA2_Ch1_IRQHandler) { + uint32_t isr; + + 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); + + CH_IRQ_EPILOGUE(); +} + +/** + * @brief DMA2 channel 2 shared interrupt handler. + * + * @isr + */ +CH_IRQ_HANDLER(DMA2_Ch2_IRQHandler) { + uint32_t isr; + + 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); + + CH_IRQ_EPILOGUE(); +} + +/** + * @brief DMA2 channel 3 shared interrupt handler. + * + * @isr + */ +CH_IRQ_HANDLER(DMA2_Ch3_IRQHandler) { + uint32_t isr; + + 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); + + CH_IRQ_EPILOGUE(); +} + +/** + * @brief DMA2 channel 4 shared interrupt handler. + * + * @isr + */ +CH_IRQ_HANDLER(DMA2_Ch4_IRQHandler) { + uint32_t isr; + + 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); + + CH_IRQ_EPILOGUE(); +} + +/** + * @brief DMA2 channel 5 shared interrupt handler. + * + * @isr + */ +CH_IRQ_HANDLER(DMA2_Ch5_IRQHandler) { + uint32_t isr; + + 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); + + CH_IRQ_EPILOGUE(); +} +#endif /* STM32_HAS_DMA2 */ + /*===========================================================================*/ /* Driver exported functions. */ /*===========================================================================*/ @@ -62,66 +300,135 @@ static cnt_t dmacnt2; void dmaInit(void) { int i; - dmacnt1 = 0; - for (i = STM32_DMA_CHANNEL_7; i >= STM32_DMA_CHANNEL_1; i--) + dmamsk1 = 0; + for (i = STM32_DMA_CHANNEL_7; i >= STM32_DMA_CHANNEL_1; i--) { dmaDisableChannel(STM32_DMA1, i); + dma1[i].dmaisrfunc = NULL; + } STM32_DMA1->IFCR = 0xFFFFFFFF; #if STM32_HAS_DMA2 - dmacnt2 = 0; - for (i = STM32_DMA_CHANNEL_5; i >= STM32_DMA_CHANNEL_1; i--) + 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; #endif } /** - * @brief Enables the specified DMA controller clock. + * @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 + * to the specified function. + * @post The channel must be freed using @p dmaRelease() before it can + * be reused with another peripheral. + * @note This function can be invoked in both ISR or thread context. * - * @param[in] dma the DMA controller id + * @param[in] dma DMA controller id + * @param[in] channel requested channel id + * @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 operation successfully allocated. + * @retval TRUE the channel was already in use. * - * @api + * @special */ -void dmaEnable(uint32_t dma) { +void dmaAllocate(uint32_t dma, uint32_t channel, + stm32_dmaisr_t func, void *param) { + chDbgCheck(func != NULL, "dmaAllocate"); + +#if STM32_HAS_DMA2 switch (dma) { - case DMA1_ID: - if (dmacnt1++ == 0) { + 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; } - break; + + dmamsk1 |= 1 << channel; + dma1[channel].dmaisrfunc = func; + dma1[channel].dmaisrparam = param; #if STM32_HAS_DMA2 - case DMA2_ID: - if (dmacnt2++ == 0) { + 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 (dmamsk1 == 0) { RCC->AHBENR |= RCC_AHBENR_DMA2EN; DMA2->IFCR = 0x0FFFFFFF; } + + dmamsk2 |= 1 << channel; + dma2[channel].dmaisrfunc = func; + dma2[channel].dmaisrparam = param; break; -#endif } +#endif } /** - * @brief Disables the specified DMA controller clock. + * @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 + * and is trapped if assertions are enabled. + * @pre The channel must have been allocated using @p dmaRequest(). + * @post The channel is again available. + * @note This function can be invoked in both ISR or thread context. * - * @param[in] dma the DMA controller id + * @param[in] dma DMA controller id + * @param[in] channel requested channel id * - * @api + * @special */ -void dmaDisable(uint32_t dma) { +void dmaRelease(uint32_t dma, uint32_t channel) { +#if STM32_HAS_DMA2 switch (dma) { - case DMA1_ID: - if (--dmacnt1 == 0) + 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; - break; #if STM32_HAS_DMA2 - case DMA2_ID: - if (--dmacnt2 == 0) + 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; -#endif } +#endif } +#endif /* STM32_DMA_REQUIRED */ + /** @} */ -- cgit v1.2.3 From b381c928c7b9e08d0594395e532aeeed6cdc6a2b Mon Sep 17 00:00:00 2001 From: gdisirio Date: Tue, 10 May 2011 18:37:26 +0000 Subject: git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@2947 35acf78f-673a-0410-8e92-d51de3d6d3f4 --- os/hal/platforms/STM32/stm32_dma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'os/hal/platforms/STM32/stm32_dma.c') diff --git a/os/hal/platforms/STM32/stm32_dma.c b/os/hal/platforms/STM32/stm32_dma.c index 023f2fdd3..621659a0b 100644 --- a/os/hal/platforms/STM32/stm32_dma.c +++ b/os/hal/platforms/STM32/stm32_dma.c @@ -370,7 +370,7 @@ void dmaAllocate(uint32_t dma, uint32_t channel, "dmaAllocate(), #2", "already allocated"); /* If the DMA unit was idle then the clock is enabled.*/ - if (dmamsk1 == 0) { + if (dmamsk2 == 0) { RCC->AHBENR |= RCC_AHBENR_DMA2EN; DMA2->IFCR = 0x0FFFFFFF; } -- cgit v1.2.3 From 16feb88c2dc82420390b56226e8fe7cbc49aeb3b Mon Sep 17 00:00:00 2001 From: gdisirio Date: Fri, 13 May 2011 09:03:46 +0000 Subject: Fixed STM8S SPI driver. Fixed STM32 DMA2 channels 4 and 5 sharing. git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@2949 35acf78f-673a-0410-8e92-d51de3d6d3f4 --- os/hal/platforms/STM32/stm32_dma.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) (limited to 'os/hal/platforms/STM32/stm32_dma.c') diff --git a/os/hal/platforms/STM32/stm32_dma.c b/os/hal/platforms/STM32/stm32_dma.c index 621659a0b..2232df448 100644 --- a/os/hal/platforms/STM32/stm32_dma.c +++ b/os/hal/platforms/STM32/stm32_dma.c @@ -251,6 +251,7 @@ CH_IRQ_HANDLER(DMA2_Ch3_IRQHandler) { CH_IRQ_EPILOGUE(); } +#if defined(STM32F10X_CL) || defined(__DOXYGEN__) /** * @brief DMA2 channel 4 shared interrupt handler. * @@ -286,6 +287,39 @@ CH_IRQ_HANDLER(DMA2_Ch5_IRQHandler) { CH_IRQ_EPILOGUE(); } + +#else /* !STM32F10X_CL */ +/** + * @brief DMA2 channels 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; + + 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); + } + + /* 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); + } + + CH_IRQ_EPILOGUE(); +} +#endif /* !STM32F10X_CL */ #endif /* STM32_HAS_DMA2 */ /*===========================================================================*/ -- cgit v1.2.3