cpu/stm32_common: add DMA implementation for F2/F4/F7

This commit is contained in:
Vincent Dupont 2018-03-12 19:01:41 +01:00
parent 8ab908146e
commit d399518ac6
5 changed files with 605 additions and 189 deletions

View File

@ -3,6 +3,7 @@
* 2014 Freie Universität Berlin * 2014 Freie Universität Berlin
* 2016 TriaGnoSys GmbH * 2016 TriaGnoSys GmbH
* 2018 Kaspar Schleiser <kaspar@schleiser.de> * 2018 Kaspar Schleiser <kaspar@schleiser.de>
* 2018 OTA keys S.A.
* *
* *
* This file is subject to the terms and conditions of the GNU Lesser General * This file is subject to the terms and conditions of the GNU Lesser General
@ -24,6 +25,7 @@
* @author Nick van IJzendoorn <nijzendoorn@engineering-spirit.nl> * @author Nick van IJzendoorn <nijzendoorn@engineering-spirit.nl>
* @author Víctor Ariño <victor.arino@zii.aero> * @author Víctor Ariño <victor.arino@zii.aero>
* @author Kaspar Schleiser <kaspar@schleiser.de> * @author Kaspar Schleiser <kaspar@schleiser.de>
* @author Vincent Dupont <vincent@otakeys.com>
* *
* @} * @}
*/ */
@ -47,6 +49,10 @@ void cpu_init(void)
periph_clk_en(APB1, BIT_APB_PWREN); periph_clk_en(APB1, BIT_APB_PWREN);
/* initialize the system clock as configured in the periph_conf.h */ /* initialize the system clock as configured in the periph_conf.h */
stmclk_init_sysclk(); stmclk_init_sysclk();
#ifdef MODULE_PERIPH_DMA
/* initialize DMA streams */
dma_init();
#endif
/* trigger static peripheral initialization */ /* trigger static peripheral initialization */
periph_init(); periph_init();
} }

View File

