diff options
author | Lorenz Meier <lm@inf.ethz.ch> | 2013-06-01 01:04:32 +0200 |
---|---|---|
committer | Lorenz Meier <lm@inf.ethz.ch> | 2013-06-01 01:04:32 +0200 |
commit | 5375bb5b86e266157ceceef08c367da711b8144e (patch) | |
tree | 88bc81cab11d8f0b2b6f9391f803051c081b2ecb /nuttx/arch/arm/src/stm32/stm32_serial.c | |
parent | 27ee36b2049167a1272122548fe61aa2993d79c1 (diff) | |
download | px4-firmware-5375bb5b86e266157ceceef08c367da711b8144e.tar.gz px4-firmware-5375bb5b86e266157ceceef08c367da711b8144e.tar.bz2 px4-firmware-5375bb5b86e266157ceceef08c367da711b8144e.zip |
Cleanup, WIP, needs a NuttX checkout to Firmware/NuttX now
Diffstat (limited to 'nuttx/arch/arm/src/stm32/stm32_serial.c')
-rw-r--r-- | nuttx/arch/arm/src/stm32/stm32_serial.c | 2252 |
1 files changed, 0 insertions, 2252 deletions
diff --git a/nuttx/arch/arm/src/stm32/stm32_serial.c b/nuttx/arch/arm/src/stm32/stm32_serial.c deleted file mode 100644 index c91f6a6d7..000000000 --- a/nuttx/arch/arm/src/stm32/stm32_serial.c +++ /dev/null @@ -1,2252 +0,0 @@ -/**************************************************************************** - * arch/arm/src/stm32/stm32_serial.c - * - * Copyright (C) 2009-2013 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt <gnutt@nuttx.org> - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. Neither the name NuttX nor the names of its contributors may be - * used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include <nuttx/config.h> - -#include <sys/types.h> -#include <stdint.h> -#include <stdbool.h> -#include <unistd.h> -#include <semaphore.h> -#include <string.h> -#include <errno.h> -#include <debug.h> - -#include <nuttx/irq.h> -#include <nuttx/arch.h> -#include <nuttx/serial/serial.h> -#include <nuttx/power/pm.h> - -#ifdef CONFIG_SERIAL_TERMIOS -# include <termios.h> -#endif - -#include <arch/serial.h> -#include <arch/board/board.h> - -#include "chip.h" -#include "stm32_uart.h" -#include "stm32_dma.h" -#include "up_arch.h" -#include "up_internal.h" -#include "os_internal.h" - -/**************************************************************************** - * Definitions - ****************************************************************************/ -/* Some sanity checks *******************************************************/ -/* DMA configuration */ - -/* If DMA is enabled on any USART, then very that other pre-requisites - * have also been selected. - */ - -#if SERIAL_HAVE_DMA - -# if defined(CONFIG_STM32_STM32F20XX) || defined(CONFIG_STM32_STM32F40XX) -/* Verify that DMA has been enabled and the DMA channel has been defined. - */ - -# 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_UART4_RXDMA) || defined(CONFIG_UART5_RXDMA) -# ifndef CONFIG_STM32_DMA1 -# error STM32 USART2/3/4/5 receive DMA requires CONFIG_STM32_DMA1 -# endif -# endif - -/* Currently RS-485 support cannot be enabled when RXDMA is in use due to lack - * of testing - RS-485 support was developed on STM32F1x - */ - -# if (defined(CONFIG_USART1_RXDMA) && defined(CONFIG_USART1_RS485)) || \ - (defined(CONFIG_USART2_RXDMA) && defined(CONFIG_USART2_RS485)) || \ - (defined(CONFIG_USART3_RXDMA) && defined(CONFIG_USART3_RS485)) || \ - (defined(CONFIG_UART4_RXDMA) && defined(CONFIG_UART4_RS485)) || \ - (defined(CONFIG_UART5_RXDMA) && defined(CONFIG_UART5_RS485)) || \ - (defined(CONFIG_USART6_RXDMA) && defined(CONFIG_USART6_RS485)) -# error "RXDMA and RS-485 cannot be enabled at the same time for the same U[S]ART" -# 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_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 - -# elif defined(CONFIG_STM32_STM32F10XX) - -# if defined(CONFIG_USART1_RXDMA) || defined(CONFIG_USART2_RXDMA) || \ - defined(CONFIG_USART3_RXDMA) -# ifndef CONFIG_STM32_DMA1 -# error STM32 USART1/2/3 receive DMA requires CONFIG_STM32_DMA1 -# endif -# endif - -# if defined(CONFIG_UART4_RXDMA) -# ifndef CONFIG_STM32_DMA2 -# error STM32 USART4 receive DMA requires CONFIG_STM32_DMA2 -# endif -# endif - -/* There are no optional DMA channel assignments for the F1 */ - -# define DMAMAP_USART1_RX DMACHAN_USART1_RX -# define DMAMAP_USART2_RX DMACHAN_USART2_RX -# define DMAMAP_USART3_RX DMACHAN_USART3_RX -# define DMAMAP_UART4_RX DMACHAN_USART4_RX - -# endif - -/* 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 - -/* DMA priority */ - -# ifndef CONFIG_USART_DMAPRIO -# if defined(CONFIG_STM32_STM32F10XX) -# define CONFIG_USART_DMAPRIO DMA_CCR_PRIMED -# elif defined(CONFIG_STM32_STM32F20XX) || defined(CONFIG_STM32_STM32F40XX) -# define CONFIG_USART_DMAPRIO DMA_SCR_PRIMED -# else -# error "Unknown STM32 DMA" -# endif -# endif -# if defined(CONFIG_STM32_STM32F10XX) -# if (CONFIG_USART_DMAPRIO & ~DMA_CCR_PL_MASK) != 0 -# error "Illegal value for CONFIG_USART_DMAPRIO" -# endif -# elif defined(CONFIG_STM32_STM32F20XX) || defined(CONFIG_STM32_STM32F40XX) -# if (CONFIG_USART_DMAPRIO & ~DMA_SCR_PL_MASK) != 0 -# error "Illegal value for CONFIG_USART_DMAPRIO" -# endif -# else -# error "Unknown STM32 DMA" -# endif - -/* DMA control word */ - -# if defined(CONFIG_STM32_STM32F20XX) || defined(CONFIG_STM32_STM32F40XX) -# define SERIAL_DMA_CONTROL_WORD \ - (DMA_SCR_DIR_P2M | \ - DMA_SCR_CIRC | \ - DMA_SCR_MINC | \ - DMA_SCR_PSIZE_8BITS | \ - DMA_SCR_MSIZE_8BITS | \ - CONFIG_USART_DMAPRIO | \ - DMA_SCR_PBURST_SINGLE | \ - DMA_SCR_MBURST_SINGLE) -# else -# define SERIAL_DMA_CONTROL_WORD \ - (DMA_CCR_CIRC | \ - DMA_CCR_MINC | \ - DMA_CCR_PSIZE_8BITS | \ - DMA_CCR_MSIZE_8BITS | \ - CONFIG_USART_DMAPRIO) -# endif - -#endif - -/* Power management definitions */ - -#if defined(CONFIG_PM) && !defined(CONFIG_PM_SERIAL_ACTIVITY) -# define CONFIG_PM_SERIAL_ACTIVITY 10 -#endif - -#ifdef USE_SERIALDRIVER -#ifdef HAVE_UART - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -struct up_dev_s -{ - struct uart_dev_s dev; /* Generic UART device */ - uint16_t ie; /* Saved interrupt mask bits value */ - uint16_t sr; /* Saved status bits */ - - /* If termios are supported, then the following fields may vary at - * runtime. - */ - -#ifdef CONFIG_SERIAL_TERMIOS - uint8_t parity; /* 0=none, 1=odd, 2=even */ - uint8_t bits; /* Number of bits (7 or 8) */ - bool stopbits2; /* True: Configure with 2 stop bits instead of 1 */ - bool iflow; /* input flow control (RTS) enabled */ - bool oflow; /* output flow control (CTS) enabled */ - uint32_t baud; /* Configured baud */ -#else - const uint8_t parity; /* 0=none, 1=odd, 2=even */ - const uint8_t bits; /* Number of bits (7 or 8) */ - const bool stopbits2; /* True: Configure with 2 stop bits instead of 1 */ - const bool iflow; /* input flow control (RTS) enabled */ - const bool oflow; /* output flow control (CTS) enabled */ - const uint32_t baud; /* Configured baud */ -#endif - - const uint8_t irq; /* IRQ associated with this USART */ - const uint32_t apbclock; /* PCLK 1 or 2 frequency */ - const uint32_t usartbase; /* Base address of USART registers */ - const uint32_t tx_gpio; /* U[S]ART TX GPIO pin configuration */ - const uint32_t rx_gpio; /* U[S]ART RX GPIO pin configuration */ - 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 - -#ifdef HAVE_RS485 - const uint32_t rs485_dir_gpio; /* U[S]ART RS-485 DIR GPIO pin configuration */ - const bool rs485_dir_polarity; /* U[S]ART RS-485 DIR pin state for TX enabled */ -#endif -}; - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -static void up_set_format(struct uart_dev_s *dev); -static int up_setup(struct uart_dev_s *dev); -static void up_shutdown(struct uart_dev_s *dev); -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_PM -static void up_pm_notify(struct pm_callback_s *cb, enum pm_state_e pmstate); -static int up_pm_prepare(struct pm_callback_s *cb, enum pm_state_e pmstate); -#endif - -#ifdef CONFIG_STM32_USART1 -static int up_interrupt_usart1(int irq, void *context); -#endif -#ifdef CONFIG_STM32_USART2 -static int up_interrupt_usart2(int irq, void *context); -#endif -#ifdef CONFIG_STM32_USART3 -static int up_interrupt_usart3(int irq, void *context); -#endif -#ifdef CONFIG_STM32_UART4 -static int up_interrupt_uart4(int irq, void *context); -#endif -#ifdef CONFIG_STM32_UART5 -static int up_interrupt_uart5(int irq, void *context); -#endif -#ifdef CONFIG_STM32_USART6 -static int up_interrupt_usart6(int irq, void *context); -#endif - -/**************************************************************************** - * Private Variables - ****************************************************************************/ - -#ifndef SERIAL_HAVE_ONLY_DMA -static const struct uart_ops_s g_uart_ops = -{ - .setup = up_setup, - .shutdown = up_shutdown, - .attach = up_attach, - .detach = up_detach, - .ioctl = up_ioctl, - .receive = up_receive, - .rxint = up_rxint, - .rxavailable = up_rxavailable, - .send = up_send, - .txint = up_txint, - .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_UART4_RXBUFSIZE]; -static char g_uart4txbuffer[CONFIG_UART4_TXBUFSIZE]; -# ifdef CONFIG_UART4_RXDMA -static char g_uart4rxfifo[RXDMA_BUFFER_SIZE]; -# endif -#endif - -#ifdef CONFIG_STM32_UART5 -static char g_uart5rxbuffer[CONFIG_UART5_RXBUFSIZE]; -static char g_uart5txbuffer[CONFIG_UART5_TXBUFSIZE]; -# ifdef CONFIG_UART5_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. */ - -#ifdef CONFIG_STM32_USART1 -static struct up_dev_s g_usart1priv = -{ - .dev = - { -#if CONSOLE_UART == 1 - .isconsole = true, -#endif - .recv = - { - .size = CONFIG_USART1_RXBUFSIZE, - .buffer = g_usart1rxbuffer, - }, - .xmit = - { - .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, - }, - - .irq = STM32_IRQ_USART1, - .parity = CONFIG_USART1_PARITY, - .bits = CONFIG_USART1_BITS, - .stopbits2 = CONFIG_USART1_2STOP, - .iflow = false, - .oflow = false, - .baud = CONFIG_USART1_BAUD, - .apbclock = STM32_PCLK2_FREQUENCY, - .usartbase = STM32_USART1_BASE, - .tx_gpio = GPIO_USART1_TX, - .rx_gpio = GPIO_USART1_RX, -#ifdef GPIO_USART1_CTS - .cts_gpio = GPIO_USART1_CTS, -#endif -#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, - -#ifdef CONFIG_USART1_RS485 - .rs485_dir_gpio = GPIO_USART1_RS485_DIR, -# if (CONFIG_USART1_RS485_DIR_POLARITY == 0) - .rs485_dir_polarity = false, -# else - .rs485_dir_polarity = true, -# endif -#endif -}; -#endif - -/* This describes the state of the STM32 USART2 port. */ - -#ifdef CONFIG_STM32_USART2 -static struct up_dev_s g_usart2priv = -{ - .dev = - { -#if CONSOLE_UART == 2 - .isconsole = true, -#endif - .recv = - { - .size = CONFIG_USART2_RXBUFSIZE, - .buffer = g_usart2rxbuffer, - }, - .xmit = - { - .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, - }, - - .irq = STM32_IRQ_USART2, - .parity = CONFIG_USART2_PARITY, - .bits = CONFIG_USART2_BITS, - .stopbits2 = CONFIG_USART2_2STOP, - .iflow = false, - .oflow = false, - .baud = CONFIG_USART2_BAUD, - .apbclock = STM32_PCLK1_FREQUENCY, - .usartbase = STM32_USART2_BASE, - .tx_gpio = GPIO_USART2_TX, - .rx_gpio = GPIO_USART2_RX, -#ifdef GPIO_USART2_CTS - .cts_gpio = GPIO_USART2_CTS, -#endif -#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, - -#ifdef CONFIG_USART2_RS485 - .rs485_dir_gpio = GPIO_USART2_RS485_DIR, -# if (CONFIG_USART2_RS485_DIR_POLARITY == 0) - .rs485_dir_polarity = false, -# else - .rs485_dir_polarity = true, -# endif -#endif -}; -#endif - -/* This describes the state of the STM32 USART3 port. */ - -#ifdef CONFIG_STM32_USART3 -static struct up_dev_s g_usart3priv = -{ - .dev = - { -#if CONSOLE_UART == 3 - .isconsole = true, -#endif - .recv = - { - .size = CONFIG_USART3_RXBUFSIZE, - .buffer = g_usart3rxbuffer, - }, - .xmit = - { - .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, - }, - - .irq = STM32_IRQ_USART3, - .parity = CONFIG_USART3_PARITY, - .bits = CONFIG_USART3_BITS, - .stopbits2 = CONFIG_USART3_2STOP, - .iflow = false, - .oflow = false, - .baud = CONFIG_USART3_BAUD, - .apbclock = STM32_PCLK1_FREQUENCY, - .usartbase = STM32_USART3_BASE, - .tx_gpio = GPIO_USART3_TX, - .rx_gpio = GPIO_USART3_RX, -#ifdef GPIO_USART3_CTS - .cts_gpio = GPIO_USART3_CTS, -#endif -#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, - -#ifdef CONFIG_USART3_RS485 - .rs485_dir_gpio = GPIO_USART3_RS485_DIR, -# if (CONFIG_USART3_RS485_DIR_POLARITY == 0) - .rs485_dir_polarity = false, -# else - .rs485_dir_polarity = true, -# endif -#endif -}; -#endif - -/* This describes the state of the STM32 UART4 port. */ - -#ifdef CONFIG_STM32_UART4 -static struct up_dev_s g_uart4priv = -{ - .dev = - { -#if CONSOLE_UART == 4 - .isconsole = true, -#endif - .recv = - { - .size = CONFIG_UART4_RXBUFSIZE, - .buffer = g_uart4rxbuffer, - }, - .xmit = - { - .size = CONFIG_UART4_TXBUFSIZE, - .buffer = g_uart4txbuffer, - }, -#ifdef CONFIG_UART4_RXDMA - .ops = &g_uart_dma_ops, -#else - .ops = &g_uart_ops, -#endif - .priv = &g_uart4priv, - }, - - .irq = STM32_IRQ_UART4, - .parity = CONFIG_UART4_PARITY, - .bits = CONFIG_UART4_BITS, - .stopbits2 = CONFIG_UART4_2STOP, - .iflow = false, - .oflow = false, - .baud = CONFIG_UART4_BAUD, - .apbclock = STM32_PCLK1_FREQUENCY, - .usartbase = STM32_UART4_BASE, - .tx_gpio = GPIO_UART4_TX, - .rx_gpio = GPIO_UART4_RX, - .cts_gpio = 0, /* flow control not supported on this port */ - .rts_gpio = 0, /* flow control not supported on this port */ -#ifdef CONFIG_UART4_RXDMA - .rxdma_channel = DMAMAP_UART4_RX, - .rxfifo = g_uart4rxfifo, -#endif - .vector = up_interrupt_uart4, - -#ifdef CONFIG_UART4_RS485 - .rs485_dir_gpio = GPIO_UART4_RS485_DIR, -# if (CONFIG_UART4_RS485_DIR_POLARITY == 0) - .rs485_dir_polarity = false, -# else - .rs485_dir_polarity = true, -# endif -#endif -}; -#endif - -/* This describes the state of the STM32 UART5 port. */ - -#ifdef CONFIG_STM32_UART5 -static struct up_dev_s g_uart5priv = -{ - .dev = - { -#if CONSOLE_UART == 5 - .isconsole = true, -#endif - .recv = - { - .size = CONFIG_UART5_RXBUFSIZE, - .buffer = g_uart5rxbuffer, - }, - .xmit = - { - .size = CONFIG_UART5_TXBUFSIZE, - .buffer = g_uart5txbuffer, - }, -#ifdef CONFIG_UART5_RXDMA - .ops = &g_uart_dma_ops, -#else - .ops = &g_uart_ops, -#endif - .priv = &g_uart5priv, - }, - - .irq = STM32_IRQ_UART5, - .parity = CONFIG_UART5_PARITY, - .bits = CONFIG_UART5_BITS, - .stopbits2 = CONFIG_UART5_2STOP, - .iflow = false, - .oflow = false, - .baud = CONFIG_UART5_BAUD, - .apbclock = STM32_PCLK1_FREQUENCY, - .usartbase = STM32_UART5_BASE, - .tx_gpio = GPIO_UART5_TX, - .rx_gpio = GPIO_UART5_RX, - .cts_gpio = 0, /* flow control not supported on this port */ - .rts_gpio = 0, /* flow control not supported on this port */ -#ifdef CONFIG_UART5_RXDMA - .rxdma_channel = DMAMAP_UART5_RX, - .rxfifo = g_uart5rxfifo, -#endif - .vector = up_interrupt_uart5, - -#ifdef CONFIG_UART5_RS485 - .rs485_dir_gpio = GPIO_UART5_RS485_DIR, -# if (CONFIG_UART5_RS485_DIR_POLARITY == 0) - .rs485_dir_polarity = false, -# else - .rs485_dir_polarity = true, -# endif -#endif -}; -#endif - -/* This describes the state of the STM32 USART6 port. */ - -#ifdef CONFIG_STM32_USART6 -static struct up_dev_s g_usart6priv = -{ - .dev = - { -#if CONSOLE_UART == 6 - .isconsole = true, -#endif - .recv = - { - .size = CONFIG_USART6_RXBUFSIZE, - .buffer = g_usart6rxbuffer, - }, - .xmit = - { - .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, - }, - - .irq = STM32_IRQ_USART6, - .parity = CONFIG_USART6_PARITY, - .bits = CONFIG_USART6_BITS, - .stopbits2 = CONFIG_USART6_2STOP, - .iflow = false, - .oflow = false, - .baud = CONFIG_USART6_BAUD, - .apbclock = STM32_PCLK2_FREQUENCY, - .usartbase = STM32_USART6_BASE, - .tx_gpio = GPIO_USART6_TX, - .rx_gpio = GPIO_USART6_RX, -#ifdef GPIO_USART6_CTS - .cts_gpio = GPIO_USART6_CTS, -#endif -#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, - -#ifdef CONFIG_USART6_RS485 - .rs485_dir_gpio = GPIO_USART6_RS485_DIR, -# if (CONFIG_USART6_RS485_DIR_POLARITY == 0) - .rs485_dir_polarity = false, -# else - .rs485_dir_polarity = true, -# endif -#endif -}; -#endif - -/* This table lets us iterate over the configured USARTs */ - -static struct up_dev_s *uart_devs[STM32_NUSART] = -{ -#ifdef CONFIG_STM32_USART1 - [0] = &g_usart1priv, -#endif -#ifdef CONFIG_STM32_USART2 - [1] = &g_usart2priv, -#endif -#ifdef CONFIG_STM32_USART3 - [2] = &g_usart3priv, -#endif -#ifdef CONFIG_STM32_UART4 - [3] = &g_uart4priv, -#endif -#ifdef CONFIG_STM32_UART5 - [4] = &g_uart5priv, -#endif -#ifdef CONFIG_STM32_USART6 - [5] = &g_usart6priv, -#endif -}; - -#ifdef CONFIG_PM -static struct pm_callback_s g_serialcb = -{ - .notify = up_pm_notify, - .prepare = up_pm_prepare, -}; -#endif - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: up_serialin - ****************************************************************************/ - -static inline uint32_t up_serialin(struct up_dev_s *priv, int offset) -{ - return getreg32(priv->usartbase + offset); -} - -/**************************************************************************** - * Name: up_serialout - ****************************************************************************/ - -static inline void up_serialout(struct up_dev_s *priv, int offset, uint32_t value) -{ - putreg32(value, priv->usartbase + offset); -} - -/**************************************************************************** - * Name: up_restoreusartint - ****************************************************************************/ - -static void up_restoreusartint(struct up_dev_s *priv, uint16_t ie) -{ - uint32_t cr; - - /* Save the interrupt mask */ - - priv->ie = ie; - - /* And restore the interrupt state (see the interrupt enable/usage table above) */ - - cr = up_serialin(priv, STM32_USART_CR1_OFFSET); - cr &= ~(USART_CR1_USED_INTS); - cr |= (ie & (USART_CR1_USED_INTS)); - up_serialout(priv, STM32_USART_CR1_OFFSET, cr); - - cr = up_serialin(priv, STM32_USART_CR3_OFFSET); - cr &= ~USART_CR3_EIE; - cr |= (ie & USART_CR3_EIE); - up_serialout(priv, STM32_USART_CR3_OFFSET, cr); -} - -/**************************************************************************** - * Name: up_disableusartint - ****************************************************************************/ - -static inline void up_disableusartint(struct up_dev_s *priv, uint16_t *ie) -{ - if (ie) - { - uint32_t cr1; - uint32_t cr3; - - /* USART interrupts: - * - * Enable Bit Status Meaning Usage - * ------------------ --- --------------- ------------------------------ ---------- - * USART_CR1_IDLEIE 4 USART_SR_IDLE Idle Line Detected (not used) - * USART_CR1_RXNEIE 5 USART_SR_RXNE Received Data Ready to be Read - * " " USART_SR_ORE Overrun Error Detected - * USART_CR1_TCIE 6 USART_SR_TC Transmission Complete (used only for RS-485) - * USART_CR1_TXEIE 7 USART_SR_TXE Transmit Data Register Empty - * USART_CR1_PEIE 8 USART_SR_PE Parity Error - * - * USART_CR2_LBDIE 6 USART_SR_LBD Break Flag (not used) - * USART_CR3_EIE 0 USART_SR_FE Framing Error - * " " USART_SR_NE Noise Error - * " " USART_SR_ORE Overrun Error Detected - * USART_CR3_CTSIE 10 USART_SR_CTS CTS flag (not used) - */ - - cr1 = up_serialin(priv, STM32_USART_CR1_OFFSET); - cr3 = up_serialin(priv, STM32_USART_CR3_OFFSET); - - /* Return the current interrupt mask value for the used interrupts. Notice - * that this depends on the fact that none of the used interrupt enable bits - * overlap. This logic would fail if we needed the break interrupt! - */ - - *ie = (cr1 & (USART_CR1_USED_INTS)) | (cr3 & USART_CR3_EIE); - } - - /* Disable all interrupts */ - - up_restoreusartint(priv, 0); -} - -/**************************************************************************** - * 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_set_format - * - * Description: - * Set the serial line format and speed. - * - ****************************************************************************/ - -#ifndef CONFIG_SUPPRESS_UART_CONFIG -static void up_set_format(struct uart_dev_s *dev) -{ - struct up_dev_s *priv = (struct up_dev_s*)dev->priv; - uint32_t usartdiv32; - uint32_t mantissa; - uint32_t fraction; - uint32_t brr; - uint32_t regval; - - /* Configure the USART Baud Rate. The baud rate for the receiver and - * transmitter (Rx and Tx) are both set to the same value as programmed - * in the Mantissa and Fraction values of USARTDIV. - * - * baud = fCK / (16 * usartdiv) - * usartdiv = fCK / (16 * baud) - * - * Where fCK is the input clock to the peripheral (PCLK1 for USART2, 3, 4, 5 - * or PCLK2 for USART1) - * - * First calculate (NOTE: all stand baud values are even so dividing by two - * does not lose precision): - * - * usartdiv32 = 32 * usartdiv = fCK / (baud/2) - */ - - usartdiv32 = priv->apbclock / (priv->baud >> 1); - - /* The mantissa part is then */ - - mantissa = usartdiv32 >> 5; - brr = mantissa << USART_BRR_MANT_SHIFT; - - /* The fractional remainder (with rounding) */ - - fraction = (usartdiv32 - (mantissa << 5) + 1) >> 1; - brr |= fraction << USART_BRR_FRAC_SHIFT; - up_serialout(priv, STM32_USART_BRR_OFFSET, brr); - - /* Configure parity mode */ - - regval = up_serialin(priv, STM32_USART_CR1_OFFSET); - regval &= ~(USART_CR1_PCE|USART_CR1_PS); - - if (priv->parity == 1) /* Odd parity */ - { - regval |= (USART_CR1_PCE|USART_CR1_PS); - } - else if (priv->parity == 2) /* Even parity */ - { - regval |= USART_CR1_PCE; - } - - up_serialout(priv, STM32_USART_CR1_OFFSET, regval); - - /* Configure STOP bits */ - - regval = up_serialin(priv, STM32_USART_CR2_OFFSET); - regval &= ~(USART_CR2_STOP_MASK); - - if (priv->stopbits2) - { - regval |= USART_CR2_STOP2; - } - up_serialout(priv, STM32_USART_CR2_OFFSET, regval); - - /* Configure hardware flow control */ - - regval = up_serialin(priv, STM32_USART_CR3_OFFSET); - regval &= ~(USART_CR3_CTSE|USART_CR3_RTSE); - - if (priv->iflow && (priv->rts_gpio != 0)) - { - regval |= USART_CR3_RTSE; - } - if (priv->oflow && (priv->cts_gpio != 0)) - { - regval |= USART_CR3_CTSE; - } - - up_serialout(priv, STM32_USART_CR3_OFFSET, regval); - -} -#endif /* CONFIG_SUPPRESS_UART_CONFIG */ - -/**************************************************************************** - * Name: up_setup - * - * Description: - * Configure the USART baud, bits, parity, etc. This method is called the - * first time that the serial port is opened. - * - ****************************************************************************/ - -static int up_setup(struct uart_dev_s *dev) -{ - struct up_dev_s *priv = (struct up_dev_s*)dev->priv; -#ifndef CONFIG_SUPPRESS_UART_CONFIG - uint32_t regval; - - /* Note: The logic here depends on the fact that that the USART module - * was enabled in stm32_lowsetup(). - */ - - /* Configure pins for USART use */ - - stm32_configgpio(priv->tx_gpio); - stm32_configgpio(priv->rx_gpio); - - if (priv->cts_gpio != 0) - { - stm32_configgpio(priv->cts_gpio); - } - - if (priv->rts_gpio != 0) - { - stm32_configgpio(priv->rts_gpio); - } - -#if HAVE_RS485 - if (priv->rs485_dir_gpio != 0) - { - stm32_configgpio(priv->rs485_dir_gpio); - stm32_gpiowrite(priv->rs485_dir_gpio, !priv->rs485_dir_polarity); - } -#endif - - /* Configure CR2 */ - /* Clear CLKEN, CPOL, CPHA, LBCL, and interrupt enable bits */ - - regval = up_serialin(priv, STM32_USART_CR2_OFFSET); - regval &= ~(USART_CR2_CLKEN|USART_CR2_CPOL| - USART_CR2_CPHA|USART_CR2_LBCL|USART_CR2_LBDIE); - - up_serialout(priv, STM32_USART_CR2_OFFSET, regval); - - /* Configure CR1 */ - /* Clear M, TE, REm and all interrupt enable bits */ - - regval = up_serialin(priv, STM32_USART_CR1_OFFSET); - regval &= ~(USART_CR1_M|USART_CR1_TE| - USART_CR1_RE|USART_CR1_ALLINTS); - - /* Configure word length */ - - if (priv->bits == 9) /* Default: 1 start, 8 data, n stop */ - { - regval |= USART_CR1_M; /* 1 start, 9 data, n stop */ - } - - up_serialout(priv, STM32_USART_CR1_OFFSET, regval); - - /* Configure CR3 */ - /* Clear CTSE, RTSE, and all interrupt enable bits */ - - regval = up_serialin(priv, STM32_USART_CR3_OFFSET); - regval &= ~(USART_CR3_CTSIE|USART_CR3_CTSE|USART_CR3_RTSE|USART_CR3_EIE); - - /* Configure hardware flow control -- Not yet supported */ - - up_serialout(priv, STM32_USART_CR3_OFFSET, regval); - - /* Configure the USART line format and speed. */ - - up_set_format(dev); - - /* Enable Rx, Tx, and the USART */ - - 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); -#endif - - /* Set up the cached interrupt enables value */ - - priv->ie = 0; - return OK; -} - -/**************************************************************************** - * 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, unless we are the console */ - - if (!dev->isconsole) - { - 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, - SERIAL_DMA_CONTROL_WORD); - - /* 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: - * Disable the USART. This method is called when the serial - * port is closed - * - ****************************************************************************/ - -static void up_shutdown(struct uart_dev_s *dev) -{ - struct up_dev_s *priv = (struct up_dev_s*)dev->priv; - uint32_t regval; - - /* Disable all interrupts */ - - up_disableusartint(priv, NULL); - - /* Disable Rx, Tx, and the UART */ - - 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: - * Configure the USART to operation in interrupt driven mode. This method is - * called when the serial port is opened. Normally, this is just after the - * the setup() method is called, however, the serial console may operate in - * a non-interrupt driven mode during the boot phase. - * - * RX and TX interrupts are not enabled when by the attach method (unless the - * hardware supports multiple levels of interrupt enabling). The RX and TX - * interrupts are not enabled until the txint() and rxint() methods are called. - * - ****************************************************************************/ - -static int up_attach(struct uart_dev_s *dev) -{ - struct up_dev_s *priv = (struct up_dev_s*)dev->priv; - int ret; - - /* Attach and enable the IRQ */ - - ret = irq_attach(priv->irq, priv->vector); - if (ret == OK) - { - /* Enable the interrupt (RX and TX interrupts are still disabled - * in the USART - */ - - up_enable_irq(priv->irq); - } - return ret; -} - -/**************************************************************************** - * Name: up_detach - * - * Description: - * Detach USART interrupts. This method is called when the serial port is - * closed normally just before the shutdown method is called. The exception - * is the serial console which is never shutdown. - * - ****************************************************************************/ - -static void up_detach(struct uart_dev_s *dev) -{ - struct up_dev_s *priv = (struct up_dev_s*)dev->priv; - up_disable_irq(priv->irq); - irq_detach(priv->irq); -} - -/**************************************************************************** - * Name: up_interrupt_common - * - * Description: - * This is the USART interrupt handler. It will be invoked when an - * interrupt received on the 'irq' It should call uart_transmitchars or - * uart_receivechar to perform the appropriate data transfers. The - * interrupt handling logic must be able to map the 'irq' number into the - * approprite uart_dev_s structure in order to call these functions. - * - ****************************************************************************/ - -static int up_interrupt_common(struct up_dev_s *priv) -{ - int passes; - bool handled; - - /* Report serial activity to the power management logic */ - -#if defined(CONFIG_PM) && CONFIG_PM_SERIAL_ACTIVITY > 0 - pm_activity(CONFIG_PM_SERIAL_ACTIVITY); -#endif - - /* Loop until there are no characters to be transferred or, - * until we have been looping for a long time. - */ - - handled = true; - for (passes = 0; passes < 256 && handled; passes++) - { - handled = false; - - /* Get the masked USART status word. */ - - priv->sr = up_serialin(priv, STM32_USART_SR_OFFSET); - - /* USART interrupts: - * - * Enable Bit Status Meaning Usage - * ------------------ --- --------------- ------------------------------- ---------- - * USART_CR1_IDLEIE 4 USART_SR_IDLE Idle Line Detected (not used) - * USART_CR1_RXNEIE 5 USART_SR_RXNE Received Data Ready to be Read - * " " USART_SR_ORE Overrun Error Detected - * USART_CR1_TCIE 6 USART_SR_TC Transmission Complete (used only for RS-485) - * USART_CR1_TXEIE 7 USART_SR_TXE Transmit Data Register Empty - * USART_CR1_PEIE 8 USART_SR_PE Parity Error - * - * USART_CR2_LBDIE 6 USART_SR_LBD Break Flag (not used) - * USART_CR3_EIE 0 USART_SR_FE Framing Error - * " " USART_SR_NE Noise Error - * " " USART_SR_ORE Overrun Error Detected - * USART_CR3_CTSIE 10 USART_SR_CTS CTS flag (not used) - * - * NOTE: Some of these status bits must be cleared by explicity writing zero - * to the SR register: USART_SR_CTS, USART_SR_LBD. Note of those are currently - * being used. - */ - -#ifdef HAVE_RS485 - /* Transmission of whole buffer is over - TC is set, TXEIE is cleared. - * Note - this should be first, to have the most recent TC bit value from - * SR register - sending data affects TC, but without refresh we will not - * know that... - */ - - if ((priv->sr & USART_SR_TC) != 0 && (priv->ie & USART_CR1_TCIE) != 0 && - (priv->ie & USART_CR1_TXEIE) == 0) - { - stm32_gpiowrite(priv->rs485_dir_gpio, !priv->rs485_dir_polarity); - up_restoreusartint(priv, priv->ie & ~USART_CR1_TCIE); - } -#endif - - /* Handle incoming, receive bytes. */ - - if ((priv->sr & USART_SR_RXNE) != 0 && (priv->ie & USART_CR1_RXNEIE) != 0) - { - /* Received data ready... process incoming bytes. NOTE the check for - * RXNEIE: We cannot call uart_recvchards of RX interrupts are disabled. - */ - - uart_recvchars(&priv->dev); - handled = true; - } - - /* We may still have to read from the DR register to clear any pending - * error conditions. - */ - - else if ((priv->sr & (USART_SR_ORE | USART_SR_NE | USART_SR_FE)) != 0) - { - /* If an error occurs, read from DR to clear the error (data has - * been lost). If ORE is set along with RXNE then it tells you - * that the byte *after* the one in the data register has been - * lost, but the data register value is correct. That case will - * be handled above if interrupts are enabled. Otherwise, that - * good byte will be lost. - */ - - (void)up_serialin(priv, STM32_USART_DR_OFFSET); - } - - /* Handle outgoing, transmit bytes */ - - if ((priv->sr & USART_SR_TXE) != 0 && (priv->ie & USART_CR1_TXEIE) != 0) - { - /* Transmit data register empty ... process outgoing bytes */ - - uart_xmitchars(&priv->dev); - handled = true; - } - } - - return OK; -} - -/**************************************************************************** - * Name: up_ioctl - * - * Description: - * All ioctl calls will be routed through this method - * - ****************************************************************************/ - -static int up_ioctl(struct file *filep, int cmd, unsigned long arg) -{ - struct inode *inode = filep->f_inode; - struct uart_dev_s *dev = inode->i_private; -#ifdef CONFIG_SERIAL_TERMIOS - struct up_dev_s *priv = (struct up_dev_s*)dev->priv; -#endif - int ret = OK; - - switch (cmd) - { - case TIOCSERGSTRUCT: - { - struct up_dev_s *user = (struct up_dev_s*)arg; - if (!user) - { - ret = -EINVAL; - } - else - { - memcpy(user, dev, sizeof(struct up_dev_s)); - } - } - break; - -#ifdef CONFIG_STM32_USART_SINGLEWIRE - case TIOCSSINGLEWIRE: - { - /* Change the TX port to be open-drain/push-pull and enable/disable - * half-duplex mode. - */ - - uint32_t cr = up_serialin(priv, STM32_USART_CR3_OFFSET); - - if (arg == SER_SINGLEWIRE_ENABLED) - { - stm32_configgpio(priv->tx_gpio | GPIO_OPENDRAIN); - cr |= USART_CR3_HDSEL; - } - else - { - stm32_configgpio(priv->tx_gpio | GPIO_PUSHPULL); - cr &= ~USART_CR3_HDSEL; - } - - up_serialout(priv, STM32_USART_CR3_OFFSET, cr); - } - break; -#endif - -#ifdef CONFIG_SERIAL_TERMIOS - case TCGETS: - { - struct termios *termiosp = (struct termios*)arg; - - if (!termiosp) - { - ret = -EINVAL; - break; - } - - cfsetispeed(termiosp, priv->baud); - - /* Note that since we only support 8/9 bit modes and - * there is no way to report 9-bit mode, we always claim 8. - */ - - termiosp->c_cflag = - ((priv->parity != 0) ? PARENB : 0) | - ((priv->parity == 1) ? PARODD : 0) | - ((priv->stopbits2) ? CSTOPB : 0) | - ((priv->oflow) ? CCTS_OFLOW : 0) | - ((priv->iflow) ? CRTS_IFLOW : 0) | - CS8; - - /* TODO: CCTS_IFLOW, CCTS_OFLOW */ - } - break; - - case TCSETS: - { - struct termios *termiosp = (struct termios*)arg; - - if (!termiosp) - { - ret = -EINVAL; - break; - } - - /* Perform some sanity checks before accepting any changes */ - - if (((termiosp->c_cflag & CSIZE) != CS8) || - ((termiosp->c_cflag & CCTS_OFLOW) && (priv->cts_gpio == 0)) || - ((termiosp->c_cflag & CRTS_IFLOW) && (priv->rts_gpio == 0))) - { - ret = -EINVAL; - break; - } - - if (termiosp->c_cflag & PARENB) - { - priv->parity = (termiosp->c_cflag & PARODD) ? 1 : 2; - } - else - { - priv->parity = 0; - } - - priv->stopbits2 = (termiosp->c_cflag & CSTOPB) != 0; - priv->oflow = (termiosp->c_cflag & CCTS_OFLOW) != 0; - priv->iflow = (termiosp->c_cflag & CRTS_IFLOW) != 0; - - /* Note that since there is no way to request 9-bit mode - * and no way to support 5/6/7-bit modes, we ignore them - * all here. - */ - - /* Note that only cfgetispeed is used because we have knowledge - * that only one speed is supported. - */ - - priv->baud = cfgetispeed(termiosp); - - /* effect the changes immediately - note that we do not implement - * TCSADRAIN / TCSAFLUSH - */ - - up_set_format(dev); - } - break; -#endif /* CONFIG_SERIAL_TERMIOS */ - -#ifdef CONFIG_USART_BREAKS - case TIOCSBRK: /* BSD compatibility: Turn break on, unconditionally */ - { - irqstate_t flags = irqsave(); - uint32_t cr2 = up_serialin(priv, STM32_USART_CR2_OFFSET); - up_serialout(priv, STM32_USART_CR2_OFFSET, cr2 | USART_CR2_LINEN); - irqrestore(flags); - } - break; - - case TIOCCBRK: /* BSD compatibility: Turn break off, unconditionally */ - { - irqstate_t flags; - flags = irqsave(); - uint32_t cr1 = up_serialin(priv, STM32_USART_CR2_OFFSET); - up_serialout(priv, STM32_USART_CR2_OFFSET, cr2 & ~USART_CR2_LINEN); - irqrestore(flags); - } - break; -#endif - - default: - ret = -ENOTTY; - break; - } - - return ret; -} - -/**************************************************************************** - * Name: up_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'. - * - ****************************************************************************/ - -#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; - uint32_t dr; - - /* Get the Rx byte */ - - dr = up_serialin(priv, STM32_USART_DR_OFFSET); - - /* Get the Rx byte plux error information. Return those in status */ - - *status = priv->sr << 16 | dr; - priv->sr = 0; - - /* Then return the actual received byte */ - - return dr & 0xff; -} -#endif - -/**************************************************************************** - * Name: up_rxint - * - * Description: - * Call to enable or disable RX interrupts - * - ****************************************************************************/ - -#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; - irqstate_t flags; - uint16_t ie; - - /* USART receive interrupts: - * - * Enable Bit Status Meaning Usage - * ------------------ --- --------------- ------------------------------- ---------- - * USART_CR1_IDLEIE 4 USART_SR_IDLE Idle Line Detected (not used) - * USART_CR1_RXNEIE 5 USART_SR_RXNE Received Data Ready to be Read - * " " USART_SR_ORE Overrun Error Detected - * USART_CR1_PEIE 8 USART_SR_PE Parity Error - * - * USART_CR2_LBDIE 6 USART_SR_LBD Break Flag (not used) - * USART_CR3_EIE 0 USART_SR_FE Framing Error - * " " USART_SR_NE Noise Error - * " " USART_SR_ORE Overrun Error Detected - */ - - flags = irqsave(); - ie = priv->ie; - if (enable) - { - /* Receive an interrupt when their is anything in the Rx data register (or an Rx - * timeout occurs). - */ - -#ifndef CONFIG_SUPPRESS_SERIAL_INTS -#ifdef CONFIG_USART_ERRINTS - ie |= (USART_CR1_RXNEIE|USART_CR1_PEIE|USART_CR3_EIE); -#else - ie |= USART_CR1_RXNEIE; -#endif -#endif - } - else - { - ie &= ~(USART_CR1_RXNEIE|USART_CR1_PEIE|USART_CR3_EIE); - } - - /* Then set the new interrupt state */ - - up_restoreusartint(priv, ie); - irqrestore(flags); -} -#endif - -/**************************************************************************** - * Name: up_rxavailable - * - * Description: - * Return true if the receive register is not empty - * - ****************************************************************************/ - -#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 - * - * Description: - * This method will send one byte on the USART - * - ****************************************************************************/ - -static void up_send(struct uart_dev_s *dev, int ch) -{ - struct up_dev_s *priv = (struct up_dev_s*)dev->priv; -#ifdef HAVE_RS485 - if (priv->rs485_dir_gpio != 0) - stm32_gpiowrite(priv->rs485_dir_gpio, priv->rs485_dir_polarity); -#endif - up_serialout(priv, STM32_USART_DR_OFFSET, (uint32_t)ch); -} - -/**************************************************************************** - * Name: up_txint - * - * Description: - * Call to enable or disable TX interrupts - * - ****************************************************************************/ - -static void up_txint(struct uart_dev_s *dev, bool enable) -{ - struct up_dev_s *priv = (struct up_dev_s*)dev->priv; - irqstate_t flags; - - /* USART transmit interrupts: - * - * Enable Bit Status Meaning Usage - * ------------------ --- --------------- ---------------------------- ---------- - * USART_CR1_TCIE 6 USART_SR_TC Transmission Complete (used only for RS-485) - * USART_CR1_TXEIE 7 USART_SR_TXE Transmit Data Register Empty - * USART_CR3_CTSIE 10 USART_SR_CTS CTS flag (not used) - */ - - flags = irqsave(); - if (enable) - { - /* Set to receive an interrupt when the TX data register is empty */ - -#ifndef CONFIG_SUPPRESS_SERIAL_INTS - uint16_t ie = priv->ie | USART_CR1_TXEIE; - - /* If RS-485 is supported on this U[S]ART, then also enable the - * transmission complete interrupt. - */ - -# ifdef HAVE_RS485 - if (priv->rs485_dir_gpio != 0) - { - ie |= USART_CR1_TCIE; - } -# endif - - up_restoreusartint(priv, ie); - - /* Fake a TX interrupt here by just calling uart_xmitchars() with - * interrupts disabled (note this may recurse). - */ - - uart_xmitchars(dev); -#endif - } - else - { - /* Disable the TX interrupt */ - - up_restoreusartint(priv, priv->ie & ~USART_CR1_TXEIE); - } - - irqrestore(flags); -} - -/**************************************************************************** - * Name: up_txready - * - * Description: - * Return true if the tranmsit data register is empty - * - ****************************************************************************/ - -static bool up_txready(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_TXE) != 0); -} - -/**************************************************************************** - * Name: up_interrupt_u[s]art[n] - * - * Description: - * Interrupt handlers for U[S]ART[n] where n=1,..,6. - * - ****************************************************************************/ - -#ifdef CONFIG_STM32_USART1 -static int up_interrupt_usart1(int irq, void *context) -{ - return up_interrupt_common(&g_usart1priv); -} -#endif - -#ifdef CONFIG_STM32_USART2 -static int up_interrupt_usart2(int irq, void *context) -{ - return up_interrupt_common(&g_usart2priv); -} -#endif - -#ifdef CONFIG_STM32_USART3 -static int up_interrupt_usart3(int irq, void *context) -{ - return up_interrupt_common(&g_usart3priv); -} -#endif - -#ifdef CONFIG_STM32_UART4 -static int up_interrupt_uart4(int irq, void *context) -{ - return up_interrupt_common(&g_uart4priv); -} -#endif - -#ifdef CONFIG_STM32_UART5 -static int up_interrupt_uart5(int irq, void *context) -{ - return up_interrupt_common(&g_uart5priv); -} -#endif - -#ifdef CONFIG_STM32_USART6 -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 */ - -/**************************************************************************** - * Name: up_pm_notify - * - * Description: - * Notify the driver of new power state. This callback is called after - * all drivers have had the opportunity to prepare for the new power state. - * - * Input Parameters: - * - * cb - Returned to the driver. The driver version of the callback - * strucure may include additional, driver-specific state data at - * the end of the structure. - * - * pmstate - Identifies the new PM state - * - * Returned Value: - * None - The driver already agreed to transition to the low power - * consumption state when when it returned OK to the prepare() call. - * - * - ****************************************************************************/ - -#ifdef CONFIG_PM -static void up_pm_notify(struct pm_callback_s *cb, enum pm_state_e pmstate) -{ - switch (pmstate) - { - case(PM_NORMAL): - { - /* Logic for PM_NORMAL goes here */ - - } - break; - - case(PM_IDLE): - { - /* Logic for PM_IDLE goes here */ - - } - break; - - case(PM_STANDBY): - { - /* Logic for PM_STANDBY goes here */ - - } - break; - - case(PM_SLEEP): - { - /* Logic for PM_SLEEP goes here */ - - } - break; - - default: - /* Should not get here */ - break; - } -} -#endif - -/**************************************************************************** - * Name: up_pm_prepare - * - * Description: - * Request the driver to prepare for a new power state. This is a warning - * that the system is about to enter into a new power state. The driver - * should begin whatever operations that may be required to enter power - * state. The driver may abort the state change mode by returning a - * non-zero value from the callback function. - * - * Input Parameters: - * - * cb - Returned to the driver. The driver version of the callback - * strucure may include additional, driver-specific state data at - * the end of the structure. - * - * pmstate - Identifies the new PM state - * - * Returned Value: - * Zero - (OK) means the event was successfully processed and that the - * driver is prepared for the PM state change. - * - * Non-zero - means that the driver is not prepared to perform the tasks - * needed achieve this power setting and will cause the state - * change to be aborted. NOTE: The prepare() method will also - * be called when reverting from lower back to higher power - * consumption modes (say because another driver refused a - * lower power state change). Drivers are not permitted to - * return non-zero values when reverting back to higher power - * consumption modes! - * - * - ****************************************************************************/ - -#ifdef CONFIG_PM -static int up_pm_prepare(struct pm_callback_s *cb, enum pm_state_e pmstate) -{ - /* Logic to prepare for a reduced power state goes here. */ - - return OK; -} -#endif - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: up_earlyserialinit - * - * Description: - * Performs the low level USART initialization early in debug so that the - * serial console will be available during bootup. This must be called - * before up_serialinit. - * - ****************************************************************************/ - -void up_earlyserialinit(void) -{ -#ifdef HAVE_UART - unsigned i; - - /* Disable all USART interrupts */ - - for (i = 0; i < STM32_NUSART; i++) - { - if (uart_devs[i]) - { - up_disableusartint(uart_devs[i], NULL); - } - } - - /* Configure whichever one is the console */ - -#if CONSOLE_UART > 0 - up_setup(&uart_devs[CONSOLE_UART - 1]->dev); -#endif -#endif /* HAVE UART */ -} - -/**************************************************************************** - * Name: up_serialinit - * - * Description: - * Register serial console and serial ports. This assumes - * that up_earlyserialinit was called previously. - * - ****************************************************************************/ - -void up_serialinit(void) -{ -#ifdef HAVE_UART - char devname[16]; - unsigned i; - unsigned minor = 0; -#ifdef CONFIG_PM - int ret; -#endif - - /* Register to receive power management callbacks */ - -#ifdef CONFIG_PM - ret = pm_register(&g_serialcb); - DEBUGASSERT(ret == OK); -#endif - - /* Register the console */ - -#if CONSOLE_UART > 0 - (void)uart_register("/dev/console", &uart_devs[CONSOLE_UART - 1]->dev); - (void)uart_register("/dev/ttyS0", &uart_devs[CONSOLE_UART - 1]->dev); - minor = 1; - - /* If we need to re-initialise the console to enable DMA do that here. */ - -# ifdef SERIAL_HAVE_CONSOLE_DMA - up_dma_setup(&uart_devs[CONSOLE_UART - 1]->dev); -# endif - -#endif /* CONSOLE_UART > 0 */ - - /* Register all remaining USARTs */ - - strcpy(devname, "/dev/ttySx"); - - for (i = 0; i < STM32_NUSART; i++) - { - - /* Don't create a device for the console - we did that above */ - - if ((uart_devs[i] == 0) || (uart_devs[i]->dev.isconsole)) - { - continue; - } - - /* Register USARTs as devices in increasing order */ - - devname[9] = '0' + minor++; - (void)uart_register(devname, &uart_devs[i]->dev); - } -#endif /* HAVE UART */ -} - -/**************************************************************************** - * 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_UART4_RXDMA - if (g_uart4priv.rxdma != NULL) - { - up_dma_rxcallback(g_uart4priv.rxdma, 0, &g_uart4priv); - } -#endif - -#ifdef CONFIG_UART5_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: - * Provide priority, low-level access to support OS debug writes - * - ****************************************************************************/ - -int up_putc(int ch) -{ -#if CONSOLE_UART > 0 - struct up_dev_s *priv = uart_devs[CONSOLE_UART - 1]; - uint16_t ie; - - up_disableusartint(priv, &ie); - - /* Check for LF */ - - if (ch == '\n') - { - /* Add CR */ - - up_lowputc('\r'); - } - - up_lowputc(ch); - up_restoreusartint(priv, ie); -#endif - return ch; -} - -#else /* USE_SERIALDRIVER */ - -/**************************************************************************** - * Name: up_putc - * - * Description: - * Provide priority, low-level access to support OS debug writes - * - ****************************************************************************/ - -int up_putc(int ch) -{ -#if CONSOLE_UART > 0 - /* Check for LF */ - - if (ch == '\n') - { - /* Add CR */ - - up_lowputc('\r'); - } - - up_lowputc(ch); -#endif - return ch; -} - -#endif /* USE_SERIALDRIVER */ |