summaryrefslogtreecommitdiff
path: root/nuttx
diff options
context:
space:
mode:
authorpx4dev <px4@purgatory.org>2013-09-01 13:21:06 -0700
committerpx4dev <px4@purgatory.org>2013-09-01 13:21:06 -0700
commitaab5581a619867df1af40924c9e99633707bf730 (patch)
tree85b4a7639cecf99abbdafdfa8efc36a1bfa62594 /nuttx
parent291d0b36d3c68af90efbed4662b28fb941633327 (diff)
downloadpx4-nuttx-aab5581a619867df1af40924c9e99633707bf730.tar.gz
px4-nuttx-aab5581a619867df1af40924c9e99633707bf730.tar.bz2
px4-nuttx-aab5581a619867df1af40924c9e99633707bf730.zip
Enhance the stm32_dmacapable implementation to give correct answers.
Diffstat (limited to 'nuttx')
-rw-r--r--nuttx/arch/arm/src/stm32/stm32_dma.h11
-rw-r--r--nuttx/arch/arm/src/stm32/stm32f10xxx_dma.c48
-rw-r--r--nuttx/arch/arm/src/stm32/stm32f20xxx_dma.c86
-rw-r--r--nuttx/arch/arm/src/stm32/stm32f40xxx_dma.c106
4 files changed, 241 insertions, 10 deletions
diff --git a/nuttx/arch/arm/src/stm32/stm32_dma.h b/nuttx/arch/arm/src/stm32/stm32_dma.h
index 771754bf9..f1f6883f5 100644
--- a/nuttx/arch/arm/src/stm32/stm32_dma.h
+++ b/nuttx/arch/arm/src/stm32/stm32_dma.h
@@ -271,9 +271,10 @@ size_t stm32_dmaresidual(DMA_HANDLE handle);
*
* Description:
* Check if the DMA controller can transfer data to/from given memory
- * address. This depends on the internal connections in the ARM bus matrix
- * of the processor. Note that this only applies to memory addresses, it
- * will return false for any peripheral address.
+ * address with the given configuration. This depends on the internal
+ * connections in the ARM bus matrix of the processor. Note that this
+ * only applies to memory addresses, it will return false for any peripheral
+ * address.
*
* Returned value:
* True, if transfer is possible.
@@ -281,9 +282,9 @@ size_t stm32_dmaresidual(DMA_HANDLE handle);
****************************************************************************/
#ifdef CONFIG_STM32_DMACAPABLE
-bool stm32_dmacapable(uintptr_t maddr);
+bool stm32_dmacapable(uintptr_t maddr, uint32_t count, uint32_t ccr);
#else
-# define stm32_dmacapable(maddr) (true)
+# define stm32_dmacapable(maddr, count, ccr) (true)
#endif
/****************************************************************************
diff --git a/nuttx/arch/arm/src/stm32/stm32f10xxx_dma.c b/nuttx/arch/arm/src/stm32/stm32f10xxx_dma.c
index 9ab64ce7e..e25138945 100644
--- a/nuttx/arch/arm/src/stm32/stm32f10xxx_dma.c
+++ b/nuttx/arch/arm/src/stm32/stm32f10xxx_dma.c
@@ -611,8 +611,54 @@ size_t stm32_dmaresidual(DMA_HANDLE handle)
****************************************************************************/
#ifdef CONFIG_STM32_DMACAPABLE
-bool stm32_dmacapable(uint32_t maddr)
+bool stm32_dmacapable(uint32_t maddr, uint32_t count, uint32_t ccr)
{
+ uint32_t transfer_size;
+ uint32_t mend;
+
+ /* Verify that the address conforms to the memory transfer size.
+ * Transfers to/from memory performed by the DMA controller are
+ * required to be aligned to their size.
+ *
+ * See ST RM0090 rev4, section 9.3.11
+ *
+ * Compute mend inline to avoid a possible non-constant integer
+ * multiply.
+ */
+
+ switch (ccr & STM32_DMA_SCR_MSIZE_MASK)
+ {
+ case DMA_SCR_MSIZE_8BITS:
+ transfer_size = 1;
+ mend = maddr + count - 1;
+ break;
+
+ case DMA_SCR_MSIZE_16BITS:
+ transfer_size = 2;
+ mend = maddr + (count << 1) - 1;
+ break;
+
+ case DMA_SCR_MSIZE_32BITS:
+ transfer_size = 4;
+ mend = maddr + (count << 2) - 1;
+ break;
+
+ default
+ return false;
+ }
+
+ if ((maddr & (transfer_size - 1)) != 0)
+ {
+ return false;
+ }
+
+ /* Verify that the transfer is to a memory region that supports DMA. */
+
+ if ((maddr & STM32_REGION_MASK) != (mend & STM32_REGION_MASK))
+ {
+ return false;
+ }
+
switch (maddr & STM32_REGION_MASK)
{
case STM32_FSMC_BANK1:
diff --git a/nuttx/arch/arm/src/stm32/stm32f20xxx_dma.c b/nuttx/arch/arm/src/stm32/stm32f20xxx_dma.c
index 71ac263fb..c6b5425aa 100644
--- a/nuttx/arch/arm/src/stm32/stm32f20xxx_dma.c
+++ b/nuttx/arch/arm/src/stm32/stm32f20xxx_dma.c
@@ -856,8 +856,92 @@ size_t stm32_dmaresidual(DMA_HANDLE handle)
****************************************************************************/
#ifdef CONFIG_STM32_DMACAPABLE
-bool stm32_dmacapable(uint32_t maddr)
+bool stm32_dmacapable(uint32_t maddr, uint32_t count, uint32_t ccr)
{
+ uint32_t transfer_size, burst_length;
+ uint32_t mend;
+
+ /* Verify that the address conforms to the memory transfer size.
+ * Transfers to/from memory performed by the DMA controller are
+ * required to be aligned to their size.
+ *
+ * See ST RM0090 rev4, section 9.3.11
+ *
+ * Compute mend inline to avoid a possible non-constant integer
+ * multiply.
+ */
+
+ switch (ccr & STM32_DMA_SCR_MSIZE_MASK)
+ {
+ case DMA_SCR_MSIZE_8BITS:
+ transfer_size = 1;
+ mend = maddr + count - 1;
+ break;
+
+ case DMA_SCR_MSIZE_16BITS:
+ transfer_size = 2;
+ mend = maddr + (count << 1) - 1;
+ break;
+
+ case DMA_SCR_MSIZE_32BITS:
+ transfer_size = 4;
+ mend = maddr + (count << 2) - 1;
+ break;
+
+ default
+ return false;
+ }
+
+ if ((maddr & (transfer_size - 1)) != 0)
+ {
+ return false;
+ }
+
+ /* Verify that burst transfers do not cross a 1KiB boundary. */
+
+ if ((maddr / 1024) != (mend / 1024))
+ {
+
+ /* The transfer as a whole crosses a 1KiB boundary.
+ * Verify that no burst does by asserting that the address
+ * is aligned to the burst length.
+ */
+
+ switch (ccr & STM32_DMA_SCR_MBURST_MASK)
+ {
+ case DMA_SCR_MBURST_SINGLE:
+ burst_length = transfer_size;
+ break;
+
+ case DMA_SCR_MBURST_INCR4:
+ burst_length = transfer_size << 2;
+ break;
+
+ case DMA_SCR_MBURST_INCR8:
+ burst_length = transfer_size << 3;
+ break;
+
+ case DMA_SCR_MBURST_INCR16:
+ burst_length = transfer_size << 4;
+ break;
+
+ default:
+ return false;
+ }
+
+ if ((maddr & (burst_length - 1)) != 0)
+ {
+ return false;
+ }
+ }
+
+ /* Verify that the transfer is to a memory region that supports DMA. */
+
+ if ((maddr & STM32_REGION_MASK) != (mend & STM32_REGION_MASK))
+ {
+ return false;
+ }
+
switch (maddr & STM32_REGION_MASK)
{
case STM32_FSMC_BANK1:
diff --git a/nuttx/arch/arm/src/stm32/stm32f40xxx_dma.c b/nuttx/arch/arm/src/stm32/stm32f40xxx_dma.c
index 5bff603b9..52382cf5b 100644
--- a/nuttx/arch/arm/src/stm32/stm32f40xxx_dma.c
+++ b/nuttx/arch/arm/src/stm32/stm32f40xxx_dma.c
@@ -607,6 +607,10 @@ void stm32_dmasetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr,
dmadbg("paddr: %08x maddr: %08x ntransfers: %d scr: %08x\n",
paddr, maddr, ntransfers, scr);
+#ifdef CONFIG_STM32_DMACAPABLE
+ DEBUGASSERT(stm32_dmacapable(maddr, ntransfers, scr))
+#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
@@ -859,8 +863,99 @@ size_t stm32_dmaresidual(DMA_HANDLE handle)
****************************************************************************/
#ifdef CONFIG_STM32_DMACAPABLE
-bool stm32_dmacapable(uint32_t maddr)
+bool stm32_dmacapable(uint32_t maddr, uint32_t count, uint32_t ccr)
{
+ uint32_t transfer_size, burst_length;
+ uint32_t mend;
+
+ dmavdbg("stm32_dmacapable: 0x%08x/%u 0x%08x\n", maddr, count, ccr);
+
+ /* Verify that the address conforms to the memory transfer size.
+ * Transfers to/from memory performed by the DMA controller are
+ * required to be aligned to their size.
+ *
+ * See ST RM0090 rev4, section 9.3.11
+ *
+ * Compute mend inline to avoid a possible non-constant integer
+ * multiply.
+ */
+
+ switch (ccr & DMA_SCR_MSIZE_MASK)
+ {
+ case DMA_SCR_MSIZE_8BITS:
+ transfer_size = 1;
+ mend = maddr + count - 1;
+ break;
+
+ case DMA_SCR_MSIZE_16BITS:
+ transfer_size = 2;
+ mend = maddr + (count << 1) - 1;
+ break;
+
+ case DMA_SCR_MSIZE_32BITS:
+ transfer_size = 4;
+ mend = maddr + (count << 2) - 1;
+ break;
+
+ default:
+ dmavdbg("stm32_dmacapable: bad transfer size in CCR\n");
+ return false;
+ }
+
+ if ((maddr & (transfer_size - 1)) != 0)
+ {
+ dmavdbg("stm32_dmacapable: transfer unaligned\n");
+ return false;
+ }
+
+ /* Verify that burst transfers do not cross a 1KiB boundary. */
+
+ if ((maddr / 1024) != (mend / 1024))
+ {
+
+ /* The transfer as a whole crosses a 1KiB boundary.
+ * Verify that no burst does by asserting that the address
+ * is aligned to the burst length.
+ */
+
+ switch (ccr & DMA_SCR_MBURST_MASK)
+ {
+ case DMA_SCR_MBURST_SINGLE:
+ burst_length = transfer_size;
+ break;
+
+ case DMA_SCR_MBURST_INCR4:
+ burst_length = transfer_size << 2;
+ break;
+
+ case DMA_SCR_MBURST_INCR8:
+ burst_length = transfer_size << 3;
+ break;
+
+ case DMA_SCR_MBURST_INCR16:
+ burst_length = transfer_size << 4;
+ break;
+
+ default:
+ dmavdbg("stm32_dmacapable: bad burst size in CCR\n");
+ return false;
+ }
+
+ if ((maddr & (burst_length - 1)) != 0)
+ {
+ dmavdbg("stm32_dmacapable: burst crosses 1KiB\n");
+ return false;
+ }
+ }
+
+ /* Verify that the transfer is to a memory region that supports DMA. */
+
+ if ((maddr & STM32_REGION_MASK) != (mend & STM32_REGION_MASK))
+ {
+ dmavdbg("stm32_dmacapable: transfer crosses memory region\n");
+ return false;
+ }
+
switch (maddr & STM32_REGION_MASK)
{
case STM32_FSMC_BANK1:
@@ -869,21 +964,26 @@ bool stm32_dmacapable(uint32_t maddr)
case STM32_FSMC_BANK4:
case STM32_SRAM_BASE:
/* All RAM is supported */
- return true;
+ break;
case STM32_CODE_BASE:
/* Everything except the CCM ram is supported */
if (maddr >= STM32_CCMRAM_BASE &&
(maddr - STM32_CCMRAM_BASE) < 65536)
{
+ dmavdbg("stm32_dmacapable: transfer targets CCMRAM\n");
return false;
}
- return true;
+ break;
default:
/* Everything else is unsupported by DMA */
+ dmavdbg("stm32_dmacapable: transfer targets unknown/unsupported region\n");
return false;
}
+
+ dmavdbg("stm32_dmacapable: transfer OK\n");
+ return true;
}
#endif