@ -218,6 +218,49 @@ typedef enum {
#endif /* ndef DOXYGEN */ #endif /* ndef DOXYGEN */
#endif /* ndef CPU_FAM_STM32F1 */ #endif /* ndef CPU_FAM_STM32F1 */
#ifdef MODULE_PERIPH_DMA
/**
* @brief DMA configuration
*/
typedef struct {
int stream; /**< DMA stream */
} dma_conf_t;
/**
* @brief DMA type
*/
typedef unsigned dma_t;
/**
* @brief DMA modes
*/
typedef enum {
DMA_PERIPH_TO_MEM, /**< Peripheral to memory */
DMA_MEM_TO_PERIPH, /**< Memory to peripheral */
DMA_MEM_TO_MEM, /**< Memory to memory */
} dma_mode_t;
/**
* @name DMA Increment modes
* @{
*/
#define DMA_INC_SRC_ADDR (0x01)
#define DMA_INC_DST_ADDR (0x02)
#define DMA_INC_BOTH_ADDR (DMA_INC_SRC_ADDR | DMA_INC_DST_ADDR)
/** @} */
/**
* @name DMA data width
* @{
*/
#define DMA_DATA_WIDTH_BYTE (0x00)
#define DMA_DATA_WIDTH_HALF_WORD (0x04)
#define DMA_DATA_WIDTH_WORD (0x08)
#define DMA_DATA_WIDTH_MASK (0x0C)
#define DMA_DATA_WIDTH_SHIFT (2)
/** @} */
#endif /* MODULE_PERIPH_DMA */
/** /**
* @brief DAC line configuration data * @brief DAC line configuration data
*/ */
@ -293,8 +336,8 @@ typedef struct {
#endif #endif
uint8_t bus; /**< APB bus */ uint8_t bus; /**< APB bus */
uint8_t irqn; /**< IRQ channel */ uint8_t irqn; /**< IRQ channel */
#if 0 /* TODO */ #ifdef MODULE_PERIPH_DMA
uint8_t dma_stream; /**< DMA stream used for TX */ dma_t dma; /**< Logical DMA stream used for TX */
uint8_t dma_chan; /**< DMA channel used for TX */ uint8_t dma_chan; /**< DMA channel used for TX */
#endif #endif
#ifdef MODULE_STM32_PERIPH_UART_HW_FC #ifdef MODULE_STM32_PERIPH_UART_HW_FC
@ -321,8 +364,15 @@ typedef struct {
#endif #endif
uint32_t rccmask; /**< bit in the RCC peripheral enable register */ uint32_t rccmask; /**< bit in the RCC peripheral enable register */
uint8_t apbbus; /**< APBx bus the device is connected to */ uint8_t apbbus; /**< APBx bus the device is connected to */
#ifdef MODULE_PERIPH_DMA
dma_t tx_dma; /**< Logical DMA stream used for TX */
uint8_t tx_dma_chan; /**< DMA channel used for TX */
dma_t rx_dma; /**< Logical DMA stream used for RX */
uint8_t rx_dma_chan; /**< DMA channel used for RX */
#endif
} spi_conf_t; } spi_conf_t;
/** /**
* @brief Get the actual bus clock frequency for the APB buses * @brief Get the actual bus clock frequency for the APB buses
* *
@ -372,6 +422,247 @@ void gpio_init_af(gpio_t pin, gpio_af_t af);
*/ */
void gpio_init_analog(gpio_t pin); void gpio_init_analog(gpio_t pin);
#ifdef MODULE_PERIPH_DMA
/**
* @brief DMA stream not defined
*/
#define DMA_STREAM_UNDEF (UINT_MAX)
/**
* @brief Initialize DMA
*/
void dma_init(void);
/**
* @brief Execute a DMA transfer
*
* This function blocks until the transfer is completed. This is a convenience
* function which configure, start, wait and stop a DMA transfer.
*
* @param[in] dma logical DMA stream
* @param[in] chan DMA channel
* @param[in] src source buffer
* @param[out] dst destination buffer
* @param[in] len length to transfer
* @param[in] mode DMA mode
* @param[in] flags DMA configuration
*
* @return < 0 on error, the number of transfered bytes otherwise
*/
int dma_transfer(dma_t dma, int chan, const void *src, void *dst, size_t len,
dma_mode_t mode, uint8_t flags);
/**
* @brief Acquire a DMA stream
*
* @param[in] dma logical DMA stream
*/
void dma_acquire(dma_t dma);
/**
* @brief Release a DMA stream
*
* @param[in] dma logical DMA stream
*/
void dma_release(dma_t dma);
/**
* @brief Start a DMA transfer on a stream
*
* Start a DMA transfer on a given stream. The stream must be configured first
* by a @p dma_configure call.
*
* @param[in] dma logical DMA stream
*/
void dma_start(dma_t dma);
/**
* @brief Suspend a DMA transfer on a stream
*
* @param[in] dma logical DMA stream
*
* @return the remaining number of bytes to transfer
*/
uint16_t dma_suspend(dma_t dma);
/**
* @brief Resume a suspended DMA transfer on a stream
*
* @param[in] dma logical DMA stream
* @param[in] reamaining the remaining number of bytes to transfer
*/
void dma_resume(dma_t dma, uint16_t remaining);
/**
* @brief Stop a DMA transfer on a stream
*
* @param[in] dma logical DMA stream
*/
void dma_stop(dma_t dma);
/**
* @brief Wait for the end of a transfer
*
* @param[in] dma logical DMA stream
*/
void dma_wait(dma_t dma);
/**
* @brief Configure a DMA stream for a new transfer
*
* @param[in] dma logical DMA stream
* @param[in] chan DMA channel
* @param[in] src source buffer
* @param[out] dst destination buffer
* @param[in] len length to transfer
* @param[in] mode DMA mode
* @param[in] flags DMA configuration
*
* @return < 0 on error, 0 on success
*/
int dma_configure(dma_t dma, int chan, const void *src, void *dst, size_t len,
dma_mode_t mode, uint8_t flags);
/**
* @brief Get DMA base register
*
* For simplifying DMA stream handling, we map the DMA channels transparently to
* one integer number, such that DMA1 stream0 equals 0, DMA2 stream0 equals 8,
* DMA2 stream 7 equals 15 and so on.
*
* @param[in] stream physical DMA stream
*/
static inline DMA_TypeDef *dma_base(int stream)
{
return (stream < 8) ? DMA1 : DMA2;
}
/**
* @brief Power on the DMA device the given stream belongs to
*
* @param[in] stream physical DMA stream
*/
static inline void dma_poweron(int stream)
{
if (stream < 8) {
periph_clk_en(AHB1, RCC_AHB1ENR_DMA1EN);
}
else {
periph_clk_en(AHB1, RCC_AHB1ENR_DMA2EN);
}
}
/**
* @brief Get the DMA stream base address
*
* @param[in] stream physical DMA stream
*
* @return base address for the selected DMA stream
*/
static inline DMA_Stream_TypeDef *dma_stream(int stream)
{
uint32_t base = (uint32_t)dma_base(stream);
return (DMA_Stream_TypeDef *)(base + (0x10 + (0x18 * (stream & 0x7))));
}
/**
* @brief Select high or low DMA interrupt register based on stream number
*
* @param[in] stream physical DMA stream
*
* @return 0 for streams 0-3, 1 for streams 3-7
*/
static inline int dma_hl(int stream)
{
return ((stream & 0x4) >> 2);
}
/**
* @brief Get the interrupt flag clear bit position in the DMA LIFCR register
*
* @param[in] stream physical DMA stream
*/
static inline uint32_t dma_ifc(int stream)
{
switch (stream & 0x3) {
case 0:
return (1 << 5);
case 1:
return (1 << 11);
case 2:
return (1 << 21);
case 3:
return (1 << 27);
default:
return 0;
}
}
/**
* @brief Enable the interrupt of a given stream
*
* @param[in] stream physical DMA stream
*/
static inline void dma_isr_enable(int stream)
{
if (stream < 7) {
NVIC_EnableIRQ((IRQn_Type)((int)DMA1_Stream0_IRQn + stream));
}
else if (stream == 7) {
NVIC_EnableIRQ(DMA1_Stream7_IRQn);
}
else if (stream < 13) {
NVIC_EnableIRQ((IRQn_Type)((int)DMA2_Stream0_IRQn + (stream - 8)));
}
else if (stream < 16) {
NVIC_EnableIRQ((IRQn_Type)((int)DMA2_Stream5_IRQn + (stream - 13)));
}
}
/**
* @brief Disable the interrupt of a given stream
*
* @param[in] stream physical DMA stream
*/
static inline void dma_isr_disable(int stream)
{
if (stream < 7) {
NVIC_DisableIRQ((IRQn_Type)((int)DMA1_Stream0_IRQn + stream));
}
else if (stream == 7) {
NVIC_DisableIRQ(DMA1_Stream7_IRQn);
}
else if (stream < 13) {
NVIC_DisableIRQ((IRQn_Type)((int)DMA2_Stream0_IRQn + (stream - 8)));
}
else if (stream < 16) {
NVIC_DisableIRQ((IRQn_Type)((int)DMA2_Stream5_IRQn + (stream - 13)));
}
}
/**
* @brief Clear the interrupt of a given stream
*
* @param[in] stream physical DMA stream
*/
static inline void dma_isr_clear(int stream)
{
if (stream < 7) {
NVIC_ClearPendingIRQ((IRQn_Type)((int)DMA1_Stream0_IRQn + stream));
}
else if (stream == 7) {
NVIC_ClearPendingIRQ((IRQn_Type)DMA1_Stream7_IRQn);
}
else if (stream < 13) {
NVIC_ClearPendingIRQ((IRQn_Type)((int)DMA2_Stream0_IRQn + (stream - 8)));
}
else if (stream < 16) {
NVIC_ClearPendingIRQ((IRQn_Type)((int)DMA2_Stream5_IRQn + (stream - 13)));
}
}
#endif /* MODULE_PERIPH_DMA */
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -0,0 +1,306 @@
/*
* Copyright (C) 2017 OTA keys S.A.
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup cpu_stm32_common
* @{
*
* @file
* @brief Low-level DMA driver implementation
*
* @author Vincent Dupont <vincent@otakeys.com>
*
* @}
*/
#include <stdint.h>
#include "periph_cpu.h"
#include "periph_conf.h"
#include "mutex.h"
#include "assert.h"
#if !(defined(CPU_FAM_STM32F2) || defined(CPU_FAM_STM32F4) || defined(CPU_FAM_STM32F7))
#error "DMA is not supported for target CPU"
#endif
#define DMA_STREAM_IT_MASK (DMA_LISR_FEIF0 | DMA_LISR_DMEIF0 | \
DMA_LISR_TEIF0 | DMA_LISR_HTIF0 | \
DMA_LISR_TCIF0)
struct dma_ctx {
mutex_t conf_lock;
mutex_t sync_lock;
uint16_t len;
};
static struct dma_ctx dma_ctx[DMA_NUMOF];
static inline uint32_t dma_all_flags(dma_t dma)
{
assert(dma < DMA_NUMOF);
switch (dma_config[dma].stream & 0x3) {
case 0: /* 0 and 4 */
return (DMA_STREAM_IT_MASK);
case 1: /* 1 and 5 */
return (DMA_STREAM_IT_MASK << 6);
case 2: /* 2 and 6 */
return (DMA_STREAM_IT_MASK << 16);
case 3: /* 3 and 7 */
return (DMA_STREAM_IT_MASK << 22);
default:
return 0;
}
}
static void dma_clear_all_flags(dma_t dma)
{
assert(dma < DMA_NUMOF);
DMA_TypeDef *stream = dma_base(dma_config[dma].stream);
/* Clear all flags */
if (dma_hl(dma_config[dma].stream) == 0) {
stream->LIFCR = dma_all_flags(dma);
}
else {
stream->HIFCR = dma_all_flags(dma);
}
}
void dma_init(void)
{
for (unsigned i = 0; i < DMA_NUMOF; i++) {
mutex_init(&dma_ctx[i].conf_lock);
mutex_init(&dma_ctx[i].sync_lock);
mutex_lock(&dma_ctx[i].sync_lock);
}
}
int dma_transfer(dma_t dma, int chan, const void *src, void *dst, size_t len,
dma_mode_t mode, uint8_t flags)
{
int ret = dma_configure(dma, chan, src, dst, len, mode, flags);
if (ret != 0) {
return ret;
}
dma_start(dma);
dma_wait(dma);
dma_stop(dma);
return len;
}
void dma_acquire(dma_t dma)
{
assert(dma < DMA_NUMOF);
mutex_lock(&dma_ctx[dma].conf_lock);
}
void dma_release(dma_t dma)
{
assert(dma < DMA_NUMOF);
mutex_unlock(&dma_ctx[dma].conf_lock);
}
int dma_configure(dma_t dma, int chan, const void *src, void *dst, size_t len,
dma_mode_t mode, uint8_t flags)
{
assert(src != NULL);
assert(dst != NULL);
assert(dma < DMA_NUMOF);
int stream_n = dma_config[dma].stream;
uint32_t inc_periph;
uint32_t inc_mem;
DMA_Stream_TypeDef *stream = dma_stream(stream_n);
dma_poweron(stream_n);
dma_clear_all_flags(dma);
switch (mode) {
case DMA_MEM_TO_MEM:
case DMA_PERIPH_TO_MEM:
stream->PAR = (uint32_t)src;
stream->M0AR = (uint32_t)dst;
inc_periph = (flags & DMA_INC_SRC_ADDR);
inc_mem = (flags & DMA_INC_DST_ADDR) >> 1;
break;
case DMA_MEM_TO_PERIPH:
stream->PAR = (uint32_t)dst;
stream->M0AR = (uint32_t)src;
inc_periph = (flags & DMA_INC_DST_ADDR) >> 1;
inc_mem = (flags & DMA_INC_SRC_ADDR);
break;
default:
return -1;
}
uint32_t width = (flags & DMA_DATA_WIDTH_MASK) >> DMA_DATA_WIDTH_SHIFT;
/* Set channel, data width, inc and mode */
stream->CR = (chan & 0xF) << DMA_SxCR_CHSEL_Pos |
width << DMA_SxCR_MSIZE_Pos | width << DMA_SxCR_PSIZE_Pos |
inc_periph << DMA_SxCR_PINC_Pos | inc_mem << DMA_SxCR_MINC_Pos |
(mode & 3) << DMA_SxCR_DIR_Pos;
/* Enable interrupts */
stream->CR |= DMA_SxCR_TCIE | DMA_SxCR_TEIE;
/* Configure FIFO */
stream->FCR = 0;
/* Set length */
stream->NDTR = len;
dma_ctx[dma].len = len;
dma_isr_enable(stream_n);
return 0;
}
void dma_start(dma_t dma)
{
assert(dma < DMA_NUMOF);
DMA_Stream_TypeDef *stream = dma_stream(dma_config[dma].stream);
stream->CR |= DMA_SxCR_EN;
}
uint16_t dma_suspend(dma_t dma)
{
assert(dma < DMA_NUMOF);
int stream_n = dma_config[dma].stream;
DMA_Stream_TypeDef *stream = dma_stream(stream_n);
uint16_t left = 0;
if ((stream->CR & DMA_SxCR_EN) == DMA_SxCR_EN) {
dma_isr_disable(stream_n);
stream->CR &= ~(uint32_t)DMA_SxCR_EN;
while ((stream->CR & DMA_SxCR_EN) == DMA_SxCR_EN) {}
dma_clear_all_flags(dma);
left = stream->NDTR;
dma_isr_clear(stream_n);
}
return left;
}
void dma_resume(dma_t dma, uint16_t remaining)
{
assert(dma < DMA_NUMOF);
int stream_n = dma_config[dma].stream;
DMA_Stream_TypeDef *stream = dma_stream(stream_n);
if (remaining > 0) {
dma_isr_enable(stream_n);
stream->NDTR = remaining;
stream->M0AR += dma_ctx[dma].len - remaining;
dma_ctx[dma].len = remaining;
stream->CR |= (uint32_t)DMA_SxCR_EN;
}
}
void dma_stop(dma_t dma)
{
assert(dma < DMA_NUMOF);
DMA_Stream_TypeDef *stream = dma_stream(dma_config[dma].stream);
stream->CR &= ~(uint32_t)DMA_SxCR_EN;
}
void dma_wait(dma_t dma)
{
assert(dma < DMA_NUMOF);
mutex_lock(&dma_ctx[dma].sync_lock);
}
void dma_isr_handler(dma_t dma)
{
dma_clear_all_flags(dma);
mutex_unlock(&dma_ctx[dma].sync_lock);
cortexm_isr_end();
}
#ifdef DMA_0_ISR
void DMA_0_ISR(void)
{
dma_isr_handler(0);
}
#endif
#ifdef DMA_1_ISR
void DMA_1_ISR(void)
{
dma_isr_handler(1);
}
#endif
#ifdef DMA_2_ISR
void DMA_2_ISR(void)
{
dma_isr_handler(2);
}
#endif
#ifdef DMA_3_ISR
void DMA_3_ISR(void)
{
dma_isr_handler(3);
}
#endif
#ifdef DMA_4_ISR
void DMA_4_ISR(void)
{
dma_isr_handler(4);
}
#endif
#ifdef DMA_5_ISR
void DMA_5_ISR(void)
{
dma_isr_handler(5);
}
#endif
#ifdef DMA_6_ISR
void DMA_6_ISR(void)
{
dma_isr_handler(6);
}
#endif
#ifdef DMA_7_ISR
void DMA_7_ISR(void)
{
dma_isr_handler(7);
}
#endif
#ifdef DMA_8_ISR
void DMA_8_ISR(void)
{
dma_isr_handler(8);
}
#endif
#ifdef DMA_9_ISR
void DMA_9_ISR(void)
{
dma_isr_handler(9);
}
#endif

