Add circular DMA support to STM32 and STM32 serial driver; Add initial configuration for the Mikroelektronika PIC32MX7 MMB board

git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@4640 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
patacongo 2012-04-22 19:50:33 +00:00
parent 868fc6e118
commit a74f601c6c
9 changed files with 768 additions and 132 deletions

View File

@ -1,7 +1,7 @@
/************************************************************************************
* arch/arm/src/stm32/chip/stm32_uart.h
*
* Copyright (C) 2009, 2011 Gregory Nutt. All rights reserved.
* Copyright (C) 2009, 2011-2012 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without

View File

@ -1,7 +1,7 @@
/****************************************************************************
* arch/arm/src/stm32/stm32_dma.c
*
* Copyright (C) 2009, 2011 Gregory Nutt. All rights reserved.
* Copyright (C) 2009, 2011-2012 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without

View File

@ -251,6 +251,19 @@ EXTERN void stm32_dmastart(DMA_HANDLE handle, dma_callback_t callback,
EXTERN void stm32_dmastop(DMA_HANDLE handle);
/****************************************************************************
* Name: stm32_dmaresidual
*
* Description:
* Returns the number of bytes remaining to be transferred
*
* Assumptions:
* - DMA handle allocated by stm32_dmachannel()
*
****************************************************************************/
EXTERN size_t stm32_dmaresidual(DMA_HANDLE handle);
/****************************************************************************
* Name: stm32_dmasample
*

View File

@ -56,89 +56,6 @@
/**************************************************************************
* Private Definitions
**************************************************************************/
/* Configuration **********************************************************/
/* Make sure that we have not enabled more U[S]ARTs than are support by
* the device.
*/
#if STM32_NUSART < 6
# undef CONFIG_STM32_USART6
#endif
#if STM32_NUSART < 5
# undef CONFIG_STM32_UART5
#endif
#if STM32_NUSART < 4
# undef CONFIG_STM32_UART4
#endif
#if STM32_NUSART < 3
# undef CONFIG_STM32_USART3
#endif
#if STM32_NUSART < 2
# undef CONFIG_STM32_USART2
#endif
#if STM32_NUSART < 1
# undef CONFIG_STM32_USART1
#endif
#if defined(CONFIG_STM32_USART1) || defined (CONFIG_STM32_USART2) || defined(CONFIG_STM32_USART3) || \
defined(CONFIG_STM32_UART4) || defined (CONFIG_STM32_UART5) || defined(CONFIG_STM32_USART6)
# define HAVE_UART
#endif
/* Is there a serial console? */
#if defined(CONFIG_USART1_SERIAL_CONSOLE) && defined(CONFIG_STM32_USART1)
# undef CONFIG_USART2_SERIAL_CONSOLE
# undef CONFIG_USART3_SERIAL_CONSOLE
# undef CONFIG_UART4_SERIAL_CONSOLE
# undef CONFIG_UART5_SERIAL_CONSOLE
# undef CONFIG_USART6_SERIAL_CONSOLE
# define HAVE_CONSOLE 1
#elif defined(CONFIG_USART2_SERIAL_CONSOLE) && defined(CONFIG_STM32_USART2)
# undef CONFIG_USART1_SERIAL_CONSOLE
# undef CONFIG_USART3_SERIAL_CONSOLE
# undef CONFIG_USART4_SERIAL_CONSOLE
# undef CONFIG_USART5_SERIAL_CONSOLE
# undef CONFIG_USART6_SERIAL_CONSOLE
# define HAVE_CONSOLE 1
#elif defined(CONFIG_USART3_SERIAL_CONSOLE) && defined(CONFIG_STM32_USART3)
# undef CONFIG_USART1_SERIAL_CONSOLE
# undef CONFIG_USART2_SERIAL_CONSOLE
# undef CONFIG_UART4_SERIAL_CONSOLE
# undef CONFIG_UART5_SERIAL_CONSOLE
# undef CONFIG_USART6_SERIAL_CONSOLE
# define HAVE_CONSOLE 1
#elif defined(CONFIG_UART4_SERIAL_CONSOLE) && defined(CONFIG_STM32_UART4)
# undef CONFIG_USART1_SERIAL_CONSOLE
# undef CONFIG_USART2_SERIAL_CONSOLE
# undef CONFIG_USART3_SERIAL_CONSOLE
# undef CONFIG_UART5_SERIAL_CONSOLE
# undef CONFIG_USART6_SERIAL_CONSOLE
# define HAVE_CONSOLE 1
#elif defined(CONFIG_UART5_SERIAL_CONSOLE) && defined(CONFIG_STM32_UART5)
# undef CONFIG_USART1_SERIAL_CONSOLE
# undef CONFIG_USART2_SERIAL_CONSOLE
# undef CONFIG_USART3_SERIAL_CONSOLE
# undef CONFIG_UART4_SERIAL_CONSOLE
# undef CONFIG_USART6_SERIAL_CONSOLE
# define HAVE_CONSOLE 1
#elif defined(CONFIG_USART6_SERIAL_CONSOLE) && defined(CONFIG_STM32_USART6)
# undef CONFIG_USART1_SERIAL_CONSOLE
# undef CONFIG_USART2_SERIAL_CONSOLE
# undef CONFIG_USART3_SERIAL_CONSOLE
# undef CONFIG_UART4_SERIAL_CONSOLE
# undef CONFIG_UART5_SERIAL_CONSOLE
# define HAVE_CONSOLE 1
#else
# undef CONFIG_USART1_SERIAL_CONSOLE
# undef CONFIG_USART2_SERIAL_CONSOLE
# undef CONFIG_USART3_SERIAL_CONSOLE
# undef CONFIG_UART4_SERIAL_CONSOLE
# undef CONFIG_UART5_SERIAL_CONSOLE
# undef CONFIG_USART6_SERIAL_CONSOLE
# undef HAVE_CONSOLE
#endif
/* Select USART parameters for the selected console */
#if defined(CONFIG_USART1_SERIAL_CONSOLE)

