From a79336981582043d760590b5f8de95b00d474f7e Mon Sep 17 00:00:00 2001 From: David Sidrane Date: Fri, 5 Jun 2020 09:03:32 -0700 Subject: [PATCH] stm32h7:DMA Add BDMA support Apply suggestions from code review Co-authored-by: Mateusz Szafoni --- arch/arm/src/stm32h7/hardware/stm32_bdma.h | 40 ++-- arch/arm/src/stm32h7/hardware/stm32_dma.h | 18 +- arch/arm/src/stm32h7/stm32_dma.c | 229 +++++++++++++++++++-- 3 files changed, 247 insertions(+), 40 deletions(-) diff --git a/arch/arm/src/stm32h7/hardware/stm32_bdma.h b/arch/arm/src/stm32h7/hardware/stm32_bdma.h index b989a460a5b..56fc68c5302 100644 --- a/arch/arm/src/stm32h7/hardware/stm32_bdma.h +++ b/arch/arm/src/stm32h7/hardware/stm32_bdma.h @@ -49,17 +49,20 @@ /* Register Offsets *****************************************************************/ -#define STM32_BDMA_OFFSET(x) (0x08+0x14*(x)) #define STM32_BDMA_ISR_OFFSET 0x0000 /* BDMA interrupt status register */ #define STM32_BDMA_IFCR_OFFSET 0x0004 /* BDMA interrupt flag clear register */ -#define STM32_BDMACH_CCR_OFFSET 0x0008 -#define STM32_BDMACH_CNDTR_OFFSET 0x000C -#define STM32_BDMACH_CPAR_OFFSET 0x0010 -#define STM32_BDMACH_CM0AR_OFFSET 0x0014 -#define STM32_BDMACH_CM1AR_OFFSET 0x0018 +#define STM32_BDMACH_CCR_OFFSET 0x0008 /* BDMA channel x configuration register */ +#define STM32_BDMACH_CNDTR_OFFSET 0x000C /* BDMA channel x number of data to transfer register */ +#define STM32_BDMACH_CPAR_OFFSET 0x0010 /* BDMA channel x peripheral address register */ +#define STM32_BDMACH_CM0AR_OFFSET 0x0014 /* BDMA channel x memory 0 address register */ +#define STM32_BDMACH_CM1AR_OFFSET 0x0018 /* BDMA channel x memory 1 address register */ -#define STM32_BDMA_CCRX_OFFSET(x) (0x0008+(x*0x0014)) /* BDMA channel x configuration register */ +#define STM32_BDMA_SPACING 0x14 +#define STM32_BDMA_OFFSET(x) (STM32_BDMA_SPACING * (x)) + +#define STM32_BDMA_CCRX_OFFSET(x) (STM32_BDMACH_CCR_OFFSET + \ + STM32_BDMA_OFFSET(x)) #define STM32_BDMA_CCR0_OFFSET STM32_BDMA_CCRX_OFFSET(0) #define STM32_BDMA_CCR1_OFFSET STM32_BDMA_CCRX_OFFSET(1) #define STM32_BDMA_CCR2_OFFSET STM32_BDMA_CCRX_OFFSET(2) @@ -69,7 +72,8 @@ #define STM32_BDMA_CCR6_OFFSET STM32_BDMA_CCRX_OFFSET(6) #define STM32_BDMA_CCR7_OFFSET STM32_BDMA_CCRX_OFFSET(7) -#define STM32_BDMA_CNDTRX_OFFSET(x) (0x000C+(x*0x0014)) /* BDMA channel x number of data to transfer register */ +#define STM32_BDMA_CNDTRX_OFFSET(x) (STM32_BDMACH_CNDTR_OFFSET + \ + STM32_BDMA_OFFSET(x)) #define STM32_BDMA_CNDTR0_OFFSET STM32_BDMA_CNDTRX_OFFSET(0) #define STM32_BDMA_CNDTR1_OFFSET STM32_BDMA_CNDTRX_OFFSET(1) #define STM32_BDMA_CNDTR2_OFFSET STM32_BDMA_CNDTRX_OFFSET(2) @@ -79,7 +83,8 @@ #define STM32_BDMA_CNDTR6_OFFSET STM32_BDMA_CNDTRX_OFFSET(6) #define STM32_BDMA_CNDTR7_OFFSET STM32_BDMA_CNDTRX_OFFSET(7) -#define STM32_BDMA_CPARX_OFFSET(x) (0x0010+(x*0x0014)) /* BDMA channel x peripheral address register */ +#define STM32_BDMA_CPARX_OFFSET(x) (STM32_BDMACH_CPAR_OFFSET + \ + STM32_BDMA_OFFSET(x)) #define STM32_BDMA_CPAR0_OFFSET STM32_BDMA_CPARX_OFFSET(0) #define STM32_BDMA_CPAR1_OFFSET STM32_BDMA_CPARX_OFFSET(1) #define STM32_BDMA_CPAR2_OFFSET STM32_BDMA_CPARX_OFFSET(2) @@ -89,7 +94,8 @@ #define STM32_BDMA_CPAR6_OFFSET STM32_BDMA_CPARX_OFFSET(6) #define STM32_BDMA_CPAR7_OFFSET STM32_BDMA_CPARX_OFFSET(7) -#define STM32_BDMA_CM0ARX_OFFSET(x) (0x0014+(x*0x0014)) /* BDMA channel x memory 0 address register */ +#define STM32_BDMA_CM0ARX_OFFSET(x) (STM32_BDMACH_CM0AR_OFFSET + \ + STM32_BDMA_OFFSET(x)) #define STM32_BDMA_CM0AR0_OFFSET STM32_BDMA_CM0ARX_OFFSET(0) #define STM32_BDMA_CM0AR1_OFFSET STM32_BDMA_CM0ARX_OFFSET(1) #define STM32_BDMA_CM0AR2_OFFSET STM32_BDMA_CM0ARX_OFFSET(2) @@ -99,7 +105,8 @@ #define STM32_BDMA_CM0AR6_OFFSET STM32_BDMA_CM0ARX_OFFSET(6) #define STM32_BDMA_CM0AR7_OFFSET STM32_BDMA_CM0ARX_OFFSET(7) -#define STM32_BDMA_CM1ARX_OFFSET(x) (0x0018+(x*0x0014)) /* BDMA channel x memory 1 address register */ +#define STM32_BDMA_CM1ARX_OFFSET(x) (STM32_BDMACH_CM1AR_OFFSET + \ + STM32_BDMA_OFFSET(x)) #define STM32_BDMA_CM1AR0_OFFSET STM32_BDMA_CM1ARX_OFFSET(0) #define STM32_BDMA_CM1AR1_OFFSET STM32_BDMA_CM1ARX_OFFSET(1) #define STM32_BDMA_CM1AR2_OFFSET STM32_BDMA_CM1ARX_OFFSET(2) @@ -172,6 +179,7 @@ #define BDMA_CHAN_TCIF (1 << 1) /* Bit 1: Transfer complete flag */ #define BDMA_CHAN_HTIF (1 << 2) /* Bit 2: half transfer complete flag */ #define BDMA_CHAN_TEIF (1 << 3) /* Bit 3: Transfer error flag */ +#define BDMA_CCR_ALLINTS (BDMA_CHAN_TCIF | BDMA_CHAN_HTIF | BDMA_CHAN_TEIF) /* BDMA interrupt status register */ @@ -240,20 +248,20 @@ # define BDMA_CCR_PSIZE_8BITS (0 << BDMA_CCR_PSIZE_SHIFT) /* 00: 8-bits */ # define BDMA_CCR_PSIZE_16BITS (1 << BDMA_CCR_PSIZE_SHIFT) /* 01: 16-bits */ # define BDMA_CCR_PSIZE_32BITS (2 << BDMA_CCR_PSIZE_SHIFT) /* 10: 32-bits */ -#define BDMA_CCR_MSIZE_SHIFT (10) /* Bits 10-11: Memory size*/ +#define BDMA_CCR_MSIZE_SHIFT (10) /* Bits 10-11: Memory size*/ #define BDMA_CCR_MSIZE_MASK (3 << BDMA_CCR_MSIZE_SHIFT) # define BDMA_CCR_MSIZE_8BITS (0 << BDMA_CCR_MSIZE_SHIFT) /* 00: 8-bits */ # define BDMA_CCR_MSIZE_16BITS (1 << BDMA_CCR_MSIZE_SHIFT) /* 01: 16-bits */ # define BDMA_CCR_MSIZE_32BITS (2 << BDMA_CCR_MSIZE_SHIFT) /* 10: 32-bits */ -#define BDMA_CCR_PL_SHIFT (12) /* Bits 12-13: Priority level */ +#define BDMA_CCR_PL_SHIFT (12) /* Bits 12-13: Priority level */ #define BDMA_CCR_PL_MASK (3 << BDMA_CCR_PL_SHIFT) # define BDMA_CCR_PRILO (0 << BDMA_CCR_PL_SHIFT) /* 00: Low */ # define BDMA_CCR_PRIMED (1 << BDMA_CCR_PL_SHIFT) /* 01: Medium */ # define BDMA_CCR_PRIHI (2 << BDMA_CCR_PL_SHIFT) /* 10: High */ # define BDMA_CCR_PRIVERYHI (3 << BDMA_CCR_PL_SHIFT) /* 11: Very high */ -#define BDMA_CCR_M2M (1 << 14) /* Bit 14: Memory-to-memory mode */ -#define BDMA_CCR_DBM (1 << 15) /* Bit 15: dobule buffer mode*/ -#define BDMA_CCR_CT (1 << 16) /* Bit 16: Current target */ +#define BDMA_CCR_M2M (1 << 14) /* Bit 14: Memory-to-memory mode */ +#define BDMA_CCR_DBM (1 << 15) /* Bit 15: dobule buffer mode*/ +#define BDMA_CCR_CT (1 << 16) /* Bit 16: Current target */ /* BDMA channel x number of data to transfer register */ diff --git a/arch/arm/src/stm32h7/hardware/stm32_dma.h b/arch/arm/src/stm32h7/hardware/stm32_dma.h index 94d7ed754ae..ffb672b2f07 100644 --- a/arch/arm/src/stm32h7/hardware/stm32_dma.h +++ b/arch/arm/src/stm32h7/hardware/stm32_dma.h @@ -47,7 +47,7 @@ * Pre-processor Definitions ************************************************************************************/ -/* 2 DMA controllers + 1 MDMA + 1 BDMA*/ +/* 2 DMA controllers + 1 MDMA + 1 BDMA */ #define MDMA (0) #define DMA1 (1) @@ -275,7 +275,7 @@ #define DMA_STREAM_HTIF_BIT (1 << 4) /* Bit 4: Stream Half Transfer flag */ #define DMA_STREAM_TCIF_BIT (1 << 5) /* Bit 5: Stream Transfer Complete flag */ -/* DMA interrupt status register and interrupt flag clear register field definitions */ +/* DMA interrupt status and interrupt clear register field definitions */ #define DMA_INT_STREAM0_SHIFT (0) /* Bits 0-5: DMA Stream 0 interrupt */ #define DMA_INT_STREAM0_MASK (DMA_STREAM_MASK << DMA_INT_STREAM0_SHIFT) @@ -308,6 +308,7 @@ # define DMA_SCR_DIR_P2M (0 << DMA_SCR_DIR_SHIFT) /* 00: Peripheral-to-memory */ # define DMA_SCR_DIR_M2P (1 << DMA_SCR_DIR_SHIFT) /* 01: Memory-to-peripheral */ # define DMA_SCR_DIR_M2M (2 << DMA_SCR_DIR_SHIFT) /* 10: Memory-to-memory */ + #define DMA_SCR_CIRC (1 << 8) /* Bit 8: Circular mode */ #define DMA_SCR_PINC (1 << 9) /* Bit 9: Peripheral increment mode */ #define DMA_SCR_MINC (1 << 10) /* Bit 10: Memory increment mode */ @@ -316,11 +317,13 @@ # define DMA_SCR_PSIZE_8BITS (0 << DMA_SCR_PSIZE_SHIFT) /* 00: 8-bits */ # define DMA_SCR_PSIZE_16BITS (1 << DMA_SCR_PSIZE_SHIFT) /* 01: 16-bits */ # define DMA_SCR_PSIZE_32BITS (2 << DMA_SCR_PSIZE_SHIFT) /* 10: 32-bits */ + #define DMA_SCR_MSIZE_SHIFT (13) /* Bits 13-14: Memory size */ #define DMA_SCR_MSIZE_MASK (3 << DMA_SCR_MSIZE_SHIFT) # define DMA_SCR_MSIZE_8BITS (0 << DMA_SCR_MSIZE_SHIFT) /* 00: 8-bits */ # define DMA_SCR_MSIZE_16BITS (1 << DMA_SCR_MSIZE_SHIFT) /* 01: 16-bits */ # define DMA_SCR_MSIZE_32BITS (2 << DMA_SCR_MSIZE_SHIFT) /* 10: 32-bits */ + #define DMA_SCR_PINCOS (1 << 15) /* Bit 15: Peripheral increment offset size */ #define DMA_SCR_PL_SHIFT (16) /* Bits 16-17: Stream Priority level */ #define DMA_SCR_PL_MASK (3 << DMA_SCR_PL_SHIFT) @@ -328,6 +331,7 @@ # define DMA_SCR_PRIMED (1 << DMA_SCR_PL_SHIFT) /* 01: Medium */ # define DMA_SCR_PRIHI (2 << DMA_SCR_PL_SHIFT) /* 10: High */ # define DMA_SCR_PRIVERYHI (3 << DMA_SCR_PL_SHIFT) /* 11: Very high */ + #define DMA_SCR_DBM (1 << 18) /* Bit 15: Double buffer mode */ #define DMA_SCR_CT (1 << 19) /* Bit 19: Current target */ /* Bit 20: Reserved */ @@ -337,13 +341,14 @@ # define DMA_SCR_PBURST_INCR4 (1 << DMA_SCR_PBURST_SHIFT) /* 01: Incremental burst of 4 beats */ # define DMA_SCR_PBURST_INCR8 (2 << DMA_SCR_PBURST_SHIFT) /* 10: Incremental burst of 8 beats */ # define DMA_SCR_PBURST_INCR16 (3 << DMA_SCR_PBURST_SHIFT) /* 11: Incremental burst of 16 beats */ + #define DMA_SCR_MBURST_SHIFT (23) /* Bits 23-24: Memory burst transfer configuration */ #define DMA_SCR_MBURST_MASK (3 << DMA_SCR_MBURST_SHIFT) # define DMA_SCR_MBURST_SINGLE (0 << DMA_SCR_MBURST_SHIFT) /* 00: Single transfer */ # define DMA_SCR_MBURST_INCR4 (1 << DMA_SCR_MBURST_SHIFT) /* 01: Incremental burst of 4 beats */ # define DMA_SCR_MBURST_INCR8 (2 << DMA_SCR_MBURST_SHIFT) /* 10: Incremental burst of 8 beats */ # define DMA_SCR_MBURST_INCR16 (3 << DMA_SCR_MBURST_SHIFT) /* 11: Incremental burst of 16 beats */ - /* Bits 25-31: Reserved */ + /* Bits 25-31: Reserved */ #define DMA_SCR_ALLINTS (DMA_SCR_DMEIE|DMA_SCR_TEIE|DMA_SCR_HTIE|DMA_SCR_TCIE) @@ -360,6 +365,7 @@ # define DMA_SFCR_FTH_HALF (1 << DMA_SFCR_FTH_SHIFT) /* 1/2 full FIFO */ # define DMA_SFCR_FTH_3QUARTER (2 << DMA_SFCR_FTH_SHIFT) /* 3/4 full FIFO */ # define DMA_SFCR_FTH_FULL (3 << DMA_SFCR_FTH_SHIFT) /* full FIFO */ + #define DMA_SFCR_DMDIS (1 << 2) /* Bit 2: Direct mode disable */ #define DMA_SFCR_FS_SHIFT (3) /* Bits 3-5: FIFO status */ #define DMA_SFCR_FS_MASK (7 << DMA_SFCR_FS_SHIFT) @@ -369,8 +375,8 @@ # define DMA_SFCR_FS_ALMOSTFULL (3 << DMA_SFCR_FS_SHIFT) /* 3/4 = fifo_level < full */ # define DMA_SFCR_FS_EMPTY (4 << DMA_SFCR_FS_SHIFT) /* FIFO is empty */ # define DMA_SFCR_FS_FULL (5 << DMA_SFCR_FS_SHIFT) /* FIFO is full */ - /* Bit 6: Reserved */ -#define DMA_SFCR_FEIE (1 << 7) /* Bit 7: FIFO error interrupt enable */ - /* Bits 8-31: Reserved */ + /* Bit 6: Reserved */ +#define DMA_SFCR_FEIE (1 << 7) /* Bit 7: FIFO error interrupt enable */ + /* Bits 8-31: Reserved */ #endif /* __ARCH_ARM_SRC_STM32H7_HARDWARE_STM32_DMA_H */ diff --git a/arch/arm/src/stm32h7/stm32_dma.c b/arch/arm/src/stm32h7/stm32_dma.c index bfa4f0d36be..80d4ec12421 100644 --- a/arch/arm/src/stm32h7/stm32_dma.c +++ b/arch/arm/src/stm32h7/stm32_dma.c @@ -1381,8 +1381,8 @@ static void stm32_sdma_start(DMA_HANDLE handle, dma_callback_t callback, DMA_CHANNEL dmachan = (DMA_CHANNEL)handle; uint32_t scr = 0; - DEBUGASSERT(dmachan->ctrl == DMA1 || dmachan->ctrl == DMA2); DEBUGASSERT(handle != NULL); + DEBUGASSERT(dmachan->ctrl == DMA1 || dmachan->ctrl == DMA2); /* Save the callback info. This will be invoked when the DMA completes */ @@ -1714,12 +1714,23 @@ static void stm32_sdma_dump(DMA_HANDLE handle, const char *msg) static void stm32_bdma_disable(DMA_CHANNEL dmachan) { - DMA_CHANNEL dmachan = (DMA_CHANNEL)handle; - uint8_t controller = dmachan->ctrl; + uint32_t regval = 0; - DEBUGASSERT(controller == BDMA); + DEBUGASSERT(dmachan->ctrl == BDMA); + DEBUGASSERT(dmachan->chan < BDMA_NCHAN); -#warning stm32_bdma_disable not implemented + /* Disable all interrupts at the DMA controller */ + + regval = dmachan_getreg(dmachan, STM32_BDMACH_CCR_OFFSET); + regval &= ~BDMA_CCR_ALLINTS; + + /* Disable the DMA stream */ + + regval &= ~BDMA_CCR_EN; + dmachan_putreg(dmachan, STM32_BDMACH_CCR_OFFSET, regval); + + dmabase_putreg(dmachan, STM32_BDMA_IFCR_OFFSET, + (BDMA_CHAN_MASK << dmachan->shift)); } /**************************************************************************** @@ -1732,7 +1743,66 @@ static void stm32_bdma_disable(DMA_CHANNEL dmachan) static int stm32_bdma_interrupt(int irq, void *context, FAR void *arg) { -#warning stm32_bdma_interrupt not implemented + DMA_CHANNEL dmachan = NULL; + uint32_t status = 0; + uint32_t scrstatus = 0; + uint8_t stream = irq - STM32_IRQ_BDMACH1; + uint8_t controller = BDMA; + + /* Get the channel structure from the stream and controller numbers */ + + dmachan = stm32_dma_channel_get(stream, controller); + + /* Get the interrupt status for this stream */ + + status = (dmabase_getreg(dmachan, STM32_BDMA_ISR_OFFSET) >> dmachan->shift) + & BDMA_CHAN_MASK; + + dmabase_putreg(dmachan, STM32_BDMA_IFCR_OFFSET, + (status << dmachan->shift)); + + /* Invoke the callback */ + + if (dmachan->callback) + { + /* Map to the SDMA status */ + + scrstatus = (status & BDMA_CHAN_TEIF) ? DMA_STREAM_FEIF_BIT : 0; + scrstatus |= (status & BDMA_CHAN_TCIF) ? DMA_STREAM_TCIF_BIT : 0; + scrstatus |= (status & BDMA_CHAN_HTIF) ? DMA_STREAM_HTIF_BIT : 0; + dmachan->callback(dmachan, scrstatus, dmachan->arg); + } + + return OK; +} + +/**************************************************************************** + * Name: stm32_sdma_scr_2_bdma_ccr + * + * Description: + * Maps the DMA SCR bits to the BDMA CCR bits + * + ****************************************************************************/ + +static inline int32_t stm32_sdma_scr_2_bdma_ccr(int32_t scr) +{ + uint32_t ccr = 0; + ccr |= (scr & DMA_SCR_CT) ? BDMA_CCR_CT : 0; + ccr |= (scr & DMA_SCR_DBM) ? BDMA_CCR_DBM : 0; + ccr |= (scr & DMA_SCR_PL_MASK) >> (DMA_SCR_PL_SHIFT - BDMA_CCR_PRILO); + ccr |= (scr & DMA_SCR_MSIZE_MASK) >> + (DMA_SCR_MSIZE_SHIFT - BDMA_CCR_MSIZE_SHIFT); + ccr |= (scr & DMA_SCR_PSIZE_MASK) >> + (DMA_SCR_PSIZE_SHIFT - BDMA_CCR_PSIZE_SHIFT); + ccr |= (scr & DMA_SCR_MINC) ? BDMA_CCR_MINC : 0; + ccr |= (scr & DMA_SCR_PINC) ? BDMA_CCR_PINC : 0; + ccr |= (scr & DMA_SCR_CIRC) ? BDMA_CCR_CIRC : 0; + ccr |= (scr & DMA_SCR_DIR_M2P) ? BDMA_CCR_DIR : 0; + ccr |= (scr & DMA_SCR_DIR_M2M) ? BDMA_CCR_M2M : 0; + ccr |= (scr & DMA_SCR_TCIE) ? BDMA_CCR_TCIE : 0; + ccr |= (scr & DMA_SCR_HTIE) ? BDMA_CCR_HTIE : 0; + ccr |= (scr & DMA_SCR_TEIE) ? BDMA_CCR_TEIE : 0; + return ccr; } /**************************************************************************** @@ -1746,11 +1816,89 @@ static int stm32_bdma_interrupt(int irq, void *context, FAR void *arg) static void stm32_bdma_setup(DMA_HANDLE handle, FAR stm32_dmacfg_t *cfg) { DMA_CHANNEL dmachan = (DMA_CHANNEL)handle; - uint8_t controller = dmachan->ctrl; + uint32_t regval = 0; + uint32_t scr = cfg->cfg1; + uint32_t ccr = 0; - DEBUGASSERT(controller == BDMA); + DEBUGASSERT(handle != NULL); + DEBUGASSERT(dmachan->ctrl == BDMA); -#warning stm32_bdma_setup not implemented + dmainfo("paddr: %08x maddr: %08x ndata: %d scr: %08x\n", + cfg->paddr, cfg->maddr, cfg->ndata, cfg->cfg1); + +#ifdef CONFIG_STM32H7_DMACAPABLE + DEBUGASSERT(stm32_bdma_capable(cfg)); +#endif + + /* "If the stream is enabled, disable it by resetting the EN bit in the + * DMA_SxCR register, then read this bit in order to confirm that there is + * no ongoing stream operation. Writing this bit to 0 is not immediately + * effective since it is actually written to 0 once all the current + * transfers have finished. When the EN bit is read as 0, this means that + * the stream is ready to be configured. It is therefore necessary to wait + * for the EN bit to be cleared before starting any stream configuration." + */ + + while ((dmachan_getreg(dmachan, STM32_BDMACH_CCR_OFFSET) & + BDMA_CCR_EN) != 0); + + /* "... All the stream dedicated bits set in the status register BDMA_ISR + * from the previous data block DMA transfer should be cleared before the + * stream can be re-enabled." + * + * Clear pending stream interrupts by setting bits in the BDMA_IFCR + * register. + */ + + dmabase_putreg(dmachan, STM32_BDMA_IFCR_OFFSET, + (BDMA_CHAN_MASK << dmachan->shift)); + + /* "Set the peripheral register address in the BDMA_SPARx register. The + * data will be moved from/to this address to/from the memory after the + * peripheral event. + */ + + dmachan_putreg(dmachan, STM32_BDMACH_CPAR_OFFSET, cfg->paddr); + + /* "Set the memory address in the BDMA_CM1ARx register. The data will be + * written to or read from this memory after the peripheral event." + * + * Note that in double-buffered mode it is explicitly assumed that the + * second buffer immediately follows the first. + */ + + dmachan_putreg(dmachan, STM32_BDMACH_CM0AR_OFFSET, cfg->maddr); + if (scr & DMA_SCR_DBM) + { + dmachan_putreg(dmachan, STM32_BDMACH_CM1AR_OFFSET, + cfg->maddr + cfg->ndata); + } + + /* "Configure the total number of data items to be transferred in the + * BDMA_CNDTRx register. After each peripheral event, this value will be + * decremented." + */ + + dmachan_putreg(dmachan, STM32_BDMACH_CNDTR_OFFSET, cfg->ndata); + + /* "Configure the stream priority using the PL[1:0] bits, data transfer + * direction, circular mode, peripheral & memory incremented mode, + * peripheral & memory data size, and interrupt after + * half and/or full transfer in the BDMACH_CCRx register." + * + * Note: The CT bit is always reset. + */ + + regval = dmachan_getreg(dmachan, STM32_BDMACH_CCR_OFFSET); + regval &= ~(BDMA_CCR_DIR | BDMA_CCR_CIRC | BDMA_CCR_PINC | + BDMA_CCR_MINC | BDMA_CCR_PSIZE_MASK | BDMA_CCR_MSIZE_MASK | + BDMA_CCR_PL_MASK | BDMA_CCR_M2M | BDMA_CCR_DBM | BDMA_CCR_CT); + ccr = stm32_sdma_scr_2_bdma_ccr(scr); + ccr &= (BDMA_CCR_DIR | BDMA_CCR_CIRC | BDMA_CCR_PINC | + BDMA_CCR_MINC | BDMA_CCR_PSIZE_MASK | BDMA_CCR_MSIZE_MASK | + BDMA_CCR_PL_MASK | BDMA_CCR_M2M | BDMA_CCR_DBM); + regval |= ccr; + dmachan_putreg(dmachan, STM32_BDMACH_CCR_OFFSET, regval); } /**************************************************************************** @@ -1764,12 +1912,59 @@ static void stm32_bdma_setup(DMA_HANDLE handle, FAR stm32_dmacfg_t *cfg) static void stm32_bdma_start(DMA_HANDLE handle, dma_callback_t callback, void *arg, bool half) { - DMA_CHANNEL dmachan = (DMA_CHANNEL)handle; - uint8_t controller = dmachan->ctrl; + DMA_CHANNEL dmachan = (DMA_CHANNEL)handle; + uint32_t ccr = 0; - DEBUGASSERT(controller == BDMA); + DEBUGASSERT(handle != NULL); + DEBUGASSERT(dmachan->ctrl == BDMA); -#warning stm32_bdma_start not implemented + /* Save the callback info. This will be invoked when the DMA completes */ + + dmachan->callback = callback; + dmachan->arg = arg; + + /* Activate the stream by setting the ENABLE bit in the DMA_SCRx register. + * As soon as the stream is enabled, it can serve any DMA request from the + * peripheral connected on the stream. + */ + + ccr = dmachan_getreg(dmachan, STM32_BDMACH_CCR_OFFSET); + ccr |= BDMA_CCR_EN; + + /* In normal mode, interrupt at either half or full completion. In circular + * and double-buffered modes, always interrupt on buffer wrap, and + * optionally interrupt at the halfway point. + */ + + if ((ccr & (BDMA_CCR_DBM | BDMA_CCR_CIRC)) == 0) + { + /* Once half of the bytes are transferred, the half-transfer flag + * (HTIF) is set and an interrupt is generated if the + * Half-Transfer Interrupt Enable bit (HTIE) is set. At the end of the + * transfer, the Transfer Complete Flag (TCIF) is set and an interrupt + * is generated if the Transfer Complete Interrupt Enable bit (TCIE) is + * set. + */ + + ccr |= (half ? (BDMA_CCR_HTIE | BDMA_CCR_TEIE) : + (BDMA_CCR_TCIE | BDMA_CCR_TEIE)); + } + else + { + /* In non-stop modes, when the transfer completes it immediately resets + * and starts again. The transfer-complete interrupt is thus always + * enabled, and the half-complete interrupt can be used in circular + * mode to determine when the buffer is half-full, or in + * double-buffered mode to determine when one of the two buffers is + * full + */ + + ccr |= (half ? BDMA_CCR_HTIE : 0) | BDMA_CCR_TCIE | BDMA_CCR_TEIE; + } + + dmachan_putreg(dmachan, STM32_BDMACH_CCR_OFFSET, ccr); + + stm32_dmadump(handle, "DMA after start"); } /**************************************************************************** @@ -1779,10 +1974,10 @@ static void stm32_bdma_start(DMA_HANDLE handle, dma_callback_t callback, static size_t stm32_bdma_residual(DMA_HANDLE handle) { DMA_CHANNEL dmachan = (DMA_CHANNEL)handle; - uint8_t controller = dmachan->ctrl; uint32_t residual = 0 - DEBUGASSERT(controller == BDMA); + DEBUGASSERT(handle != NULL); + DEBUGASSERT(dmachan->ctrl == BDMA); /* Fetch the count of bytes remaining to be transferred */ @@ -1804,10 +1999,8 @@ static bool stm32_bdma_capable(FAR stm32_dmacfg_t *cfg) dmainfo("0x%08x/%u 0x%08x\n", cfg->maddr, cfg->ndata, cfg->cfg1); -#warning REVISIT - /* Verify that the address conforms to the memory transfer size. - * Transfers to/from memory performed by the DMA controller are + * Transfers to/from memory performed by the BDMA controller are * required to be aligned to their size. * * See ST RM0090 rev4, section 9.3.11