From 5cbe3a8aad4f44ccee64c309836901b0a33f4bb6 Mon Sep 17 00:00:00 2001 From: Giovanni Di Sirio Date: Tue, 4 Aug 2015 15:22:57 +0000 Subject: [PATCH] STM32 DMAv2 driver added. git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@8156 35acf78f-673a-0410-8e92-d51de3d6d3f4 --- os/hal/ports/STM32/LLD/DMAv2/stm32_dma.c | 532 ++++++++++++++++++ os/hal/ports/STM32/LLD/DMAv2/stm32_dma.h | 459 +++++++++++++++ os/hal/ports/STM32/LLD/USARTv2/serial_lld.c | 2 +- os/hal/ports/STM32/LLD/USARTv2/uart_lld.c | 13 + os/hal/ports/STM32/STM32F7xx/hal_lld.h | 2 +- os/hal/ports/STM32/STM32F7xx/platform.mk | 3 +- os/hal/ports/STM32/STM32F7xx/stm32_registry.h | 34 ++ readme.txt | 5 +- 8 files changed, 1044 insertions(+), 6 deletions(-) create mode 100644 os/hal/ports/STM32/LLD/DMAv2/stm32_dma.c create mode 100644 os/hal/ports/STM32/LLD/DMAv2/stm32_dma.h diff --git a/os/hal/ports/STM32/LLD/DMAv2/stm32_dma.c b/os/hal/ports/STM32/LLD/DMAv2/stm32_dma.c new file mode 100644 index 000000000..9e8d31bc8 --- /dev/null +++ b/os/hal/ports/STM32/LLD/DMAv2/stm32_dma.c @@ -0,0 +1,532 @@ +/* + ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file DMAv2/stm32_dma.c + * @brief Enhanced DMA helper driver code. + * + * @addtogroup STM32_DMA + * @details DMA sharing helper driver. In the STM32 the DMA streams are a + * shared resource, this driver allows to allocate and free DMA + * 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 + * ISRs when allocating streams. + * @{ + */ + +#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 0x000000FFU + +/** + * @brief Mask of the DMA2 streams in @p dma_streams_mask. + */ +#define STM32_DMA2_STREAMS_MASK 0x0000FF00U + +/** + * @brief Post-reset value of the stream CR register. + */ +#define STM32_DMA_CR_RESET_VALUE 0x00000000U + +/** + * @brief Post-reset value of the stream FCR register. + */ +#define STM32_DMA_FCR_RESET_VALUE 0x00000021U + +/*===========================================================================*/ +/* 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_STREAM0, @p STM32_DMA1_STREAM1 etc. + */ +const stm32_dma_stream_t _stm32_dma_streams[STM32_DMA_STREAMS] = { + {DMA1_Stream0, &DMA1->LIFCR, 0, 0, STM32_DMA1_CH0_NUMBER}, + {DMA1_Stream1, &DMA1->LIFCR, 6, 1, STM32_DMA1_CH1_NUMBER}, + {DMA1_Stream2, &DMA1->LIFCR, 16, 2, STM32_DMA1_CH2_NUMBER}, + {DMA1_Stream3, &DMA1->LIFCR, 22, 3, STM32_DMA1_CH3_NUMBER}, + {DMA1_Stream4, &DMA1->HIFCR, 0, 4, STM32_DMA1_CH4_NUMBER}, + {DMA1_Stream5, &DMA1->HIFCR, 6, 5, STM32_DMA1_CH5_NUMBER}, + {DMA1_Stream6, &DMA1->HIFCR, 16, 6, STM32_DMA1_CH6_NUMBER}, + {DMA1_Stream7, &DMA1->HIFCR, 22, 7, STM32_DMA1_CH7_NUMBER}, + {DMA2_Stream0, &DMA2->LIFCR, 0, 8, STM32_DMA2_CH0_NUMBER}, + {DMA2_Stream1, &DMA2->LIFCR, 6, 9, STM32_DMA2_CH1_NUMBER}, + {DMA2_Stream2, &DMA2->LIFCR, 16, 10, STM32_DMA2_CH2_NUMBER}, + {DMA2_Stream3, &DMA2->LIFCR, 22, 11, STM32_DMA2_CH3_NUMBER}, + {DMA2_Stream4, &DMA2->HIFCR, 0, 12, STM32_DMA2_CH4_NUMBER}, + {DMA2_Stream5, &DMA2->HIFCR, 6, 13, STM32_DMA2_CH5_NUMBER}, + {DMA2_Stream6, &DMA2->HIFCR, 16, 14, STM32_DMA2_CH6_NUMBER}, + {DMA2_Stream7, &DMA2->HIFCR, 22, 15, STM32_DMA2_CH7_NUMBER}, +}; + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/** + * @brief DMA ISR redirector type. + */ +typedef struct { + stm32_dmaisr_t dma_func; /**< @brief DMA callback function. */ + void *dma_param; /**< @brief DMA callback parameter. */ +} dma_isr_redir_t; + +/** + * @brief Mask of the allocated streams. + */ +static uint32_t dma_streams_mask; + +/** + * @brief DMA IRQ redirectors. + */ +static dma_isr_redir_t dma_isr_redir[STM32_DMA_STREAMS]; + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +/** + * @brief DMA1 stream 0 shared interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_DMA1_CH0_HANDLER) { + uint32_t flags; + + OSAL_IRQ_PROLOGUE(); + + flags = (DMA1->LISR >> 0U) & STM32_DMA_ISR_MASK; + DMA1->LIFCR = flags << 0U; + if (dma_isr_redir[0].dma_func) + dma_isr_redir[0].dma_func(dma_isr_redir[0].dma_param, flags); + + OSAL_IRQ_EPILOGUE(); +} + +/** + * @brief DMA1 stream 1 shared interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_DMA1_CH1_HANDLER) { + uint32_t flags; + + OSAL_IRQ_PROLOGUE(); + + flags = (DMA1->LISR >> 6U) & STM32_DMA_ISR_MASK; + DMA1->LIFCR = flags << 6U; + if (dma_isr_redir[1].dma_func) + dma_isr_redir[1].dma_func(dma_isr_redir[1].dma_param, flags); + + OSAL_IRQ_EPILOGUE(); +} + +/** + * @brief DMA1 stream 2 shared interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_DMA1_CH2_HANDLER) { + uint32_t flags; + + OSAL_IRQ_PROLOGUE(); + + flags = (DMA1->LISR >> 16U) & STM32_DMA_ISR_MASK; + DMA1->LIFCR = flags << 16U; + if (dma_isr_redir[2].dma_func) + dma_isr_redir[2].dma_func(dma_isr_redir[2].dma_param, flags); + + OSAL_IRQ_EPILOGUE(); +} + +/** + * @brief DMA1 stream 3 shared interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_DMA1_CH3_HANDLER) { + uint32_t flags; + + OSAL_IRQ_PROLOGUE(); + + flags = (DMA1->LISR >> 22U) & STM32_DMA_ISR_MASK; + DMA1->LIFCR = flags << 22U; + if (dma_isr_redir[3].dma_func) + dma_isr_redir[3].dma_func(dma_isr_redir[3].dma_param, flags); + + OSAL_IRQ_EPILOGUE(); +} + +/** + * @brief DMA1 stream 4 shared interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_DMA1_CH4_HANDLER) { + uint32_t flags; + + OSAL_IRQ_PROLOGUE(); + + flags = (DMA1->HISR >> 0U) & STM32_DMA_ISR_MASK; + DMA1->HIFCR = flags << 0U; + if (dma_isr_redir[4].dma_func) + dma_isr_redir[4].dma_func(dma_isr_redir[4].dma_param, flags); + + OSAL_IRQ_EPILOGUE(); +} + +/** + * @brief DMA1 stream 5 shared interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_DMA1_CH5_HANDLER) { + uint32_t flags; + + OSAL_IRQ_PROLOGUE(); + + flags = (DMA1->HISR >> 6U) & STM32_DMA_ISR_MASK; + DMA1->HIFCR = flags << 6U; + if (dma_isr_redir[5].dma_func) + dma_isr_redir[5].dma_func(dma_isr_redir[5].dma_param, flags); + + OSAL_IRQ_EPILOGUE(); +} + +/** + * @brief DMA1 stream 6 shared interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_DMA1_CH6_HANDLER) { + uint32_t flags; + + OSAL_IRQ_PROLOGUE(); + + flags = (DMA1->HISR >> 16U) & STM32_DMA_ISR_MASK; + DMA1->HIFCR = flags << 16U; + if (dma_isr_redir[6].dma_func) + dma_isr_redir[6].dma_func(dma_isr_redir[6].dma_param, flags); + + OSAL_IRQ_EPILOGUE(); +} + +/** + * @brief DMA1 stream 7 shared interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_DMA1_CH7_HANDLER) { + uint32_t flags; + + OSAL_IRQ_PROLOGUE(); + + flags = (DMA1->HISR >> 22U) & STM32_DMA_ISR_MASK; + DMA1->HIFCR = flags << 22U; + if (dma_isr_redir[7].dma_func) + dma_isr_redir[7].dma_func(dma_isr_redir[7].dma_param, flags); + + OSAL_IRQ_EPILOGUE(); +} + +/** + * @brief DMA2 stream 0 shared interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_DMA2_CH0_HANDLER) { + uint32_t flags; + + OSAL_IRQ_PROLOGUE(); + + flags = (DMA2->LISR >> 0U) & STM32_DMA_ISR_MASK; + DMA2->LIFCR = flags << 0U; + if (dma_isr_redir[8].dma_func) + dma_isr_redir[8].dma_func(dma_isr_redir[8].dma_param, flags); + + OSAL_IRQ_EPILOGUE(); +} + +/** + * @brief DMA2 stream 1 shared interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_DMA2_CH1_HANDLER) { + uint32_t flags; + + OSAL_IRQ_PROLOGUE(); + + flags = (DMA2->LISR >> 6U) & STM32_DMA_ISR_MASK; + DMA2->LIFCR = flags << 6U; + if (dma_isr_redir[9].dma_func) + dma_isr_redir[9].dma_func(dma_isr_redir[9].dma_param, flags); + + OSAL_IRQ_EPILOGUE(); +} + +/** + * @brief DMA2 stream 2 shared interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_DMA2_CH2_HANDLER) { + uint32_t flags; + + OSAL_IRQ_PROLOGUE(); + + flags = (DMA2->LISR >> 16U) & STM32_DMA_ISR_MASK; + DMA2->LIFCR = flags << 16U; + if (dma_isr_redir[10].dma_func) + dma_isr_redir[10].dma_func(dma_isr_redir[10].dma_param, flags); + + OSAL_IRQ_EPILOGUE(); +} + +/** + * @brief DMA2 stream 3 shared interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_DMA2_CH3_HANDLER) { + uint32_t flags; + + OSAL_IRQ_PROLOGUE(); + + flags = (DMA2->LISR >> 22U) & STM32_DMA_ISR_MASK; + DMA2->LIFCR = flags << 22U; + if (dma_isr_redir[11].dma_func) + dma_isr_redir[11].dma_func(dma_isr_redir[11].dma_param, flags); + + OSAL_IRQ_EPILOGUE(); +} + +/** + * @brief DMA2 stream 4 shared interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_DMA2_CH4_HANDLER) { + uint32_t flags; + + OSAL_IRQ_PROLOGUE(); + + flags = (DMA2->HISR >> 0U) & STM32_DMA_ISR_MASK; + DMA2->HIFCR = flags << 0U; + if (dma_isr_redir[12].dma_func) + dma_isr_redir[12].dma_func(dma_isr_redir[12].dma_param, flags); + + OSAL_IRQ_EPILOGUE(); +} + +/** + * @brief DMA2 stream 5 shared interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_DMA2_CH5_HANDLER) { + uint32_t flags; + + OSAL_IRQ_PROLOGUE(); + + flags = (DMA2->HISR >> 6U) & STM32_DMA_ISR_MASK; + DMA2->HIFCR = flags << 6U; + if (dma_isr_redir[13].dma_func) + dma_isr_redir[13].dma_func(dma_isr_redir[13].dma_param, flags); + + OSAL_IRQ_EPILOGUE(); +} + +/** + * @brief DMA2 stream 6 shared interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_DMA2_CH6_HANDLER) { + uint32_t flags; + + OSAL_IRQ_PROLOGUE(); + + flags = (DMA2->HISR >> 16U) & STM32_DMA_ISR_MASK; + DMA2->HIFCR = flags << 16U; + if (dma_isr_redir[14].dma_func) + dma_isr_redir[14].dma_func(dma_isr_redir[14].dma_param, flags); + + OSAL_IRQ_EPILOGUE(); +} + +/** + * @brief DMA2 stream 7 shared interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_DMA2_CH7_HANDLER) { + uint32_t flags; + + OSAL_IRQ_PROLOGUE(); + + flags = (DMA2->HISR >> 22U) & STM32_DMA_ISR_MASK; + DMA2->HIFCR = flags << 22U; + if (dma_isr_redir[15].dma_func) + dma_isr_redir[15].dma_func(dma_isr_redir[15].dma_param, flags); + + OSAL_IRQ_EPILOGUE(); +} + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief STM32 DMA helper initialization. + * + * @init + */ +void dmaInit(void) { + unsigned i; + + dma_streams_mask = 0U; + for (i = 0U; i < STM32_DMA_STREAMS; i++) { + _stm32_dma_streams[i].stream->CR = 0U; + dma_isr_redir[i].dma_func = NULL; + } + DMA1->LIFCR = 0xFFFFFFFFU; + DMA1->HIFCR = 0xFFFFFFFFU; + DMA2->LIFCR = 0xFFFFFFFFU; + DMA2->HIFCR = 0xFFFFFFFFU; +} + +/** + * @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 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] dmastp pointer to a stm32_dma_stream_t structure + * @param[in] priority IRQ priority mask for the DMA stream + * @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 + */ +bool dmaStreamAllocate(const stm32_dma_stream_t *dmastp, + uint32_t priority, + stm32_dmaisr_t func, + void *param) { + + osalDbgCheck(dmastp != NULL); + + /* Checks if the stream is already taken.*/ + if ((dma_streams_mask & (1U << dmastp->selfindex)) != 0U) + 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 |= (1U << dmastp->selfindex); + + /* Enabling DMA clocks required by the current streams set.*/ + if ((dma_streams_mask & STM32_DMA1_STREAMS_MASK) != 0U) { + rccEnableDMA1(false); + } + if ((dma_streams_mask & STM32_DMA2_STREAMS_MASK) != 0U) { + rccEnableDMA2(false); + } + + /* Putting the stream in a safe state.*/ + dmaStreamDisable(dmastp); + dmastp->stream->CR = STM32_DMA_CR_RESET_VALUE; + dmastp->stream->FCR = STM32_DMA_FCR_RESET_VALUE; + + /* Enables the associated IRQ vector if a callback is defined.*/ + if (func != NULL) { + nvicEnableVector(dmastp->vector, priority); + } + + return false; +} + +/** + * @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 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] dmastp pointer to a stm32_dma_stream_t structure + * + * @special + */ +void dmaStreamRelease(const stm32_dma_stream_t *dmastp) { + + osalDbgCheck(dmastp != NULL); + + /* Check if the streams is not taken.*/ + osalDbgAssert((dma_streams_mask & (1U << dmastp->selfindex)) != 0U, + "not allocated"); + + /* Disables the associated IRQ vector.*/ + nvicDisableVector(dmastp->vector); + + /* Marks the stream as not allocated.*/ + dma_streams_mask &= ~(1U << dmastp->selfindex); + + /* Shutting down clocks that are no more required, if any.*/ + if ((dma_streams_mask & STM32_DMA1_STREAMS_MASK) == 0U) { + rccDisableDMA1(false); + } + if ((dma_streams_mask & STM32_DMA2_STREAMS_MASK) == 0U) { + rccDisableDMA2(false); + } +} + +#endif /* STM32_DMA_REQUIRED */ + +/** @} */ diff --git a/os/hal/ports/STM32/LLD/DMAv2/stm32_dma.h b/os/hal/ports/STM32/LLD/DMAv2/stm32_dma.h new file mode 100644 index 000000000..2c05ba470 --- /dev/null +++ b/os/hal/ports/STM32/LLD/DMAv2/stm32_dma.h @@ -0,0 +1,459 @@ +/* + ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file DMAv2/stm32_dma.h + * @brief Enhanced-DMA helper driver header. + * + * @addtogroup STM32_DMA + * @{ + */ + +#ifndef _STM32_DMA_H_ +#define _STM32_DMA_H_ + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @brief Total number of DMA streams. + * @note This is the total number of streams among all the DMA units. + */ +#define STM32_DMA_STREAMS 16U + +/** + * @brief Mask of the ISR bits passed to the DMA callback functions. + */ +#define STM32_DMA_ISR_MASK 0x3DU + +/** + * @brief Returns the channel associated to the specified stream. + * + * @param[in] id the unique numeric stream identifier + * @param[in] c a stream/channel association word, one channel per + * nibble + * @return Returns the channel associated to the stream. + */ +#define STM32_DMA_GETCHANNEL(id, c) (((c) >> (((id) & 7U) * 4U)) & 7U) + +/** + * @brief Checks if a DMA priority is within the valid range. + * @param[in] prio DMA priority + * + * @retval The check result. + * @retval FALSE invalid DMA priority. + * @retval TRUE correct DMA priority. + */ +#define STM32_DMA_IS_VALID_PRIORITY(prio) (((prio) >= 0U) && ((prio) <= 3U)) + +/** + * @brief Returns an unique numeric identifier for a DMA stream. + * + * @param[in] dma the DMA unit number + * @param[in] stream the stream number + * @return An unique numeric stream identifier. + */ +#define STM32_DMA_STREAM_ID(dma, stream) ((((dma) - 1U) * 8U) + (stream)) + +/** + * @brief Returns a DMA stream identifier mask. + * + * + * @param[in] dma the DMA unit number + * @param[in] stream the stream number + * @return A DMA stream identifier mask. + */ +#define STM32_DMA_STREAM_ID_MSK(dma, stream) \ + (1U << STM32_DMA_STREAM_ID(dma, stream)) + +/** + * @brief Checks if a DMA stream unique identifier belongs to a mask. + * @param[in] id the stream numeric identifier + * @param[in] mask the stream numeric identifiers mask + * + * @retval The check result. + * @retval FALSE id does not belong to the mask. + * @retval TRUE id belongs to the mask. + */ +#define STM32_DMA_IS_VALID_ID(id, mask) (((1U << (id)) & (mask))) + +/** + * @name DMA streams identifiers + * @{ + */ +/** + * @brief Returns a pointer to a stm32_dma_stream_t structure. + * + * @param[in] id the stream numeric identifier + * @return A pointer to the stm32_dma_stream_t constant structure + * associated to the DMA stream. + */ +#define STM32_DMA_STREAM(id) (&_stm32_dma_streams[id]) + +#define STM32_DMA1_STREAM0 STM32_DMA_STREAM(0) +#define STM32_DMA1_STREAM1 STM32_DMA_STREAM(1) +#define STM32_DMA1_STREAM2 STM32_DMA_STREAM(2) +#define STM32_DMA1_STREAM3 STM32_DMA_STREAM(3) +#define STM32_DMA1_STREAM4 STM32_DMA_STREAM(4) +#define STM32_DMA1_STREAM5 STM32_DMA_STREAM(5) +#define STM32_DMA1_STREAM6 STM32_DMA_STREAM(6) +#define STM32_DMA1_STREAM7 STM32_DMA_STREAM(7) +#define STM32_DMA2_STREAM0 STM32_DMA_STREAM(8) +#define STM32_DMA2_STREAM1 STM32_DMA_STREAM(9) +#define STM32_DMA2_STREAM2 STM32_DMA_STREAM(10) +#define STM32_DMA2_STREAM3 STM32_DMA_STREAM(11) +#define STM32_DMA2_STREAM4 STM32_DMA_STREAM(12) +#define STM32_DMA2_STREAM5 STM32_DMA_STREAM(13) +#define STM32_DMA2_STREAM6 STM32_DMA_STREAM(14) +#define STM32_DMA2_STREAM7 STM32_DMA_STREAM(15) +/** @} */ + +/** + * @name CR register constants common to all DMA types + * @{ + */ +#define STM32_DMA_CR_EN DMA_SxCR_EN +#define STM32_DMA_CR_TEIE DMA_SxCR_TEIE +#define STM32_DMA_CR_HTIE DMA_SxCR_HTIE +#define STM32_DMA_CR_TCIE DMA_SxCR_TCIE +#define STM32_DMA_CR_DIR_MASK DMA_SxCR_DIR +#define STM32_DMA_CR_DIR_P2M 0 +#define STM32_DMA_CR_DIR_M2P DMA_SxCR_DIR_0 +#define STM32_DMA_CR_DIR_M2M DMA_SxCR_DIR_1 +#define STM32_DMA_CR_CIRC DMA_SxCR_CIRC +#define STM32_DMA_CR_PINC DMA_SxCR_PINC +#define STM32_DMA_CR_MINC DMA_SxCR_MINC +#define STM32_DMA_CR_PSIZE_MASK DMA_SxCR_PSIZE +#define STM32_DMA_CR_PSIZE_BYTE 0 +#define STM32_DMA_CR_PSIZE_HWORD DMA_SxCR_PSIZE_0 +#define STM32_DMA_CR_PSIZE_WORD DMA_SxCR_PSIZE_1 +#define STM32_DMA_CR_MSIZE_MASK DMA_SxCR_MSIZE +#define STM32_DMA_CR_MSIZE_BYTE 0 +#define STM32_DMA_CR_MSIZE_HWORD DMA_SxCR_MSIZE_0 +#define STM32_DMA_CR_MSIZE_WORD DMA_SxCR_MSIZE_1 +#define STM32_DMA_CR_SIZE_MASK (STM32_DMA_CR_PSIZE_MASK | \ + STM32_DMA_CR_MSIZE_MASK) +#define STM32_DMA_CR_PL_MASK DMA_SxCR_PL +#define STM32_DMA_CR_PL(n) ((n) << 16U) +/** @} */ + +/** + * @name CR register constants only found in STM32F2xx/STM32F4xx + * @{ + */ +#define STM32_DMA_CR_DMEIE DMA_SxCR_DMEIE +#define STM32_DMA_CR_PFCTRL DMA_SxCR_PFCTRL +#define STM32_DMA_CR_PINCOS DMA_SxCR_PINCOS +#define STM32_DMA_CR_DBM DMA_SxCR_DBM +#define STM32_DMA_CR_CT DMA_SxCR_CT +#define STM32_DMA_CR_PBURST_MASK DMA_SxCR_PBURST +#define STM32_DMA_CR_PBURST_SINGLE 0 +#define STM32_DMA_CR_PBURST_INCR4 DMA_SxCR_PBURST_0 +#define STM32_DMA_CR_PBURST_INCR8 DMA_SxCR_PBURST_1 +#define STM32_DMA_CR_PBURST_INCR16 (DMA_SxCR_PBURST_0 | DMA_SxCR_PBURST_1) +#define STM32_DMA_CR_MBURST_MASK DMA_SxCR_MBURST +#define STM32_DMA_CR_MBURST_SINGLE 0 +#define STM32_DMA_CR_MBURST_INCR4 DMA_SxCR_MBURST_0 +#define STM32_DMA_CR_MBURST_INCR8 DMA_SxCR_MBURST_1 +#define STM32_DMA_CR_MBURST_INCR16 (DMA_SxCR_MBURST_0 | DMA_SxCR_MBURST_1) +#define STM32_DMA_CR_CHSEL_MASK DMA_SxCR_CHSEL +#define STM32_DMA_CR_CHSEL(n) ((n) << 25U) +/** @} */ + +/** + * @name FCR register constants only found in STM32F2xx/STM32F4xx + * @{ + */ +#define STM32_DMA_FCR_FEIE DMA_SxFCR_FEIE +#define STM32_DMA_FCR_FS_MASK DMA_SxFCR_FS +#define STM32_DMA_FCR_DMDIS DMA_SxFCR_DMDIS +#define STM32_DMA_FCR_FTH_MASK DMA_SxFCR_FTH +#define STM32_DMA_FCR_FTH_1Q 0 +#define STM32_DMA_FCR_FTH_HALF DMA_SxFCR_FTH_0 +#define STM32_DMA_FCR_FTH_3Q DMA_SxFCR_FTH_1 +#define STM32_DMA_FCR_FTH_FULL (DMA_SxFCR_FTH_0 | DMA_SxFCR_FTH_1) +/** @} */ + +/** + * @name Status flags passed to the ISR callbacks + */ +#define STM32_DMA_ISR_FEIF DMA_LISR_FEIF0 +#define STM32_DMA_ISR_DMEIF DMA_LISR_DMEIF0 +#define STM32_DMA_ISR_TEIF DMA_LISR_TEIF0 +#define STM32_DMA_ISR_HTIF DMA_LISR_HTIF0 +#define STM32_DMA_ISR_TCIF DMA_LISR_TCIF0 +/** @} */ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief STM32 DMA stream descriptor structure. + */ +typedef struct { + DMA_Stream_TypeDef *stream; /**< @brief Associated DMA stream. */ + 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 xISR register, the bits + * are aligned to bit zero + */ +typedef void (*stm32_dmaisr_t)(void *p, uint32_t flags); + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/** + * @name Macro Functions + * @{ + */ +/** + * @brief Associates a peripheral data register to a DMA stream. + * @note This function can be invoked in both ISR or thread context. + * @pre The stream must have been allocated using @p dmaStreamAllocate(). + * @post After use the stream can be released using @p dmaStreamRelease(). + * + * @param[in] dmastp pointer to a stm32_dma_stream_t structure + * @param[in] addr value to be written in the PAR register + * + * @special + */ +#define dmaStreamSetPeripheral(dmastp, addr) { \ + (dmastp)->stream->PAR = (uint32_t)(addr); \ +} + +/** + * @brief Associates a memory destination to a DMA stream. + * @note This function can be invoked in both ISR or thread context. + * @pre The stream must have been allocated using @p dmaStreamAllocate(). + * @post After use the stream can be released using @p dmaStreamRelease(). + * + * @param[in] dmastp pointer to a stm32_dma_stream_t structure + * @param[in] addr value to be written in the M0AR register + * + * @special + */ +#define dmaStreamSetMemory0(dmastp, addr) { \ + (dmastp)->stream->M0AR = (uint32_t)(addr); \ +} + +/** + * @brief Associates an alternate memory destination to a DMA stream. + * @note This function can be invoked in both ISR or thread context. + * + * @param[in] dmastp pointer to a stm32_dma_stream_t structure + * @param[in] addr value to be written in the M1AR register + * + * @special + */ +#define dmaStreamSetMemory1(dmastp, addr) { \ + (dmastp)->stream->M1AR = (uint32_t)(addr); \ +} + +/** + * @brief Sets the number of transfers to be performed. + * @note This function can be invoked in both ISR or thread context. + * @pre The stream must have been allocated using @p dmaStreamAllocate(). + * @post After use the stream can be released using @p dmaStreamRelease(). + * + * @param[in] dmastp pointer to a stm32_dma_stream_t structure + * @param[in] size value to be written in the CNDTR register + * + * @special + */ +#define dmaStreamSetTransactionSize(dmastp, size) { \ + (dmastp)->stream->NDTR = (uint32_t)(size); \ +} + +/** + * @brief Returns the number of transfers to be performed. + * @note This function can be invoked in both ISR or thread context. + * @pre The stream must have been allocated using @p dmaStreamAllocate(). + * @post After use the stream can be released using @p dmaStreamRelease(). + * + * @param[in] dmastp pointer to a stm32_dma_stream_t structure + * @return The number of transfers to be performed. + * + * @special + */ +#define dmaStreamGetTransactionSize(dmastp) ((size_t)((dmastp)->stream->NDTR)) + +/** + * @brief Programs the stream mode settings. + * @note This function can be invoked in both ISR or thread context. + * @pre The stream must have been allocated using @p dmaStreamAllocate(). + * @post After use the stream can be released using @p dmaStreamRelease(). + * + * @param[in] dmastp pointer to a stm32_dma_stream_t structure + * @param[in] mode value to be written in the CR register + * + * @special + */ +#define dmaStreamSetMode(dmastp, mode) { \ + (dmastp)->stream->CR = (uint32_t)(mode); \ +} + +/** + * @brief Programs the stream FIFO settings. + * @note This function can be invoked in both ISR or thread context. + * @pre The stream must have been allocated using @p dmaStreamAllocate(). + * @post After use the stream can be released using @p dmaStreamRelease(). + * + * @param[in] dmastp pointer to a stm32_dma_stream_t structure + * @param[in] mode value to be written in the FCR register + * + * @special + */ +#define dmaStreamSetFIFO(dmastp, mode) { \ + (dmastp)->stream->FCR = (uint32_t)(mode); \ +} + +/** + * @brief DMA stream enable. + * @note This function can be invoked in both ISR or thread context. + * @pre The stream must have been allocated using @p dmaStreamAllocate(). + * @post After use the stream can be released using @p dmaStreamRelease(). + * + * @param[in] dmastp pointer to a stm32_dma_stream_t structure + * + * @special + */ +#define dmaStreamEnable(dmastp) { \ + (dmastp)->stream->CR |= STM32_DMA_CR_EN; \ +} + +/** + * @brief DMA stream disable. + * @details The function disables the specified stream, waits for the disable + * operation to complete and then clears any pending interrupt. + * @note This function can be invoked in both ISR or thread context. + * @note Interrupts enabling flags are set to zero after this call, see + * bug 3607518. + * @pre The stream must have been allocated using @p dmaStreamAllocate(). + * @post After use the stream can be released using @p dmaStreamRelease(). + * + * @param[in] dmastp pointer to a stm32_dma_stream_t structure + * + * @special + */ +#define dmaStreamDisable(dmastp) { \ + (dmastp)->stream->CR &= ~(STM32_DMA_CR_TCIE | STM32_DMA_CR_HTIE | \ + STM32_DMA_CR_TEIE | STM32_DMA_CR_DMEIE | \ + STM32_DMA_CR_EN); \ + while (((dmastp)->stream->CR & STM32_DMA_CR_EN) != 0U) \ + ; \ + dmaStreamClearInterrupt(dmastp); \ +} + +/** + * @brief DMA stream interrupt sources clear. + * @note This function can be invoked in both ISR or thread context. + * @pre The stream must have been allocated using @p dmaStreamAllocate(). + * @post After use the stream can be released using @p dmaStreamRelease(). + * + * @param[in] dmastp pointer to a stm32_dma_stream_t structure + * + * @special + */ +#define dmaStreamClearInterrupt(dmastp) { \ + *(dmastp)->ifcr = STM32_DMA_ISR_MASK << (dmastp)->ishift; \ +} + +/** + * @brief Starts a memory to memory operation using the specified stream. + * @note The default transfer data mode is "byte to byte" but it can be + * changed by specifying extra options in the @p mode parameter. + * @pre The stream must have been allocated using @p dmaStreamAllocate(). + * @post After use the stream can be released using @p dmaStreamRelease(). + * + * @param[in] dmastp pointer to a stm32_dma_stream_t structure + * @param[in] mode value to be written in the CCR register, this value + * is implicitly ORed with: + * - @p STM32_DMA_CR_MINC + * - @p STM32_DMA_CR_PINC + * - @p STM32_DMA_CR_DIR_M2M + * - @p STM32_DMA_CR_EN + * . + * @param[in] src source address + * @param[in] dst destination address + * @param[in] n number of data units to copy + */ +#define dmaStartMemCopy(dmastp, mode, src, dst, n) { \ + dmaStreamSetPeripheral(dmastp, src); \ + dmaStreamSetMemory0(dmastp, dst); \ + dmaStreamSetTransactionSize(dmastp, n); \ + dmaStreamSetMode(dmastp, (mode) | \ + STM32_DMA_CR_MINC | STM32_DMA_CR_PINC | \ + STM32_DMA_CR_DIR_M2M | STM32_DMA_CR_EN); \ +} + +/** + * @brief Polled wait for DMA transfer end. + * @pre The stream must have been allocated using @p dmaStreamAllocate(). + * @post After use the stream can be released using @p dmaStreamRelease(). + * + * @param[in] dmastp pointer to a stm32_dma_stream_t structure + */ +#define dmaWaitCompletion(dmastp) { \ + while ((dmastp)->stream->NDTR > 0U) \ + ; \ + dmaStreamDisable(dmastp); \ +} +/** @} */ + +/*===========================================================================*/ +/* 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); + bool 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 + +#endif /* _STM32_DMA_H_ */ + +/** @} */ diff --git a/os/hal/ports/STM32/LLD/USARTv2/serial_lld.c b/os/hal/ports/STM32/LLD/USARTv2/serial_lld.c index 0c459c84e..0b8b3710d 100644 --- a/os/hal/ports/STM32/LLD/USARTv2/serial_lld.c +++ b/os/hal/ports/STM32/LLD/USARTv2/serial_lld.c @@ -30,7 +30,7 @@ /* Driver local definitions. */ /*===========================================================================*/ -/* STM32L0xx ST headers bug.*/ +/* STM32L0xx/STM32F7xx ST headers difference.*/ #if !defined(USART_ISR_LBDF) #define USART_ISR_LBDF USART_ISR_LBD #endif diff --git a/os/hal/ports/STM32/LLD/USARTv2/uart_lld.c b/os/hal/ports/STM32/LLD/USARTv2/uart_lld.c index aacc7c925..59bb6c229 100644 --- a/os/hal/ports/STM32/LLD/USARTv2/uart_lld.c +++ b/os/hal/ports/STM32/LLD/USARTv2/uart_lld.c @@ -30,6 +30,11 @@ /* Driver local definitions. */ /*===========================================================================*/ +/* STM32L0xx/STM32F7xx ST headers difference.*/ +#if !defined(USART_ISR_LBDF) +#define USART_ISR_LBDF USART_ISR_LBD +#endif + #define USART1_RX_DMA_CHANNEL \ STM32_DMA_GETCHANNEL(STM32_UART_USART1_RX_DMA_STREAM, \ STM32_USART1_RX_DMA_CHN) @@ -70,6 +75,14 @@ STM32_DMA_GETCHANNEL(STM32_UART_UART5_TX_DMA_STREAM, \ STM32_UART5_TX_DMA_CHN) +#define USART6_RX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_UART_USART6_RX_DMA_STREAM, \ + STM32_USART6_RX_DMA_CHN) + +#define USART6_TX_DMA_CHANNEL \ + STM32_DMA_GETCHANNEL(STM32_UART_USART6_TX_DMA_STREAM, \ + STM32_USART6_TX_DMA_CHN) + #define UART7_RX_DMA_CHANNEL \ STM32_DMA_GETCHANNEL(STM32_UART_UART7_RX_DMA_STREAM, \ STM32_UART7_RX_DMA_CHN) diff --git a/os/hal/ports/STM32/STM32F7xx/hal_lld.h b/os/hal/ports/STM32/STM32F7xx/hal_lld.h index 124670971..f76260825 100644 --- a/os/hal/ports/STM32/STM32F7xx/hal_lld.h +++ b/os/hal/ports/STM32/STM32F7xx/hal_lld.h @@ -1877,7 +1877,7 @@ /* Various helpers.*/ #include "nvic.h" -//#include "stm32_dma.h" +#include "stm32_dma.h" #include "stm32_rcc.h" #ifdef __cplusplus diff --git a/os/hal/ports/STM32/STM32F7xx/platform.mk b/os/hal/ports/STM32/STM32F7xx/platform.mk index b03f9a91e..4161dab50 100644 --- a/os/hal/ports/STM32/STM32F7xx/platform.mk +++ b/os/hal/ports/STM32/STM32F7xx/platform.mk @@ -4,9 +4,8 @@ HALCONF := $(strip $(shell cat halconf.h | egrep -e "define")) PLATFORMSRC := $(CHIBIOS)/os/hal/ports/common/ARMCMx/nvic.c \ $(CHIBIOS)/os/hal/ports/STM32/STM32F7xx/hal_lld.c \ + $(CHIBIOS)/os/hal/ports/STM32/LLD/DMAv2/stm32_dma.c \ $(CHIBIOS)/os/hal/ports/STM32/LLD/TIMv1/st_lld.c -# $(CHIBIOS)/os/hal/ports/STM32/LLD/DMAv2/stm32_dma.c \ - ifneq ($(findstring HAL_USE_ADC TRUE,$(HALCONF)),) PLATFORMSRC += $(CHIBIOS)/os/hal/ports/STM32/LLD/ADCv2/adc_lld.c endif diff --git a/os/hal/ports/STM32/STM32F7xx/stm32_registry.h b/os/hal/ports/STM32/STM32F7xx/stm32_registry.h index 2ed95fc0e..853a4f0c2 100644 --- a/os/hal/ports/STM32/STM32F7xx/stm32_registry.h +++ b/os/hal/ports/STM32/STM32F7xx/stm32_registry.h @@ -97,8 +97,42 @@ /* DMA attributes.*/ #define STM32_ADVANCED_DMA TRUE + #define STM32_HAS_DMA1 TRUE +#define STM32_DMA1_CH0_HANDLER Vector6C +#define STM32_DMA1_CH1_HANDLER Vector70 +#define STM32_DMA1_CH2_HANDLER Vector74 +#define STM32_DMA1_CH3_HANDLER Vector78 +#define STM32_DMA1_CH4_HANDLER Vector7C +#define STM32_DMA1_CH5_HANDLER Vector80 +#define STM32_DMA1_CH6_HANDLER Vector84 +#define STM32_DMA1_CH7_HANDLER VectorFC +#define STM32_DMA1_CH0_NUMBER 11 +#define STM32_DMA1_CH1_NUMBER 12 +#define STM32_DMA1_CH2_NUMBER 13 +#define STM32_DMA1_CH3_NUMBER 14 +#define STM32_DMA1_CH4_NUMBER 15 +#define STM32_DMA1_CH5_NUMBER 16 +#define STM32_DMA1_CH6_NUMBER 17 +#define STM32_DMA1_CH7_NUMBER 47 + #define STM32_HAS_DMA2 TRUE +#define STM32_DMA2_CH0_HANDLER Vector120 +#define STM32_DMA2_CH1_HANDLER Vector124 +#define STM32_DMA2_CH2_HANDLER Vector128 +#define STM32_DMA2_CH3_HANDLER Vector12C +#define STM32_DMA2_CH4_HANDLER Vector130 +#define STM32_DMA2_CH5_HANDLER Vector150 +#define STM32_DMA2_CH6_HANDLER Vector154 +#define STM32_DMA2_CH7_HANDLER Vector158 +#define STM32_DMA2_CH0_NUMBER 56 +#define STM32_DMA2_CH1_NUMBER 57 +#define STM32_DMA2_CH2_NUMBER 58 +#define STM32_DMA2_CH3_NUMBER 59 +#define STM32_DMA2_CH4_NUMBER 60 +#define STM32_DMA2_CH5_NUMBER 68 +#define STM32_DMA2_CH6_NUMBER 69 +#define STM32_DMA2_CH7_NUMBER 70 /* ETH attributes.*/ #define STM32_HAS_ETH TRUE diff --git a/readme.txt b/readme.txt index fca1e94ea..137f10997 100644 --- a/readme.txt +++ b/readme.txt @@ -79,8 +79,9 @@ - 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 shared DMAv2 driver supporting channel selection (F2, F4, F7). +- HAL: New STM32 shared DMAv1 driver supporting channel selection and fixing + the behavior with shared IRQs (F0, L0). - 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