View File

@ -57,6 +57,7 @@
#include "chip.h"
#include "stm32_uart.h"
#include "stm32_dma.h"
#include "up_arch.h"
#include "up_internal.h"
#include "os_internal.h"
@ -65,36 +66,69 @@
* Definitions
****************************************************************************/
/* Some sanity checks *******************************************************/
/* Is there a USART enabled? */
/* DMA configuration */
#if defined(CONFIG_STM32_USART1) || defined(CONFIG_STM32_USART2) || \
defined(CONFIG_STM32_USART3) || defined(CONFIG_STM32_UART4) || \
defined(CONFIG_STM32_UART5) || defined(CONFIG_STM32_USART6)
# define HAVE_UART 1
#endif
/* Is there a serial console? */
#if defined(CONFIG_USART1_SERIAL_CONSOLE) && defined(CONFIG_STM32_USART1)
# define CONSOLE_UART 1
#elif defined(CONFIG_USART2_SERIAL_CONSOLE) && defined(CONFIG_STM32_USART2)
# define CONSOLE_UART 2
#elif defined(CONFIG_USART3_SERIAL_CONSOLE) && defined(CONFIG_STM32_USART3)
# define CONSOLE_UART 3
#elif defined(CONFIG_USART4_SERIAL_CONSOLE) && defined(CONFIG_STM32_UART4)
# define CONSOLE_UART 4
#elif defined(CONFIG_USART5_SERIAL_CONSOLE) && defined(CONFIG_STM32_UART5)
# define CONSOLE_UART 5
#elif defined(CONFIG_USART6_SERIAL_CONSOLE) && defined(CONFIG_STM32_USART6)
# define CONSOLE_UART 6
#else
# define CONSOLE_UART 0
#endif
/* If we are not using the serial driver for the console, then we still must
* provide some minimal implementation of up_putc.
/* If DMA is enabled on any USART, then very that other pre-requisites
* have also been selected.
*/
#if SERIAL_HAVE_DMA
/* Verify that DMA has been enabled an the DMA channel has been defined.
* NOTE: These assignments may only be true for the F4.
*/
# if defined(CONFIG_USART1_RXDMA) || defined(CONFIG_USART6_RXDMA)
# ifndef CONFIG_STM32_DMA2
# error STM32 USART1/6 receive DMA requires CONFIG_STM32_DMA2
# endif
# endif
# if defined(CONFIG_USART2_RXDMA) || defined(CONFIG_USART3_RXDMA) || \
defined(CONFIG_USART4_RXDMA) || defined(CONFIG_USART5_RXDMA)
# ifndef CONFIG_STM32_DMA1
# error STM32 USART2/3/4/5 receive DMA requires CONFIG_STM32_DMA1
# endif
# endif
/* For the F4, there are alternate DMA channels for USART1 and 6.
* Logic in the board.h file make the DMA channel selection by defining
* the following in the board.h file.
*/
# if defined(CONFIG_USART1_RXDMA) && !defined(DMAMAP_USART1_RX)
# error "USART1 DMA channel not defined (DMAMAP_USART1_RX)"
# endif
# if defined(CONFIG_USART2_RXDMA) && !defined(DMAMAP_USART2_RX)
# error "USART2 DMA channel not defined (DMAMAP_USART2_RX)"
# endif
# if defined(CONFIG_USART3_RXDMA) && !defined(DMAMAP_USART3_RX)
# error "USART3 DMA channel not defined (DMAMAP_USART3_RX)"
# endif
# if defined(CONFIG_USART4_RXDMA) && !defined(DMAMAP_UART4_RX)
# error "UART4 DMA channel not defined (DMAMAP_UART4_RX)"
# endif
# if defined(CONFIG_USART5_RXDMA) && !defined(DMAMAP_UART5_RX)
# error "UART5 DMA channel not defined (DMAMAP_UART5_RX)"
# endif
# if defined(CONFIG_USART6_RXDMA) && !defined(DMAMAP_USART6_RX)
# error "USART6 DMA channel not defined (DMAMAP_USART6_RX)"
# endif
/* The DMA buffer size when using RX DMA to emulate a FIFO.
*
* When streaming data, the generic serial layer will be called
* everytime the FIFO receives half this number of bytes.
*/
# define RXDMA_BUFFER_SIZE 32
#endif
#ifdef USE_SERIALDRIVER
#ifdef HAVE_UART
@ -120,7 +154,20 @@ struct up_dev_s
const uint32_t rts_gpio; /* U[S]ART RTS GPIO pin configuration */
const uint32_t cts_gpio; /* U[S]ART CTS GPIO pin configuration */
#ifdef SERIAL_HAVE_DMA
const unsigned int rxdma_channel; /* DMA channel assigned */
#endif
int (* const vector)(int irq, void *context); /* Interrupt handler */
/* RX DMA state */
#ifdef SERIAL_HAVE_DMA
DMA_HANDLE rxdma; /* currently-open receive DMA stream */
bool rxenable; /* DMA-based reception en/disable */
uint32_t rxdmanext; /* Next byte in the DMA buffer to be read */
char *const rxfifo; /* Receive DMA buffer */
#endif
};
/****************************************************************************
@ -133,13 +180,25 @@ static int up_attach(struct uart_dev_s *dev);
static void up_detach(struct uart_dev_s *dev);
static int up_interrupt_common(struct up_dev_s *dev);
static int up_ioctl(struct file *filep, int cmd, unsigned long arg);
#ifndef SERIAL_HAVE_ONLY_DMA
static int up_receive(struct uart_dev_s *dev, uint32_t *status);
static void up_rxint(struct uart_dev_s *dev, bool enable);
static bool up_rxavailable(struct uart_dev_s *dev);
#endif
static void up_send(struct uart_dev_s *dev, int ch);
static void up_txint(struct uart_dev_s *dev, bool enable);
static bool up_txready(struct uart_dev_s *dev);
#ifdef SERIAL_HAVE_DMA
static int up_dma_setup(struct uart_dev_s *dev);
static void up_dma_shutdown(struct uart_dev_s *dev);
static int up_dma_receive(struct uart_dev_s *dev, uint32_t *status);
static void up_dma_rxint(struct uart_dev_s *dev, bool enable);
static bool up_dma_rxavailable(struct uart_dev_s *dev);
static void up_dma_rxcallback(DMA_HANDLE handle, uint8_t status, void *arg);
#endif
#ifdef CONFIG_STM32_USART1
static int up_interrupt_usart1(int irq, void *context);
#endif
@ -163,6 +222,7 @@ static int up_interrupt_usart6(int irq, void *context);
* Private Variables
****************************************************************************/
#ifndef SERIAL_HAVE_ONLY_DMA
static const struct uart_ops_s g_uart_ops =
{
.setup = up_setup,
@ -178,32 +238,74 @@ static const struct uart_ops_s g_uart_ops =
.txready = up_txready,
.txempty = up_txready,
};
#endif
#ifdef SERIAL_HAVE_DMA
static const struct uart_ops_s g_uart_dma_ops =
{
.setup = up_dma_setup,
.shutdown = up_dma_shutdown,
.attach = up_attach,
.detach = up_detach,
.ioctl = up_ioctl,
.receive = up_dma_receive,
.rxint = up_dma_rxint,
.rxavailable = up_dma_rxavailable,
.send = up_send,
.txint = up_txint,
.txready = up_txready,
.txempty = up_txready,
};
#endif
/* I/O buffers */
#ifdef CONFIG_STM32_USART1
static char g_usart1rxbuffer[CONFIG_USART1_RXBUFSIZE];
static char g_usart1txbuffer[CONFIG_USART1_TXBUFSIZE];
# ifdef CONFIG_USART1_RXDMA
static char g_usart1rxfifo[RXDMA_BUFFER_SIZE];
# endif
#endif
#ifdef CONFIG_STM32_USART2
static char g_usart2rxbuffer[CONFIG_USART2_RXBUFSIZE];
static char g_usart2txbuffer[CONFIG_USART2_TXBUFSIZE];
# ifdef CONFIG_USART2_RXDMA
static char g_usart2rxfifo[RXDMA_BUFFER_SIZE];
# endif
#endif
#ifdef CONFIG_STM32_USART3
static char g_usart3rxbuffer[CONFIG_USART3_RXBUFSIZE];
static char g_usart3txbuffer[CONFIG_USART3_TXBUFSIZE];
# ifdef CONFIG_USART3_RXDMA
static char g_usart3rxfifo[RXDMA_BUFFER_SIZE];
# endif
#endif
#ifdef CONFIG_STM32_UART4
static char g_uart4rxbuffer[CONFIG_USART4_RXBUFSIZE];
static char g_uart4txbuffer[CONFIG_USART4_TXBUFSIZE];
# ifdef CONFIG_USART4_RXDMA
static char g_uart4rxfifo[RXDMA_BUFFER_SIZE];
# endif
#endif
#ifdef CONFIG_STM32_UART5
static char g_uart5rxbuffer[CONFIG_USART5_RXBUFSIZE];
static char g_uart5txbuffer[CONFIG_USART5_TXBUFSIZE];
# ifdef CONFIG_USART5_RXDMA
static char g_uart5rxfifo[RXDMA_BUFFER_SIZE];
# endif
#endif
#ifdef CONFIG_STM32_USART6
static char g_usart6rxbuffer[CONFIG_USART6_RXBUFSIZE];
static char g_usart6txbuffer[CONFIG_USART6_TXBUFSIZE];
# ifdef CONFIG_USART6_RXDMA
static char g_usart6rxfifo[RXDMA_BUFFER_SIZE];
# endif
#endif
/* This describes the state of the STM32 USART1 ports. */
@ -226,7 +328,11 @@ static struct up_dev_s g_usart1priv =
.size = CONFIG_USART1_TXBUFSIZE,
.buffer = g_usart1txbuffer,
},
#ifdef CONFIG_USART1_RXDMA
.ops = &g_uart_dma_ops,
#else
.ops = &g_uart_ops,
#endif
.priv = &g_usart1priv,
},
@ -244,6 +350,10 @@ static struct up_dev_s g_usart1priv =
#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,
};
@ -269,7 +379,11 @@ static struct up_dev_s g_usart2priv =
.size = CONFIG_USART2_TXBUFSIZE,
.buffer = g_usart2txbuffer,
},
#ifdef CONFIG_USART2_RXDMA
.ops = &g_uart_dma_ops,
#else
.ops = &g_uart_ops,
#endif
.priv = &g_usart2priv,
},
@ -287,6 +401,10 @@ static struct up_dev_s g_usart2priv =
#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,
};
@ -312,7 +430,11 @@ static struct up_dev_s g_usart3priv =
.size = CONFIG_USART3_TXBUFSIZE,
.buffer = g_usart3txbuffer,
},
#ifdef CONFIG_USART3_RXDMA
.ops = &g_uart_dma_ops,
#else
.ops = &g_uart_ops,
#endif
.priv = &g_usart3priv,
},
@ -330,6 +452,10 @@ static struct up_dev_s g_usart3priv =
#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,
};
@ -355,7 +481,11 @@ static struct up_dev_s g_uart4priv =
.size = CONFIG_USART4_TXBUFSIZE,
.buffer = g_uart4txbuffer,
},
#ifdef CONFIG_USART4_RXDMA
.ops = &g_uart_dma_ops,
#else
.ops = &g_uart_ops,
#endif
.priv = &g_uart4priv,
},
@ -373,6 +503,10 @@ static struct up_dev_s g_uart4priv =
#endif
#ifdef GPIO_USART4_RTS
.rts_gpio = GPIO_UART4_RTS,
#endif
#ifdef CONFIG_USART4_RXDMA
.rxdma_channel = DMAMAP_UART4_RX,
.rxfifo = g_uart4rxfifo,
#endif
.vector = up_interrupt_uart4,
};
@ -398,7 +532,11 @@ static struct up_dev_s g_uart5priv =
.size = CONFIG_USART5_TXBUFSIZE,
.buffer = g_uart5txbuffer,
},
#ifdef CONFIG_USART5_RXDMA
.ops = &g_uart_dma_ops,
#else
.ops = &g_uart_ops,
#endif
.priv = &g_uart5priv,
},
@ -416,6 +554,10 @@ static struct up_dev_s g_uart5priv =
#endif
#ifdef GPIO_USART5_RTS
.rts_gpio = GPIO_UART5_RTS,
#endif
#ifdef CONFIG_USART5_RXDMA
.rxdma_channel = DMAMAP_UART5_RX,
.rxfifo = g_uart5rxfifo,
#endif
.vector = up_interrupt_uart5,
};
@ -441,7 +583,11 @@ static struct up_dev_s g_usart6priv =
.size = CONFIG_USART6_TXBUFSIZE,
.buffer = g_usart6txbuffer,
},
#ifdef CONFIG_USART6_RXDMA
.ops = &g_uart_dma_ops,
#else
.ops = &g_uart_ops,
#endif
.priv = &g_usart6priv,
},
@ -459,6 +605,10 @@ static struct up_dev_s g_usart6priv =
#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,
};
@ -580,6 +730,26 @@ static inline void up_disableusartint(struct up_dev_s *priv, uint16_t *ie)
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_setup
*
@ -642,19 +812,20 @@ static int up_setup(struct uart_dev_s *dev)
/* Configure word length and parity mode */
if (priv->bits == 9) /* Default: 1 start, 8 data, n stop */
if (priv->bits == 9) /* Default: 1 start, 8 data, n stop */
{
regval |= USART_CR1_M; /* 1 start, 9 data, n stop */
regval |= USART_CR1_M; /* 1 start, 9 data, n stop */
}
if (priv->parity == 1) /* Odd parity */
if (priv->parity == 1) /* Odd parity */
{
regval |= (USART_CR1_PCE|USART_CR1_PS);
}
else if (priv->parity == 2) /* Even parity */
else if (priv->parity == 2) /* Even parity */
{
regval |= USART_CR1_PCE;
}
up_serialout(priv, STM32_USART_CR1_OFFSET, regval);
/* Configure CR3 */
@ -709,6 +880,71 @@ static int up_setup(struct uart_dev_s *dev)
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 */
result = up_setup(dev);
if (result != OK)
{
return result;
}
/* Acquire the DMA channel. This should always succeed. */
priv->rxdma = stm32_dmachannel(priv->rxdma_channel);
/* Configure for circular DMA reception into the RX fifo */
stm32_dmasetup(priv->rxdma,
priv->usartbase + STM32_USART_DR_OFFSET,
(uint32_t)priv->rxfifo,
RXDMA_BUFFER_SIZE,
DMA_SCR_DIR_P2M |
DMA_SCR_CIRC |
DMA_SCR_MINC |
DMA_SCR_PSIZE_8BITS |
DMA_SCR_MSIZE_8BITS |
DMA_SCR_PBURST_SINGLE |
DMA_SCR_MBURST_SINGLE);
/* Reset our DMA shadow pointer to match the address just
* programmed above.
*/
priv->rxdmanext = 0;
/* Enable receive DMA for the UART */
regval = up_serialin(priv, STM32_USART_CR3_OFFSET);
regval |= USART_CR3_DMAR;
up_serialout(priv, STM32_USART_CR3_OFFSET, regval);
/* Start the DMA channel, and arrange for callbacks at the half and
* full points in the FIFO. This ensures that we have half a FIFO
* worth of time to claim bytes before they are overwritten.
*/
stm32_dmastart(priv->rxdma, up_dma_rxcallback, (void *)priv, true);
return OK;
}
#endif
/****************************************************************************
* Name: up_shutdown
*
@ -729,11 +965,40 @@ static void up_shutdown(struct uart_dev_s *dev)
/* Disable Rx, Tx, and the UART */
regval = up_serialin(priv, STM32_USART_CR1_OFFSET);
regval &= ~(USART_CR1_UE|USART_CR1_TE|USART_CR1_RE);
regval = up_serialin(priv, STM32_USART_CR1_OFFSET);
regval &= ~(USART_CR1_UE|USART_CR1_TE|USART_CR1_RE);
up_serialout(priv, STM32_USART_CR1_OFFSET, regval);
}
/****************************************************************************
* Name: up_dma_shutdown
*
* Description:
* Disable the USART. This method is called when the serial
* port is closed
*
****************************************************************************/
#ifdef SERIAL_HAVE_DMA
static void up_dma_shutdown(struct uart_dev_s *dev)
{
struct up_dev_s *priv = (struct up_dev_s*)dev->priv;
/* Perform the normal UART shutdown */
up_shutdown(dev);
/* Stop the DMA channel */
stm32_dmastop(priv->rxdma);
/* Release the DMA channel */
stm32_dmafree(priv->rxdma);
priv->rxdma = NULL;
}
#endif
/****************************************************************************
* Name: up_attach
*
@ -951,6 +1216,7 @@ static int up_ioctl(struct file *filep, int cmd, unsigned long arg)
*
****************************************************************************/
#ifndef SERIAL_HAVE_ONLY_DMA
static int up_receive(struct uart_dev_s *dev, uint32_t *status)
{
struct up_dev_s *priv = (struct up_dev_s*)dev->priv;
@ -969,6 +1235,7 @@ static int up_receive(struct uart_dev_s *dev, uint32_t *status)
return dr & 0xff;
}
#endif
/****************************************************************************
* Name: up_rxint
@ -978,6 +1245,7 @@ static int up_receive(struct uart_dev_s *dev, uint32_t *status)
*
****************************************************************************/
#ifndef SERIAL_HAVE_ONLY_DMA
static void up_rxint(struct uart_dev_s *dev, bool enable)
{
struct up_dev_s *priv = (struct up_dev_s*)dev->priv;
@ -1025,6 +1293,7 @@ static void up_rxint(struct uart_dev_s *dev, bool enable)
up_restoreusartint(priv, ie);
irqrestore(flags);
}
#endif
/****************************************************************************
* Name: up_rxavailable
@ -1034,11 +1303,90 @@ static void up_rxint(struct uart_dev_s *dev, bool enable)
*
****************************************************************************/
#ifndef SERIAL_HAVE_ONLY_DMA
static bool up_rxavailable(struct uart_dev_s *dev)
{
struct up_dev_s *priv = (struct up_dev_s*)dev->priv;
return ((up_serialin(priv, STM32_USART_SR_OFFSET) & USART_SR_RXNE) != 0);
}
#endif
/****************************************************************************
* Name: up_dma_receive
*
* Description:
* Called (usually) from the interrupt level to receive one
* character from the USART. Error bits associated with the
* receipt are provided in the return 'status'.
*
****************************************************************************/
#ifdef SERIAL_HAVE_DMA
static int up_dma_receive(struct uart_dev_s *dev, uint32_t *status)
{
struct up_dev_s *priv = (struct up_dev_s*)dev->priv;
int c = 0;
if (up_dma_nextrx(priv) != priv->rxdmanext)
{
c = priv->rxfifo[priv->rxdmanext];
priv->rxdmanext++;
if (priv->rxdmanext == RXDMA_BUFFER_SIZE)
{
priv->rxdmanext = 0;
}
}
return c;
}
#endif
/****************************************************************************
* Name: up_dma_rxint
*
* Description:
* Call to enable or disable RX interrupts
*
****************************************************************************/
#ifdef SERIAL_HAVE_DMA
static void up_dma_rxint(struct uart_dev_s *dev, bool enable)
{
struct up_dev_s *priv = (struct up_dev_s*)dev->priv;
/* En/disable DMA reception.
*
* Note that it is not safe to check for available bytes and immediately
* pass them to uart_recvchars as that could potentially recurse back
* to us again. Instead, bytes must wait until the next up_dma_poll or
* DMA event.
*/
priv->rxenable = enable;
}
#endif
/****************************************************************************
* Name: up_dma_rxavailable
*
* Description:
* Return true if the receive register is not empty
*
****************************************************************************/
#ifdef SERIAL_HAVE_DMA
static bool up_dma_rxavailable(struct uart_dev_s *dev)
{
struct up_dev_s *priv = (struct up_dev_s*)dev->priv;
/* Compare our receive pointer to the current DMA pointer, if they
* do not match, then there are bytes to be received.
*/
return (up_dma_nextrx(priv) != priv->rxdmanext);
}
#endif
/****************************************************************************
* Name: up_send
@ -1163,6 +1511,28 @@ static int up_interrupt_usart6(int irq, void *context)
return up_interrupt_common(&g_usart6priv);
}
#endif
/****************************************************************************
* Name: up_dma_rxcallback
*
* Description:
* This function checks the current DMA state and calls the generic
* serial stack when bytes appear to be available.
*
****************************************************************************/
#ifdef SERIAL_HAVE_DMA
static void up_dma_rxcallback(DMA_HANDLE handle, uint8_t status, void *arg)
{
struct up_dev_s *priv = (struct up_dev_s*)arg;
if (priv->rxenable && up_dma_rxavailable(&priv->dev))
{
uart_recvchars(&priv->dev);
}
}
#endif
#endif /* HAVE UART */
/****************************************************************************
@ -1246,6 +1616,70 @@ void up_serialinit(void)
#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_USART4_RXDMA
if (g_uart4priv.rxdma != NULL)
{
up_dma_rxcallback(g_uart4priv.rxdma, 0, &g_uart4priv);
}
#endif
#ifdef CONFIG_USART5_RXDMA
if (g_uart5priv.rxdma != NULL)
{
up_dma_rxcallback(g_uart5priv.rxdma, 0, &g_uart5priv);
}
#endif
#ifdef CONFIG_USART6_RXDMA
if (g_usart6priv.rxdma != NULL)
{
up_dma_rxcallback(g_usart6priv.rxdma, 0, &g_usart6priv);
}
#endif
irqrestore(flags);
}
#endif
/****************************************************************************
* Name: up_putc
*

View File

@ -532,6 +532,9 @@ static inline void spi_dmarxwakeup(FAR struct stm32_spidev_s *priv)
static void spi_dmarxcallback(DMA_HANDLE handle, uint8_t isr, void *arg)
{
FAR struct stm32_spidev_s *priv = (FAR struct stm32_spidev_s *)arg;
/* Wake-up the SPI driver */
priv->rxresult = isr | 0x080; /* OR'ed with 0x80 to assure non-zero */
spi_dmarxwakeup(priv);
}
@ -549,6 +552,9 @@ static void spi_dmarxcallback(DMA_HANDLE handle, uint8_t isr, void *arg)
static void spi_dmatxcallback(DMA_HANDLE handle, uint8_t isr, void *arg)
{
FAR struct stm32_spidev_s *priv = (FAR struct stm32_spidev_s *)arg;
/* Wake-up the SPI driver */
priv->txresult = isr | 0x080; /* OR'ed with 0x80 to assure non-zero */
spi_dmatxwakeup(priv);
}

