From baeaf54c6c3aa9371696a2012769403a9b169b50 Mon Sep 17 00:00:00 2001 From: David Sidrane Date: Tue, 3 Dec 2019 07:21:58 -0600 Subject: [PATCH] arch/arm/src/stm32f7/stm32_serial.c: Add Tx U[S]ART DMA. --- arch/arm/src/stm32f7/Kconfig | 60 ++- arch/arm/src/stm32f7/stm32_serial.c | 717 ++++++++++++++++++++++------ arch/arm/src/stm32f7/stm32_uart.h | 120 ++++- 3 files changed, 728 insertions(+), 169 deletions(-) diff --git a/arch/arm/src/stm32f7/Kconfig b/arch/arm/src/stm32f7/Kconfig index f4bebad6e7..9c57e57b63 100644 --- a/arch/arm/src/stm32f7/Kconfig +++ b/arch/arm/src/stm32f7/Kconfig @@ -1785,6 +1785,13 @@ config USART1_RXDMA ---help--- In high data rate usage, Rx DMA may eliminate Rx overrun errors +config USART1_TXDMA + bool "USART1 Tx DMA" + default n + depends on STM32F7_USART1 && STM32F7_DMA2 + ---help--- + In high data rate usage, Rx DMA may reduce CPU Load + config USART2_RS485 bool "RS-485 on USART2" default n @@ -1810,6 +1817,13 @@ config USART2_RXDMA ---help--- In high data rate usage, Rx DMA may eliminate Rx overrun errors +config USART2_TXDMA + bool "USART2 Tx DMA" + default n + depends on STM32F7_USART2 && STM32F7_DMA1 + ---help--- + In high data rate usage, Rx DMA may reduce CPU Load + config USART3_RS485 bool "RS-485 on USART3" default n @@ -1835,6 +1849,13 @@ config USART3_RXDMA ---help--- In high data rate usage, Rx DMA may eliminate Rx overrun errors +config USART3_TXDMA + bool "USART3 Tx DMA" + default n + depends on STM32F7_USART3 && STM32F7_DMA1 + ---help--- + In high data rate usage, Rx DMA may reduce CPU Load + config UART4_RS485 bool "RS-485 on UART4" default n @@ -1860,6 +1881,13 @@ config UART4_RXDMA ---help--- In high data rate usage, Rx DMA may eliminate Rx overrun errors +config UART4_TXDMA + bool "UART4 Tx DMA" + default n + depends on STM32F7_UART4 && STM32F7_DMA1 + ---help--- + In high data rate usage, Rx DMA may reduce CPU Load + config UART5_RS485 bool "RS-485 on UART5" default n @@ -1885,6 +1913,13 @@ config UART5_RXDMA ---help--- In high data rate usage, Rx DMA may eliminate Rx overrun errors +config UART5_TXDMA + bool "UART5 Tx DMA" + default n + depends on STM32F7_UART5 && STM32F7_DMA1 + ---help--- + In high data rate usage, Rx DMA may reduce CPU Load + config USART6_RS485 bool "RS-485 on USART6" default n @@ -1910,6 +1945,13 @@ config USART6_RXDMA ---help--- In high data rate usage, Rx DMA may eliminate Rx overrun errors +config USART6_TXDMA + bool "USART6 Tx DMA" + default n + depends on STM32F7_USART6 && STM32F7_DMA2 + ---help--- + In high data rate usage, Rx DMA may reduce CPU Load + config UART7_RS485 bool "RS-485 on UART7" default n @@ -1931,10 +1973,17 @@ config UART7_RS485_DIR_POLARITY config UART7_RXDMA bool "UART7 Rx DMA" default n - depends on STM32F7_UART7 && STM32F7_DMA2 + depends on STM32F7_UART7 && STM32F7_DMA1 ---help--- In high data rate usage, Rx DMA may eliminate Rx overrun errors +config UART7_TXDMA + bool "UART7 Tx DMA" + default n + depends on STM32F7_UART7 && STM32F7_DMA1 + ---help--- + In high data rate usage, Rx DMA may reduce CPU Load + config UART8_RS485 bool "RS-485 on UART8" default n @@ -1956,10 +2005,17 @@ config UART8_RS485_DIR_POLARITY config UART8_RXDMA bool "UART8 Rx DMA" default n - depends on STM32F7_UART8 && STM32F7_DMA2 + depends on STM32F7_UART8 && STM32F7_DMA1 ---help--- In high data rate usage, Rx DMA may eliminate Rx overrun errors +config UART8_TXDMA + bool "UART8 Tx DMA" + default n + depends on STM32F7_UART8 && STM32F7_DMA1 + ---help--- + In high data rate usage, Rx DMA may reduce CPU Load + config STM32F7_SERIAL_RXDMA_BUFFER_SIZE int "Rx DMA buffer size" default 32 diff --git a/arch/arm/src/stm32f7/stm32_serial.c b/arch/arm/src/stm32f7/stm32_serial.c index f161f868c7..de70b4c3c5 100644 --- a/arch/arm/src/stm32f7/stm32_serial.c +++ b/arch/arm/src/stm32f7/stm32_serial.c @@ -87,7 +87,7 @@ * have also been selected. */ -#ifdef SERIAL_HAVE_DMA +#ifdef SERIAL_HAVE_RXDMA /* Verify that DMA has been enabled and the DMA channel has been defined. */ @@ -121,7 +121,7 @@ # error "RXDMA and RS-485 cannot be enabled at the same time for the same U[S]ART" # endif -/* There may be alternate DMA channels for each U[S]ART. Logic in the +/* There may be alternate DMA channels for USART 1 & 6. Logic in the * board.h file should provide definitions to select among the alternatives. */ @@ -129,34 +129,10 @@ # 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_UART4_RXDMA) && !defined(DMAMAP_UART4_RX) -# error "UART4 DMA channel not defined (DMAMAP_UART4_RX)" -# endif - -# if defined(CONFIG_UART5_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 defined(CONFIG_UART7_RXDMA) && !defined(DMAMAP_UART7_RX) -# error "UART7 DMA channel not defined (DMAMAP_UART7_RX)" -# endif - -# if defined(CONFIG_UART8_RXDMA) && !defined(DMAMAP_UART8_RX) -# error "UART8 DMA channel not defined (DMAMAP_UART8_RX)" -# endif - /* The DMA buffer size when using RX DMA to emulate a FIFO. * * When streaming data, the generic serial layer will be called every time @@ -196,7 +172,7 @@ /* DMA control words */ -# define SERIAL_DMA_CONTROL_WORD \ +# define SERIAL_RXDMA_CONTROL_WORD \ (DMA_SCR_DIR_P2M | \ DMA_SCR_CIRC | \ DMA_SCR_MINC | \ @@ -205,16 +181,167 @@ CONFIG_USART_RXDMAPRIO | \ DMA_SCR_PBURST_SINGLE | \ DMA_SCR_MBURST_SINGLE) +#endif /* SERIAL_HAVE_RXDMA */ -# define SERIAL_DMA_CONTROL_WORD_TX \ +/* Verify that DMA has been enabled and the DMA channel has been defined. + */ + +#if defined(CONFIG_USART1_TXDMA) || defined(CONFIG_USART6_TXDMA) +# ifndef CONFIG_STM32F7_DMA2 +# error STM32 USART1/6 transmit DMA requires CONFIG_STM32F7_DMA2 +# endif +#endif + +#if defined(CONFIG_USART2_TXDMA) || defined(CONFIG_USART3_TXDMA) || \ + defined(CONFIG_UART4_TXDMA) || defined(CONFIG_UART5_TXDMA) || \ + defined(CONFIG_UART7_TXDMA) || defined(CONFIG_UART8_TXDMA) +# ifndef CONFIG_STM32F7_DMA1 +# error STM32 USART2/3/4/5/7/8 transmit DMA requires CONFIG_STM32F7_DMA1 +# endif +#endif + +/* Currently RS-485 support cannot be enabled when TXDMA is in use due to lack + * of testing - RS-485 support was developed on STM32F1x + */ + +#if (defined(CONFIG_USART1_TXDMA) && defined(CONFIG_USART1_RS485)) || \ + (defined(CONFIG_USART2_TXDMA) && defined(CONFIG_USART2_RS485)) || \ + (defined(CONFIG_USART3_TXDMA) && defined(CONFIG_USART3_RS485)) || \ + (defined(CONFIG_UART4_TXDMA) && defined(CONFIG_UART4_RS485)) || \ + (defined(CONFIG_UART5_TXDMA) && defined(CONFIG_UART5_RS485)) || \ + (defined(CONFIG_USART6_TXDMA) && defined(CONFIG_USART6_RS485)) || \ + (defined(CONFIG_UART7_TXDMA) && defined(CONFIG_UART7_RS485)) || \ + (defined(CONFIG_UART8_TXDMA) && defined(CONFIG_UART8_RS485)) +# error "TXDMA and RS-485 cannot be enabled at the same time for the same U[S]ART" +#endif + +/* There may be alternate DMA channels for USART 1 & 6. Logic in the + * board.h file should provide definitions to select among the alternatives. + */ + +# if defined(CONFIG_USART1_TXDMA) && !defined(DMAMAP_USART1_TX) +# error "USART1 DMA channel not defined (DMAMAP_USART1_TX)" +# endif + +# if defined(CONFIG_USART6_TXDMA) && !defined(DMAMAP_USART6_TX) +# error "USART6 DMA channel not defined (DMAMAP_USART6_TX)" +# endif + +/* The DMA buffer size when using TX DMA. + * + * This TX buffer size should be an even multiple of the Cortex-M7 D-Cache line + * size, ARMV7M_DCACHE_LINESIZE, so that it can be individually invalidated. + * + * Should there be a Cortex-M7 without a D-Cache, ARMV7M_DCACHE_LINESIZE + * would be zero! + */ + +#if !defined(ARMV7M_DCACHE_LINESIZE) || ARMV7M_DCACHE_LINESIZE == 0 +# undef ARMV7M_DCACHE_LINESIZE +# define ARMV7M_DCACHE_LINESIZE 32 +#endif + +#define TXDMA_BUFFER_MASK (ARMV7M_DCACHE_LINESIZE - 1) +#define TXDMA_BUFFER_SIZE ((CONFIG_STM32F7_SERIAL_RXDMA_BUFFER_SIZE \ + + RXDMA_BUFFER_MASK) & ~RXDMA_BUFFER_MASK) + +/* If built with CONFIG_ARMV7M_DCACHE Buffers need to be aligned and multiples + * of ARMV7M_DCACHE_LINESIZE + */ + +#if defined(CONFIG_ARMV7M_DCACHE) +# define TXDMA_BUF_SIZE(b) (((b) + TXDMA_BUFFER_MASK) & ~TXDMA_BUFFER_MASK) +# define TXDMA_BUF_ALIGN aligned_data(ARMV7M_DCACHE_LINESIZE); +#else +# define TXDMA_BUF_SIZE(b) (b) +# define TXDMA_BUF_ALIGN +#endif + +#if !defined(CONFIG_USART1_TXDMA) +# define USART1_TXBUFSIZE_ADJUSTED CONFIG_USART1_TXBUFSIZE +# define USART1_TXBUFSIZE_ALGN +#else +# define USART1_TXBUFSIZE_ADJUSTED TXDMA_BUF_SIZE(CONFIG_USART1_TXBUFSIZE) +# define USART1_TXBUFSIZE_ALGN TXDMA_BUF_ALIGN +#endif + +#if !defined(CONFIG_USART2_TXDMA) +# define USART2_TXBUFSIZE_ADJUSTED CONFIG_USART2_TXBUFSIZE +# define USART2_TXBUFSIZE_ALGN +#else +# define USART2_TXBUFSIZE_ADJUSTED TXDMA_BUF_SIZE(CONFIG_USART2_TXBUFSIZE) +# define USART2_TXBUFSIZE_ALGN TXDMA_BUF_ALIGN +#endif + +#if !defined(CONFIG_USART3_TXDMA) +# define USART3_TXBUFSIZE_ADJUSTED CONFIG_USART3_TXBUFSIZE +# define USART3_TXBUFSIZE_ALGN +#else +# define USART3_TXBUFSIZE_ADJUSTED TXDMA_BUF_SIZE(CONFIG_USART3_TXBUFSIZE) +# define USART3_TXBUFSIZE_ALGN TXDMA_BUF_ALIGN +#endif + +#if !defined(CONFIG_UART4_TXDMA) +# define UART4_TXBUFSIZE_ADJUSTED CONFIG_UART4_TXBUFSIZE +# define UART4_TXBUFSIZE_ALGN +#else +# define UART4_TXBUFSIZE_ADJUSTED TXDMA_BUF_SIZE(CONFIG_UART4_TXBUFSIZE) +# define UART4_TXBUFSIZE_ALGN TXDMA_BUF_ALIGN +#endif + +#if !defined(CONFIG_UART5_TXDMA) +# define UART5_TXBUFSIZE_ADJUSTED CONFIG_UART5_TXBUFSIZE +# define UART5_TXBUFSIZE_ALGN +#else +# define UART5_TXBUFSIZE_ADJUSTED TXDMA_BUF_SIZE(CONFIG_UART5_TXBUFSIZE) +# define UART5_TXBUFSIZE_ALGN TXDMA_BUF_ALIGN +#endif + +#if !defined(CONFIG_USART6_TXDMA) +# define USART6_TXBUFSIZE_ADJUSTED CONFIG_USART6_TXBUFSIZE +# define USART6_TXBUFSIZE_ALGN +#else +# define USART6_TXBUFSIZE_ADJUSTED TXDMA_BUF_SIZE(CONFIG_USART6_TXBUFSIZE) +# define USART6_TXBUFSIZE_ALGN TXDMA_BUF_ALIGN +#endif + +#if !defined(CONFIG_UART7_TXDMA) +# define UART7_TXBUFSIZE_ADJUSTED CONFIG_UART7_TXBUFSIZE +# define UART7_TXBUFSIZE_ALGN +#else +# define UART7_TXBUFSIZE_ADJUSTED TXDMA_BUF_SIZE(CONFIG_UART7_TXBUFSIZE) +# define UART7_TXBUFSIZE_ALGN TXDMA_BUF_ALIGN +#endif + +#if !defined(CONFIG_UART8_TXDMA) +# define UART8_TXBUFSIZE_ADJUSTED CONFIG_UART8_TXBUFSIZE +# define UART8_TXBUFSIZE_ALGN +#else +# define UART8_TXBUFSIZE_ADJUSTED TXDMA_BUF_SIZE(CONFIG_UART8_TXBUFSIZE) +# define UART8_TXBUFSIZE_ALGN TXDMA_BUF_ALIGN +#endif + +#if SERIAL_HAVE_TXDMA +/* DMA priority */ + +# ifndef CONFIG_USART_TXDMAPRIO +# define CONFIG_USART_TXDMAPRIO DMA_SCR_PRIMED +# endif + +# if (CONFIG_USART_TXDMAPRIO & ~DMA_SCR_PL_MASK) != 0 +# error "Illegal value for CONFIG_USART_TXDMAPRIO" +# endif + +# define SERIAL_TXDMA_CONTROL_WORD \ (DMA_SCR_DIR_M2P | \ DMA_SCR_MINC | \ DMA_SCR_PSIZE_8BITS | \ DMA_SCR_MSIZE_8BITS | \ DMA_SCR_PBURST_SINGLE | \ DMA_SCR_MBURST_SINGLE | \ - CONFIG_USART_RXDMAPRIO) -#endif /* SERIAL_HAVE_RXDMA */ + CONFIG_USART_TXDMAPRIO) + +#endif /* SERIAL_HAVE_TXDMA */ /* Power management definitions */ @@ -225,6 +352,14 @@ # define PM_IDLE_DOMAIN 0 /* Revisit */ #endif +/* Since RX DMA or TX DMA or both may be enabled for a given U[S]ART. + * We need runtime detection in up_dma_setup and up_dma_shutdown + * We use the default struct default init value of 0 which maps to + * STM32_DMA_MAP(DMA1,DMA_STREAM0,DMA_CHAN0) which is not a U[S]ART. + */ + +#define INVALID_SERIAL_DMA_CHANNEL 0 + /* Keep track if a Break was set * * Note: @@ -359,13 +494,17 @@ struct up_dev_s const uint32_t cts_gpio; /* U[S]ART CTS GPIO pin configuration */ #endif -#ifdef SERIAL_HAVE_DMA - const unsigned int rxdma_channel; /* DMA channel assigned */ + /* TX DMA state */ + +#ifdef SERIAL_HAVE_TXDMA + const unsigned int txdma_channel; /* DMA channel assigned */ + DMA_HANDLE txdma; /* currently-open trasnmit DMA stream */ #endif /* RX DMA state */ -#ifdef SERIAL_HAVE_DMA +#ifdef SERIAL_HAVE_RXDMA + const unsigned int rxdma_channel; /* DMA channel assigned */ DMA_HANDLE rxdma; /* currently-open receive DMA stream */ bool rxenable; /* DMA-based reception en/disable */ #ifdef CONFIG_PM @@ -387,6 +526,14 @@ struct up_dev_s #endif }; +#ifdef CONFIG_PM +struct pm_config_s +{ + struct pm_callback_s pm_cb; + bool serial_suspended; +}; +#endif + /**************************************************************************** * Private Function Prototypes ****************************************************************************/ @@ -400,7 +547,7 @@ static int up_attach(struct uart_dev_s *dev); static void up_detach(struct uart_dev_s *dev); static int up_interrupt(int irq, void *context, FAR void *arg); static int up_ioctl(struct file *filep, int cmd, unsigned long arg); -#ifndef SERIAL_HAVE_ONLY_DMA +#if !defined(SERIAL_HAVE_ONLY_DMA) static int up_receive(struct uart_dev_s *dev, unsigned int *status); static void up_rxint(struct uart_dev_s *dev, bool enable); static bool up_rxavailable(struct uart_dev_s *dev); @@ -413,9 +560,19 @@ 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 +#ifdef SERIAL_HAVE_TXDMA +static void up_dma_send(struct uart_dev_s *dev); +static void up_dma_txint(struct uart_dev_s *dev, bool enable); +static void up_dma_txavailable(struct uart_dev_s *dev); +static void up_dma_txcallback(DMA_HANDLE handle, uint8_t status, void *arg); +#endif + +#if defined(SERIAL_HAVE_RXDMA) || defined(SERIAL_HAVE_TXDMA) static int up_dma_setup(struct uart_dev_s *dev); static void up_dma_shutdown(struct uart_dev_s *dev); +#endif + +#ifdef SERIAL_HAVE_RXDMA static int up_dma_receive(struct uart_dev_s *dev, unsigned int *status); #ifdef CONFIG_PM static void up_dma_reenable(struct up_dev_s *priv); @@ -439,7 +596,7 @@ static int up_pm_prepare(struct pm_callback_s *cb, int domain, * Private Data ****************************************************************************/ -#ifndef SERIAL_HAVE_ONLY_DMA +#if !defined(SERIAL_HAVE_ONLY_DMA) static const struct uart_ops_s g_uart_ops = { .setup = up_setup, @@ -460,8 +617,30 @@ static const struct uart_ops_s g_uart_ops = }; #endif -#ifdef SERIAL_HAVE_DMA -static const struct uart_ops_s g_uart_dma_ops = +#if defined(SERIAL_HAVE_RXDMA) && defined(SERIAL_HAVE_TXDMA) +static const struct uart_ops_s g_uart_rxtxdma_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, +#ifdef CONFIG_SERIAL_IFLOWCONTROL + .rxflowcontrol = up_rxflowcontrol, +#endif + .send = up_send, + .txint = up_dma_txint, + .txready = up_txready, + .txempty = up_txready, + .dmatxavail = up_dma_txavailable, + .dmasend = up_dma_send, +}; +#endif +#if !defined(SERIAL_HAVE_ONLY_DMA) && defined(SERIAL_HAVE_RXDMA) +static const struct uart_ops_s g_uart_rxdma_ops = { .setup = up_dma_setup, .shutdown = up_dma_shutdown, @@ -481,7 +660,30 @@ static const struct uart_ops_s g_uart_dma_ops = }; #endif -/* DMA buffers. DMA buffers must: +#if !defined(SERIAL_HAVE_ONLY_DMA) && defined(SERIAL_HAVE_TXDMA) +static const struct uart_ops_s g_uart_txdma_ops = +{ + .setup = up_dma_setup, + .shutdown = up_dma_shutdown, + .attach = up_attach, + .detach = up_detach, + .ioctl = up_ioctl, + .receive = up_receive, + .rxint = up_rxint, + .rxavailable = up_rxavailable, + #ifdef CONFIG_SERIAL_IFLOWCONTROL + .rxflowcontrol = up_rxflowcontrol, + #endif + .send = up_send, + .txint = up_dma_txint, + .txready = up_txready, + .txempty = up_txready, + .dmatxavail = up_dma_txavailable, + .dmasend = up_dma_send, +}; +#endif + +/* DMA buffers. RX DMA buffers must: * * 1. Be a multiple of the D-Cache line size. This requirement is assured * by the definition of RXDMA buffer size above. @@ -494,84 +696,92 @@ static const struct uart_ops_s g_uart_dma_ops = #ifdef CONFIG_USART1_RXDMA static char g_usart1rxfifo[RXDMA_BUFFER_SIZE] - __attribute__((aligned(ARMV7M_DCACHE_LINESIZE))); + aligned_data(ARMV7M_DCACHE_LINESIZE); #endif # ifdef CONFIG_USART2_RXDMA static char g_usart2rxfifo[RXDMA_BUFFER_SIZE] - __attribute__((aligned(ARMV7M_DCACHE_LINESIZE))); + aligned_data(ARMV7M_DCACHE_LINESIZE); #endif #ifdef CONFIG_USART3_RXDMA static char g_usart3rxfifo[RXDMA_BUFFER_SIZE] - __attribute__((aligned(ARMV7M_DCACHE_LINESIZE))); + aligned_data(ARMV7M_DCACHE_LINESIZE); #endif #ifdef CONFIG_UART4_RXDMA static char g_uart4rxfifo[RXDMA_BUFFER_SIZE] - __attribute__((aligned(ARMV7M_DCACHE_LINESIZE))); + aligned_data(ARMV7M_DCACHE_LINESIZE); #endif #ifdef CONFIG_UART5_RXDMA static char g_uart5rxfifo[RXDMA_BUFFER_SIZE] - __attribute__((aligned(ARMV7M_DCACHE_LINESIZE))); + aligned_data(ARMV7M_DCACHE_LINESIZE); #endif #ifdef CONFIG_USART6_RXDMA static char g_usart6rxfifo[RXDMA_BUFFER_SIZE] - __attribute__((aligned(ARMV7M_DCACHE_LINESIZE))); + aligned_data(ARMV7M_DCACHE_LINESIZE); #endif #ifdef CONFIG_UART7_RXDMA static char g_uart7rxfifo[RXDMA_BUFFER_SIZE] - __attribute__((aligned(ARMV7M_DCACHE_LINESIZE))); + aligned_data(ARMV7M_DCACHE_LINESIZE); #endif #ifdef CONFIG_UART8_RXDMA static char g_uart8rxfifo[RXDMA_BUFFER_SIZE] - __attribute__((aligned(ARMV7M_DCACHE_LINESIZE))); + aligned_data(ARMV7M_DCACHE_LINESIZE); #endif /* Receive/Transmit buffers */ #ifdef CONFIG_STM32F7_USART1 static char g_usart1rxbuffer[CONFIG_USART1_RXBUFSIZE]; -static char g_usart1txbuffer[CONFIG_USART1_TXBUFSIZE]; +static char g_usart1txbuffer[USART1_TXBUFSIZE_ADJUSTED] \ + USART1_TXBUFSIZE_ALGN; #endif #ifdef CONFIG_STM32F7_USART2 static char g_usart2rxbuffer[CONFIG_USART2_RXBUFSIZE]; -static char g_usart2txbuffer[CONFIG_USART2_TXBUFSIZE]; +static char g_usart2txbuffer[USART2_TXBUFSIZE_ADJUSTED] \ + USART2_TXBUFSIZE_ALGN; #endif #ifdef CONFIG_STM32F7_USART3 static char g_usart3rxbuffer[CONFIG_USART3_RXBUFSIZE]; -static char g_usart3txbuffer[CONFIG_USART3_TXBUFSIZE]; +static char g_usart3txbuffer[USART3_TXBUFSIZE_ADJUSTED] \ + USART3_TXBUFSIZE_ALGN; #endif #ifdef CONFIG_STM32F7_UART4 static char g_uart4rxbuffer[CONFIG_UART4_RXBUFSIZE]; -static char g_uart4txbuffer[CONFIG_UART4_TXBUFSIZE]; +static char g_uart4txbuffer[UART4_TXBUFSIZE_ADJUSTED] \ + UART4_TXBUFSIZE_ALGN; #endif #ifdef CONFIG_STM32F7_UART5 static char g_uart5rxbuffer[CONFIG_UART5_RXBUFSIZE]; -static char g_uart5txbuffer[CONFIG_UART5_TXBUFSIZE]; +static char g_uart5txbuffer[UART5_TXBUFSIZE_ADJUSTED] \ + UART5_TXBUFSIZE_ALGN; #endif #ifdef CONFIG_STM32F7_USART6 static char g_usart6rxbuffer[CONFIG_USART6_RXBUFSIZE]; -static char g_usart6txbuffer[CONFIG_USART6_TXBUFSIZE]; +static char g_usart6txbuffer[USART6_TXBUFSIZE_ADJUSTED] \ + USART6_TXBUFSIZE_ALGN; #endif #ifdef CONFIG_STM32F7_UART7 static char g_uart7rxbuffer[CONFIG_UART7_RXBUFSIZE]; -static char g_uart7txbuffer[CONFIG_UART7_TXBUFSIZE]; +static char g_uart7txbuffer[UART7_TXBUFSIZE_ADJUSTED] \ + UART7_TXBUFSIZE_ALGN; #endif #ifdef CONFIG_STM32F7_UART8 static char g_uart8rxbuffer[CONFIG_UART8_RXBUFSIZE]; -static char g_uart8txbuffer[CONFIG_UART8_TXBUFSIZE]; +static char g_uart8txbuffer[UART8_TXBUFSIZE_ADJUSTED] \ + UART8_TXBUFSIZE_ALGN; #endif /* This describes the state of the STM32 USART1 ports. */ @@ -586,16 +796,20 @@ static struct up_dev_s g_usart1priv = #endif .recv = { - .size = CONFIG_USART1_RXBUFSIZE, + .size = sizeof(g_usart1rxbuffer), .buffer = g_usart1rxbuffer, }, .xmit = { - .size = CONFIG_USART1_TXBUFSIZE, + .size = sizeof(g_usart1txbuffer), .buffer = g_usart1txbuffer, }, -#ifdef CONFIG_USART1_RXDMA - .ops = &g_uart_dma_ops, +#if defined(CONFIG_USART1_RXDMA) && defined(CONFIG_USART1_TXDMA) + .ops = &g_uart_rxtxdma_ops, +#elif defined(CONFIG_USART1_RXDMA) && !defined(CONFIG_USART1_TXDMA) + .ops = &g_uart_rxdma_ops, +#elif !defined(CONFIG_USART1_RXDMA) && defined(CONFIG_USART1_TXDMA) + .ops = &g_uart_txdma_ops, #else .ops = &g_uart_ops, #endif @@ -619,6 +833,9 @@ static struct up_dev_s g_usart1priv = .iflow = true, .rts_gpio = GPIO_USART1_RTS, #endif +#ifdef CONFIG_USART1_TXDMA + .txdma_channel = DMAMAP_USART1_TX, +#endif #ifdef CONFIG_USART1_RXDMA .rxdma_channel = DMAMAP_USART1_RX, .rxfifo = g_usart1rxfifo, @@ -647,16 +864,20 @@ static struct up_dev_s g_usart2priv = #endif .recv = { - .size = CONFIG_USART2_RXBUFSIZE, + .size = sizeof(g_usart2rxbuffer), .buffer = g_usart2rxbuffer, }, .xmit = { - .size = CONFIG_USART2_TXBUFSIZE, + .size = sizeof(g_usart2txbuffer), .buffer = g_usart2txbuffer, }, -#ifdef CONFIG_USART2_RXDMA - .ops = &g_uart_dma_ops, +#if defined(CONFIG_USART2_RXDMA) && defined(CONFIG_USART2_TXDMA) + .ops = &g_uart_rxtxdma_ops, +#elif defined(CONFIG_USART2_RXDMA) && !defined(CONFIG_USART2_TXDMA) + .ops = &g_uart_rxdma_ops, +#elif !defined(CONFIG_USART2_RXDMA) && defined(CONFIG_USART2_TXDMA) + .ops = &g_uart_txdma_ops, #else .ops = &g_uart_ops, #endif @@ -680,6 +901,9 @@ static struct up_dev_s g_usart2priv = .iflow = true, .rts_gpio = GPIO_USART2_RTS, #endif +#ifdef CONFIG_USART2_TXDMA + .txdma_channel = DMAMAP_USART2_TX, +#endif #ifdef CONFIG_USART2_RXDMA .rxdma_channel = DMAMAP_USART2_RX, .rxfifo = g_usart2rxfifo, @@ -708,16 +932,20 @@ static struct up_dev_s g_usart3priv = #endif .recv = { - .size = CONFIG_USART3_RXBUFSIZE, + .size = sizeof(g_usart3rxbuffer), .buffer = g_usart3rxbuffer, }, .xmit = { - .size = CONFIG_USART3_TXBUFSIZE, + .size = sizeof(g_usart3txbuffer), .buffer = g_usart3txbuffer, }, -#ifdef CONFIG_USART3_RXDMA - .ops = &g_uart_dma_ops, +#if defined(CONFIG_USART3_RXDMA) && defined(CONFIG_USART3_TXDMA) + .ops = &g_uart_rxtxdma_ops, +#elif defined(CONFIG_USART3_RXDMA) && !defined(CONFIG_USART3_TXDMA) + .ops = &g_uart_rxdma_ops, +#elif !defined(CONFIG_USART3_RXDMA) && defined(CONFIG_USART3_TXDMA) + .ops = &g_uart_txdma_ops, #else .ops = &g_uart_ops, #endif @@ -741,6 +969,9 @@ static struct up_dev_s g_usart3priv = .iflow = true, .rts_gpio = GPIO_USART3_RTS, #endif +#ifdef CONFIG_USART3_TXDMA + .txdma_channel = DMAMAP_USART3_TX, +#endif #ifdef CONFIG_USART3_RXDMA .rxdma_channel = DMAMAP_USART3_RX, .rxfifo = g_usart3rxfifo, @@ -769,16 +1000,20 @@ static struct up_dev_s g_uart4priv = #endif .recv = { - .size = CONFIG_UART4_RXBUFSIZE, + .size = sizeof(g_uart4rxbuffer), .buffer = g_uart4rxbuffer, }, .xmit = { - .size = CONFIG_UART4_TXBUFSIZE, + .size = sizeof(g_uart4txbuffer), .buffer = g_uart4txbuffer, }, -#ifdef CONFIG_UART4_RXDMA - .ops = &g_uart_dma_ops, +#if defined(CONFIG_UART4_RXDMA) && defined(CONFIG_UART4_TXDMA) + .ops = &g_uart_rxtxdma_ops, +#elif defined(CONFIG_UART4_RXDMA) && !defined(CONFIG_UART4_TXDMA) + .ops = &g_uart_rxdma_ops, +#elif !defined(CONFIG_UART4_RXDMA) && defined(CONFIG_UART4_TXDMA) + .ops = &g_uart_txdma_ops, #else .ops = &g_uart_ops, #endif @@ -802,6 +1037,9 @@ static struct up_dev_s g_uart4priv = .usartbase = STM32_UART4_BASE, .tx_gpio = GPIO_UART4_TX, .rx_gpio = GPIO_UART4_RX, +#ifdef CONFIG_UART4_TXDMA + .txdma_channel = DMAMAP_UART4_TX, +#endif #ifdef CONFIG_UART4_RXDMA .rxdma_channel = DMAMAP_UART4_RX, .rxfifo = g_uart4rxfifo, @@ -838,10 +1076,14 @@ static struct up_dev_s g_uart5priv = .size = CONFIG_UART5_TXBUFSIZE, .buffer = g_uart5txbuffer, }, -#ifdef CONFIG_UART5_RXDMA - .ops = &g_uart_dma_ops, +#if defined(CONFIG_UART5_RXDMA) && defined(CONFIG_UART5_TXDMA) + .ops = &g_uart_rxtxdma_ops, +#elif defined(CONFIG_UART5_RXDMA) && !defined(CONFIG_UART5_TXDMA) + .ops = &g_uart_rxdma_ops, +#elif !defined(CONFIG_UART5_RXDMA) && defined(CONFIG_UART5_TXDMA) + .ops = &g_uart_txdma_ops, #else - .ops = &g_uart_ops, + .ops = &g_uart_ops, #endif .priv = &g_uart5priv, }, @@ -863,6 +1105,9 @@ static struct up_dev_s g_uart5priv = .usartbase = STM32_UART5_BASE, .tx_gpio = GPIO_UART5_TX, .rx_gpio = GPIO_UART5_RX, +#ifdef CONFIG_UART5_TXDMA + .txdma_channel = DMAMAP_UART5_TX, +#endif #ifdef CONFIG_UART5_RXDMA .rxdma_channel = DMAMAP_UART5_RX, .rxfifo = g_uart5rxfifo, @@ -891,18 +1136,22 @@ static struct up_dev_s g_usart6priv = #endif .recv = { - .size = CONFIG_USART6_RXBUFSIZE, + .size = sizeof(g_usart6rxbuffer), .buffer = g_usart6rxbuffer, }, .xmit = { - .size = CONFIG_USART6_TXBUFSIZE, + .size = sizeof(g_usart6txbuffer), .buffer = g_usart6txbuffer, }, -#ifdef CONFIG_USART6_RXDMA - .ops = &g_uart_dma_ops, +#if defined(CONFIG_USART6_RXDMA) && defined(CONFIG_USART6_TXDMA) + .ops = &g_uart_rxtxdma_ops, +#elif defined(CONFIG_USART6_RXDMA) && !defined(CONFIG_USART6_TXDMA) + .ops = &g_uart_rxdma_ops, +#elif !defined(CONFIG_USART6_RXDMA) && defined(CONFIG_USART6_TXDMA) + .ops = &g_uart_txdma_ops, #else - .ops = &g_uart_ops, + .ops = &g_uart_ops, #endif .priv = &g_usart6priv, }, @@ -924,6 +1173,9 @@ static struct up_dev_s g_usart6priv = .iflow = true, .rts_gpio = GPIO_USART6_RTS, #endif +#ifdef CONFIG_USART6_TXDMA + .txdma_channel = DMAMAP_USART6_TX, +#endif #ifdef CONFIG_USART6_RXDMA .rxdma_channel = DMAMAP_USART6_RX, .rxfifo = g_usart6rxfifo, @@ -952,18 +1204,22 @@ static struct up_dev_s g_uart7priv = #endif .recv = { - .size = CONFIG_UART7_RXBUFSIZE, + .size = sizeof(g_uart7rxbuffer), .buffer = g_uart7rxbuffer, }, .xmit = { - .size = CONFIG_UART7_TXBUFSIZE, + .size = sizeof(g_uart7txbuffer), .buffer = g_uart7txbuffer, }, -#ifdef CONFIG_UART7_RXDMA - .ops = &g_uart_dma_ops, +#if defined(CONFIG_UART7_RXDMA) && defined(CONFIG_UART7_TXDMA) + .ops = &g_uart_rxtxdma_ops, +#elif defined(CONFIG_UART7_RXDMA) && !defined(CONFIG_UART7_TXDMA) + .ops = &g_uart_rxdma_ops, +#elif !defined(CONFIG_UART7_RXDMA) && defined(CONFIG_UART7_TXDMA) + .ops = &g_uart_txdma_ops, #else - .ops = &g_uart_ops, + .ops = &g_uart_ops, #endif .priv = &g_uart7priv, }, @@ -985,6 +1241,9 @@ static struct up_dev_s g_uart7priv = .iflow = true, .rts_gpio = GPIO_UART7_RTS, #endif +#ifdef CONFIG_UART7_RXDMA + .txdma_channel = DMAMAP_UART7_TX, +#endif #ifdef CONFIG_UART7_RXDMA .rxdma_channel = DMAMAP_UART7_RX, .rxfifo = g_uart7rxfifo, @@ -1013,18 +1272,22 @@ static struct up_dev_s g_uart8priv = #endif .recv = { - .size = CONFIG_UART8_RXBUFSIZE, + .size = sizeof(g_uart8rxbuffer), .buffer = g_uart8rxbuffer, }, .xmit = { - .size = CONFIG_UART8_TXBUFSIZE, + .size = sizeof(g_uart8txbuffer), .buffer = g_uart8txbuffer, }, -#ifdef CONFIG_UART8_RXDMA - .ops = &g_uart_dma_ops, +#if defined(CONFIG_UART8_RXDMA) && defined(CONFIG_UART8_TXDMA) + .ops = &g_uart_rxtxdma_ops, +#elif defined(CONFIG_UART8_RXDMA) && !defined(CONFIG_UART8_TXDMA) + .ops = &g_uart_rxdma_ops, +#elif !defined(CONFIG_UART8_RXDMA) && defined(CONFIG_UART8_TXDMA) + .ops = &g_uart_txdma_ops, #else - .ops = &g_uart_ops, + .ops = &g_uart_ops, #endif .priv = &g_uart8priv, }, @@ -1046,6 +1309,9 @@ static struct up_dev_s g_uart8priv = .iflow = true, .rts_gpio = GPIO_UART8_RTS, #endif +#ifdef CONFIG_UART8_TXDMA + .txdma_channel = DMAMAP_UART8_TX, +#endif #ifdef CONFIG_UART8_RXDMA .rxdma_channel = DMAMAP_UART8_RX, .rxfifo = g_uart8rxfifo, @@ -1093,11 +1359,7 @@ static struct up_dev_s * const g_uart_devs[STM32_NSERIAL] = }; #ifdef CONFIG_PM -static struct -{ - struct pm_callback_s pm_cb; - bool serial_suspended; -} g_serialpm = +static struct pm_config_s g_serialpm = { .pm_cb.notify = up_pm_notify, .pm_cb.prepare = up_pm_prepare, @@ -1227,7 +1489,7 @@ static void up_disableusartint(struct up_dev_s *priv, uint16_t *ie) * ****************************************************************************/ -#ifdef SERIAL_HAVE_DMA +#ifdef SERIAL_HAVE_RXDMA static int up_dma_nextrx(struct up_dev_s *priv) { size_t dmaresidual; @@ -1407,7 +1669,7 @@ static void up_setsuspend(struct uart_dev_s *dev, bool suspend) { struct up_dev_s *priv = (struct up_dev_s *)dev->priv; int passes; -#ifdef SERIAL_HAVE_DMA +#ifdef SERIAL_HAVE_RXDMA bool dmarestored = false; #endif @@ -1446,7 +1708,7 @@ static void up_setsuspend(struct uart_dev_s *dev, bool suspend) } } -#ifdef SERIAL_HAVE_DMA +#ifdef SERIAL_HAVE_RXDMA if (priv->dev.ops == &g_uart_dma_ops && !priv->rxdmasusp) { /* Suspend Rx DMA. */ @@ -1458,7 +1720,7 @@ static void up_setsuspend(struct uart_dev_s *dev, bool suspend) } else { -#ifdef SERIAL_HAVE_DMA +#ifdef SERIAL_HAVE_RXDMA if (priv->dev.ops == &g_uart_dma_ops && priv->rxdmasusp) { /* Re-enable DMA. */ @@ -1484,7 +1746,7 @@ static void up_setsuspend(struct uart_dev_s *dev, bool suspend) #endif } -#ifdef SERIAL_HAVE_DMA +#ifdef SERIAL_HAVE_RXDMA if (dmarestored) { irqstate_t flags; @@ -1754,12 +2016,11 @@ static int up_setup(struct uart_dev_s *dev) * ****************************************************************************/ -#ifdef SERIAL_HAVE_DMA +#if defined(SERIAL_HAVE_RXDMA) || defined(SERIAL_HAVE_TXDMA) 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, unless we are the console */ @@ -1772,39 +2033,55 @@ static int up_dma_setup(struct uart_dev_s *dev) } } - /* Acquire the DMA channel. This should always succeed. */ +#if defined(SERIAL_HAVE_TXDMA) + /* Acquire the Tx DMA channel. This should always succeed. */ - priv->rxdma = stm32_dmachannel(priv->rxdma_channel); + if (priv->txdma_channel != INVALID_SERIAL_DMA_CHANNEL) + { + priv->txdma = stm32_dmachannel(priv->txdma_channel); - /* Configure for circular DMA reception into the RX FIFO */ + /* Enable receive Tx DMA for the UART */ - stm32_dmasetup(priv->rxdma, - priv->usartbase + STM32_USART_RDR_OFFSET, - (uint32_t)priv->rxfifo, - RXDMA_BUFFER_SIZE, - SERIAL_DMA_CONTROL_WORD); - - /* Reset our DMA shadow pointer and Rx data availability count to match - * the address just programmed above. - */ - - priv->rxdmanext = 0; -#ifdef CONFIG_ARMV7M_DCACHE - priv->rxdmaavail = 0; + modifyreg32(priv->usartbase + STM32_USART_CR3_OFFSET, 0, USART_CR3_DMAT); + } #endif - /* Enable receive DMA for the UART */ +#if defined(SERIAL_HAVE_RXDMA) + /* Acquire the Rx DMA channel. This should always succeed. */ - regval = up_serialin(priv, STM32_USART_CR3_OFFSET); - regval |= USART_CR3_DMAR; - up_serialout(priv, STM32_USART_CR3_OFFSET, regval); + if (priv->rxdma_channel != INVALID_SERIAL_DMA_CHANNEL) + { + priv->rxdma = stm32_dmachannel(priv->rxdma_channel); - /* 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. - */ + /* Configure for circular DMA reception into the RX FIFO */ - stm32_dmastart(priv->rxdma, up_dma_rxcallback, (void *)priv, true); + stm32_dmasetup(priv->rxdma, + priv->usartbase + STM32_USART_RDR_OFFSET, + (uint32_t)priv->rxfifo, + RXDMA_BUFFER_SIZE, + SERIAL_RXDMA_CONTROL_WORD); + + /* Reset our DMA shadow pointer and Rx data availability count to match + * the address just programmed above. + */ + + priv->rxdmanext = 0; +#ifdef CONFIG_ARMV7M_DCACHE + priv->rxdmaavail = 0; +#endif + + /* Enable receive Rx DMA for the UART */ + + modifyreg32(priv->usartbase + STM32_USART_CR3_OFFSET, 0, USART_CR3_DMAR); + + /* 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); + } +#endif return OK; } @@ -1884,7 +2161,7 @@ static void up_shutdown(struct uart_dev_s *dev) * ****************************************************************************/ -#ifdef SERIAL_HAVE_DMA +#if defined(SERIAL_HAVE_RXDMA) || defined(SERIAL_HAVE_TXDMA) static void up_dma_shutdown(struct uart_dev_s *dev) { struct up_dev_s *priv = (struct up_dev_s *)dev->priv; @@ -1893,14 +2170,33 @@ static void up_dma_shutdown(struct uart_dev_s *dev) up_shutdown(dev); - /* Stop the DMA channel */ +#if defined(SERIAL_HAVE_RXDMA) + /* Stop the RX DMA channel */ - stm32_dmastop(priv->rxdma); + if (priv->rxdma_channel != INVALID_SERIAL_DMA_CHANNEL) + { + stm32_dmastop(priv->rxdma); - /* Release the DMA channel */ + /* Release the RX DMA channel */ - stm32_dmafree(priv->rxdma); - priv->rxdma = NULL; + stm32_dmafree(priv->rxdma); + priv->rxdma = NULL; + } +#endif + +#if defined(SERIAL_HAVE_TXDMA) + /* Stop the TX DMA channel */ + + if (priv->txdma_channel != INVALID_SERIAL_DMA_CHANNEL) + { + stm32_dmastop(priv->txdma); + + /* Release the TX DMA channel */ + + stm32_dmafree(priv->txdma); + priv->txdma = NULL; + } +#endif } #endif @@ -1935,6 +2231,7 @@ static int up_attach(struct uart_dev_s *dev) up_enable_irq(priv->irq); } + return ret; } @@ -2435,7 +2732,7 @@ static int up_ioctl(struct file *filep, int cmd, unsigned long arg) * ****************************************************************************/ -#ifndef SERIAL_HAVE_ONLY_DMA +#ifndef SERIAL_HAVE_ONLY_RXDMA static int up_receive(struct uart_dev_s *dev, unsigned int *status) { struct up_dev_s *priv = (struct up_dev_s *)dev->priv; @@ -2464,7 +2761,7 @@ static int up_receive(struct uart_dev_s *dev, unsigned int *status) * ****************************************************************************/ -#ifndef SERIAL_HAVE_ONLY_DMA +#ifndef SERIAL_HAVE_ONLY_RXDMA static void up_rxint(struct uart_dev_s *dev, bool enable) { struct up_dev_s *priv = (struct up_dev_s *)dev->priv; @@ -2522,7 +2819,7 @@ static void up_rxint(struct uart_dev_s *dev, bool enable) * ****************************************************************************/ -#ifndef SERIAL_HAVE_ONLY_DMA +#ifndef SERIAL_HAVE_ONLY_RXDMA static bool up_rxavailable(struct uart_dev_s *dev) { struct up_dev_s *priv = (struct up_dev_s *)dev->priv; @@ -2636,7 +2933,7 @@ static bool up_rxflowcontrol(struct uart_dev_s *dev, * ****************************************************************************/ -#ifdef SERIAL_HAVE_DMA +#ifdef SERIAL_HAVE_RXDMA static int up_dma_receive(struct uart_dev_s *dev, unsigned int *status) { struct up_dev_s *priv = (struct up_dev_s *)dev->priv; @@ -2719,7 +3016,7 @@ static int up_dma_receive(struct uart_dev_s *dev, unsigned int *status) * ****************************************************************************/ -#if defined(SERIAL_HAVE_DMA) && defined(CONFIG_PM) +#if defined(SERIAL_HAVE_RXDMA) && defined(CONFIG_PM) static void up_dma_reenable(struct up_dev_s *priv) { /* Configure for circular DMA reception into the RX FIFO */ @@ -2728,7 +3025,7 @@ static void up_dma_reenable(struct up_dev_s *priv) priv->usartbase + STM32_USART_RDR_OFFSET, (uint32_t)priv->rxfifo, RXDMA_BUFFER_SIZE, - SERIAL_DMA_CONTROL_WORD); + SERIAL_RXDMA_CONTROL_WORD); /* Reset our DMA shadow pointer and Rx data availability count to match * the address just programmed above. @@ -2760,7 +3057,7 @@ static void up_dma_reenable(struct up_dev_s *priv) * ****************************************************************************/ -#ifdef SERIAL_HAVE_DMA +#ifdef SERIAL_HAVE_RXDMA static void up_dma_rxint(struct uart_dev_s *dev, bool enable) { struct up_dev_s *priv = (struct up_dev_s *)dev->priv; @@ -2785,7 +3082,7 @@ static void up_dma_rxint(struct uart_dev_s *dev, bool enable) * ****************************************************************************/ -#ifdef SERIAL_HAVE_DMA +#ifdef SERIAL_HAVE_RXDMA static bool up_dma_rxavailable(struct uart_dev_s *dev) { struct up_dev_s *priv = (struct up_dev_s *)dev->priv; @@ -2798,6 +3095,106 @@ static bool up_dma_rxavailable(struct uart_dev_s *dev) } #endif +/**************************************************************************** + * Name: up_dma_txcallback + * + * Description: + * This function clears dma buffer at complete of DMA transfer and wakes up + * threads waiting for space in buffer. + * + ****************************************************************************/ + +#ifdef SERIAL_HAVE_TXDMA +static void up_dma_txcallback(DMA_HANDLE handle, uint8_t status, void *arg) +{ + struct up_dev_s *priv = (struct up_dev_s *)arg; + + /* Update 'nbytes' indicating number of bytes actually transferred by DMA. + * This is important to free TX buffer space by 'uart_xmitchars_done'. + */ + + if (status & DMA_SCR_HTIE) + { + priv->dev.dmatx.nbytes = priv->dev.dmatx.length / 2; + } + else if (status & DMA_SCR_TCIE) + { + priv->dev.dmatx.nbytes = priv->dev.dmatx.length; + } + + /* Adjust the pointers */ + + uart_xmitchars_done(&priv->dev); + + /* Kick off the next DMA to keep the channel as busy as possible */ + + uart_xmitchars_dma(&priv->dev); +} +#endif + +/**************************************************************************** + * Name: up_dma_txavailable + * + * Description: + * Informs DMA that Tx data is available and is ready for transfer. + * + ****************************************************************************/ + +#ifdef SERIAL_HAVE_TXDMA +static void up_dma_txavailable(struct uart_dev_s *dev) +{ + struct up_dev_s *priv = (struct up_dev_s *)dev->priv; + + /* Only send when the DMA is idle */ + + if (stm32_dmaresidual(priv->txdma) == 0) + { + uart_xmitchars_dma(dev); + } +} +#endif + +/**************************************************************************** + * Name: up_dma_send + * + * Description: + * Called (usually) from the interrupt level to start DMA transfer. + * (Re-)Configures DMA Stream updating buffer and buffer length. + * + ****************************************************************************/ + +#ifdef SERIAL_HAVE_TXDMA +static void up_dma_send(struct uart_dev_s *dev) +{ + struct up_dev_s *priv = (struct up_dev_s *)dev->priv; + + /* We need to stop DMA before reconfiguration */ + + stm32_dmastop(priv->txdma); + + /* Wait until TX UART is ready for new transfer it should be */ + + while (!up_txready(dev)); + + /* Flush the contents of the TX buffer into physical memory */ + + up_clean_dcache((uintptr_t)dev->dmatx.buffer, + (uintptr_t)dev->dmatx.buffer + dev->dmatx.length); + + /* Make use of setup function to update buffer and its length for next transfer */ + + stm32_dmasetup(priv->txdma, + priv->usartbase + STM32_USART_TDR_OFFSET, + (uint32_t) dev->dmatx.buffer, + (size_t) dev->dmatx.length, + SERIAL_TXDMA_CONTROL_WORD); + + /* Start transmission with the callback on DMA completion */ + + stm32_dmastart(priv->txdma, up_dma_txcallback, (void *)priv, false); +} +#endif + /**************************************************************************** * Name: up_send * @@ -2820,6 +3217,28 @@ static void up_send(struct uart_dev_s *dev, int ch) up_serialout(priv, STM32_USART_TDR_OFFSET, (uint32_t)ch); } +/**************************************************************************** + * Name: up_dma_txint + * + * Description: + * Call to enable or disable TX interrupts from the UART. + * + ****************************************************************************/ + +#ifdef SERIAL_HAVE_TXDMA +static void up_dma_txint(struct uart_dev_s *dev, bool enable) +{ + /* Nothing to do. */ + + /* In case of DMA transfer we do not want to make use of UART interrupts. + * Instead, we use DMA interrupts that are activated once during boot + * sequence. Furthermore we can use up_dma_txcallback() to handle staff at + * half DMA transfer or after transfer completion (depending configuration, + * see stm32_dmastart(...) ). + */ +} +#endif + /**************************************************************************** * Name: up_txint * @@ -2910,7 +3329,7 @@ static bool up_txready(struct uart_dev_s *dev) * ****************************************************************************/ -#ifdef SERIAL_HAVE_DMA +#ifdef SERIAL_HAVE_RXDMA static void up_dma_rxcallback(DMA_HANDLE handle, uint8_t status, void *arg) { struct up_dev_s *priv = (struct up_dev_s *)arg; @@ -2993,6 +3412,7 @@ static void up_pm_notify(struct pm_callback_s *cb, int domain, break; default: + /* Should not get here */ break; @@ -3050,7 +3470,7 @@ static int up_pm_prepare(struct pm_callback_s *cb, int domain, case PM_STANDBY: case PM_SLEEP: -#ifdef SERIAL_HAVE_DMA +#ifdef SERIAL_HAVE_RXDMA /* Flush Rx DMA buffers before checking state of serial device * buffers. */ @@ -3093,6 +3513,7 @@ static int up_pm_prepare(struct pm_callback_s *cb, int domain, { return ERROR; } + if (priv->dev.recv.head != priv->dev.recv.tail) { return ERROR; @@ -3101,6 +3522,7 @@ static int up_pm_prepare(struct pm_callback_s *cb, int domain, break; default: + /* Should not get here */ break; @@ -3172,6 +3594,15 @@ void up_serialinit(void) int ret; #endif +#if !defined(SERIAL_HAVE_ONLY_DMA) +# if defined(SERIAL_HAVE_RXDMA) + UNUSED(g_uart_rxdma_ops); +# endif +# if defined(SERIAL_HAVE_TXDMA) + UNUSED(g_uart_txdma_ops); +# endif +#endif + #ifdef CONFIG_PM /* Register to receive power management callbacks */ @@ -3242,7 +3673,7 @@ void up_serialinit(void) * ****************************************************************************/ -#ifdef SERIAL_HAVE_DMA +#ifdef SERIAL_HAVE_RXDMA void stm32_serial_dma_poll(void) { irqstate_t flags; diff --git a/arch/arm/src/stm32f7/stm32_uart.h b/arch/arm/src/stm32f7/stm32_uart.h index 15ad3dfca5..9c326811d8 100644 --- a/arch/arm/src/stm32f7/stm32_uart.h +++ b/arch/arm/src/stm32f7/stm32_uart.h @@ -187,101 +187,173 @@ #if !defined(HAVE_UART) || !defined(CONFIG_ARCH_DMA) # undef CONFIG_USART1_RXDMA +# undef CONFIG_USART1_TXDMA # undef CONFIG_USART2_RXDMA +# undef CONFIG_USART2_TXDMA # undef CONFIG_USART3_RXDMA +# undef CONFIG_USART3_TXDMA # undef CONFIG_UART4_RXDMA +# undef CONFIG_UART4_TXDMA # undef CONFIG_UART5_RXDMA +# undef CONFIG_UART5_TXDMA # undef CONFIG_USART6_RXDMA +# undef CONFIG_USART6_TXDMA # undef CONFIG_UART7_RXDMA +# undef CONFIG_UART7_TXDMA # undef CONFIG_UART8_RXDMA +# undef CONFIG_UART8_TXDMA #endif /* Disable the DMA configuration on all unused USARTs */ #ifndef CONFIG_STM32F7_USART1 # undef CONFIG_USART1_RXDMA +# undef CONFIG_USART1_TXDMA #endif #ifndef CONFIG_STM32F7_USART2 # undef CONFIG_USART2_RXDMA +# undef CONFIG_USART2_TXDMA #endif #ifndef CONFIG_STM32F7_USART3 # undef CONFIG_USART3_RXDMA +# undef CONFIG_USART3_TXDMA #endif #ifndef CONFIG_STM32F7_UART4 # undef CONFIG_UART4_RXDMA +# undef CONFIG_UART4_TXDMA #endif #ifndef CONFIG_STM32F7_UART5 # undef CONFIG_UART5_RXDMA +# undef CONFIG_UART5_TXDMA #endif #ifndef CONFIG_STM32F7_USART6 # undef CONFIG_USART6_RXDMA +# undef CONFIG_USART6_TXDMA #endif #ifndef CONFIG_STM32F7_UART7 # undef CONFIG_UART7_RXDMA +# undef CONFIG_UART7_TXDMA #endif #ifndef CONFIG_STM32F7_UART8 # undef CONFIG_UART8_RXDMA +# undef CONFIG_UART8_TXDMA #endif -/* Is DMA available on any (enabled) USART? */ +/* Is RX DMA available on any (enabled) USART? */ -#undef SERIAL_HAVE_DMA +#undef SERIAL_HAVE_RXDMA #if defined(CONFIG_USART1_RXDMA) || defined(CONFIG_USART2_RXDMA) || \ defined(CONFIG_USART3_RXDMA) || defined(CONFIG_UART4_RXDMA) || \ defined(CONFIG_UART5_RXDMA) || defined(CONFIG_USART6_RXDMA) || \ defined(CONFIG_UART7_RXDMA) || defined(CONFIG_UART8_RXDMA) -# define SERIAL_HAVE_DMA 1 +# define SERIAL_HAVE_RXDMA 1 #endif -/* Is DMA used on the console UART? */ +/* Is TX DMA available on any (enabled) USART? */ -#undef SERIAL_HAVE_CONSOLE_DMA +#undef SERIAL_HAVE_TXDMA +#if defined(CONFIG_USART1_TXDMA) || defined(CONFIG_USART2_TXDMA) || \ + defined(CONFIG_USART3_TXDMA) || defined(CONFIG_UART4_TXDMA) || \ + defined(CONFIG_UART5_TXDMA) || defined(CONFIG_USART6_TXDMA) || \ + defined(CONFIG_UART7_TXDMA) || defined(CONFIG_UART8_TXDMA) +# define SERIAL_HAVE_TXDMA 1 +#endif + +/* Is RX DMA used on the console UART? */ + +#undef SERIAL_HAVE_CONSOLE_RXDMA #if defined(CONFIG_USART1_SERIAL_CONSOLE) && defined(CONFIG_USART1_RXDMA) -# define SERIAL_HAVE_CONSOLE_DMA 1 +# define SERIAL_HAVE_CONSOLE_RXDMA 1 #elif defined(CONFIG_USART2_SERIAL_CONSOLE) && defined(CONFIG_USART2_RXDMA) -# define SERIAL_HAVE_CONSOLE_DMA 1 +# define SERIAL_HAVE_CONSOLE_RXDMA 1 #elif defined(CONFIG_USART3_SERIAL_CONSOLE) && defined(CONFIG_USART3_RXDMA) -# define SERIAL_HAVE_CONSOLE_DMA 1 +# define SERIAL_HAVE_CONSOLE_RXDMA 1 #elif defined(CONFIG_UART4_SERIAL_CONSOLE) && defined(CONFIG_UART4_RXDMA) -# define SERIAL_HAVE_CONSOLE_DMA 1 +# define SERIAL_HAVE_CONSOLE_RXDMA 1 #elif defined(CONFIG_UART5_SERIAL_CONSOLE) && defined(CONFIG_UART5_RXDMA) -# define SERIAL_HAVE_CONSOLE_DMA 1 +# define SERIAL_HAVE_CONSOLE_RXDMA 1 #elif defined(CONFIG_USART6_SERIAL_CONSOLE) && defined(CONFIG_USART6_RXDMA) -# define SERIAL_HAVE_CONSOLE_DMA 1 +# define SERIAL_HAVE_CONSOLE_RXDMA 1 #elif defined(CONFIG_UART7_SERIAL_CONSOLE) && defined(CONFIG_UART7_RXDMA) -# define SERIAL_HAVE_CONSOLE_DMA 1 +# define SERIAL_HAVE_CONSOLE_RXDMA 1 #elif defined(CONFIG_UART8_SERIAL_CONSOLE) && defined(CONFIG_UART8_RXDMA) -# define SERIAL_HAVE_CONSOLE_DMA 1 +# define SERIAL_HAVE_CONSOLE_RXDMA 1 #endif -/* Is DMA used on all (enabled) USARTs */ +/* Is TX DMA used on the console UART? */ -#define SERIAL_HAVE_ONLY_DMA 1 +#undef SERIAL_HAVE_CONSOLE_TXDMA +#if defined(CONFIG_USART1_SERIAL_CONSOLE) && defined(CONFIG_USART1_TXDMA) +# define SERIAL_HAVE_CONSOLE_TXDMA 1 +#elif defined(CONFIG_USART2_SERIAL_CONSOLE) && defined(CONFIG_USART2_TXDMA) +# define SERIAL_HAVE_CONSOLE_TXDMA 1 +#elif defined(CONFIG_USART3_SERIAL_CONSOLE) && defined(CONFIG_USART3_TXDMA) +# define SERIAL_HAVE_CONSOLE_TXDMA 1 +#elif defined(CONFIG_UART4_SERIAL_CONSOLE) && defined(CONFIG_UART4_TXDMA) +# define SERIAL_HAVE_CONSOLE_TXDMA 1 +#elif defined(CONFIG_UART5_SERIAL_CONSOLE) && defined(CONFIG_UART5_TXDMA) +# define SERIAL_HAVE_CONSOLE_TXDMA 1 +#elif defined(CONFIG_USART6_SERIAL_CONSOLE) && defined(CONFIG_USART6_TXDMA) +# define SERIAL_HAVE_CONSOLE_TXDMA 1 +#elif defined(CONFIG_UART7_SERIAL_CONSOLE) && defined(CONFIG_UART7_TXDMA) +# define SERIAL_HAVE_CONSOLE_TXDMA 1 +#elif defined(CONFIG_UART8_SERIAL_CONSOLE) && defined(CONFIG_UART8_TXDMA) +# define SERIAL_HAVE_CONSOLE_TXDMA 1 +#endif + +/* Is RX DMA used on all (enabled) USARTs */ + +#define SERIAL_HAVE_ONLY_RXDMA 1 #if defined(CONFIG_STM32F7_USART1) && !defined(CONFIG_USART1_RXDMA) -# undef SERIAL_HAVE_ONLY_DMA +# undef SERIAL_HAVE_ONLY_RXDMA #elif defined(CONFIG_STM32F7_USART2) && !defined(CONFIG_USART2_RXDMA) -# undef SERIAL_HAVE_ONLY_DMA +# undef SERIAL_HAVE_ONLY_RXDMA #elif defined(CONFIG_STM32F7_USART3) && !defined(CONFIG_USART3_RXDMA) -# undef SERIAL_HAVE_ONLY_DMA +# undef SERIAL_HAVE_ONLY_RXDMA #elif defined(CONFIG_STM32F7_UART4) && !defined(CONFIG_UART4_RXDMA) -# undef SERIAL_HAVE_ONLY_DMA +# undef SERIAL_HAVE_ONLY_RXDMA #elif defined(CONFIG_STM32F7_UART5) && !defined(CONFIG_UART5_RXDMA) -# undef SERIAL_HAVE_ONLY_DMA +# undef SERIAL_HAVE_ONLY_RXDMA #elif defined(CONFIG_STM32F7_USART6) && !defined(CONFIG_USART6_RXDMA) -# undef SERIAL_HAVE_ONLY_DMA +# undef SERIAL_HAVE_ONLY_RXDMA #elif defined(CONFIG_STM32F7_UART7) && !defined(CONFIG_UART7_RXDMA) -# undef SERIAL_HAVE_ONLY_DMA +# undef SERIAL_HAVE_ONLY_RXDMA #elif defined(CONFIG_STM32F7_UART8) && !defined(CONFIG_UART8_RXDMA) -# undef SERIAL_HAVE_ONLY_DMA +# undef SERIAL_HAVE_ONLY_RXDMA #endif +/* Is TX DMA used on all (enabled) USARTs */ + +#define SERIAL_HAVE_ONLY_TXDMA 1 +#if defined(CONFIG_STM32F7_USART1) && !defined(CONFIG_USART1_TXDMA) +# undef SERIAL_HAVE_ONLY_TXDMA +#elif defined(CONFIG_STM32F7_USART2) && !defined(CONFIG_USART2_TXDMA) +# undef SERIAL_HAVE_ONLY_TXDMA +#elif defined(CONFIG_STM32F7_USART3) && !defined(CONFIG_USART3_TXDMA) +# undef SERIAL_HAVE_ONLY_TXDMA +#elif defined(CONFIG_STM32F7_UART4) && !defined(CONFIG_UART4_TXDMA) +# undef SERIAL_HAVE_ONLY_TXDMA +#elif defined(CONFIG_STM32F7_UART5) && !defined(CONFIG_UART5_TXDMA) +# undef SERIAL_HAVE_ONLY_TXDMA +#elif defined(CONFIG_STM32F7_USART6) && !defined(CONFIG_USART6_TXDMA) +# undef SERIAL_HAVE_ONLY_TXDMA +#elif defined(CONFIG_STM32F7_UART7) && !defined(CONFIG_UART7_TXDMA) +# undef SERIAL_HAVE_ONLY_TXDMA +#elif defined(CONFIG_STM32F7_UART8) && !defined(CONFIG_UART8_TXDMA) +# undef SERIAL_HAVE_ONLY_TXDMA +#endif + +#undef SERIAL_HAVE_ONLY_DMA +#if defined(SERIAL_HAVE_ONLY_RXDMA) && defined(SERIAL_HAVE_ONLY_TXDMA) +#define SERIAL_HAVE_ONLY_DMA +#endif /* Is RS-485 used? */ #if defined(CONFIG_USART1_RS485) || defined(CONFIG_USART2_RS485) || \ @@ -333,7 +405,7 @@ extern "C" * ************************************************************************************/ -#ifdef SERIAL_HAVE_DMA +#ifdef SERIAL_HAVE_RXDMA void stm32_serial_dma_poll(void); #endif