diff options
Diffstat (limited to 'os/hal/ports/STM32/LLD/DMAv1')
-rw-r--r-- | os/hal/ports/STM32/LLD/DMAv1/stm32_dma.c | 217 | ||||
-rw-r--r-- | os/hal/ports/STM32/LLD/DMAv1/stm32_dma.h | 63 |
2 files changed, 183 insertions, 97 deletions
diff --git a/os/hal/ports/STM32/LLD/DMAv1/stm32_dma.c b/os/hal/ports/STM32/LLD/DMAv1/stm32_dma.c index f7b51abd5..3b8e5769d 100644 --- a/os/hal/ports/STM32/LLD/DMAv1/stm32_dma.c +++ b/os/hal/ports/STM32/LLD/DMAv1/stm32_dma.c @@ -217,27 +217,35 @@ const stm32_dma_stream_t _stm32_dma_streams[STM32_DMA_STREAMS] = { #endif
};
-/**
- * @brief DMA IRQ redirectors.
- */
-dma_isr_redir_t _stm32_dma_isr_redir[STM32_DMA_STREAMS];
-
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
/**
- * @brief Masks regarding the allocated streams.
+ * @brief Global DMA-related data structures.
*/
static struct {
/**
- * @brief Mask of the enabled streams.
+ * @brief Mask of the allocated streams.
+ */
+ uint32_t allocated_mask;
+ /**
+ * @brief Mask of the enabled streams ISRs.
*/
- uint32_t streams_mask;
+ uint32_t isr_mask;
/**
- * @brief Mask of the enabled stream ISRs.
+ * @brief DMA IRQ redirectors.
*/
- uint32_t isr_mask;
+ struct {
+ /**
+ * @brief DMA callback function.
+ */
+ stm32_dmaisr_t func;
+ /**
+ * @brief DMA callback parameter.
+ */
+ void *param;
+ } streams[STM32_DMA_STREAMS];
} dma;
/*===========================================================================*/
@@ -484,11 +492,11 @@ OSAL_IRQ_HANDLER(STM32_DMA2_CH7_HANDLER) { void dmaInit(void) {
int i;
- dma.streams_mask = 0U;
- dma.isr_mask = 0U;
+ dma.allocated_mask = 0U;
+ dma.isr_mask = 0U;
for (i = 0; i < STM32_DMA_STREAMS; i++) {
_stm32_dma_streams[i].channel->CCR = 0U;
- _stm32_dma_isr_redir[i].dma_func = NULL;
+ dma.streams[i].func = NULL;
}
DMA1->IFCR = 0xFFFFFFFFU;
#if STM32_DMA2_NUM_CHANNELS > 0
@@ -508,67 +516,134 @@ void dmaInit(void) { * @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] id numeric identifiers of a specific stream or:
+ * - @p STM32_DMA_STREAM_ID_ANY for any stream.
+ * - @p STM32_DMA_STREAM_ID_ANY_DMA1 for any stream
+ * on DMA1.
+ * - @p STM32_DMA_STREAM_ID_ANY_DMA2 for any stream
+ * on DMA2.
+ * .
* @param[in] priority IRQ priority 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.
+ * @return Pointer to the allocated @p stm32_dma_stream_t
+ * structure.
+ * @retval NULL if a/the stream is not available.
*
- * @special
+ * @iclass
*/
-bool dmaStreamAllocate(const stm32_dma_stream_t *dmastp,
- uint32_t priority,
- stm32_dmaisr_t func,
- void *param) {
-
- osalDbgCheck(dmastp != NULL);
+const stm32_dma_stream_t *dmaStreamAllocI(uint32_t id,
+ uint32_t priority,
+ stm32_dmaisr_t func,
+ void *param) {
+ uint32_t i, startid, endid;
- /* Checks if the stream is already taken.*/
- if ((dma.streams_mask & (1U << dmastp->selfindex)) != 0U)
- return true;
+ osalDbgCheckClassI();
- /* Installs the DMA handler.*/
- _stm32_dma_isr_redir[dmastp->selfindex].dma_func = func;
- _stm32_dma_isr_redir[dmastp->selfindex].dma_param = param;
-
- /* Enabling DMA clocks required by the current streams set.*/
- if ((dma.streams_mask & STM32_DMA1_STREAMS_MASK) == 0U) {
- rccEnableDMA1(true);
+ if (id < STM32_DMA_STREAMS) {
+ startid = id;
+ endid = id;
+ }
+ else if (id == STM32_DMA_STREAM_ID_ANY) {
+ startid = 0U;
+ endid = STM32_DMA1_NUM_CHANNELS + STM32_DMA2_NUM_CHANNELS - 1U;
+ }
+ else if (id == STM32_DMA_STREAM_ID_ANY_DMA1) {
+ startid = 0U;
+ endid = STM32_DMA1_NUM_CHANNELS - 1U;
}
#if STM32_DMA2_NUM_CHANNELS > 0
- if ((dma.streams_mask & STM32_DMA2_STREAMS_MASK) == 0U) {
- rccEnableDMA2(true);
+ else if (id == STM32_DMA_STREAM_ID_ANY_DMA2) {
+ startid = 7U;
+ endid = STM32_DMA1_NUM_CHANNELS + STM32_DMA2_NUM_CHANNELS - 1U;
+ }
+#endif
+ else {
+ osalDbgCheck(false);
}
+
+ for (i = startid; i <= endid; i++) {
+ uint32_t mask = (1U << i);
+ if ((dma.allocated_mask & mask) == 0U) {
+ const stm32_dma_stream_t *dmastp = STM32_DMA_STREAM(i);
+
+ /* Installs the DMA handler.*/
+ dma.streams[i].func = func;
+ dma.streams[i].param = param;
+
+ /* Enabling DMA clocks required by the current streams set.*/
+ if (((STM32_DMA1_STREAMS_MASK & dma.allocated_mask) == 0U) &&
+ ((STM32_DMA1_STREAMS_MASK & mask) != 0U)){
+ rccEnableDMA1(true);
+ }
+#if STM32_DMA2_NUM_CHANNELS > 0
+ if (((STM32_DMA2_STREAMS_MASK & dma.allocated_mask) == 0U) &&
+ ((STM32_DMA2_STREAMS_MASK & mask) != 0U)){
+ rccEnableDMA2(true);
+ }
#endif
#if STM32_DMA_SUPPORTS_DMAMUX == TRUE
- /* Enabling DMAMUX if present.*/
- if (dma.streams_mask == 0U) {
- rccEnableDMAMUX(true);
- }
+ /* Enabling DMAMUX if present.*/
+ if (dma.allocated_mask == 0U) {
+ rccEnableDMAMUX(true);
+ }
#endif
- /* Putting the stream in a safe state.*/
- dmaStreamDisable(dmastp);
- dmastp->channel->CCR = STM32_DMA_CCR_RESET_VALUE;
+ /* Enables the associated IRQ vector if not already enabled and if a
+ callback is defined.*/
+ if (func != NULL) {
+ if ((dma.isr_mask & dmastp->cmask) == 0U) {
+ nvicEnableVector(dmastp->vector, priority);
+ }
+ dma.isr_mask |= mask;
+ }
+
+ /* Marks the stream as allocated.*/
+ dma.allocated_mask |= mask;
- /* Enables the associated IRQ vector if not already enabled and if a
- callback is defined.*/
- if (func != NULL) {
- if ((dma.isr_mask & dmastp->cmask) == 0U) {
- nvicEnableVector(dmastp->vector, priority);
+ /* Putting the stream in a known state.*/
+ dmastp->channel->CCR = STM32_DMA_CCR_RESET_VALUE;
+
+ return dmastp;
}
- dma.isr_mask |= (1U << dmastp->selfindex);
}
- /* Marks the stream as allocated.*/
- dma.streams_mask |= (1U << dmastp->selfindex);
+ return NULL;
+}
+
+/**
+ * @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 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.
+ *
+ * @iclass
+ * @deprecated
+ */
+bool dmaStreamAllocate(const stm32_dma_stream_t *dmastp,
+ uint32_t priority,
+ stm32_dmaisr_t func,
+ void *param) {
- return false;
+ return dmaStreamAllocI(dmastp->selfindex, priority, func, param) == NULL;
}
/**
@@ -589,40 +664,60 @@ void dmaStreamRelease(const stm32_dma_stream_t *dmastp) { osalDbgCheck(dmastp != NULL);
/* Check if the streams is not taken.*/
- osalDbgAssert((dma.streams_mask & (1 << dmastp->selfindex)) != 0U,
+ osalDbgAssert((dma.allocated_mask & (1 << dmastp->selfindex)) != 0U,
"not allocated");
/* Marks the stream as not allocated.*/
- dma.streams_mask &= ~(1U << dmastp->selfindex);
+ dma.allocated_mask &= ~(1U << dmastp->selfindex);
dma.isr_mask &= ~(1U << dmastp->selfindex);
/* Disables the associated IRQ vector if it is no more in use.*/
- if ((dma.streams_mask & dmastp->cmask) == 0U) {
+ if ((dma.allocated_mask & dmastp->cmask) == 0U) {
nvicDisableVector(dmastp->vector);
}
/* Removes the DMA handler.*/
- _stm32_dma_isr_redir[dmastp->selfindex].dma_func = NULL;
- _stm32_dma_isr_redir[dmastp->selfindex].dma_param = NULL;
+ dma.streams[dmastp->selfindex].func = NULL;
+ dma.streams[dmastp->selfindex].param = NULL;
/* Shutting down clocks that are no more required, if any.*/
- if ((dma.streams_mask & STM32_DMA1_STREAMS_MASK) == 0U) {
+ if ((dma.allocated_mask & STM32_DMA1_STREAMS_MASK) == 0U) {
rccDisableDMA1();
}
#if STM32_DMA2_NUM_CHANNELS > 0
- if ((dma.streams_mask & STM32_DMA2_STREAMS_MASK) == 0U) {
+ if ((dma.allocated_mask & STM32_DMA2_STREAMS_MASK) == 0U) {
rccDisableDMA2();
}
#endif
#if STM32_DMA_SUPPORTS_DMAMUX == TRUE
/* Shutting down DMAMUX if present.*/
- if (dma.streams_mask == 0U) {
+ if (dma.allocated_mask == 0U) {
rccDisableDMAMUX();
}
#endif
}
+/**
+ * @brief Serves a DMA IRQ.
+ *
+ * @param[in] dmastp pointer to a stm32_dma_stream_t structure
+ *
+ * @special
+ */
+void dmaServeInterrupt(const stm32_dma_stream_t *dmastp) {
+ uint32_t flags;
+ uint32_t idx = (dmastp)->selfindex;
+
+ flags = (dmastp->dma->ISR >> dmastp->shift) & STM32_DMA_ISR_MASK;
+ if (flags & dmastp->channel->CCR) {
+ dmastp->dma->IFCR = flags << dmastp->shift;
+ if (dma.streams[idx].func) {
+ dma.streams[idx].func(dma.streams[idx].param, flags);
+ }
+ }
+}
+
#if (STM32_DMA_SUPPORTS_DMAMUX == TRUE) || defined(__DOXYGEN__)
/**
* @brief Associates a peripheral request to a DMA stream.
diff --git a/os/hal/ports/STM32/LLD/DMAv1/stm32_dma.h b/os/hal/ports/STM32/LLD/DMAv1/stm32_dma.h index 6c3fd36a6..4fe24c631 100644 --- a/os/hal/ports/STM32/LLD/DMAv1/stm32_dma.h +++ b/os/hal/ports/STM32/LLD/DMAv1/stm32_dma.h @@ -121,6 +121,15 @@ #define STM32_DMA_IS_VALID_ID(id, mask) (((1U << (id)) & (mask)))
/**
+ * @name Special stream identifiers
+ * @{
+ */
+#define STM32_DMA_STREAM_ID_ANY 16
+#define STM32_DMA_STREAM_ID_ANY_DMA1 17
+#define STM32_DMA_STREAM_ID_ANY_DMA2 18
+/** @} */
+
+/**
* @name DMA streams identifiers
* @{
*/
@@ -237,6 +246,10 @@ #error "STM32_DMA2_NUM_CHANNELS not defined in registry"
#endif
+#if (STM32_DMA1_NUM_CHANNELS < 7) && (STM32_DMA2_NUM_CHANNELS > 0)
+#error "unsupported channels configuration"
+#endif
+
#if (STM32_DMA_SUPPORTS_DMAMUX == TRUE) || defined(__DOXYGEN__)
#include "stm32_dmamux.h"
#endif
@@ -246,6 +259,15 @@ /*===========================================================================*/
/**
+ * @brief Type of a DMA callback.
+ *
+ * @param[in] p parameter for the registered function
+ * @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);
+
+/**
* @brief STM32 DMA stream descriptor structure.
*/
typedef struct {
@@ -266,23 +288,6 @@ typedef struct { 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, the bits
- * are aligned to bit zero
- */
-typedef void (*stm32_dmaisr_t)(void *p, uint32_t flags);
-
-/**
- * @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;
-
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
@@ -462,24 +467,6 @@ typedef struct { ; \
dmaStreamDisable(dmastp); \
}
-
-/**
- * @brief Serves a DMA IRQ.
- *
- * @param[in] dmastp pointer to a stm32_dma_stream_t structure
- */
-#define dmaServeInterrupt(dmastp) { \
- uint32_t flags; \
- uint32_t idx = (dmastp)->selfindex; \
- \
- flags = ((dmastp)->dma->ISR >> (dmastp)->shift) & STM32_DMA_ISR_MASK; \
- if (flags & (dmastp)->channel->CCR) { \
- (dmastp)->dma->IFCR = flags << (dmastp)->shift; \
- if (_stm32_dma_isr_redir[idx].dma_func) { \
- _stm32_dma_isr_redir[idx].dma_func(_stm32_dma_isr_redir[idx].dma_param, flags); \
- } \
- } \
-}
/** @} */
/*===========================================================================*/
@@ -488,18 +475,22 @@ typedef struct { #if !defined(__DOXYGEN__)
extern const stm32_dma_stream_t _stm32_dma_streams[STM32_DMA_STREAMS];
-extern dma_isr_redir_t _stm32_dma_isr_redir[STM32_DMA_STREAMS];
#endif
#ifdef __cplusplus
extern "C" {
#endif
void dmaInit(void);
+ const stm32_dma_stream_t *dmaStreamAllocI(uint32_t id,
+ uint32_t priority,
+ stm32_dmaisr_t func,
+ void *param);
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);
+ void dmaServeInterrupt(const stm32_dma_stream_t *dmastp);
#if STM32_DMA_SUPPORTS_DMAMUX == TRUE
void dmaSetRequestSource(const stm32_dma_stream_t *dmastp, uint32_t per);
#endif
|