View File

@ -1,7 +1,7 @@
/************************************************************************************
* arch/arm/src/stm32/stm32_uart.h
*
* Copyright (C) 2009 Gregory Nutt. All rights reserved.
* Copyright (C) 2009, 2012 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@ -48,6 +48,163 @@
/************************************************************************************
* Pre-processor Definitions
************************************************************************************/
/* Make sure that we have not enabled more U[S]ARTs than are support by
* the device.
*/
#if STM32_NUSART < 6
# undef CONFIG_STM32_USART6
#endif
#if STM32_NUSART < 5
# undef CONFIG_STM32_UART5
#endif
#if STM32_NUSART < 4
# undef CONFIG_STM32_UART4
#endif
#if STM32_NUSART < 3
# undef CONFIG_STM32_USART3
#endif
#if STM32_NUSART < 2
# undef CONFIG_STM32_USART2
#endif
#if STM32_NUSART < 1
# undef CONFIG_STM32_USART1
#endif
/* Is there a USART enabled? */
#if defined(CONFIG_STM32_USART1) || defined(CONFIG_STM32_USART2) || \
defined(CONFIG_STM32_USART3) || defined(CONFIG_STM32_UART4) || \
defined(CONFIG_STM32_UART5) || defined(CONFIG_STM32_USART6)
# define HAVE_UART 1
#endif
/* Is there a serial console? */
#if defined(CONFIG_USART1_SERIAL_CONSOLE) && defined(CONFIG_STM32_USART1)
# undef CONFIG_USART2_SERIAL_CONSOLE
# undef CONFIG_USART3_SERIAL_CONSOLE
# undef CONFIG_UART4_SERIAL_CONSOLE
# undef CONFIG_UART5_SERIAL_CONSOLE
# undef CONFIG_USART6_SERIAL_CONSOLE
# define CONSOLE_UART 1
# define HAVE_CONSOLE 1
#elif defined(CONFIG_USART2_SERIAL_CONSOLE) && defined(CONFIG_STM32_USART2)
# undef CONFIG_USART1_SERIAL_CONSOLE
# undef CONFIG_USART3_SERIAL_CONSOLE
# undef CONFIG_USART4_SERIAL_CONSOLE
# undef CONFIG_USART5_SERIAL_CONSOLE
# undef CONFIG_USART6_SERIAL_CONSOLE
# define CONSOLE_UART 2
# define HAVE_CONSOLE 1
#elif defined(CONFIG_USART3_SERIAL_CONSOLE) && defined(CONFIG_STM32_USART3)
# undef CONFIG_USART1_SERIAL_CONSOLE
# undef CONFIG_USART2_SERIAL_CONSOLE
# undef CONFIG_UART4_SERIAL_CONSOLE
# undef CONFIG_UART5_SERIAL_CONSOLE
# undef CONFIG_USART6_SERIAL_CONSOLE
# define CONSOLE_UART 3
# define HAVE_CONSOLE 1
#elif defined(CONFIG_USART4_SERIAL_CONSOLE) && defined(CONFIG_STM32_UART4)
# undef CONFIG_USART1_SERIAL_CONSOLE
# undef CONFIG_USART2_SERIAL_CONSOLE
# undef CONFIG_USART3_SERIAL_CONSOLE
# undef CONFIG_UART5_SERIAL_CONSOLE
# undef CONFIG_USART6_SERIAL_CONSOLE
# define CONSOLE_UART 4
# define HAVE_CONSOLE 1
#elif defined(CONFIG_USART5_SERIAL_CONSOLE) && defined(CONFIG_STM32_UART5)
# undef CONFIG_USART1_SERIAL_CONSOLE
# undef CONFIG_USART2_SERIAL_CONSOLE
# undef CONFIG_USART3_SERIAL_CONSOLE
# undef CONFIG_UART4_SERIAL_CONSOLE
# undef CONFIG_USART6_SERIAL_CONSOLE
# define CONSOLE_UART 5
# define HAVE_CONSOLE 1
#elif defined(CONFIG_USART6_SERIAL_CONSOLE) && defined(CONFIG_STM32_USART6)
# undef CONFIG_USART1_SERIAL_CONSOLE
# undef CONFIG_USART2_SERIAL_CONSOLE
# undef CONFIG_USART3_SERIAL_CONSOLE
# undef CONFIG_UART4_SERIAL_CONSOLE
# undef CONFIG_UART5_SERIAL_CONSOLE
# define CONSOLE_UART 6
# define HAVE_CONSOLE 1
#else
# undef CONFIG_USART1_SERIAL_CONSOLE
# undef CONFIG_USART2_SERIAL_CONSOLE
# undef CONFIG_USART3_SERIAL_CONSOLE
# undef CONFIG_UART4_SERIAL_CONSOLE
# undef CONFIG_UART5_SERIAL_CONSOLE
# undef CONFIG_USART6_SERIAL_CONSOLE
# define CONSOLE_UART 0
# undef HAVE_CONSOLE
#endif
/* DMA support is only provided if CONFIG_ARCH_DMA is in the NuttX configuration.
* Furthermore, DMA support is currently only implemented for the F4 (but could be
* extended to the F1 and F2 with a little effort in the DMA code.
*/
#if !defined(HAVE_UART) || !defined(CONFIG_ARCH_DMA) || !defined(CONFIG_STM32_STM32F40XX)
# undef CONFIG_USART1_RXDMA
# undef CONFIG_USART2_RXDMA
# undef CONFIG_USART3_RXDMA
# undef CONFIG_USART4_RXDMA
# undef CONFIG_USART5_RXDMA
# undef CONFIG_USART6_RXDMA
#endif
/* Disable the DMA configuration on all unused USARTs */
#ifndef CONFIG_STM32_USART1
# undef CONFIG_USART1_RXDMA
#endif
#ifndef CONFIG_STM32_USART2
# undef CONFIG_USART2_RXDMA
#endif
#ifndef CONFIG_STM32_USART3
# undef CONFIG_USART3_RXDMA
#endif
#ifndef CONFIG_STM32_USART4
# undef CONFIG_USART4_RXDMA
#endif
#ifndef CONFIG_STM32_USART5
# undef CONFIG_USART5_RXDMA
#endif
#ifndef CONFIG_STM32_USART6
# undef CONFIG_USART6_RXDMA
#endif
/* Is DMA available on any (enabled) USART? */
#undef SERIAL_HAVE_DMA
#if defined(CONFIG_USART1_RXDMA) || defined(CONFIG_USART2_RXDMA) || \
defined(CONFIG_USART3_RXDMA) || defined(CONFIG_USART4_RXDMA) || \
defined(CONFIG_USART5_RXDMA) || defined(CONFIG_USART6_RXDMA)
# define SERIAL_HAVE_DMA 1
#endif
/* Is DMA used on all (enabled) USARTs */
#define SERIAL_HAVE_ONLY_DMA 1
#if defined(CONFIG_STM32_USART1) && !defined(CONFIG_USART1_RXDMA)
# undef SERIAL_HAVE_ONLY_DMA
#elif defined(CONFIG_STM32_USART2) && !defined(CONFIG_USART2_RXDMA)
# undef SERIAL_HAVE_ONLY_DMA
#elif defined(CONFIG_STM32_USART3) && !defined(CONFIG_USART3_RXDMA)
# undef SERIAL_HAVE_ONLY_DMA
#elif defined(CONFIG_STM32_UART4) && !defined(CONFIG_USART4_RXDMA)
# undef SERIAL_HAVE_ONLY_DMA
#elif defined(CONFIG_STM32_UART5) && !defined(CONFIG_USART5_RXDMA)
# undef SERIAL_HAVE_ONLY_DMA
#elif defined(CONFIG_STM32_USART6) && !defined(CONFIG_USART6_RXDMA)
# undef SERIAL_HAVE_ONLY_DMA
#endif
/************************************************************************************
* Public Types
@ -57,8 +214,41 @@
* Public Data
************************************************************************************/
#ifndef __ASSEMBLY__
#undef EXTERN
#if defined(__cplusplus)
#define EXTERN extern "C"
extern "C" {
#else
#define EXTERN extern
#endif
/************************************************************************************
* Public Functions
************************************************************************************/
/****************************************************************************
* Name: stm32_serial_dma_poll
*
* Description:
* Must be called periodically if any STM32 UART is configured for DMA.
* The DMA callback is triggered for each fifo size/2 bytes, but this can
* result in some bytes being transferred but not collected if the incoming
* data is not a whole multiple of half the FIFO size.
*
* May be safely called from either interrupt or thread context.
*
****************************************************************************/
#ifdef SERIAL_HAVE_DMA
EXTERN void stm32_serial_dma_poll(void);
#endif
#undef EXTERN
#if defined(__cplusplus)
}
#endif
#endif /* __ASSEMBLY__ */
#endif /* __ARCH_ARM_STC_STM32_STM32_UART_H */

View File

@ -94,6 +94,7 @@ struct stm32_dma_s
uint8_t irq; /* DMA stream IRQ number */
uint8_t shift; /* ISR/IFCR bit shift value */
uint8_t channel; /* DMA channel number (0-7) */
bool nonstop; /* Stream is configured in a non-stopping mode. */
sem_t sem; /* Used to wait for DMA channel to become available */
uint32_t base; /* DMA register channel base address */
dma_callback_t callback; /* Callback invoked when the DMA completes */
@ -429,9 +430,20 @@ static int stm32_dmainterrupt(int irq, void *context)
status = (dmabase_getreg(dmast, regoffset) >> dmast->shift) & DMA_STREAM_MASK;
/* Disable the DMA stream */
/* Clear fetched stream interrupts by setting bits in the upper or lower IFCR
* register
*/
stm32_dmastreamdisable(dmast);
if (stream < 4)
{
regoffset = STM32_DMA_LIFCR_OFFSET;
}
else
{
regoffset = STM32_DMA_HIFCR_OFFSET;
}
dmabase_putreg(dmast, regoffset, (status << dmast->shift));
/* Invoke the callback */
@ -636,11 +648,15 @@ void stm32_dmasetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr,
/* "Set the memory address in the DMA_SM0ARx ... register. The data will be
* written to or read from this memory after the peripheral event."
*
* Note that only single-buffer mode is currently supported so SM1ARx
* is not used."
* Note that in double-buffered mode it is explicitly assumed that the second
* buffer immediately follows the first.
*/
dmast_putreg(dmast, STM32_DMA_SM0AR_OFFSET, maddr);
if (scr & DMA_SCR_DBM)
{
dmast_putreg(dmast, STM32_DMA_SM1AR_OFFSET, maddr + ntransfers);
}
/* "Configure the total number of data items to be transferred in the
* DMA_SNDTRx register. After each peripheral event, this value will be
@ -677,28 +693,42 @@ void stm32_dmasetup(DMA_HANDLE handle, uint32_t paddr, uint32_t maddr,
* generated when the stream is enabled, then the stream will be automatically
* disabled."
*
* The FIFO is disabled in circular mode when transferring data from a
* peripheral to memory, as in this case it is usually desirable to know that
* every byte from the peripheral is transferred immediately to memory. It is
* not practical to flush the DMA FIFO, as this requires disabling the channel
* which triggers the transfer-complete interrupt.
*
* NOTE: The FEIFx error interrupt is not enabled because the FEIFx seems to
* be reported spuriously causing good transfers to be marked as failures.
*/
regval = dmast_getreg(dmast, STM32_DMA_SFCR_OFFSET);
regval &= ~(DMA_SFCR_FTH_MASK | DMA_SFCR_FS_MASK | DMA_SFCR_FEIE);
regval |= (DMA_SFCR_FTH_FULL | DMA_SFCR_DMDIS);
if (!((scr & (DMA_SCR_CIRC | DMA_SCR_DIR_MASK)) == (DMA_SCR_CIRC | DMA_SCR_DIR_P2M)))
{
regval |= (DMA_SFCR_FTH_FULL | DMA_SFCR_DMDIS);
}
dmast_putreg(dmast, STM32_DMA_SFCR_OFFSET, regval);
/* "Configure data transfer direction, circular mode, peripheral & memory
* incremented mode, peripheral & memory data size, and interrupt after
* half and/or full transfer in the DMA_CCRx register."
*
* Note: The CT bit is always reset.
*/
regval = dmast_getreg(dmast, STM32_DMA_SCR_OFFSET);
regval &= ~(DMA_SCR_PFCTRL|DMA_SCR_DIR_MASK|DMA_SCR_PINC|DMA_SCR_MINC|
DMA_SCR_PSIZE_MASK|DMA_SCR_MSIZE_MASK|DMA_SCR_PINCOS|
DMA_SCR_CIRC|DMA_SCR_DBM|DMA_SCR_CT|
DMA_SCR_PBURST_MASK|DMA_SCR_MBURST_MASK);
scr &= (DMA_SCR_PFCTRL|DMA_SCR_DIR_MASK|DMA_SCR_PINC|DMA_SCR_MINC|
DMA_SCR_PSIZE_MASK|DMA_SCR_MSIZE_MASK|DMA_SCR_PINCOS|
DMA_SCR_DBM|DMA_SCR_CIRC|
DMA_SCR_PBURST_MASK|DMA_SCR_MBURST_MASK);
regval |= scr;
dmast->nonstop = (scr & (DMA_SCR_DBM|DMA_SCR_CIRC)) != 0;
dmast_putreg(dmast, STM32_DMA_SCR_OFFSET, regval);
}
@ -734,14 +764,28 @@ void stm32_dmastart(DMA_HANDLE handle, dma_callback_t callback, void *arg, bool
scr = dmast_getreg(dmast, STM32_DMA_SCR_OFFSET);
scr |= DMA_SCR_EN;
/* Once half of the bytes are transferred, the half-transfer flag (HTIF) is
* set and an interrupt is generated if the Half-Transfer Interrupt Enable
* bit (HTIE) is set. At the end of the transfer, the Transfer Complete Flag
* (TCIF) is set and an interrupt is generated if the Transfer Complete
* Interrupt Enable bit (TCIE) is set.
*/
if (!dmast->nonstop)
{
/* Once half of the bytes are transferred, the half-transfer flag (HTIF) is
* set and an interrupt is generated if the Half-Transfer Interrupt Enable
* bit (HTIE) is set. At the end of the transfer, the Transfer Complete Flag
* (TCIF) is set and an interrupt is generated if the Transfer Complete
* Interrupt Enable bit (TCIE) is set.
*/
scr |= (half ? (DMA_SCR_HTIE|DMA_SCR_TEIE) : (DMA_SCR_TCIE|DMA_SCR_TEIE));
}
else
{
/* In nonstop mode, when the transfer completes it immediately resets
* and starts again. The transfer-complete interrupt is thus always
* enabled, and the half-complete interrupt can be used in circular
* mode to determine when the buffer is half-full, or in double-buffered
* mode to determine when one of the two buffers is full.
*/
scr |= (half ? DMA_SCR_HTIE : 0) | DMA_SCR_TCIE | DMA_SCR_TEIE;
}
scr |= (half ? (DMA_SCR_HTIE|DMA_SCR_TEIE) : (DMA_SCR_TCIE|DMA_SCR_TEIE));
dmast_putreg(dmast, STM32_DMA_SCR_OFFSET, scr);
}
@ -764,6 +808,38 @@ void stm32_dmastop(DMA_HANDLE handle)
stm32_dmastreamdisable(dmast);
}
/****************************************************************************
* Name: stm32_dmaresidual
*
* Description:
* Read the DMA bytes-remaining register.
*
* Assumptions:
* - DMA handle allocated by stm32_dmachannel()
*
****************************************************************************/
size_t stm32_dmaresidual(DMA_HANDLE handle)
{
struct stm32_dma_s *dmast = (struct stm32_dma_s *)handle;
uint32_t residual;
/* Fetch the count of bytes remaining to be transferred.
*
* If the FIFO is enabled, this count may be inaccurate. ST don't
* appear to document whether this counts the peripheral or the memory
* side of the channel, and they don't make the memory pointer
* available either.
*
* For reception in circular mode the FIFO is disabled in order that
* this value can be useful.
*/
residual = dmast_getreg(dmast, STM32_DMA_SNDTR_OFFSET);
return (size_t)residual;
}
/****************************************************************************
* Name: stm32_dmasample
*

View File

@ -660,7 +660,7 @@ config PIC32MX_UART2PRIO
---help---
UART 2. Range 4-31, Default 16.
config PIC32MX_CN
config PIC32MX_CNPRIO
int "CN"
default 16
depends on PIC32MX_CN