diff options
author | px4dev <px4@purgatory.org> | 2013-09-01 13:21:06 -0700 |
---|---|---|
committer | px4dev <px4@purgatory.org> | 2013-09-01 13:21:06 -0700 |
commit | aab5581a619867df1af40924c9e99633707bf730 (patch) | |
tree | 85b4a7639cecf99abbdafdfa8efc36a1bfa62594 /nuttx | |
parent | 291d0b36d3c68af90efbed4662b28fb941633327 (diff) | |
download | px4-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.h | 11 | ||||
-rw-r--r-- | nuttx/arch/arm/src/stm32/stm32f10xxx_dma.c | 48 | ||||
-rw-r--r-- | nuttx/arch/arm/src/stm32/stm32f20xxx_dma.c | 86 | ||||
-rw-r--r-- | nuttx/arch/arm/src/stm32/stm32f40xxx_dma.c | 106 |
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 |