diff --git a/include/libopencm3/stm32/f1/dma.h b/include/libopencm3/stm32/f1/dma.h index b08803f7..6e5cc20f 100644 --- a/include/libopencm3/stm32/f1/dma.h +++ b/include/libopencm3/stm32/f1/dma.h @@ -141,9 +141,30 @@ LGPL License Terms @ref lgpl_license /* --- DMA_ISR values ------------------------------------------------------ */ +/* --- DMA Interrupt Flag offset values ------------------------------------- */ +/* These are based on every interrupt flag and flag clear being at the same relative location */ +/** @defgroup dma_if_offset DMA Interrupt Flag Offsets within stream flag group. +@ingroup STM32F1xx_dma_defines + +@{*/ +/** Transfer Error Interrupt Flag */ +#define DMA_TEIF (1 << 3) +/** Half Transfer Interrupt Flag */ +#define DMA_HTIF (1 << 2) +/** Transfer Complete Interrupt Flag */ +#define DMA_TCIF (1 << 1) +/** Global Interrupt Flag */ +#define DMA_GIF (1 << 0) +/**@}*/ + +/* Offset within interrupt status register to start of stream interrupt flag field */ +#define DMA_FLAG_OFFSET(channel) (4*(channel - 1)) +#define DMA_FLAGS (DMA_TEIF | DMA_TCIF | DMA_HTIF | DMA_GIF) +#define DMA_ISR_MASK(channel) DMA_FLAGS << DMA_FLAG_OFFSET(channel) + /* TEIF: Transfer error interrupt flag */ -#define DMA_ISR_TEIF_BIT (1 << 3) -#define DMA_ISR_TEIF(channel) (DMA_ISR_TEIF_BIT << (4 * ((channel) -1))) +#define DMA_ISR_TEIF_BIT DMA_ISR_TEIF +#define DMA_ISR_TEIF(channel) (DMA_ISR_TEIF_BIT << DMA_FLAG_OFFSET(channel))) #define DMA_ISR_TEIF1 DMA_ISR_TEIF(DMA_CHANNEL1) #define DMA_ISR_TEIF2 DMA_ISR_TEIF(DMA_CHANNEL2) @@ -154,8 +175,8 @@ LGPL License Terms @ref lgpl_license #define DMA_ISR_TEIF7 DMA_ISR_TEIF(DMA_CHANNEL7) /* HTIF: Half transfer interrupt flag */ -#define DMA_ISR_HTIF_BIT (1 << 2) -#define DMA_ISR_HTIF(channel) (DMA_ISR_HTIF_BIT << (4 * ((channel) -1))) +#define DMA_ISR_HTIF_BIT DMA_HTIF +#define DMA_ISR_HTIF(channel) (DMA_ISR_HTIF_BIT << DMA_FLAG_OFFSET(channel))) #define DMA_ISR_HTIF1 DMA_ISR_HTIF(DMA_CHANNEL1) #define DMA_ISR_HTIF2 DMA_ISR_HTIF(DMA_CHANNEL2) @@ -166,8 +187,8 @@ LGPL License Terms @ref lgpl_license #define DMA_ISR_HTIF7 DMA_ISR_HTIF(DMA_CHANNEL7) /* TCIF: Transfer complete interrupt flag */ -#define DMA_ISR_TCIF_BIT (1 << 1) -#define DMA_ISR_TCIF(channel) (DMA_ISR_TCIF_BIT << (4 * ((channel) -1))) +#define DMA_ISR_TCIF_BIT DMA_TCIF +#define DMA_ISR_TCIF(channel) (DMA_ISR_TCIF_BIT << (DMA_FLAG_OFFSET(channel))) #define DMA_ISR_TCIF1 DMA_ISR_TCIF(DMA_CHANNEL1) #define DMA_ISR_TCIF2 DMA_ISR_TCIF(DMA_CHANNEL2) @@ -178,8 +199,8 @@ LGPL License Terms @ref lgpl_license #define DMA_ISR_TCIF7 DMA_ISR_TCIF(DMA_CHANNEL7) /* GIF: Global interrupt flag */ -#define DMA_ISR_GIF_BIT (1 << 0) -#define DMA_ISR_GIF(channel) (DMA_ISR_GIF_BIT << (4 * ((channel) -1))) +#define DMA_ISR_GIF_BIT DMA_GIF +#define DMA_ISR_GIF(channel) (DMA_ISR_GIF_BIT << (DMA_FLAG_OFFSET(channel))) #define DMA_ISR_GIF1 DMA_ISR_GIF(DMA_CHANNEL1) #define DMA_ISR_GIF2 DMA_ISR_GIF(DMA_CHANNEL2) @@ -192,8 +213,8 @@ LGPL License Terms @ref lgpl_license /* --- DMA_IFCR values ----------------------------------------------------- */ /* CTEIF: Transfer error clear */ -#define DMA_IFCR_CTEIF_BIT (1 << 3) -#define DMA_IFCR_CTEIF(channel) (DMA_IFCR_CTEIF_BIT << (4 * ((channel) -1))) +#define DMA_IFCR_CTEIF_BIT DMA_TEIF +#define DMA_IFCR_CTEIF(channel) (DMA_IFCR_CTEIF_BIT << (DMA_FLAG_OFFSET(channel))) #define DMA_IFCR_CTEIF1 DMA_IFCR_CTEIF(DMA_CHANNEL1) #define DMA_IFCR_CTEIF2 DMA_IFCR_CTEIF(DMA_CHANNEL2) @@ -204,8 +225,8 @@ LGPL License Terms @ref lgpl_license #define DMA_IFCR_CTEIF7 DMA_IFCR_CTEIF(DMA_CHANNEL7) /* CHTIF: Half transfer clear */ -#define DMA_IFCR_CHTIF_BIT (1 << 2) -#define DMA_IFCR_CHTIF(channel) (DMA_IFCR_CHTIF_BIT << (4 * ((channel) -1))) +#define DMA_IFCR_CHTIF_BIT DMA_HTIF +#define DMA_IFCR_CHTIF(channel) (DMA_IFCR_CHTIF_BIT << (DMA_FLAG_OFFSET(channel))) #define DMA_IFCR_CHTIF1 DMA_IFCR_CHTIF(DMA_CHANNEL1) #define DMA_IFCR_CHTIF2 DMA_IFCR_CHTIF(DMA_CHANNEL2) @@ -216,8 +237,8 @@ LGPL License Terms @ref lgpl_license #define DMA_IFCR_CHTIF7 DMA_IFCR_CHTIF(DMA_CHANNEL7) /* CTCIF: Transfer complete clear */ -#define DMA_IFCR_CTCIF_BIT (1 << 1) -#define DMA_IFCR_CTCIF(channel) (DMA_IFCR_CTCIF_BIT << (4 * ((channel) -1))) +#define DMA_IFCR_CTCIF_BIT DMA_TCIF +#define DMA_IFCR_CTCIF(channel) (DMA_IFCR_CTCIF_BIT << (DMA_FLAG_OFFSET(channel))) #define DMA_IFCR_CTCIF1 DMA_IFCR_CTCIF(DMA_CHANNEL1) #define DMA_IFCR_CTCIF2 DMA_IFCR_CTCIF(DMA_CHANNEL2) @@ -228,8 +249,8 @@ LGPL License Terms @ref lgpl_license #define DMA_IFCR_CTCIF7 DMA_IFCR_CTCIF(DMA_CHANNEL7) /* CGIF: Global interrupt clear */ -#define DMA_IFCR_CGIF_BIT (1 << 0) -#define DMA_IFCR_CGIF(channel) (DMA_IFCR_CGIF_BIT << (4 * ((channel) -1))) +#define DMA_IFCR_CGIF_BIT DMA_GIF +#define DMA_IFCR_CGIF(channel) (DMA_IFCR_CGIF_BIT << (DMA_FLAG_OFFSET(channel))) #define DMA_IFCR_CGIF1 DMA_IFCR_CGIF(DMA_CHANNEL1) #define DMA_IFCR_CGIF2 DMA_IFCR_CGIF(DMA_CHANNEL2) @@ -241,7 +262,7 @@ LGPL License Terms @ref lgpl_license /* Clear interrupts mask */ #define DMA_IFCR_CIF_BIT 0xF -#define DMA_IFCR_CIF(channel) (DMA_IFCR_CIF_BIT << (4 * ((channel) - 1))) +#define DMA_IFCR_CIF(channel) (DMA_IFCR_CIF_BIT << (DMA_FLAG_OFFSET(channel))) #define DMA_IFCR_CIF1 DMA_IFCR_CIF(DMA_CHANNEL1) #define DMA_IFCR_CIF2 DMA_IFCR_CIF(DMA_CHANNEL2) @@ -349,12 +370,16 @@ LGPL License Terms @ref lgpl_license BEGIN_DECLS void dma_channel_reset(u32 dma, u8 channel); +void dma_clear_interrupt_flags(u32 dma, u8 channel, u32 interrupts); +bool dma_get_interrupt_flag(u32 dma, u8 channel, u32 interrupts); void dma_enable_mem2mem_mode(u32 dma, u8 channel); void dma_set_priority(u32 dma, u8 channel, u32 prio); void dma_set_memory_size(u32 dma, u8 channel, u32 mem_size); void dma_set_peripheral_size(u32 dma, u8 channel, u32 peripheral_size); void dma_enable_memory_increment_mode(u32 dma, u8 channel); +void dma_disable_memory_increment_mode(u32 dma, u8 channel); void dma_enable_peripheral_increment_mode(u32 dma, u8 channel); +void dma_disable_peripheral_increment_mode(u32 dma, u8 channel); void dma_enable_circular_mode(u32 dma, u8 channel); void dma_set_read_from_peripheral(u32 dma, u8 channel); void dma_set_read_from_memory(u32 dma, u8 channel); diff --git a/lib/stm32/f1/dma.c b/lib/stm32/f1/dma.c index 04cb8a10..c26020af 100644 --- a/lib/stm32/f1/dma.c +++ b/lib/stm32/f1/dma.c @@ -10,12 +10,18 @@ @date 18 August 2012 -This library supports the DMA -Control System in the STM32F1xx series of ARM Cortex Microcontrollers -by ST Microelectronics. It can provide for two DMA controllers, -one with 7 channels and one with 5. Channels are hardware dedicated -and each is shared with a number of different sources (only one can be -used at a time, under the responsibility of the programmer). +This library supports the DMA Control System in the STM32 series of ARM Cortex +Microcontrollers by ST Microelectronics. + +Up to two DMA controllers are supported. 12 DMA channels are allocated 7 to +the first DMA controller and 5 to the second. Each channel is connected to +between 3 and 6 hardware peripheral DMA signals in a logical OR arrangement. + +DMA transfers can be configured to occur between peripheral and memory in +any combination including memory to memory. Circular mode transfers are +also supported in transfers involving a peripheral. An arbiter is provided +to resolve priority DMA requests. Transfers can be made with 8, 16 or 32 bit +words. LGPL License Terms @ref lgpl_license */ @@ -67,6 +73,42 @@ void dma_channel_reset(u32 dma, u8 channel) DMA_IFCR(dma) |= DMA_IFCR_CIF(channel); } +/*-----------------------------------------------------------------------------*/ +/** @brief DMA Channel Clear Interrupt Flag + +The interrupt flag for the channel is cleared. More than one interrupt for the +same channel may be cleared by using the logical OR of the interrupt flags. + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] channel unsigned int8. Channel number: @ref dma_st_number +@param[in] interrupts unsigned int32. Logical OR of interrupt numbers: @ref dma_if_offset +*/ + +void dma_clear_interrupt_flags(u32 dma, u8 channel, u32 interrupts) +{ +/* Get offset to interrupt flag location in channel field */ + u32 flags = (interrupts << DMA_FLAG_OFFSET(channel)); + DMA_IFCR(dma) = flags; +} + +/*-----------------------------------------------------------------------------*/ +/** @brief DMA Channel Read Interrupt Flag + +The interrupt flag for the channel is returned. + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] channel unsigned int8. Channel number: @ref dma_st_number +@param[in] interrupt unsigned int32. Interrupt number: @ref dma_st_number +@returns bool interrupt flag is set. +*/ + +bool dma_get_interrupt_flag(u32 dma, u8 channel, u32 interrupt) +{ +/* get offset to interrupt flag location in channel field. */ + u32 flag = (interrupt << DMA_FLAG_OFFSET(channel)); + return ((DMA_ISR(dma) & flag) > 0); +} + /*-----------------------------------------------------------------------------*/ /** @brief DMA Channel Enable Memory to Memory Transfers @@ -160,11 +202,39 @@ void dma_enable_memory_increment_mode(u32 dma, u8 channel) @param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2 */ +void dma_disable_memory_increment_mode(u32 dma, u8 channel) +{ + DMA_CCR(dma, channel) &= ~DMA_CCR_MINC; +} + +/*-----------------------------------------------------------------------------*/ +/** @brief DMA Channel Enable Peripheral Increment after Transfer + +Following each transfer the current peripheral address is incremented by +1, 2 or 4 depending on the data size set in @ref dma_set_peripheral_size. The +value held by the base peripheral address register is unchanged. + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2 +*/ + void dma_enable_peripheral_increment_mode(u32 dma, u8 channel) { DMA_CCR(dma, channel) |= DMA_CCR_PINC; } +/*-----------------------------------------------------------------------------*/ +/** @brief DMA Channel Disable Peripheral Increment after Transfer + +@param[in] dma unsigned int32. DMA controller base address: DMA1 or DMA2 +@param[in] channel unsigned int8. Channel number: 1-7 for DMA1 or 1-5 for DMA2 +*/ + +void dma_disable_peripheral_increment_mode(u32 dma, u8 channel) +{ + DMA_CCR(dma, channel) &= ~DMA_CCR_PINC; +} + /*-----------------------------------------------------------------------------*/ /** @brief DMA Channel Enable Memory Circular Mode