diff --git a/cpu/stm32/include/periph/cpu_dma.h b/cpu/stm32/include/periph/cpu_dma.h index 74dd58e8cde0..f9cfd118f8d2 100644 --- a/cpu/stm32/include/periph/cpu_dma.h +++ b/cpu/stm32/include/periph/cpu_dma.h @@ -16,6 +16,7 @@ * * @author Hauke Petersen * @author Vincent Dupont + * @author Joshua DeWeese */ #ifndef PERIPH_CPU_DMA_H @@ -38,7 +39,7 @@ typedef struct { * - 8: DAM2 / Stream0 * - ... * - 15: DMA2 / Stream7 - * STM32F0/1/L0/1/4: + * STM32F0/1/3/L0/1/4: * - 0: DMA1 / Channel1 * - ... * - 4: DMA1 / Channel5 @@ -88,10 +89,8 @@ typedef enum { * @{ */ #define DMA_DATA_WIDTH_BYTE (0x00) /**< Byte width */ -#define DMA_DATA_WIDTH_HALF_WORD (0x01) /**< Half word width */ -#define DMA_DATA_WIDTH_WORD (0x02) /**< Word width */ -#define DMA_DATA_WIDTH_MASK (0x03) /**< Width mask */ -#define DMA_DATA_WIDTH_SHIFT (0) /**< Width position */ +#define DMA_DATA_WIDTH_HALF_WORD (0x01) /**< Half word width (2 bytes)*/ +#define DMA_DATA_WIDTH_WORD (0x02) /**< Word width (4 bytes)*/ /** @} */ #ifdef MODULE_PERIPH_DMA @@ -115,7 +114,7 @@ void dma_init(void); * @param[in] chan DMA channel (on stm32f2/4/7, CxS or unused on others) * @param[in] src source buffer * @param[out] dst destination buffer - * @param[in] len length to transfer + * @param[in] len number of transfers to perform * @param[in] mode DMA mode * @param[in] flags DMA configuration * @@ -153,7 +152,7 @@ void dma_start(dma_t dma); * * @param[in] dma logical DMA stream * - * @return the remaining number of bytes to transfer + * @return the remaining number of transfers to perform */ uint16_t dma_suspend(dma_t dma); @@ -161,7 +160,7 @@ 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 + * @param[in] reamaining the remaining number of transfers to perform */ void dma_resume(dma_t dma, uint16_t remaining); @@ -186,7 +185,7 @@ void dma_wait(dma_t dma); * @param[in] chan DMA channel (on stm32f2/4/7, CxS or unused on others) * @param[in] src source buffer * @param[out] dst destination buffer - * @param[in] len length to transfer + * @param[in] len number of transfers to perform * @param[in] mode DMA mode * @param[in] flags DMA configuration * @@ -206,7 +205,7 @@ int dma_configure(dma_t dma, int chan, const volatile void *src, volatile void * * @param[in] chan DMA channel (on stm32f2/4/7, CxS or unused on others) * @param[in] periph_addr Peripheral register address * @param[in] mode DMA direction mode - * @param[in] width DMA transfer width + * @param[in] width DMA transfer width (one of DMA_DATA_WIDTH_*) * @param[in] inc_periph Increment peripheral address after read/write */ void dma_setup(dma_t dma, int chan, void *periph_addr, dma_mode_t mode, @@ -217,8 +216,8 @@ void dma_setup(dma_t dma, int chan, void *periph_addr, dma_mode_t mode, * * @param[in] dma Logical DMA stream * @param[in] mem Memory address - * @param[in] len Transfer length - * @param[in] inc_mem Increment the memory address after read/write + * @param[in] len Number of transfers to perform + * @param[in] inc_mem Increment the memory address (by the transfer width) after read/write */ void dma_prepare(dma_t dma, void *mem, size_t len, bool incr_mem); diff --git a/cpu/stm32/periph/dma.c b/cpu/stm32/periph/dma.c index c61106f6b815..2d720e806a63 100644 --- a/cpu/stm32/periph/dma.c +++ b/cpu/stm32/periph/dma.c @@ -14,6 +14,7 @@ * @brief Low-level DMA driver implementation * * @author Vincent Dupont + * @author Joshua DeWeese * * @} */ @@ -84,6 +85,9 @@ #endif #endif /* CPU_FAM_STM32F2 || CPU_FAM_STM32F4 || CPU_FAM_STM32F7 */ +#define DMA_DATA_WIDTH_MASK (0x03) +#define DMA_DATA_WIDTH_SHIFT (0) + struct dma_ctx { STM32_DMA_Stream_Type *stream; mutex_t conf_lock; @@ -193,22 +197,28 @@ static IRQn_Type dma_get_irqn(int stream) return ((IRQn_Type)((int)DMA1_Channel1_IRQn + stream)); } #if defined(DMA2_BASE) + /* stream 7 is invalid for these CPU families */ + else if (stream == 7) { + return -1; + } #if defined(CPU_FAM_STM32F1) else if (stream < 11) { #else else if (stream < 13 ) { #endif - return ((IRQn_Type)((int)DMA2_Channel1_IRQn + stream)); + /* magic number 8 is first DMA2 stream */ + return ((IRQn_Type)((int)DMA2_Channel1_IRQn + stream - 8)); } -#if !defined(CPU_FAM_STM32L1) +#if !defined(CPU_FAM_STM32L1) && !defined(CPU_FAM_STM32F3) else { #if defined(CPU_FAM_STM32F1) return (DMA2_Channel4_5_IRQn); #else - return ((IRQn_Type)((int)DMA2_Channel6_IRQn + stream)); + /* magic number 13 is 8 (first DMA2 stream) + 5 (Channel6) */ + return ((IRQn_Type)((int)DMA2_Channel6_IRQn + stream - 13)); #endif } -#endif /* !defined(CPU_FAM_STM32L1) */ +#endif /* !defined(CPU_FAM_STM32L1) && !defined(CPU_FAM_STM32F3) */ #endif /* defined(DMA2_BASE) */ #endif @@ -392,7 +402,7 @@ void dma_prepare(dma_t dma, void *mem, size_t len, bool incr_mem) STM32_DMA_Stream_Type *stream = dma_ctx[dma].stream; uint32_t ctr_reg = stream->CONTROL_REG; -#if CPU_FAM_STM32F2 || CPU_FAM_STM32F4 || CPU_FAM_STM32F7 +#ifdef DMA_SxCR_MINC stream->CONTROL_REG = (ctr_reg & ~(DMA_SxCR_MINC)) | (incr_mem << DMA_SxCR_MINC_Pos); #else @@ -479,10 +489,30 @@ void dma_resume(dma_t dma, uint16_t remaining) int stream_n = dma_config[dma].stream; STM32_DMA_Stream_Type *stream = dma_ctx[dma].stream; +#ifdef DMA_SxCR_MINC + const bool mem_inc = stream->CONTROL_REG & DMA_SxCR_MINC; + const bool periph_inc = stream->CONTROL_REG & DMA_SxCR_PINC; + const int msize_reg = + (stream->CONTROL_REG & DMA_SxCR_MSIZE) >> DMA_SxCR_MSIZE_Pos; + const int psize_reg = + (stream->CONTROL_REG & DMA_SxCR_MSIZE) >> DMA_SxCR_MSIZE_Pos; +#else + const bool mem_inc = stream->CONTROL_REG & DMA_CCR_MINC; + const bool periph_inc = stream->CONTROL_REG & DMA_CCR_PINC; + const int msize_reg = + (stream->CONTROL_REG & DMA_CCR_MSIZE) >> DMA_CCR_MSIZE_Pos; + const int psize_reg = + (stream->CONTROL_REG & DMA_CCR_PSIZE) >> DMA_CCR_PSIZE_Pos; +#endif + + const int mpitch = (mem_inc) ? msize_reg + 1 : 0; + const int ppitch = (periph_inc) ? psize_reg + 1 : 0; + if (remaining > 0) { dma_isr_enable(stream_n); stream->NDTR_REG = remaining; - stream->MEM_ADDR += dma_ctx[dma].len - remaining; + stream->MEM_ADDR += mpitch * (dma_ctx[dma].len - remaining); + stream->PERIPH_ADDR += ppitch * (dma_ctx[dma].len - remaining); dma_ctx[dma].len = remaining; stream->CONTROL_REG |= DMA_EN; }