You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by ag...@apache.org on 2020/06/06 18:17:21 UTC
[incubator-nuttx] branch master updated: stm32h7:DMA Add BDMA
support
This is an automated email from the ASF dual-hosted git repository.
aguettouche pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git
The following commit(s) were added to refs/heads/master by this push:
new a793369 stm32h7:DMA Add BDMA support
a793369 is described below
commit a79336981582043d760590b5f8de95b00d474f7e
Author: David Sidrane <Da...@NscDg.com>
AuthorDate: Fri Jun 5 09:03:32 2020 -0700
stm32h7:DMA Add BDMA support
Apply suggestions from code review
Co-authored-by: Mateusz Szafoni <ra...@gmail.com>
---
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 b989a46..56fc68c 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 94d7ed7..ffb672b 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 bfa4f0d..80d4ec1 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);
+
+ /* 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);
-#warning stm32_bdma_disable not implemented
+ 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);
+
+ 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);
-#warning stm32_bdma_setup not implemented
+ /* "... 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);
+
+ /* 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;
-#warning stm32_bdma_start not implemented
+ /* 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