View File

@ -76,101 +76,6 @@ typedef enum {
} adc_res_t; } adc_res_t;
/** @} */ /** @} */
/**
* @brief Power on the DMA device the given stream belongs to
*
* @param[in] stream logical DMA stream
*/
static inline void dma_poweron(int stream)
{
if (stream < 8) {
periph_clk_en(AHB1, RCC_AHB1ENR_DMA1EN);
} else {
periph_clk_en(AHB1, RCC_AHB1ENR_DMA2EN);
}
}
/**
* @brief Get DMA base register
*
* For simplifying DMA stream handling, we map the DMA channels transparently to
* one integer number, such that DMA1 stream0 equals 0, DMA2 stream0 equals 8,
* DMA2 stream 7 equals 15 and so on.
*
* @param[in] stream logical DMA stream
*/
static inline DMA_TypeDef *dma_base(int stream)
{
return (stream < 8) ? DMA1 : DMA2;
}
/**
* @brief Get the DMA stream base address
*
* @param[in] stream logical DMA stream
*
* @return base address for the selected DMA stream
*/
static inline DMA_Stream_TypeDef *dma_stream(int stream)
{
uint32_t base = (uint32_t)dma_base(stream);
return (DMA_Stream_TypeDef *)(base + (0x10 + (0x18 * (stream & 0x7))));
}
/**
* @brief Select high or low DMA interrupt register based on stream number
*
* @param[in] stream logical DMA stream
*
* @return 0 for streams 0-3, 1 for streams 3-7
*/
static inline int dma_hl(int stream)
{
return ((stream & 0x4) >> 2);
}
/**
* @brief Get the interrupt flag clear bit position in the DMA LIFCR register
*
* @param[in] stream logical DMA stream
*/
static inline uint32_t dma_ifc(int stream)
{
switch (stream & 0x3) {
case 0: /* 0 and 4 */
return (1 << 5);
case 1: /* 1 and 5 */
return (1 << 11);
case 2: /* 2 and 6 */
return (1 << 21);
case 3: /* 3 and 7 */
return (1 << 27);
default:
return 0;
}
}
/**
* @brief Enable DMA interrupts
*
* @param[in] stream logical DMA stream
*/
static inline void dma_isr_enable(int stream)
{
if (stream < 7) {
NVIC_EnableIRQ((IRQn_Type)((int)DMA1_Stream0_IRQn + stream));
}
else if (stream == 7) {
NVIC_EnableIRQ(DMA1_Stream7_IRQn);
}
else if (stream < 13) {
NVIC_EnableIRQ((IRQn_Type)((int)DMA2_Stream0_IRQn + (stream - 8)));
}
else if (stream < 16) {
NVIC_EnableIRQ((IRQn_Type)((int)DMA2_Stream5_IRQn + (stream - 13)));
}
}
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -89,98 +89,6 @@ typedef struct {
uint8_t chan; /**< CPU ADC channel connected to the pin */ uint8_t chan; /**< CPU ADC channel connected to the pin */
} adc_conf_t; } adc_conf_t;
/**
* @brief Power on the DMA device the given stream belongs to
*
* @param[in] stream logical DMA stream
*/
static inline void dma_poweron(int stream)
{
if (stream < 8) {
periph_clk_en(AHB1, RCC_AHB1ENR_DMA1EN);
}
else {
periph_clk_en(AHB1, RCC_AHB1ENR_DMA2EN);
}
}
/**
* @brief Get DMA base register
*
* For simplifying DMA stream handling, we map the DMA channels transparently to
* one integer number, such that DMA1 stream0 equals 0, DMA2 stream0 equals 8,
* DMA2 stream 7 equals 15 and so on.
*
* @param[in] stream logical DMA stream
*/
static inline DMA_TypeDef *dma_base(int stream)
{
return (stream < 8) ? DMA1 : DMA2;
}
/**
* @brief Get the DMA stream base address
*
* @param[in] stream logical DMA stream
*
* @return base address for the selected DMA stream
*/
static inline DMA_Stream_TypeDef *dma_stream(int stream)
{
uint32_t base = (uint32_t)dma_base(stream);
return (DMA_Stream_TypeDef *)(base + (0x10 + (0x18 * (stream & 0x7))));
}
/**
* @brief Select high or low DMA interrupt register based on stream number
*
* @param[in] stream logical DMA stream
*
* @return 0 for streams 0-3, 1 for streams 3-7
*/
static inline int dma_hl(int stream)
{
return ((stream & 0x4) >> 2);
}
/**
* @brief Get the interrupt flag clear bit position in the DMA LIFCR register
*
* @param[in] stream logical DMA stream
*/
static inline uint32_t dma_ifc(int stream)
{
switch (stream & 0x3) {
case 0:
return (1 << 5);
case 1:
return (1 << 11);
case 2:
return (1 << 21);
case 3:
return (1 << 27);
default:
return 0;
}
}
static inline void dma_isr_enable(int stream)
{
if (stream < 7) {
NVIC_EnableIRQ((IRQn_Type)((int)DMA1_Stream0_IRQn + stream));
}
else if (stream == 7) {
NVIC_EnableIRQ(DMA1_Stream7_IRQn);
}
else if (stream < 13) {
NVIC_EnableIRQ((IRQn_Type)((int)DMA2_Stream0_IRQn + (stream - 8)));
}
else if (stream < 16) {
NVIC_EnableIRQ((IRQn_Type)((int)DMA2_Stream5_IRQn + (stream - 13)));
}
}
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif