aboutsummaryrefslogtreecommitdiff
path: root/nuttx/arch/arm/src
diff options
context:
space:
mode:
authorpatacongo <patacongo@7fd9a85b-ad96-42d3-883c-3090e2eb8679>2012-04-22 19:50:33 +0000
committerpatacongo <patacongo@7fd9a85b-ad96-42d3-883c-3090e2eb8679>2012-04-22 19:50:33 +0000
commitec81f66d5c33285c3d25cca6fcfcb6183ae551ca (patch)
treee015520caeb1c1d4f8e4211ceae807a778ca7826 /nuttx/arch/arm/src
parentcfbb78e2668603e63dfabdd127b8bf01b6744059 (diff)
downloadpx4-firmware-ec81f66d5c33285c3d25cca6fcfcb6183ae551ca.tar.gz
px4-firmware-ec81f66d5c33285c3d25cca6fcfcb6183ae551ca.tar.bz2
px4-firmware-ec81f66d5c33285c3d25cca6fcfcb6183ae551ca.zip
Add circular DMA support to STM32 and STM32 serial driver; Add initial configuration for the Mikroelektronika PIC32MX7 MMB board
git-svn-id: https://nuttx.svn.sourceforge.net/svnroot/nuttx/trunk@4640 7fd9a85b-ad96-42d3-883c-3090e2eb8679
Diffstat (limited to 'nuttx/arch/arm/src')
-rw-r--r--nuttx/arch/arm/src/stm32/chip/stm32_uart.h2
-rw-r--r--nuttx/arch/arm/src/stm32/stm32_dma.c2
-rw-r--r--nuttx/arch/arm/src/stm32/stm32_dma.h13
-rw-r--r--nuttx/arch/arm/src/stm32/stm32_lowputc.c83
-rw-r--r--nuttx/arch/arm/src/stm32/stm32_serial.c500
-rw-r--r--nuttx/arch/arm/src/stm32/stm32_spi.c6
-rw-r--r--nuttx/arch/arm/src/stm32/stm32_uart.h192
-rw-r--r--nuttx/arch/arm/src/stm32/stm32f40xxx_dma.c100
8 files changed, 767 insertions, 131 deletions
diff --git a/nuttx/arch/arm/src/stm32/chip/stm32_uart.h b/nuttx/arch/arm/src/stm32/chip/stm32_uart.h
index 14c1bab79..d3c1e137e 100644
--- a/nuttx/arch/arm/src/stm32/chip/stm32_uart.h
+++ b/nuttx/arch/arm/src/stm32/chip/stm32_uart.h
@@ -1,7 +1,7 @@
/************************************************************************************
* arch/arm/src/stm32/chip/stm32_uart.h
*
- * Copyright (C) 2009, 2011 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2009, 2011-2012 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
diff --git a/nuttx/arch/arm/src/stm32/stm32_dma.c b/nuttx/arch/arm/src/stm32/stm32_dma.c
index 1e642e085..0dd8eb94e 100644
--- a/nuttx/arch/arm/src/stm32/stm32_dma.c
+++ b/nuttx/arch/arm/src/stm32/stm32_dma.c
@@ -1,7 +1,7 @@
/****************************************************************************
* arch/arm/src/stm32/stm32_dma.c
*
- * Copyright (C) 2009, 2011 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2009, 2011-2012 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
diff --git a/nuttx/arch/arm/src/stm32/stm32_dma.h b/nuttx/arch/arm/src/stm32/stm32_dma.h
index c4df0d1dd..cccbc41f0 100644
--- a/nuttx/arch/arm/src/stm32/stm32_dma.h
+++ b/nuttx/arch/arm/src/stm32/stm32_dma.h
@@ -252,6 +252,19 @@ EXTERN void stm32_dmastart(DMA_HANDLE handle, dma_callback_t callback,
EXTERN void stm32_dmastop(DMA_HANDLE handle);
/****************************************************************************
+ * Name: stm32_dmaresidual
+ *
+ * Description:
+ * Returns the number of bytes remaining to be transferred
+ *
+ * Assumptions:
+ * - DMA handle allocated by stm32_dmachannel()
+ *
+ ****************************************************************************/
+
+EXTERN size_t stm32_dmaresidual(DMA_HANDLE handle);
+
+/****************************************************************************
* Name: stm32_dmasample
*
* Description:
diff --git a/nuttx/arch/arm/src/stm32/stm32_lowputc.c b/nuttx/arch/arm/src/stm32/stm32_lowputc.c
index d56f43f00..7a2167b07 100644
--- a/nuttx/arch/arm/src/stm32/stm32_lowputc.c
+++ b/nuttx/arch/arm/src/stm32/stm32_lowputc.c
@@ -56,89 +56,6 @@
/**************************************************************************
* Private Definitions
**************************************************************************/
-/* Configuration **********************************************************/
-/* Make sure that we have not enabled more U[S]ARTs than are support by
- * the device.
- */
-
-#if STM32_NUSART < 6
-# undef CONFIG_STM32_USART6
-#endif
-#if STM32_NUSART < 5
-# undef CONFIG_STM32_UART5
-#endif
-#if STM32_NUSART < 4
-# undef CONFIG_STM32_UART4
-#endif
-#if STM32_NUSART < 3
-# undef CONFIG_STM32_USART3
-#endif
-#if STM32_NUSART < 2
-# undef CONFIG_STM32_USART2
-#endif
-#if STM32_NUSART < 1
-# undef CONFIG_STM32_USART1
-#endif
-
-#if defined(CONFIG_STM32_USART1) || defined (CONFIG_STM32_USART2) || defined(CONFIG_STM32_USART3) || \
- defined(CONFIG_STM32_UART4) || defined (CONFIG_STM32_UART5) || defined(CONFIG_STM32_USART6)
-# define HAVE_UART
-#endif
-
-/* Is there a serial console? */
-
-#if defined(CONFIG_USART1_SERIAL_CONSOLE) && defined(CONFIG_STM32_USART1)
-# undef CONFIG_USART2_SERIAL_CONSOLE
-# undef CONFIG_USART3_SERIAL_CONSOLE
-# undef CONFIG_UART4_SERIAL_CONSOLE
-# undef CONFIG_UART5_SERIAL_CONSOLE
-# undef CONFIG_USART6_SERIAL_CONSOLE
-# define HAVE_CONSOLE 1
-#elif defined(CONFIG_USART2_SERIAL_CONSOLE) && defined(CONFIG_STM32_USART2)
-# undef CONFIG_USART1_SERIAL_CONSOLE
-# undef CONFIG_USART3_SERIAL_CONSOLE
-# undef CONFIG_USART4_SERIAL_CONSOLE
-# undef CONFIG_USART5_SERIAL_CONSOLE
-# undef CONFIG_USART6_SERIAL_CONSOLE
-# define HAVE_CONSOLE 1
-#elif defined(CONFIG_USART3_SERIAL_CONSOLE) && defined(CONFIG_STM32_USART3)
-# undef CONFIG_USART1_SERIAL_CONSOLE
-# undef CONFIG_USART2_SERIAL_CONSOLE
-# undef CONFIG_UART4_SERIAL_CONSOLE
-# undef CONFIG_UART5_SERIAL_CONSOLE
-# undef CONFIG_USART6_SERIAL_CONSOLE
-# define HAVE_CONSOLE 1
-#elif defined(CONFIG_UART4_SERIAL_CONSOLE) && defined(CONFIG_STM32_UART4)
-# undef CONFIG_USART1_SERIAL_CONSOLE
-# undef CONFIG_USART2_SERIAL_CONSOLE
-# undef CONFIG_USART3_SERIAL_CONSOLE
-# undef CONFIG_UART5_SERIAL_CONSOLE
-# undef CONFIG_USART6_SERIAL_CONSOLE
-# define HAVE_CONSOLE 1
-#elif defined(CONFIG_UART5_SERIAL_CONSOLE) && defined(CONFIG_STM32_UART5)
-# undef CONFIG_USART1_SERIAL_CONSOLE
-# undef CONFIG_USART2_SERIAL_CONSOLE
-# undef CONFIG_USART3_SERIAL_CONSOLE
-# undef CONFIG_UART4_SERIAL_CONSOLE
-# undef CONFIG_USART6_SERIAL_CONSOLE
-# define HAVE_CONSOLE 1
-#elif defined(CONFIG_USART6_SERIAL_CONSOLE) && defined(CONFIG_STM32_USART6)
-# undef CONFIG_USART1_SERIAL_CONSOLE
-# undef CONFIG_USART2_SERIAL_CONSOLE
-# undef CONFIG_USART3_SERIAL_CONSOLE
-# undef CONFIG_UART4_SERIAL_CONSOLE
-# undef CONFIG_UART5_SERIAL_CONSOLE
-# define HAVE_CONSOLE 1
-#else
-# undef CONFIG_USART1_SERIAL_CONSOLE
-# undef CONFIG_USART2_SERIAL_CONSOLE
-# undef CONFIG_USART3_SERIAL_CONSOLE
-# undef CONFIG_UART4_SERIAL_CONSOLE
-# undef CONFIG_UART5_SERIAL_CONSOLE
-# undef CONFIG_USART6_SERIAL_CONSOLE
-# undef HAVE_CONSOLE
-#endif
-
/* Select USART parameters for the selected console */
#if defined(CONFIG_USART1_SERIAL_CONSOLE)
diff --git a/nuttx/arch/arm/src/stm32/stm32_serial.c b/nuttx/arch/arm/src/stm32/stm32_serial.c
index 680a77216..b9682eae4 100644
--- a/nuttx/arch/arm/src/stm32/stm32_serial.c
+++ b/nuttx/arch/arm/src/stm32/stm32_serial.c
@@ -57,6 +57,7 @@
#include "chip.h"
#include "stm32_uart.h"
+#include "stm32_dma.h"
#include "up_arch.h"
#include "up_internal.h"
#include "os_internal.h"
@@ -65,36 +66,69 @@
* Definitions
****************************************************************************/
/* Some sanity checks *******************************************************/
-/* Is there a USART enabled? */
-
-#if defined(CONFIG_STM32_USART1) || defined(CONFIG_STM32_USART2) || \
- defined(CONFIG_STM32_USART3) || defined(CONFIG_STM32_UART4) || \
- defined(CONFIG_STM32_UART5) || defined(CONFIG_STM32_USART6)
-# define HAVE_UART 1
-#endif
-
-/* Is there a serial console? */
-
-#if defined(CONFIG_USART1_SERIAL_CONSOLE) && defined(CONFIG_STM32_USART1)
-# define CONSOLE_UART 1
-#elif defined(CONFIG_USART2_SERIAL_CONSOLE) && defined(CONFIG_STM32_USART2)
-# define CONSOLE_UART 2
-#elif defined(CONFIG_USART3_SERIAL_CONSOLE) && defined(CONFIG_STM32_USART3)
-# define CONSOLE_UART 3
-#elif defined(CONFIG_USART4_SERIAL_CONSOLE) && defined(CONFIG_STM32_UART4)
-# define CONSOLE_UART 4
-#elif defined(CONFIG_USART5_SERIAL_CONSOLE) && defined(CONFIG_STM32_UART5)
-# define CONSOLE_UART 5
-#elif defined(CONFIG_USART6_SERIAL_CONSOLE) && defined(CONFIG_STM32_USART6)
-# define CONSOLE_UART 6
-#else
-# define CONSOLE_UART 0
-#endif
+/* DMA configuration */
+
+/* If DMA is enabled on any USART, then very that other pre-requisites
+ * have also been selected.
+ */
+
+#if SERIAL_HAVE_DMA
+
+/* Verify that DMA has been enabled an the DMA channel has been defined.
+ * NOTE: These assignments may only be true for the F4.
+ */
+
+# if defined(CONFIG_USART1_RXDMA) || defined(CONFIG_USART6_RXDMA)
+# ifndef CONFIG_STM32_DMA2
+# error STM32 USART1/6 receive DMA requires CONFIG_STM32_DMA2
+# endif
+# endif
+
+# if defined(CONFIG_USART2_RXDMA) || defined(CONFIG_USART3_RXDMA) || \
+ defined(CONFIG_USART4_RXDMA) || defined(CONFIG_USART5_RXDMA)
+# ifndef CONFIG_STM32_DMA1
+# error STM32 USART2/3/4/5 receive DMA requires CONFIG_STM32_DMA1
+# endif
+# endif
+
+/* For the F4, there are alternate DMA channels for USART1 and 6.
+ * Logic in the board.h file make the DMA channel selection by defining
+ * the following in the board.h file.
+ */
+
+# if defined(CONFIG_USART1_RXDMA) && !defined(DMAMAP_USART1_RX)
+# error "USART1 DMA channel not defined (DMAMAP_USART1_RX)"
+# endif
+
+# if defined(CONFIG_USART2_RXDMA) && !defined(DMAMAP_USART2_RX)
+# error "USART2 DMA channel not defined (DMAMAP_USART2_RX)"
+# endif
+
+# if defined(CONFIG_USART3_RXDMA) && !defined(DMAMAP_USART3_RX)
+# error "USART3 DMA channel not defined (DMAMAP_USART3_RX)"
+# endif
+
+# if defined(CONFIG_USART4_RXDMA) && !defined(DMAMAP_UART4_RX)
+# error "UART4 DMA channel not defined (DMAMAP_UART4_RX)"
+# endif
+
+# if defined(CONFIG_USART5_RXDMA) && !defined(DMAMAP_UART5_RX)
+# error "UART5 DMA channel not defined (DMAMAP_UART5_RX)"
+# endif
+
+# if defined(CONFIG_USART6_RXDMA) && !defined(DMAMAP_USART6_RX)
+# error "USART6 DMA channel not defined (DMAMAP_USART6_RX)"
+# endif
-/* If we are not using the serial driver for the console, then we still must
- * provide some minimal implementation of up_putc.
+/* The DMA buffer size when using RX DMA to emulate a FIFO.
+ *
+ * When streaming data, the generic serial layer will be called
+ * everytime the FIFO receives half this number of bytes.
*/
+# define RXDMA_BUFFER_SIZE 32
+#endif
+
#ifdef USE_SERIALDRIVER
#ifdef HAVE_UART
@@ -120,7 +154,20 @@ struct up_dev_s
const uint32_t rts_gpio; /* U[S]ART RTS GPIO pin configuration */
const uint32_t cts_gpio; /* U[S]ART CTS GPIO pin configuration */
+#ifdef SERIAL_HAVE_DMA
+ const unsigned int rxdma_channel; /* DMA channel assigned */
+#endif
+
int (* const vector)(int irq, void *context); /* Interrupt handler */
+
+ /* RX DMA state */
+
+#ifdef SERIAL_HAVE_DMA
+ DMA_HANDLE rxdma; /* currently-open receive DMA stream */
+ bool rxenable; /* DMA-based reception en/disable */
+ uint32_t rxdmanext; /* Next byte in the DMA buffer to be read */
+ char *const rxfifo; /* Receive DMA buffer */
+#endif
};
/****************************************************************************
@@ -133,13 +180,25 @@ static int up_attach(struct uart_dev_s *dev);
static void up_detach(struct uart_dev_s *dev);
static int up_interrupt_common(struct up_dev_s *dev);
static int up_ioctl(struct file *filep, int cmd, unsigned long arg);
+#ifndef SERIAL_HAVE_ONLY_DMA
static int up_receive(struct uart_dev_s *dev, uint32_t *status);
static void up_rxint(struct uart_dev_s *dev, bool enable);
static bool up_rxavailable(struct uart_dev_s *dev);
+#endif
static void up_send(struct uart_dev_s *dev, int ch);
static void up_txint(struct uart_dev_s *dev, bool enable);
static bool up_txready(struct uart_dev_s *dev);
+#ifdef SERIAL_HAVE_DMA
+static int up_dma_setup(struct uart_dev_s *dev);
+static void up_dma_shutdown(struct uart_dev_s *dev);
+static int up_dma_receive(struct uart_dev_s *dev, uint32_t *status);
+static void up_dma_rxint(struct uart_dev_s *dev, bool enable);
+static bool up_dma_rxavailable(struct uart_dev_s *dev);
+
+static void up_dma_rxcallback(DMA_HANDLE handle, uint8_t status, void *arg);
+#endif
+
#ifdef CONFIG_STM32_USART1
static int up_interrupt_usart1(int irq, void *context);
#endif
@@ -163,6 +222,7 @@ static int up_interrupt_usart6(int irq, void *context);
* Private Variables
****************************************************************************/
+#ifndef SERIAL_HAVE_ONLY_DMA
static const struct uart_ops_s g_uart_ops =
{
.setup = up_setup,
@@ -178,32 +238,74 @@ static const struct uart_ops_s g_uart_ops =
.txready = up_txready,
.txempty = up_txready,
};
+#endif
+
+#ifdef SERIAL_HAVE_DMA
+static const struct uart_ops_s g_uart_dma_ops =
+{
+ .setup = up_dma_setup,
+ .shutdown = up_dma_shutdown,
+ .attach = up_attach,
+ .detach = up_detach,
+ .ioctl = up_ioctl,
+ .receive = up_dma_receive,
+ .rxint = up_dma_rxint,
+ .rxavailable = up_dma_rxavailable,
+ .send = up_send,
+ .txint = up_txint,
+ .txready = up_txready,
+ .txempty = up_txready,
+};
+#endif
/* I/O buffers */
#ifdef CONFIG_STM32_USART1
static char g_usart1rxbuffer[CONFIG_USART1_RXBUFSIZE];
static char g_usart1txbuffer[CONFIG_USART1_TXBUFSIZE];
+# ifdef CONFIG_USART1_RXDMA
+static char g_usart1rxfifo[RXDMA_BUFFER_SIZE];
+# endif
#endif
+
#ifdef CONFIG_STM32_USART2
static char g_usart2rxbuffer[CONFIG_USART2_RXBUFSIZE];
static char g_usart2txbuffer[CONFIG_USART2_TXBUFSIZE];
+# ifdef CONFIG_USART2_RXDMA
+static char g_usart2rxfifo[RXDMA_BUFFER_SIZE];
+# endif
#endif
+
#ifdef CONFIG_STM32_USART3
static char g_usart3rxbuffer[CONFIG_USART3_RXBUFSIZE];
static char g_usart3txbuffer[CONFIG_USART3_TXBUFSIZE];
+# ifdef CONFIG_USART3_RXDMA
+static char g_usart3rxfifo[RXDMA_BUFFER_SIZE];
+# endif
#endif
+
#ifdef CONFIG_STM32_UART4
static char g_uart4rxbuffer[CONFIG_USART4_RXBUFSIZE];
static char g_uart4txbuffer[CONFIG_USART4_TXBUFSIZE];
+# ifdef CONFIG_USART4_RXDMA
+static char g_uart4rxfifo[RXDMA_BUFFER_SIZE];
+# endif
#endif
+
#ifdef CONFIG_STM32_UART5
static char g_uart5rxbuffer[CONFIG_USART5_RXBUFSIZE];
static char g_uart5txbuffer[CONFIG_USART5_TXBUFSIZE];
+# ifdef CONFIG_USART5_RXDMA
+static char g_uart5rxfifo[RXDMA_BUFFER_SIZE];
+# endif
#endif
+
#ifdef CONFIG_STM32_USART6
static char g_usart6rxbuffer[CONFIG_USART6_RXBUFSIZE];
static char g_usart6txbuffer[CONFIG_USART6_TXBUFSIZE];
+# ifdef CONFIG_USART6_RXDMA
+static char g_usart6rxfifo[RXDMA_BUFFER_SIZE];
+# endif
#endif
/* This describes the state of the STM32 USART1 ports. */
@@ -226,7 +328,11 @@ static struct up_dev_s g_usart1priv =
.size = CONFIG_USART1_TXBUFSIZE,
.buffer = g_usart1txbuffer,
},
+#ifdef CONFIG_USART1_RXDMA
+ .ops = &g_uart_dma_ops,
+#else
.ops = &g_uart_ops,
+#endif
.priv = &g_usart1priv,
},
@@ -245,6 +351,10 @@ static struct up_dev_s g_usart1priv =
#ifdef GPIO_USART1_RTS
.rts_gpio = GPIO_USART1_RTS,
#endif
+#ifdef CONFIG_USART1_RXDMA
+ .rxdma_channel = DMAMAP_USART1_RX,
+ .rxfifo = g_usart1rxfifo,
+#endif
.vector = up_interrupt_usart1,
};
#endif
@@ -269,7 +379,11 @@ static struct up_dev_s g_usart2priv =
.size = CONFIG_USART2_TXBUFSIZE,
.buffer = g_usart2txbuffer,
},
+#ifdef CONFIG_USART2_RXDMA
+ .ops = &g_uart_dma_ops,
+#else
.ops = &g_uart_ops,
+#endif
.priv = &g_usart2priv,
},
@@ -288,6 +402,10 @@ static struct up_dev_s g_usart2priv =
#ifdef GPIO_USART2_RTS
.rts_gpio = GPIO_USART2_RTS,
#endif
+#ifdef CONFIG_USART2_RXDMA
+ .rxdma_channel = DMAMAP_USART2_RX,
+ .rxfifo = g_usart2rxfifo,
+#endif
.vector = up_interrupt_usart2,
};
#endif
@@ -312,7 +430,11 @@ static struct up_dev_s g_usart3priv =
.size = CONFIG_USART3_TXBUFSIZE,
.buffer = g_usart3txbuffer,
},
+#ifdef CONFIG_USART3_RXDMA
+ .ops = &g_uart_dma_ops,
+#else
.ops = &g_uart_ops,
+#endif
.priv = &g_usart3priv,
},
@@ -331,6 +453,10 @@ static struct up_dev_s g_usart3priv =
#ifdef GPIO_USART3_RTS
.rts_gpio = GPIO_USART3_RTS,
#endif
+#ifdef CONFIG_USART3_RXDMA
+ .rxdma_channel = DMAMAP_USART3_RX,
+ .rxfifo = g_usart3rxfifo,
+#endif
.vector = up_interrupt_usart3,
};
#endif
@@ -355,7 +481,11 @@ static struct up_dev_s g_uart4priv =
.size = CONFIG_USART4_TXBUFSIZE,
.buffer = g_uart4txbuffer,
},
+#ifdef CONFIG_USART4_RXDMA
+ .ops = &g_uart_dma_ops,
+#else
.ops = &g_uart_ops,
+#endif
.priv = &g_uart4priv,
},
@@ -374,6 +504,10 @@ static struct up_dev_s g_uart4priv =
#ifdef GPIO_USART4_RTS
.rts_gpio = GPIO_UART4_RTS,
#endif
+#ifdef CONFIG_USART4_RXDMA
+ .rxdma_channel = DMAMAP_UART4_RX,
+ .rxfifo = g_uart4rxfifo,
+#endif
.vector = up_interrupt_uart4,
};
#endif
@@ -398,7 +532,11 @@ static struct up_dev_s g_uart5priv =
.size = CONFIG_USART5_TXBUFSIZE,
.buffer = g_uart5txbuffer,
},
+#ifdef CONFIG_USART5_RXDMA
+ .ops = &g_uart_dma_ops,
+#else
.ops = &g_uart_ops,
+#endif
.priv = &g_uart5priv,
},
@@ -417,6 +555,10 @@ static struct up_dev_s g_uart5priv =
#ifdef GPIO_USART5_RTS
.rts_gpio = GPIO_UART5_RTS,
#endif
+#ifdef CONFIG_USART5_RXDMA
+ .rxdma_channel = DMAMAP_UART5_RX,
+ .rxfifo = g_uart5rxfifo,
+#endif
.vector = up_interrupt_uart5,
};
#endif
@@ -441,7 +583,11 @@ static struct up_dev_s g_usart6priv =
.size = CONFIG_USART6_TXBUFSIZE,
.buffer = g_usart6txbuffer,
},
+#ifdef CONFIG_USART6_RXDMA
+ .ops = &g_uart_dma_ops,
+#else
.ops = &g_uart_ops,
+#endif
.priv = &g_usart6priv,
},
@@ -460,6 +606,10 @@ static struct up_dev_s g_usart6priv =
#ifdef GPIO_USART6_RTS
.rts_gpio = GPIO_USART6_RTS,
#endif
+#ifdef CONFIG_USART6_RXDMA
+ .rxdma_channel = DMAMAP_USART6_RX,
+ .rxfifo = g_usart6rxfifo,
+#endif
.vector = up_interrupt_usart6,
};
#endif
@@ -581,6 +731,26 @@ static inline void up_disableusartint(struct up_dev_s *priv, uint16_t *ie)
}
/****************************************************************************
+ * Name: up_dma_nextrx
+ *
+ * Description:
+ * Returns the index into the RX FIFO where the DMA will place the next
+ * byte that it receives.
+ *
+ ****************************************************************************/
+
+#ifdef SERIAL_HAVE_DMA
+static int up_dma_nextrx(struct up_dev_s *priv)
+{
+ size_t dmaresidual;
+
+ dmaresidual = stm32_dmaresidual(priv->rxdma);
+
+ return (RXDMA_BUFFER_SIZE - (int)dmaresidual);
+}
+#endif
+
+/****************************************************************************
* Name: up_setup
*
* Description:
@@ -642,19 +812,20 @@ static int up_setup(struct uart_dev_s *dev)
/* Configure word length and parity mode */
- if (priv->bits == 9) /* Default: 1 start, 8 data, n stop */
+ if (priv->bits == 9) /* Default: 1 start, 8 data, n stop */
{
- regval |= USART_CR1_M; /* 1 start, 9 data, n stop */
+ regval |= USART_CR1_M; /* 1 start, 9 data, n stop */
}
- if (priv->parity == 1) /* Odd parity */
+ if (priv->parity == 1) /* Odd parity */
{
regval |= (USART_CR1_PCE|USART_CR1_PS);
}
- else if (priv->parity == 2) /* Even parity */
+ else if (priv->parity == 2) /* Even parity */
{
regval |= USART_CR1_PCE;
}
+
up_serialout(priv, STM32_USART_CR1_OFFSET, regval);
/* Configure CR3 */
@@ -710,6 +881,71 @@ static int up_setup(struct uart_dev_s *dev)
}
/****************************************************************************
+ * Name: up_dma_setup
+ *
+ * Description:
+ * Configure the USART baud, bits, parity, etc. This method is called the
+ * first time that the serial port is opened.
+ *
+ ****************************************************************************/
+
+#ifdef SERIAL_HAVE_DMA
+static int up_dma_setup(struct uart_dev_s *dev)
+{
+ struct up_dev_s *priv = (struct up_dev_s*)dev->priv;
+ int result;
+ uint32_t regval;
+
+ /* Do the basic UART setup first */
+
+ result = up_setup(dev);
+ if (result != OK)
+ {
+ return result;
+ }
+
+ /* Acquire the DMA channel. This should always succeed. */
+
+ priv->rxdma = stm32_dmachannel(priv->rxdma_channel);
+
+ /* Configure for circular DMA reception into the RX fifo */
+
+ stm32_dmasetup(priv->rxdma,
+ priv->usartbase + STM32_USART_DR_OFFSET,
+ (uint32_t)priv->rxfifo,
+ RXDMA_BUFFER_SIZE,
+ DMA_SCR_DIR_P2M |
+ DMA_SCR_CIRC |
+ DMA_SCR_MINC |
+ DMA_SCR_PSIZE_8BITS |
+ DMA_SCR_MSIZE_8BITS |
+ DMA_SCR_PBURST_SINGLE |
+ DMA_SCR_MBURST_SINGLE);
+
+ /* Reset our DMA shadow pointer to match the address just
+ * programmed above.
+ */
+
+ priv->rxdmanext = 0;
+
+ /* Enable receive DMA for the UART */
+
+ regval = up_serialin(priv, STM32_USART_CR3_OFFSET);
+ regval |= USART_CR3_DMAR;
+ up_serialout(priv, STM32_USART_CR3_OFFSET, regval);
+
+ /* Start the DMA channel, and arrange for callbacks at the half and
+ * full points in the FIFO. This ensures that we have half a FIFO
+ * worth of time to claim bytes before they are overwritten.
+ */
+
+ stm32_dmastart(priv->rxdma, up_dma_rxcallback, (void *)priv, true);
+
+ return OK;
+}
+#endif
+
+/****************************************************************************
* Name: up_shutdown
*
* Description:
@@ -729,12 +965,41 @@ static void up_shutdown(struct uart_dev_s *dev)
/* Disable Rx, Tx, and the UART */
- regval = up_serialin(priv, STM32_USART_CR1_OFFSET);
- regval &= ~(USART_CR1_UE|USART_CR1_TE|USART_CR1_RE);
+ regval = up_serialin(priv, STM32_USART_CR1_OFFSET);
+ regval &= ~(USART_CR1_UE|USART_CR1_TE|USART_CR1_RE);
up_serialout(priv, STM32_USART_CR1_OFFSET, regval);
}
/****************************************************************************
+ * Name: up_dma_shutdown
+ *
+ * Description:
+ * Disable the USART. This method is called when the serial
+ * port is closed
+ *
+ ****************************************************************************/
+
+#ifdef SERIAL_HAVE_DMA
+static void up_dma_shutdown(struct uart_dev_s *dev)
+{
+ struct up_dev_s *priv = (struct up_dev_s*)dev->priv;
+
+ /* Perform the normal UART shutdown */
+
+ up_shutdown(dev);
+
+ /* Stop the DMA channel */
+
+ stm32_dmastop(priv->rxdma);
+
+ /* Release the DMA channel */
+
+ stm32_dmafree(priv->rxdma);
+ priv->rxdma = NULL;
+}
+#endif
+
+/****************************************************************************
* Name: up_attach
*
* Description:
@@ -951,6 +1216,7 @@ static int up_ioctl(struct file *filep, int cmd, unsigned long arg)
*
****************************************************************************/
+#ifndef SERIAL_HAVE_ONLY_DMA
static int up_receive(struct uart_dev_s *dev, uint32_t *status)
{
struct up_dev_s *priv = (struct up_dev_s*)dev->priv;
@@ -969,6 +1235,7 @@ static int up_receive(struct uart_dev_s *dev, uint32_t *status)
return dr & 0xff;
}
+#endif
/****************************************************************************
* Name: up_rxint
@@ -978,6 +1245,7 @@ static int up_receive(struct uart_dev_s *dev, uint32_t *status)
*
****************************************************************************/
+#ifndef SERIAL_HAVE_ONLY_DMA
static void up_rxint(struct uart_dev_s *dev, bool enable)
{
struct up_dev_s *priv = (struct up_dev_s*)dev->priv;
@@ -1025,6 +1293,7 @@ static void up_rxint(struct uart_dev_s *dev, bool enable)
up_restoreusartint(priv, ie);
irqrestore(flags);
}
+#endif
/****************************************************************************
* Name: up_rxavailable
@@ -1034,11 +1303,90 @@ static void up_rxint(struct uart_dev_s *dev, bool enable)
*
****************************************************************************/
+#ifndef SERIAL_HAVE_ONLY_DMA
static bool up_rxavailable(struct uart_dev_s *dev)
{
struct up_dev_s *priv = (struct up_dev_s*)dev->priv;
return ((up_serialin(priv, STM32_USART_SR_OFFSET) & USART_SR_RXNE) != 0);
}
+#endif
+
+/****************************************************************************
+ * Name: up_dma_receive
+ *
+ * Description:
+ * Called (usually) from the interrupt level to receive one
+ * character from the USART. Error bits associated with the
+ * receipt are provided in the return 'status'.
+ *
+ ****************************************************************************/
+
+#ifdef SERIAL_HAVE_DMA
+static int up_dma_receive(struct uart_dev_s *dev, uint32_t *status)
+{
+ struct up_dev_s *priv = (struct up_dev_s*)dev->priv;
+ int c = 0;
+
+ if (up_dma_nextrx(priv) != priv->rxdmanext)
+ {
+ c = priv->rxfifo[priv->rxdmanext];
+
+ priv->rxdmanext++;
+ if (priv->rxdmanext == RXDMA_BUFFER_SIZE)
+ {
+ priv->rxdmanext = 0;
+ }
+ }
+
+ return c;
+}
+#endif
+
+/****************************************************************************
+ * Name: up_dma_rxint
+ *
+ * Description:
+ * Call to enable or disable RX interrupts
+ *
+ ****************************************************************************/
+
+#ifdef SERIAL_HAVE_DMA
+static void up_dma_rxint(struct uart_dev_s *dev, bool enable)
+{
+ struct up_dev_s *priv = (struct up_dev_s*)dev->priv;
+
+ /* En/disable DMA reception.
+ *
+ * Note that it is not safe to check for available bytes and immediately
+ * pass them to uart_recvchars as that could potentially recurse back
+ * to us again. Instead, bytes must wait until the next up_dma_poll or
+ * DMA event.
+ */
+
+ priv->rxenable = enable;
+}
+#endif
+
+/****************************************************************************
+ * Name: up_dma_rxavailable
+ *
+ * Description:
+ * Return true if the receive register is not empty
+ *
+ ****************************************************************************/
+
+#ifdef SERIAL_HAVE_DMA
+static bool up_dma_rxavailable(struct uart_dev_s *dev)
+{
+ struct up_dev_s *priv = (struct up_dev_s*)dev->priv;
+
+ /* Compare our receive pointer to the current DMA pointer, if they
+ * do not match, then there are bytes to be received.
+ */
+
+ return (up_dma_nextrx(priv) != priv->rxdmanext);
+}
+#endif
/****************************************************************************
* Name: up_send
@@ -1163,6 +1511,28 @@ static int up_interrupt_usart6(int irq, void *context)
return up_interrupt_common(&g_usart6priv);
}
#endif
+
+/****************************************************************************
+ * Name: up_dma_rxcallback
+ *
+ * Description:
+ * This function checks the current DMA state and calls the generic
+ * serial stack when bytes appear to be available.
+ *
+ ****************************************************************************/
+
+#ifdef SERIAL_HAVE_DMA
+static void up_dma_rxcallback(DMA_HANDLE handle, uint8_t status, void *arg)
+{
+ struct up_dev_s *priv = (struct up_dev_s*)arg;
+
+ if (priv->rxenable && up_dma_rxavailable(&priv->dev))
+ {
+ uart_recvchars(&priv->dev);
+ }
+}
+#endif
+
#endif /* HAVE UART */
/****************************************************************************
@@ -1247,6 +1617,70 @@ void up_serialinit(void)
}
/****************************************************************************
+ * Name: stm32_serial_dma_poll
+ *
+ * Description:
+ * Checks receive DMA buffers for received bytes that have not accumulated
+ * to the point where the DMA half/full interrupt has triggered.
+ *
+ * This function should be called from a timer or other periodic context.
+ *
+ ****************************************************************************/
+
+#ifdef SERIAL_HAVE_DMA
+void stm32_serial_dma_poll(void)
+{
+ irqstate_t flags;
+
+ flags = irqsave();
+
+#ifdef CONFIG_USART1_RXDMA
+ if (g_usart1priv.rxdma != NULL)
+ {
+ up_dma_rxcallback(g_usart1priv.rxdma, 0, &g_usart1priv);
+ }
+#endif
+
+#ifdef CONFIG_USART2_RXDMA
+ if (g_usart2priv.rxdma != NULL)
+ {
+ up_dma_rxcallback(g_usart2priv.rxdma, 0, &g_usart2priv);
+ }
+#endif
+
+#ifdef CONFIG_USART3_RXDMA
+ if (g_usart3priv.rxdma != NULL)
+ {
+ up_dma_rxcallback(g_usart3priv.rxdma, 0, &g_usart3priv);
+ }
+#endif
+
+#ifdef CONFIG_USART4_RXDMA
+ if (g_uart4priv.rxdma != NULL)
+ {
+ up_dma_rxcallback(g_uart4priv.rxdma, 0, &g_uart4priv);
+ }
+#endif
+
+#ifdef CONFIG_USART5_RXDMA
+ if (g_uart5priv.rxdma != NULL)
+ {
+ up_dma_rxcallback(g_uart5priv.rxdma, 0, &g_uart5priv);
+ }
+#endif
+
+#ifdef CONFIG_USART6_RXDMA
+ if (g_usart6priv.rxdma != NULL)
+ {
+ up_dma_rxcallback(g_usart6priv.rxdma, 0, &g_usart6priv);
+ }
+#endif
+
+ irqrestore(flags);
+}
+#endif
+
+/****************************************************************************
* Name: up_putc
*
* Description:
diff --git a/nuttx/arch/arm/src/stm32/stm32_spi.c b/nuttx/arch/arm/src/stm32/stm32_spi.c
index 6386d0d58..7fdd988cb 100644
--- a/nuttx/arch/arm/src/stm32/stm32_spi.c
+++ b/nuttx/arch/arm/src/stm32/stm32_spi.c
@@ -532,6 +532,9 @@ static inline void spi_dmarxwakeup(FAR struct stm32_spidev_s *priv)
static void spi_dmarxcallback(DMA_HANDLE handle, uint8_t isr, void *arg)
{
FAR struct stm32_spidev_s *priv = (FAR struct stm32_spidev_s *)arg;
+
+ /* Wake-up the SPI driver */
+
priv->rxresult = isr | 0x080; /* OR'ed with 0x80 to assure non-zero */
spi_dmarxwakeup(priv);
}
@@ -549,6 +552,9 @@ static void spi_dmarxcallback(DMA_HANDLE handle, uint8_t isr, void *arg)
static void spi_dmatxcallback(DMA_HANDLE handle, uint8_t isr, void *arg)
{
FAR struct stm32_spidev_s *priv = (FAR struct stm32_spidev_s *)arg;
+
+ /* Wake-up the SPI driver */
+
priv->txresult = isr | 0x080; /* OR'ed with 0x80 to assure non-zero */
spi_dmatxwakeup(priv);
}
diff --git a/nuttx/arch/arm/src/stm32/stm32_uart.h b/nuttx/arch/arm/src/stm32/stm32_uart.h
index c50581996..bd00c34e6 100644
--- a/nuttx/arch/arm/src/stm32/stm32_uart.h
+++ b/nuttx/arch/arm/src/stm32/stm32_uart.h
@@ -1,7 +1,7 @@
/************************************************************************************
* arch/arm/src/stm32/stm32_uart.h
*
- * Copyright (C) 2009 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2009, 2012 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@@ -48,6 +48,163 @@
/************************************************************************************
* Pre-processor Definitions
************************************************************************************/
+/* Make sure that we have not enabled more U[S]ARTs than are support by
+ * the device.
+ */
+
+#if STM32_NUSART < 6
+# undef CONFIG_STM32_USART6
+#endif
+#if STM32_NUSART < 5
+# undef CONFIG_STM32_UART5
+#endif
+#if STM32_NUSART < 4
+# undef CONFIG_STM32_UART4
+#endif
+#if STM32_NUSART < 3
+# undef CONFIG_STM32_USART3
+#endif
+#if STM32_NUSART < 2
+# undef CONFIG_STM32_USART2
+#endif
+#if STM32_NUSART < 1
+# undef CONFIG_STM32_USART1
+#endif
+
+/* Is there a USART enabled? */
+
+#if defined(CONFIG_STM32_USART1) || defined(CONFIG_STM32_USART2) || \
+ defined(CONFIG_STM32_USART3) || defined(CONFIG_STM32_UART4) || \
+ defined(CONFIG_STM32_UART5) || defined(CONFIG_STM32_USART6)
+# define HAVE_UART 1
+#endif
+
+/* Is there a serial console? */
+
+#if defined(CONFIG_USART1_SERIAL_CONSOLE) && defined(CONFIG_STM32_USART1)
+# undef CONFIG_USART2_SERIAL_CONSOLE
+# undef CONFIG_USART3_SERIAL_CONSOLE
+# undef CONFIG_UART4_SERIAL_CONSOLE
+# undef CONFIG_UART5_SERIAL_CONSOLE
+# undef CONFIG_USART6_SERIAL_CONSOLE
+# define CONSOLE_UART 1
+# define HAVE_CONSOLE 1
+#elif defined(CONFIG_USART2_SERIAL_CONSOLE) && defined(CONFIG_STM32_USART2)
+# undef CONFIG_USART1_SERIAL_CONSOLE
+# undef CONFIG_USART3_SERIAL_CONSOLE
+# undef CONFIG_USART4_SERIAL_CONSOLE
+# undef CONFIG_USART5_SERIAL_CONSOLE
+# undef CONFIG_USART6_SERIAL_CONSOLE
+# define CONSOLE_UART 2
+# define HAVE_CONSOLE 1
+#elif defined(CONFIG_USART3_SERIAL_CONSOLE) && defined(CONFIG_STM32_USART3)
+# undef CONFIG_USART1_SERIAL_CONSOLE
+# undef CONFIG_USART2_SERIAL_CONSOLE
+# undef CONFIG_UART4_SERIAL_CONSOLE
+# undef CONFIG_UART5_SERIAL_CONSOLE
+# undef CONFIG_USART6_SERIAL_CONSOLE
+# define CONSOLE_UART 3
+# define HAVE_CONSOLE 1
+#elif defined(CONFIG_USART4_SERIAL_CONSOLE) && defined(CONFIG_STM32_UART4)
+# undef CONFIG_USART1_SERIAL_CONSOLE
+# undef CONFIG_USART2_SERIAL_CONSOLE
+# undef CONFIG_USART3_SERIAL_CONSOLE
+# undef CONFIG_UART5_SERIAL_CONSOLE
+# undef CONFIG_USART6_SERIAL_CONSOLE
+# define CONSOLE_UART 4
+# define HAVE_CONSOLE 1
+#elif defined(CONFIG_USART5_SERIAL_CONSOLE) && defined(CONFIG_STM32_UART5)
+# undef CONFIG_USART1_SERIAL_CONSOLE
+# undef CONFIG_USART2_SERIAL_CONSOLE
+# undef CONFIG_USART3_SERIAL_CONSOLE
+# undef CONFIG_UART4_SERIAL_CONSOLE
+# undef CONFIG_USART6_SERIAL_CONSOLE
+# define CONSOLE_UART 5
+# define HAVE_CONSOLE 1
+#elif defined(CONFIG_USART6_SERIAL_CONSOLE) && defined(CONFIG_STM32_USART6)
+# undef CONFIG_USART1_SERIAL_CONSOLE
+# undef CONFIG_USART2_SERIAL_CONSOLE
+# undef CONFIG_USART3_SERIAL_CONSOLE
+# undef CONFIG_UART4_SERIAL_CONSOLE
+# undef CONFIG_UART5_SERIAL_CONSOLE
+# define CONSOLE_UART 6
+# define HAVE_CONSOLE 1
+#else
+# undef CONFIG_USART1_SERIAL_CONSOLE
+# undef CONFIG_USART2_SERIAL_CONSOLE
+# undef CONFIG_USART3_SERIAL_CONSOLE
+# undef CONFIG_UART4_SERIAL_CONSOLE
+# undef CONFIG_UART5_SERIAL_CONSOLE
+# undef CONFIG_USART6_SERIAL_CONSOLE
+# define CONSOLE_UART 0
+# undef HAVE_CONSOLE
+#endif
+
+/* DMA support is only provided if CONFIG_ARCH_DMA is in the NuttX configuration.
+ * Furthermore, DMA support is currently only implemented for the F4 (but could be
+ * extended to the F1 and F2 with a little effort in the DMA code.
+ */
+
+#if !defined(HAVE_UART) || !defined(CONFIG_ARCH_DMA) || !defined(CONFIG_STM32_STM32F40XX)
+# undef CONFIG_USART1_RXDMA
+# undef CONFIG_USART2_RXDMA
+# undef CONFIG_USART3_RXDMA
+# undef CONFIG_USART4_RXDMA
+# undef CONFIG_USART5_RXDMA
+# undef CONFIG_USART6_RXDMA
+#endif
+
+/* Disable the DMA configuration on all unused USARTs */
+
+#ifndef CONFIG_STM32_USART1
+# undef CONFIG_USART1_RXDMA
+#endif
+
+#ifndef CONFIG_STM32_USART2
+# undef CONFIG_USART2_RXDMA
+#endif
+
+#ifndef CONFIG_STM32_USART3
+# undef CONFIG_USART3_RXDMA
+#endif
+
+#ifndef CONFIG_STM32_USART4
+# undef CONFIG_USART4_RXDMA
+#endif
+
+#ifndef CONFIG_STM32_USART5
+# undef CONFIG_USART5_RXDMA
+#endif
+
+#ifndef CONFIG_STM32_USART6
+# undef CONFIG_USART6_RXDMA
+#endif
+
+/* Is DMA available on any (enabled) USART? */
+
+#undef SERIAL_HAVE_DMA
+#if defined(CONFIG_USART1_RXDMA) || defined(CONFIG_USART2_RXDMA) || \
+ defined(CONFIG_USART3_RXDMA) || defined(CONFIG_USART4_RXDMA) || \
+ defined(CONFIG_USART5_RXDMA) || defined(CONFIG_USART6_RXDMA)
+# define SERIAL_HAVE_DMA 1
+#endif
+
+/* Is DMA used on all (enabled) USARTs */
+
+#define SERIAL_HAVE_ONLY_DMA 1
+#if defined(CONFIG_STM32_USART1) && !defined(CONFIG_USART1_RXDMA)
+# undef SERIAL_HAVE_ONLY_DMA
+#elif defined(CONFIG_STM32_USART2) && !defined(CONFIG_USART2_RXDMA)
+# undef SERIAL_HAVE_ONLY_DMA
+#elif defined(CONFIG_STM32_USART3) && !defined(CONFIG_USART3_RXDMA)
+# undef SERIAL_HAVE_ONLY_DMA
+#elif defined(CONFIG_STM32_UART4) && !defined(CONFIG_USART4_RXDMA)
+# undef SERIAL_HAVE_ONLY_DMA
+#elif defined(CONFIG_STM32_UART5) && !defined(CONFIG_USART5_RXDMA)
+# undef SERIAL_HAVE_ONLY_DMA
+#elif defined(CONFIG_STM32_USART6) && !defined(CONFIG_USART6_RXDMA)
+# undef SERIAL_HAVE_ONLY_DMA
+#endif
/************************************************************************************
* Public Types
@@ -57,8 +214,41 @@
* Public Data
************************************************************************************/
+#ifndef __ASSEMBLY__
+
+#undef EXTERN
+#if defined(__cplusplus)
+#define EXTERN extern "C"
+extern "C" {
+#else
+#define EXTERN extern
+#endif
+
/************************************************************************************
* Public Functions
************************************************************************************/
+/****************************************************************************
+ * Name: stm32_serial_dma_poll
+ *
+ * Description:
+ * Must be called periodically if any STM32 UART is configured for DMA.
+ * The DMA callback is triggered for each fifo size/2 bytes, but this can
+ * result in some bytes being transferred but not collected if the incoming
+ * data is not a whole multiple of half the FIFO size.
+ *
+ * May be safely called from either interrupt or thread context.
+ *
+ ****************************************************************************/
+
+#ifdef SERIAL_HAVE_DMA
+EXTERN void stm32_serial_dma_poll(void);
+#endif
+
+#undef EXTERN
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* __ASSEMBLY__ */
#endif /* __ARCH_ARM_STC_STM32_STM32_UART_H */
diff --git a/nuttx/arch/arm/src/stm32/stm32f40xxx_dma.c b/nuttx/arch/arm/src/stm32/stm32f40xxx_dma.c
index db09cfd2e..55a48a5f5 100644
--- a/nuttx/arch/arm/src/stm32/stm32f40xxx_dma.c
+++ b/nuttx/arch/arm/src/stm32/stm32f40xxx_dma.c
@@ -94,6 +94,7 @@ struct stm32_dma_s
uint8_t irq; /* DMA stream IRQ number */
uint8_t shift; /* ISR/IFCR bit shift value */
uint8_t channel; /* DMA channel number (0-7) */
+ bool nonstop; /* Stream is configured in a non-stopping mode. */
sem_t sem; /* Used to wait for DMA channel to become available */
uint32_t base; /* DMA register channel base address */
dma_callback_t callback; /* Callback invoked when the DMA completes */
@@ -429,9 +430,20 @@ static int stm32_dmainterrupt(int irq, void *context)
status = (dmabase_getreg(dmast, regoffset) >> dmast->shift) & DMA_STREAM_MASK;
- /* Disable the DMA stream */
+ /* Clear fetched stream interrupts by setting bits in the upper or lower IFCR
+ * register
+ */
- stm32_dmastreamdisable(dmast);
+ if (stream < 4)
+ {
+ regoffset = STM32_DMA_LIFCR_OFFSET;
+ }
+ else
+ {
+ regoffset = STM32_DMA_HIFCR_OFFSET;
+ }
+
+ dmabase_putreg(dmast, regoffset, (status << dmast->shift));
/* Invoke the callback */
@@ -636,11 +648,15 @@ void stm32_dmasetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr,
/* "Set the memory address in the DMA_SM0ARx ... register. The data will be
* written to or read from this memory after the peripheral event."
*
- * Note that only single-buffer mode is currently supported so SM1ARx
- * is not used."
+ * Note that in double-buffered mode it is explicitly assumed that the second
+ * buffer immediately follows the first.
*/
dmast_putreg(dmast, STM32_DMA_SM0AR_OFFSET, maddr);
+ if (scr & DMA_SCR_DBM)
+ {
+ dmast_putreg(dmast, STM32_DMA_SM1AR_OFFSET, maddr + ntransfers);
+ }
/* "Configure the total number of data items to be transferred in the
* DMA_SNDTRx register. After each peripheral event, this value will be
@@ -677,28 +693,42 @@ void stm32_dmasetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr,
* generated when the stream is enabled, then the stream will be automatically
* disabled."
*
+ * The FIFO is disabled in circular mode when transferring data from a
+ * peripheral to memory, as in this case it is usually desirable to know that
+ * every byte from the peripheral is transferred immediately to memory. It is
+ * not practical to flush the DMA FIFO, as this requires disabling the channel
+ * which triggers the transfer-complete interrupt.
+ *
* NOTE: The FEIFx error interrupt is not enabled because the FEIFx seems to
* be reported spuriously causing good transfers to be marked as failures.
*/
regval = dmast_getreg(dmast, STM32_DMA_SFCR_OFFSET);
regval &= ~(DMA_SFCR_FTH_MASK | DMA_SFCR_FS_MASK | DMA_SFCR_FEIE);
- regval |= (DMA_SFCR_FTH_FULL | DMA_SFCR_DMDIS);
+ if (!((scr & (DMA_SCR_CIRC | DMA_SCR_DIR_MASK)) == (DMA_SCR_CIRC | DMA_SCR_DIR_P2M)))
+ {
+ regval |= (DMA_SFCR_FTH_FULL | DMA_SFCR_DMDIS);
+ }
dmast_putreg(dmast, STM32_DMA_SFCR_OFFSET, regval);
/* "Configure data transfer direction, circular mode, peripheral & memory
* incremented mode, peripheral & memory data size, and interrupt after
* half and/or full transfer in the DMA_CCRx register."
+ *
+ * Note: The CT bit is always reset.
*/
regval = dmast_getreg(dmast, STM32_DMA_SCR_OFFSET);
regval &= ~(DMA_SCR_PFCTRL|DMA_SCR_DIR_MASK|DMA_SCR_PINC|DMA_SCR_MINC|
DMA_SCR_PSIZE_MASK|DMA_SCR_MSIZE_MASK|DMA_SCR_PINCOS|
+ DMA_SCR_CIRC|DMA_SCR_DBM|DMA_SCR_CT|
DMA_SCR_PBURST_MASK|DMA_SCR_MBURST_MASK);
scr &= (DMA_SCR_PFCTRL|DMA_SCR_DIR_MASK|DMA_SCR_PINC|DMA_SCR_MINC|
DMA_SCR_PSIZE_MASK|DMA_SCR_MSIZE_MASK|DMA_SCR_PINCOS|
+ DMA_SCR_DBM|DMA_SCR_CIRC|
DMA_SCR_PBURST_MASK|DMA_SCR_MBURST_MASK);
regval |= scr;
+ dmast->nonstop = (scr & (DMA_SCR_DBM|DMA_SCR_CIRC)) != 0;
dmast_putreg(dmast, STM32_DMA_SCR_OFFSET, regval);
}
@@ -734,14 +764,28 @@ void stm32_dmastart(DMA_HANDLE handle, dma_callback_t callback, void *arg, bool
scr = dmast_getreg(dmast, STM32_DMA_SCR_OFFSET);
scr |= DMA_SCR_EN;
- /* 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.
- */
+ if (!dmast->nonstop)
+ {
+ /* 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.
+ */
+
+ scr |= (half ? (DMA_SCR_HTIE|DMA_SCR_TEIE) : (DMA_SCR_TCIE|DMA_SCR_TEIE));
+ }
+ else
+ {
+ /* In nonstop mode, 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.
+ */
+ scr |= (half ? DMA_SCR_HTIE : 0) | DMA_SCR_TCIE | DMA_SCR_TEIE;
+ }
- scr |= (half ? (DMA_SCR_HTIE|DMA_SCR_TEIE) : (DMA_SCR_TCIE|DMA_SCR_TEIE));
dmast_putreg(dmast, STM32_DMA_SCR_OFFSET, scr);
}
@@ -765,6 +809,38 @@ void stm32_dmastop(DMA_HANDLE handle)
}
/****************************************************************************
+ * Name: stm32_dmaresidual
+ *
+ * Description:
+ * Read the DMA bytes-remaining register.
+ *
+ * Assumptions:
+ * - DMA handle allocated by stm32_dmachannel()
+ *
+ ****************************************************************************/
+
+size_t stm32_dmaresidual(DMA_HANDLE handle)
+{
+ struct stm32_dma_s *dmast = (struct stm32_dma_s *)handle;
+ uint32_t residual;
+
+ /* Fetch the count of bytes remaining to be transferred.
+ *
+ * If the FIFO is enabled, this count may be inaccurate. ST don't
+ * appear to document whether this counts the peripheral or the memory
+ * side of the channel, and they don't make the memory pointer
+ * available either.
+ *
+ * For reception in circular mode the FIFO is disabled in order that
+ * this value can be useful.
+ */
+
+ residual = dmast_getreg(dmast, STM32_DMA_SNDTR_OFFSET);
+
+ return (size_t)residual;
+}
+
+/****************************************************************************
* Name: stm32_dmasample
*
* Description: