diff options
author | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2009-11-26 00:18:22 +0000 |
---|---|---|
committer | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2009-11-26 00:18:22 +0000 |
commit | ca1f8ac53e4af7c72a36f294fb720a3f63cac34d (patch) | |
tree | c83293bc87950c579a15a48bef067abff307d040 /nuttx/arch/arm/src/stm32 | |
parent | beaf6630fced304d34f92f630eeb9b181f6e6567 (diff) | |
download | px4-nuttx-ca1f8ac53e4af7c72a36f294fb720a3f63cac34d.tar.gz px4-nuttx-ca1f8ac53e4af7c72a36f294fb720a3f63cac34d.tar.bz2 px4-nuttx-ca1f8ac53e4af7c72a36f294fb720a3f63cac34d.zip |
Numerous fixes for basic STM32 SDIO DMA access
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@2279 42af7a65-404d-4744-a932-0658087f49c3
Diffstat (limited to 'nuttx/arch/arm/src/stm32')
-rwxr-xr-x | nuttx/arch/arm/src/stm32/stm32_dma.c | 182 | ||||
-rw-r--r-- | nuttx/arch/arm/src/stm32/stm32_dma.h | 3 | ||||
-rwxr-xr-x | nuttx/arch/arm/src/stm32/stm32_internal.h | 90 | ||||
-rw-r--r-- | nuttx/arch/arm/src/stm32/stm32_sdio.c | 31 |
4 files changed, 214 insertions, 92 deletions
diff --git a/nuttx/arch/arm/src/stm32/stm32_dma.c b/nuttx/arch/arm/src/stm32/stm32_dma.c index 7fc5cb6f5..feda25a4e 100755 --- a/nuttx/arch/arm/src/stm32/stm32_dma.c +++ b/nuttx/arch/arm/src/stm32/stm32_dma.c @@ -44,9 +44,12 @@ #include <debug.h> #include <errno.h> +#include <nuttx/irq.h> +#include <nuttx/arch.h> #include <arch/irq.h> #include "up_arch.h" +#include "up_internal.h" #include "os_internal.h" #include "chip.h" #include "stm32_dma.h" @@ -64,6 +67,10 @@ # define DMA_NCHANNELS DMA1_NCHANNELS #endif +#ifndef CONFIG_DMA_PRI +# define CONFIG_DMA_PRI NVIC_SYSH_PRIORITY_DEFAULT +#endif + /* Convert the DMA channel base address to the DMA register block address */ #define DMA_BASE(ch) (ch & 0xfffffc00) @@ -76,7 +83,7 @@ struct stm32_dma_s { - ubyte chan; /* DMA channel number */ + ubyte chan; /* DMA channel number (0-6) */ ubyte irq; /* DMA channel IRQ number */ sem_t sem; /* Used to wait for DMA channel to become available */ uint32 base; /* DMA register channel base address */ @@ -93,69 +100,69 @@ struct stm32_dma_s static struct stm32_dma_s g_dma[DMA_NCHANNELS] = { { - .chan = STM32_DMA1_CHAN1, - .irq = STM32_IRQ_DMA1CH1, + .chan = 0, + .irq = STM32_IRQ_DMA1CH1, .base = STM32_DMA1_BASE + STM32_DMACHAN_OFFSET(0), }, { - .chan = STM32_DMA1_CHAN2, - .irq = STM32_IRQ_DMA1CH2, + .chan = 1, + .irq = STM32_IRQ_DMA1CH2, .base = STM32_DMA1_BASE + STM32_DMACHAN_OFFSET(1), }, { - .chan = STM32_DMA1_CHAN3, - .irq = STM32_IRQ_DMA1CH3, + .chan = 2, + .irq = STM32_IRQ_DMA1CH3, .base = STM32_DMA1_BASE + STM32_DMACHAN_OFFSET(2), }, { - .chan = STM32_DMA1_CHAN4, - .irq = STM32_IRQ_DMA1CH4, + .chan = 3, + .irq = STM32_IRQ_DMA1CH4, .base = STM32_DMA1_BASE + STM32_DMACHAN_OFFSET(3), }, { - .chan = STM32_DMA1_CHAN5, - .irq = STM32_IRQ_DMA1CH5, + .chan = 4, + .irq = STM32_IRQ_DMA1CH5, .base = STM32_DMA1_BASE + STM32_DMACHAN_OFFSET(4), }, { - .chan = STM32_DMA1_CHAN6, - .irq = STM32_IRQ_DMA1CH6, + .chan = 5, + .irq = STM32_IRQ_DMA1CH6, .base = STM32_DMA1_BASE + STM32_DMACHAN_OFFSET(5), }, { - .chan = STM32_DMA1_CHAN7, - .irq = STM32_IRQ_DMA1CH7, + .chan = 6, + .irq = STM32_IRQ_DMA1CH7, .base = STM32_DMA1_BASE + STM32_DMACHAN_OFFSET(6), }, #if STM32_NDMA > 1 { - .chan = STM32_DMA2_CHAN1, - .irq = STM32_IRQ_DMA2CH1, + .chan = 0, + .irq = STM32_IRQ_DMA2CH1, .base = STM32_DMA2_BASE + STM32_DMACHAN_OFFSET(0), }, { - .chan = STM32_DMA2_CHAN2, - .irq = STM32_IRQ_DMA2CH2, + .chan = 1, + .irq = STM32_IRQ_DMA2CH2, .base = STM32_DMA2_BASE + STM32_DMACHAN_OFFSET(1), }, { - .chan = STM32_DMA2_CHAN3, - .irq = STM32_IRQ_DMA2CH3, + .chan = 2, + .irq = STM32_IRQ_DMA2CH3, .base = STM32_DMA2_BASE + STM32_DMACHAN_OFFSET(2), }, { - .chan = STM32_DMA2_CHAN4, + .chan = 3, #ifdef CONFIG_STM32_CONNECTIVITY_LINE - .irq = STM32_IRQ_DMA2CH4, + .irq = STM32_IRQ_DMA2CH4, #else .irq = STM32_IRQ_DMA2CH45, #endif .base = STM32_DMA2_BASE + STM32_DMACHAN_OFFSET(3), }, { - .chan = STM32_DMA2_CHAN5, + .chan = 4, #ifdef CONFIG_STM32_CONNECTIVITY_LINE - .irq = STM32_IRQ_DMA2CH5, + .irq = STM32_IRQ_DMA2CH5, #else .irq = STM32_IRQ_DMA2CH45, #endif @@ -228,6 +235,33 @@ static inline void stm32_dmagive(FAR struct stm32_dma_s *dmach) } /************************************************************************************ + * Name: stm32_dmachandisable + * + * Description: + * Disable the DMA channel + * + ************************************************************************************/ + +static void stm32_dmachandisable(struct stm32_dma_s *dmach) +{ + uint32 regval; + + /* Disable all interrupts at the DMA controller */ + + regval = dmachan_getreg(dmach, STM32_DMACHAN_CCR_OFFSET); + regval &= ~DMA_CCR_ALLINTS; + + /* Disable the DMA channel */ + + regval &= ~DMA_CCR_EN; + dmachan_putreg(dmach, STM32_DMACHAN_CCR_OFFSET, regval); + + /* Clear pending channel interrupts */ + + dmabase_putreg(dmach, STM32_DMA_IFCR_OFFSET, DMA_ISR_CHAN_MASK(dmach->chan)); +} + +/************************************************************************************ * Name: stm32_dmainterrupt * * Description: @@ -239,13 +273,13 @@ static int stm32_dmainterrupt(int irq, void *context) { struct stm32_dma_s *dmach; uint32 isr; - int chan; + int chndx; /* Get the channel structure from the interrupt number */ if (irq >= STM32_IRQ_DMA1CH1 && irq <= STM32_IRQ_DMA1CH7) { - chan = irq - STM32_IRQ_DMA1CH1; + chndx = irq - STM32_IRQ_DMA1CH1; } else #if STM32_NDMA > 1 @@ -255,28 +289,28 @@ static int stm32_dmainterrupt(int irq, void *context) if (irq >= STM32_IRQ_DMA2CH1 && irq <= STM32_IRQ_DMA2CH45) #endif { - chan = irq - STM32_IRQ_DMA2CH1 + DMA1_NCHANNELS; + chndx = irq - STM32_IRQ_DMA2CH1 + DMA1_NCHANNELS; } else #endif { PANIC(OSERR_INTERNAL); } - dmach = &g_dma[chan]; + dmach = &g_dma[chndx]; /* Get the interrupt status (for this channel only) */ - isr = dmabase_getreg(dmach, STM32_DMA_ISR_OFFSET) & ~DMA_ISR_CHAN_MASK(chan); + isr = dmabase_getreg(dmach, STM32_DMA_ISR_OFFSET) & DMA_ISR_CHAN_MASK(dmach->chan); - /* Clear pending interrupts (for this channel only) */ + /* Disable the DMA channel */ - dmabase_putreg(dmach, STM32_DMA_IFCR_OFFSET, isr); + stm32_dmachandisable(dmach); /* Invoke the callback */ if (dmach->callback) { - dmach->callback(dmach, isr >> DMA_ISR_CHAN_SHIFT(chan), dmach->arg); + dmach->callback(dmach, isr >> DMA_ISR_CHAN_SHIFT(dmach->chan), dmach->arg); } return OK; } @@ -296,16 +330,33 @@ static int stm32_dmainterrupt(int irq, void *context) * ****************************************************************************/ -void weak_function stm32_dmainitialize(void) +void weak_function up_dmainitialize(void) { - int chan; + struct stm32_dma_s *dmach; + int chndx; - /* Attach DMA interrupt vectors */ + /* Initialize each DMA channel */ - for (chan = 0; chan < DMA_NCHANNELS; chan++) + for (chndx = 0; chndx < DMA_NCHANNELS; chndx++) { - sem_init(&g_dma[chan].sem, 0, 1); - irq_attach(g_dma[chan].irq, stm32_dmainterrupt); + dmach = &g_dma[chndx]; + sem_init(&dmach->sem, 0, 1); + + /* Attach DMA interrupt vectors */ + + (void)irq_attach(dmach->irq, stm32_dmainterrupt); + + /* Disable the DMA channel */ + + stm32_dmachandisable(dmach); + + /* Enable the IRQ at the NVIC (still disabled at the DMA controller) */ + + up_enable_irq(dmach->irq); + + /* Set the interrrupt priority */ + + up_prioritize_irq(dmach->irq, CONFIG_DMA_PRI); } } @@ -314,7 +365,7 @@ void weak_function stm32_dmainitialize(void) * * Description: * Allocate a DMA channel. This function gives the caller mutually - * exclusive access to the DMA channel specified by the 'chan' argument. + * exclusive access to the DMA channel specified by the 'chndx' argument. * DMA channels are shared on the STM32: Devices sharing the same DMA * channel cannot do DMA concurrently! See the DMACHAN_* definitions in * stm32_dma.h. @@ -330,8 +381,8 @@ void weak_function stm32_dmainitialize(void) * version. Feel free to do that if that is what you need. * * Returned Value: - * Provided that 'chan' is valid, this function ALWAYS returns a non-NULL, - * void* DMA channel handle. (If 'chan' is invalid, the function will + * Provided that 'chndx' is valid, this function ALWAYS returns a non-NULL, + * void* DMA channel handle. (If 'chndx' is invalid, the function will * assert if debug is enabled or do something ignorant otherwise). * * Assumptions: @@ -341,11 +392,11 @@ void weak_function stm32_dmainitialize(void) * ****************************************************************************/ -DMA_HANDLE stm32_dmachannel(int chan) +DMA_HANDLE stm32_dmachannel(int chndx) { - struct stm32_dma_s *dmach = &g_dma[chan]; + struct stm32_dma_s *dmach = &g_dma[chndx]; - DEBUGASSERT(chan < DMA_NCHANNELS); + DEBUGASSERT(chndx < DMA_NCHANNELS); /* Get exclusive access to the DMA channel -- OR wait until the channel * is available if it is currently being used by another driver @@ -478,3 +529,44 @@ void stm32_dmastart(DMA_HANDLE handle, dma_callback_t callback, void *arg, boole ccr |= (half ? (DMA_CCR_HTIE|DMA_CCR_TEIE) : (DMA_CCR_TCIE|DMA_CCR_TEIE)); dmachan_putreg(dmach, STM32_DMACHAN_CCR_OFFSET, ccr); } + +/**************************************************************************** + * Name: stm32_dmadump + * + * Description: + * Dump DMA register contents + * + * Assumptions: + * - DMA handle allocated by stm32_dmachannel() + * + ****************************************************************************/ + +#ifdef CONFIG_DEBUG_DMA +void stm32_dmadump(DMA_HANDLE handle, const char *msg) +{ + struct stm32_dma_s *dmach = (struct stm32_dma_s *)handle; + uint32 dmabase = DMA_BASE(dmach->base); + irqstate_t flags; + uint32 addr; + + dmalldbg("%s: base: %08x Channel base: %08x \n", msg, dmabase, dmach->base); + + flags = irqsave(); + addr = dmabase + STM32_DMA_ISR_OFFSET; + dmalldbg(" ISRC[%08x]: %08x\n", addr, getreg32(addr)); + + addr = dmach->base + STM32_DMACHAN_CCR_OFFSET; + dmalldbg(" CCR[%08x]: %08x\n", addr, getreg32(addr)); + + addr = dmach->base + STM32_DMACHAN_CNDTR_OFFSET; + dmalldbg(" CNDTR[%08x]: %08x\n", addr, getreg32(addr)); + + addr = dmach->base + STM32_DMACHAN_CPAR_OFFSET; + dmalldbg(" CPAR[%08x]: %08x\n", addr, getreg32(addr)); + + addr = dmach->base + STM32_DMACHAN_CMAR_OFFSET; + dmalldbg(" CMAR[%08x]: %08x\n", addr, getreg32(addr)); + irqrestore(flags); +} +#endif + diff --git a/nuttx/arch/arm/src/stm32/stm32_dma.h b/nuttx/arch/arm/src/stm32/stm32_dma.h index f5409d7f6..e2e16edbd 100644 --- a/nuttx/arch/arm/src/stm32/stm32_dma.h +++ b/nuttx/arch/arm/src/stm32/stm32_dma.h @@ -229,6 +229,7 @@ #define DMA_IFCR_CHAN6_MASK (DMA_CHAN_MASK << DMA_IFCR_CHAN6_SHIFT) #define DMA_IFCR_CHAN7_SHIFT (24) /* Bits 27-24: DMA Channel 7 interrupt flag clear */ #define DMA_IFCR_CHAN7_MASK (DMA_CHAN_MASK << DMA_IFCR_CHAN7_SHIFT) +#define DMA_IFCR_ALLCHANNELS (0x0fffffff) #define DMA_IFCR_CGIF(n) (DMA_CHAN_GIF_BIT << DMA_IFCR_CHAN_SHIFT(n)) #define DMA_IFCR_CTCIF(n) (DMA_CHAN_TCIF_BIT << DMA_IFCR_CHAN_SHIFT(n)) @@ -263,6 +264,8 @@ #define DMA_CCR_TCIE (1 << 1) /* Bit 1: Transfer complete interrupt enable */ #define DMA_CCR_EN (1 << 0) /* Bit 0: Channel enable */ +#define DMA_CCR_ALLINTS (DMA_CCR_TEIE|DMA_CCR_HTIE|DMA_CCR_TCIE) + /* DMA channel number of data register */ #define DMA_CNDTR_NDT_SHIFT (0) /* Bits 15-0: Number of data to Transfer */ diff --git a/nuttx/arch/arm/src/stm32/stm32_internal.h b/nuttx/arch/arm/src/stm32/stm32_internal.h index 9964c1130..b567c5d0f 100755 --- a/nuttx/arch/arm/src/stm32/stm32_internal.h +++ b/nuttx/arch/arm/src/stm32/stm32_internal.h @@ -50,6 +50,12 @@ * Definitions ************************************************************************************/ +/* Configuration ********************************************************************/ + +#if !defined(CONFIG_DEBUG) || !defined(CONFIG_DEBUG_VERBOSE) +# undef CONFIG_DEBUG_DMA +#endif + /* NVIC priority levels *************************************************************/ #define NVIC_SYSH_PRIORITY_MIN 0xff /* All bits set in minimum priority */ @@ -266,19 +272,6 @@ EXTERN int stm32_dumpgpio(uint32 pinset, const char *msg); #endif /**************************************************************************** - * Name: stm32_dmainitialize - * - * Description: - * Initialize the DMA subsystem - * - * Returned Value: - * None - * - ****************************************************************************/ - -EXTERN void weak_function stm32_dmainitialize(void); - -/**************************************************************************** * Name: stm32_dmachannel * * Description: @@ -359,6 +352,23 @@ EXTERN void stm32_dmasetup(DMA_HANDLE handle, uint32 paddr, uint32 maddr, EXTERN void stm32_dmastart(DMA_HANDLE handle, dma_callback_t callback, void *arg, boolean half); +/**************************************************************************** + * Name: stm32_dmadump + * + * Description: + * Dump DMA register contents + * + * Assumptions: + * - DMA handle allocated by stm32_dmachannel() + * + ****************************************************************************/ + +#ifdef CONFIG_DEBUG_DMA +EXTERN void stm32_dmadump(DMA_HANDLE handle, const char *msg); +#else +# define stm32_dmadump(handle) +#endif + /************************************************************************************ * Function: stm32_ethinitialize * @@ -445,31 +455,31 @@ EXTERN int stm32_usbpullup(FAR struct usbdev_s *dev, boolean enable); struct usbdev_s; EXTERN void stm32_usbsuspend(FAR struct usbdev_s *dev, boolean resume); -/****************************************************************************
- * Name: sdio_initialize
- *
- * Description:
- * Initialize SDIO for operation.
- *
+/**************************************************************************** + * Name: sdio_initialize + * + * Description: + * Initialize SDIO for operation. + * * Input Parameters: * slotno - Not used. * * Returned Values: * A reference to an SDIO interface structure. NULL is returned on failures. - *
- ****************************************************************************/
- -struct sdio_dev_s; /* See include/nuttx/sdio.h */
-EXTERN FAR struct sdio_dev_s *sdio_initialize(int slotno);
-
-/****************************************************************************
- * Name: sdio_mediachange
- *
+ * + ****************************************************************************/ + +struct sdio_dev_s; /* See include/nuttx/sdio.h */ +EXTERN FAR struct sdio_dev_s *sdio_initialize(int slotno); + +/**************************************************************************** + * Name: sdio_mediachange + * * Description: * Called by board-specific logic -- posssible from an interrupt handler -- * in order to signal to the driver that a card has been inserted or - * removed from the slot
- *
+ * removed from the slot + * * Input Parameters: * dev - An instance of the SDIO driver device state structure. * cardinslot - TRUE is a card has been detected in the slot; FALSE if a @@ -478,27 +488,27 @@ EXTERN FAR struct sdio_dev_s *sdio_initialize(int slotno); * * Returned Values: * None - *
- ****************************************************************************/
-
+ * + ****************************************************************************/ + EXTERN void sdio_mediachange(FAR struct sdio_dev_s *dev, boolean cardinslot); -/****************************************************************************
- * Name: sdio_wrprotect
- *
+/**************************************************************************** + * Name: sdio_wrprotect + * * Description: * Called by board-specific logic to report if the card in the slot is * mechanically write protected. - *
+ * * Input Parameters: * dev - An instance of the SDIO driver device state structure. * wrprotect - TRUE is a card is writeprotected. * * Returned Values: * None - *
- ****************************************************************************/
-
+ * + ****************************************************************************/ + EXTERN void sdio_wrprotect(FAR struct sdio_dev_s *dev, boolean wrprotect); #undef EXTERN diff --git a/nuttx/arch/arm/src/stm32/stm32_sdio.c b/nuttx/arch/arm/src/stm32/stm32_sdio.c index b46147f04..b3b6d47fd 100644 --- a/nuttx/arch/arm/src/stm32/stm32_sdio.c +++ b/nuttx/arch/arm/src/stm32/stm32_sdio.c @@ -118,10 +118,10 @@ /* DMA CCR register settings */
-#define SDIO_RXDMA16_CONFIG (CONFIG_SDIO_DMAPRIO|DMA_CCR_MSIZE_16BITS|\
- DMA_CCR_PSIZE_16BITS|DMA_CCR_MINC)
-#define SDIO_TXDMA16_CONFIG (CONFIG_SDIO_DMAPRIO|DMA_CCR_MSIZE_16BITS|\
- DMA_CCR_PSIZE_16BITS|DMA_CCR_MINC|DMA_CCR_DIR)
+#define SDIO_RXDMA32_CONFIG (CONFIG_SDIO_DMAPRIO|DMA_CCR_MSIZE_32BITS|\
+ DMA_CCR_PSIZE_32BITS|DMA_CCR_MINC)
+#define SDIO_TXDMA32_CONFIG (CONFIG_SDIO_DMAPRIO|DMA_CCR_MSIZE_32BITS|\
+ DMA_CCR_PSIZE_32BITS|DMA_CCR_MINC|DMA_CCR_DIR)
/* FIFO sizes */
@@ -528,6 +528,8 @@ static void stm32_dmacallback(DMA_HANDLE handle, ubyte isr, void *arg) /* We don't really do anything at the completion of DMA. The termination
* of the transfer is driven by the SDIO interrupts.
*/
+
+ stm32_dmadump(handle, "DMA Callback");
}
#endif
@@ -837,6 +839,15 @@ static void stm32_endtransfer(struct stm32_dev_s *priv, sdio_eventset_t wkupeven priv->remaining = 0;
+ /* DMA debug instrumentation */
+
+#if defined(CONFIG_SDIO_DMA) && defined(CONFIG_DEBUG_DMA)
+ if (priv->dmamode)
+ {
+ stm32_dmadump(priv->dma, "End of Transfer");
+ }
+#endif
+
/* Is a data transfer complete event expected? */
if ((priv->waitevents & wkupevent) != 0)
@@ -1978,6 +1989,8 @@ static int stm32_dmarecvsetup(FAR struct sdio_dev_s *dev, FAR ubyte *buffer, if (priv->widebus)
{
+ stm32_dmadump(priv->dma, "Before RECV Setup");
+
/* Save the destination buffer information for use by the interrupt handler */
priv->buffer = (uint32*)buffer;
@@ -1995,11 +2008,12 @@ static int stm32_dmarecvsetup(FAR struct sdio_dev_s *dev, FAR ubyte *buffer, putreg32(1, SDIO_DCTRL_DMAEN_BB);
stm32_dmasetup(priv->dma, STM32_SDIO_FIFO, (uint32)buffer,
- (buflen + 3) >> 2, SDIO_RXDMA16_CONFIG);
+ (buflen + 3) >> 2, SDIO_RXDMA32_CONFIG);
/* Start the DMA */
stm32_dmastart(priv->dma, stm32_dmacallback, priv, FALSE);
+ stm32_dmadump(priv->dma, "After RECV Setup");
ret = OK;
}
return ret;
@@ -2027,7 +2041,7 @@ static int stm32_dmarecvsetup(FAR struct sdio_dev_s *dev, FAR ubyte *buffer, #ifdef CONFIG_SDIO_DMA
static int stm32_dmasendsetup(FAR struct sdio_dev_s *dev,
- FAR const ubyte *buffer, size_t buflen)
+ FAR const ubyte *buffer, size_t buflen)
{
struct stm32_dev_s *priv = (struct stm32_dev_s *)dev;
uint32 dblocksize;
@@ -2044,6 +2058,8 @@ static int stm32_dmasendsetup(FAR struct sdio_dev_s *dev, if (priv->widebus)
{
+ stm32_dmadump(priv->dma, "Before SEND Setup");
+
/* Save the source buffer information for use by the interrupt handler */
priv->buffer = (uint32*)buffer;
@@ -2062,12 +2078,13 @@ static int stm32_dmasendsetup(FAR struct sdio_dev_s *dev, /* Configure the TX DMA */
stm32_dmasetup(priv->dma, STM32_SDIO_FIFO, (uint32)buffer,
- (buflen + 3) >> 2, SDIO_TXDMA16_CONFIG);
+ (buflen + 3) >> 2, SDIO_TXDMA32_CONFIG);
putreg32(1, SDIO_DCTRL_DMAEN_BB);
/* Start the DMA */
stm32_dmastart(priv->dma, stm32_dmacallback, priv, FALSE);
+ stm32_dmadump(priv->dma, "After SEND Setup");
ret = OK;
}
return ret;
|