diff options
author | patacongo <patacongo@7fd9a85b-ad96-42d3-883c-3090e2eb8679> | 2012-04-22 19:50:33 +0000 |
---|---|---|
committer | patacongo <patacongo@7fd9a85b-ad96-42d3-883c-3090e2eb8679> | 2012-04-22 19:50:33 +0000 |
commit | ec81f66d5c33285c3d25cca6fcfcb6183ae551ca (patch) | |
tree | e015520caeb1c1d4f8e4211ceae807a778ca7826 /nuttx/arch/arm/src | |
parent | cfbb78e2668603e63dfabdd127b8bf01b6744059 (diff) | |
download | px4-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.h | 2 | ||||
-rw-r--r-- | nuttx/arch/arm/src/stm32/stm32_dma.c | 2 | ||||
-rw-r--r-- | nuttx/arch/arm/src/stm32/stm32_dma.h | 13 | ||||
-rw-r--r-- | nuttx/arch/arm/src/stm32/stm32_lowputc.c | 83 | ||||
-rw-r--r-- | nuttx/arch/arm/src/stm32/stm32_serial.c | 500 | ||||
-rw-r--r-- | nuttx/arch/arm/src/stm32/stm32_spi.c | 6 | ||||
-rw-r--r-- | nuttx/arch/arm/src/stm32/stm32_uart.h | 192 | ||||
-rw-r--r-- | nuttx/arch/arm/src/stm32/stm32f40xxx_dma.c | 100 |
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: |