arch/arm/stm32h5: Add DMA Support to STM32H5 Serial Driver

Style fixes.
This commit is contained in:
kywwilson11 2025-07-25 11:49:22 -05:00 committed by Xiang Xiao
parent ec64401c62
commit 4995c836f3
5 changed files with 304 additions and 222 deletions

View file

@ -4397,6 +4397,13 @@ config LPUART1_RS485_DIR_POLARITY
Polarity of DIR pin for RS-485 on LPUART1. Set to state on DIR pin which
enables TX (0 - low / nTXEN, 1 - high / TXEN).
config LPUART1_RXDMA
bool "LPUART1 RX DMA"
default n
depends on STM32H5_LPUART1 && (STM32H5_DMA1 || STM32H5_DMA2)
---help---
In high data rate usage, Rx DMA may eliminate Rx overrun errors
endif # LPUART1_SERIALDRIVER
choice
@ -4431,6 +4438,13 @@ config USART1_RS485_DIR_POLARITY
Polarity of DIR pin for RS-485 on USART1. Set to state on DIR pin which
enables TX (0 - low / nTXEN, 1 - high / TXEN).
config USART1_RXDMA
bool "USART1 RX DMA"
default n
depends on STM32H5_USART1 && (STM32H5_DMA1 || STM32H5_DMA2)
---help---
In high data rate usage, Rx DMA may eliminate Rx overrun errors
endif # USART1_SERIALDRIVER
choice
@ -4465,6 +4479,13 @@ config USART2_RS485_DIR_POLARITY
Polarity of DIR pin for RS-485 on USART2. Set to state on DIR pin which
enables TX (0 - low / nTXEN, 1 - high / TXEN).
config USART2_RXDMA
bool "USART2 RX DMA"
default n
depends on STM32H5_USART2 && (STM32H5_DMA1 || STM32H5_DMA2)
---help---
In high data rate usage, Rx DMA may eliminate Rx overrun errors
endif # USART2_SERIALDRIVER
choice
@ -4499,6 +4520,13 @@ config USART3_RS485_DIR_POLARITY
Polarity of DIR pin for RS-485 on USART3. Set to state on DIR pin which
enables TX (0 - low / nTXEN, 1 - high / TXEN).
config USART3_RXDMA
bool "USART3 RX DMA"
default n
depends on STM32H5_USART3 && (STM32H5_DMA1 || STM32H5_DMA2)
---help---
In high data rate usage, Rx DMA may eliminate Rx overrun errors
endif # USART3_SERIALDRIVER
choice
@ -4533,6 +4561,13 @@ config UART4_RS485_DIR_POLARITY
Polarity of DIR pin for RS-485 on UART4. Set to state on DIR pin which
enables TX (0 - low / nTXEN, 1 - high / TXEN).
config UART4_RXDMA
bool "UART4 RX DMA"
default n
depends on STM32H5_UART4 && (STM32H5_DMA1 || STM32H5_DMA2)
---help---
In high data rate usage, Rx DMA may eliminate Rx overrun errors
endif # UART4_SERIALDRIVER
choice
@ -4567,6 +4602,13 @@ config UART5_RS485_DIR_POLARITY
Polarity of DIR pin for RS-485 on UART5. Set to state on DIR pin which
enables TX (0 - low / nTXEN, 1 - high / TXEN).
config UART5_RXDMA
bool "UART5 RX DMA"
default n
depends on STM32H5_UART5 && (STM32H5_DMA1 || STM32H5_DMA2)
---help---
In high data rate usage, Rx DMA may eliminate Rx overrun errors
endif # UART5_SERIALDRIVER
choice
@ -4601,6 +4643,13 @@ config USART6_RS485_DIR_POLARITY
Polarity of DIR pin for RS-485 on USART6. Set to state on DIR pin which
enables TX (0 - low / nTXEN, 1 - high / TXEN).
config USART6_RXDMA
bool "USART6 RX DMA"
default n
depends on STM32H5_USART6 && (STM32H5_DMA1 || STM32H5_DMA2)
---help---
In high data rate usage, Rx DMA may eliminate Rx overrun errors
endif # USART6_SERIALDRIVER
if UART7_SERIALDRIVER
@ -4623,6 +4672,13 @@ config UART7_RS485_DIR_POLARITY
Polarity of DIR pin for RS-485 on UART7. Set to state on DIR pin which
enables TX (0 - low / nTXEN, 1 - high / TXEN).
config UART7_RXDMA
bool "UART7 RX DMA"
default n
depends on STM32H5_UART7 && (STM32H5_DMA1 || STM32H5_DMA2)
---help---
In high data rate usage, Rx DMA may eliminate Rx overrun errors
endif # UART7_SERIALDRIVER
if UART8_SERIALDRIVER
@ -4645,6 +4701,13 @@ config UART8_RS485_DIR_POLARITY
Polarity of DIR pin for RS-485 on UART8. Set to state on DIR pin which
enables TX (0 - low / nTXEN, 1 - high / TXEN).
config UART8_RXDMA
bool "UART8 RX DMA"
default n
depends on STM32H5_UART8 && (STM32H5_DMA1 || STM32H5_DMA2)
---help---
In high data rate usage, Rx DMA may eliminate Rx overrun errors
endif # UART8_SERIALDRIVER
if UART9_SERIALDRIVER
@ -4667,6 +4730,13 @@ config UART9_RS485_DIR_POLARITY
Polarity of DIR pin for RS-485 on UART9. Set to state on DIR pin which
enables TX (0 - low / nTXEN, 1 - high / TXEN).
config UART9_RXDMA
bool "UART9 RX DMA"
default n
depends on STM32H5_UART9 && (STM32H5_DMA1 || STM32H5_DMA2)
---help---
In high data rate usage, Rx DMA may eliminate Rx overrun errors
endif # UART9_SERIALDRIVER
if USART10_SERIALDRIVER
@ -4689,6 +4759,13 @@ config USART10_RS485_DIR_POLARITY
Polarity of DIR pin for RS-485 on USART10. Set to state on DIR pin which
enables TX (0 - low / nTXEN, 1 - high / TXEN).
config USART10_RXDMA
bool "USART10 RX DMA"
default n
depends on STM32H5_USART10 && (STM32H5_DMA1 || STM32H5_DMA2)
---help---
In high data rate usage, Rx DMA may eliminate Rx overrun errors
endif # USART10_SERIALDRIVER
if USART11_SERIALDRIVER
@ -4711,6 +4788,13 @@ config USART11_RS485_DIR_POLARITY
Polarity of DIR pin for RS-485 on USART11. Set to state on DIR pin which
enables TX (0 - low / nTXEN, 1 - high / TXEN).
config USART11_RXDMA
bool "USART11 RX DMA"
default n
depends on STM32H5_USART11 && (STM32H5_DMA1 || STM32H5_DMA2)
---help---
In high data rate usage, Rx DMA may eliminate Rx overrun errors
endif # USART11_SERIALDRIVER
if UART12_SERIALDRIVER
@ -4733,12 +4817,33 @@ config UART12_RS485_DIR_POLARITY
Polarity of DIR pin for RS-485 on UART12. Set to state on DIR pin which
enables TX (0 - low / nTXEN, 1 - high / TXEN).
config UART12_RXDMA
bool "UART12 RX DMA"
default n
depends on STM32H5_UART12 && (STM32H5_DMA1 || STM32H5_DMA2)
---help---
In high data rate usage, Rx DMA may eliminate Rx overrun errors
endif # UART12_SERIALDRIVER
if STM32H5_SERIALDRIVER
comment "Serial Driver Configuration"
config STM32H5_SERIAL_RXDMA_BUFFER_SIZE
int "Rx DMA buffer size"
default 32
depends on USART1_RXDMA || USART2_RXDMA || USART3_RXDMA || USART6_RXDMA || USART10_RXDMA || \
USART11_RXDMA || UART4_RXDMA || UART5_RXDMA || UART7_RXDMA || UART8_RXDMA || \
UART9_RXDMA || UART12_RXDMA || LPUART1_RXDMA
---help---
The DMA buffer size when using RX DMA to emulate a FIFO.
When streaming data, the generic serial layer will be called
every time the FIFO receives half this number of bytes.
Value given here will be rounded up to next multiple of 32 bytes.
config STM32H5_SERIAL_DISABLE_REORDERING
bool "Disable reordering of ttySx devices."
depends on STM32H5_USART1 || STM32H5_USART2 || STM32H5_USART3 || STM32H5_UART4 || STM32H5_UART5

View file

@ -70,10 +70,10 @@
#define GPDMA_REQ_UART8_TX (36)
#define GPDMA_REQ_UART9_RX (37)
#define GPDMA_REQ_UART9_TX (38)
#define GPDMA_REQ_UART10_RX (39)
#define GPDMA_REQ_UART10_TX (40)
#define GPDMA_REQ_UART11_RX (41)
#define GPDMA_REQ_UART11_TX (42)
#define GPDMA_REQ_USART10_RX (39)
#define GPDMA_REQ_USART10_TX (40)
#define GPDMA_REQ_USART11_RX (41)
#define GPDMA_REQ_USART11_TX (42)
#define GPDMA_REQ_UART12_RX (43)
#define GPDMA_REQ_UART12_TX (44)
#define GPDMA_REQ_LPUART1_RX (45)

View file

@ -51,7 +51,7 @@
* off this in this file.
*/
#define CH_BASE_OFFSET(ch) (0x80*(ch))
#define CH_BASE_OFFSET(ch) (0x80*(ch))
#define CH_CXLBAR_OFFSET 0x50
#define CH_CXFCR_OFFSET 0x5C
#define CH_CXSR_OFFSET 0x60
@ -694,6 +694,31 @@ void stm32_dmastop(DMA_HANDLE handle)
/* gpdma_ch_abort(chan); */
}
/****************************************************************************
* Name: stm32_dmaresidual
*
* Description:
* Returns the number of data beats remaining to transfer in the current
* STM32H5 GPDMA block. This reads the BNDT[15:0] field from the
* GPDMA_CxBR1 register, which indicates how many beats are left in the
* programmed transfer.
*
* Assumptions:
* - DMA handle was allocated by stm32_dmachannel().
* - The handle refers to a valid STM32H5 GPDMA channel.
*
****************************************************************************/
size_t stm32_dmaresidual(DMA_HANDLE handle)
{
struct gpdma_ch_s *chan = (struct gpdma_ch_s *)handle;
uint32_t br1 = getreg32(chan->base + CH_CXBR1_OFFSET);
/* BNDT[15:0] = beats remaining in current block transfer */
return (size_t)(br1 & GPDMA_CXBR1_BNDT_MASK);
}
#ifdef CONFIG_STM32H5_DMACAPABLE
/****************************************************************************
* Name: stm32_dmacapable
@ -760,4 +785,4 @@ void stm32_dmasample(DMA_HANDLE handle, struct stm32_dmaregs_s *regs)
{
#warning "stm32_dmasample() not implemented yet!"
}
#endif
#endif

View file

@ -52,13 +52,7 @@
#include "chip.h"
#include "stm32_gpio.h"
#include "stm32_uart.h"
/* DMA has not been implemented for H5 chip yet, so disable any serial DMA */
#ifdef SERIAL_HAVE_DMA
# error Serial DMA not implemented for STM32H5 chips.
#undef SERIAL_HAVE_DMA
#endif
#include "stm32_dma.h"
#include "stm32_rcc.h"
#include "arm_internal.h"
@ -81,22 +75,18 @@
* 5 X
*/
#ifdef CONFIG_SERIAL_IFLOWCONTROL
# warning STM32H5 Serial IFLOWCONTROL is untested
#endif
#ifdef SERIAL_HAVE_DMA
/* Verify that DMA has been enabled and the DMA channel has been defined.
*/
# if defined(CONFIG_USART2_RXDMA) || defined(CONFIG_USART3_RXDMA)
# if !defined(CONFIG_STM32H5_DMA1) && !defined(CONFIG_STM32H5_DMAMUX)
# error STM32H5 USART2/3 receive DMA requires CONFIG_STM32H5_DMA1
# endif
# endif
# if defined(CONFIG_UART4_RXDMA) || defined(CONFIG_UART5_RXDMA)
# if !defined(CONFIG_STM32H5_DMA2) && !defined(CONFIG_STM32H5_DMAMUX)
# error STM32H5 UART4/5 receive DMA requires CONFIG_STM32H5_DMA2
# endif
# endif
#if !defined(CONFIG_STM32H5_DMA1) && !defined(CONFIG_STM32H5_DMA2)
# error STM32H5 Serial DMA requires one of DMA1 or DMA2 to be enabled
#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
@ -110,40 +100,6 @@
# error "RXDMA and RS-485 cannot be enabled at the same time for the same U[S]ART"
# endif
/* For the L4, there are alternate DMA channels for USART1.
* 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
/* UART2-5 have no alternate channels without DMAMUX */
# ifndef CONFIG_STM32H5_HAVE_DMAMUX
# define DMAMAP_USART2_RX DMACHAN_USART2_RX
# define DMAMAP_USART3_RX DMACHAN_USART3_RX
# define DMAMAP_UART4_RX DMACHAN_UART4_RX
# define DMAMAP_UART5_RX DMACHAN_UART5_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
/* The DMA buffer size when using RX DMA to emulate a FIFO.
*
* When streaming data, the generic serial layer will be called
@ -161,31 +117,6 @@
# define RXDMA_BUFFER_SIZE ((CONFIG_STM32H5_SERIAL_RXDMA_BUFFER_SIZE + 31) & ~31)
# endif
/* DMA priority */
# ifndef CONFIG_USART_DMAPRIO
# define CONFIG_USART_DMAPRIO DMA_CCR_PRIMED
# endif
# if (CONFIG_USART_DMAPRIO & ~DMA_CCR_PL_MASK) != 0
# error "Illegal value for CONFIG_USART_DMAPRIO"
# endif
/* DMA control words */
# define SERIAL_DMA_CONTROL_WORD \
(DMA_CCR_CIRC | \
DMA_CCR_MINC | \
DMA_CCR_PSIZE_8BITS | \
DMA_CCR_MSIZE_8BITS | \
CONFIG_USART_DMAPRIO)
# ifdef CONFIG_SERIAL_IFLOWCONTROL
# define SERIAL_DMA_IFLOW_CONTROL_WORD \
(DMA_CCR_MINC | \
DMA_CCR_PSIZE_8BITS | \
DMA_CCR_MSIZE_8BITS | \
CONFIG_USART_DMAPRIO)
# endif
#endif
/* Power management definitions */
@ -243,9 +174,6 @@ struct stm32_serial_s
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 */
#ifdef CONFIG_SERIAL_IFLOWCONTROL
bool iflow; /* input flow control (RTS) enabled */
#endif
#ifdef CONFIG_SERIAL_OFLOWCONTROL
bool oflow; /* output flow control (CTS) enabled */
#endif
@ -254,15 +182,11 @@ struct stm32_serial_s
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 */
#ifdef CONFIG_SERIAL_IFLOWCONTROL
const bool iflow; /* input flow control (RTS) enabled */
#endif
#ifdef CONFIG_SERIAL_OFLOWCONTROL
const bool oflow; /* output flow control (CTS) enabled */
#endif
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 */
@ -274,10 +198,7 @@ struct stm32_serial_s
#ifdef CONFIG_SERIAL_OFLOWCONTROL
const uint32_t cts_gpio; /* U[S]ART CTS GPIO pin configuration */
#endif
#ifdef SERIAL_HAVE_DMA
const unsigned int rxdma_channel; /* DMA channel assigned */
#endif
const bool iflow; /* input flow control (RTS) enabled */
/* RX DMA state */
@ -288,7 +209,8 @@ struct stm32_serial_s
bool rxdmasusp; /* Rx DMA suspended */
#endif
uint32_t rxdmanext; /* Next byte in the DMA buffer to be read */
char *const rxfifo; /* Receive DMA buffer */
uint16_t rxdma_req; /* GPDMA Request number */
char *const rxfifo; /* Receive DMA buffer */
#endif
#ifdef HAVE_RS485
@ -543,8 +465,8 @@ static struct stm32_serial_s g_lpuart1priv =
.rts_gpio = GPIO_LPUART1_RTS,
# endif
# ifdef CONFIG_LPUART1_RXDMA
.rxdma_channel = DMAMAP_LPUSART_RX,
.rxfifo = g_lpuart1rxfifo,
.rxdma_req = GPDMA_REQ_LPUART1_RX,
# endif
# ifdef CONFIG_USART1_RS485
@ -604,8 +526,8 @@ static struct stm32_serial_s g_usart1priv =
.rts_gpio = GPIO_USART1_RTS,
# endif
# ifdef CONFIG_USART1_RXDMA
.rxdma_channel = DMAMAP_USART1_RX,
.rxfifo = g_usart1rxfifo,
.rxdma_req = GPDMA_REQ_USART1_RX,
# endif
# ifdef CONFIG_USART1_RS485
@ -667,8 +589,8 @@ static struct stm32_serial_s g_usart2priv =
.rts_gpio = GPIO_USART2_RTS,
# endif
# ifdef CONFIG_USART2_RXDMA
.rxdma_channel = DMAMAP_USART2_RX,
.rxfifo = g_usart2rxfifo,
.rxdma_req = GPDMA_REQ_USART2_RX,
# endif
# ifdef CONFIG_USART2_RS485
@ -730,8 +652,8 @@ static struct stm32_serial_s g_usart3priv =
.rts_gpio = GPIO_USART3_RTS,
# endif
# ifdef CONFIG_USART3_RXDMA
.rxdma_channel = DMAMAP_USART3_RX,
.rxfifo = g_usart3rxfifo,
.rxdma_req = GPDMA_REQ_USART3_RX,
# endif
# ifdef CONFIG_USART3_RS485
@ -793,8 +715,8 @@ static struct stm32_serial_s g_uart4priv =
.tx_gpio = GPIO_UART4_TX,
.rx_gpio = GPIO_UART4_RX,
# ifdef CONFIG_UART4_RXDMA
.rxdma_channel = DMAMAP_UART4_RX,
.rxfifo = g_uart4rxfifo,
.rxdma_req = GPDMA_REQ_UART4_RX,
# endif
# ifdef CONFIG_UART4_RS485
@ -856,8 +778,8 @@ static struct stm32_serial_s g_uart5priv =
.tx_gpio = GPIO_UART5_TX,
.rx_gpio = GPIO_UART5_RX,
# ifdef CONFIG_UART5_RXDMA
.rxdma_channel = DMAMAP_UART5_RX,
.rxfifo = g_uart5rxfifo,
.rxdma_req = GPDMA_REQ_UART5_RX,
# endif
# ifdef CONFIG_UART5_RS485
@ -919,8 +841,8 @@ static struct stm32_serial_s g_usart6priv =
.rts_gpio = GPIO_USART6_RTS,
# endif
# ifdef CONFIG_USART6_RXDMA
.rxdma_channel = DMAMAP_USART6_RX,
.rxfifo = g_usart6rxfifo,
.rxdma_req = GPDMA_REQ_USART6_RX,
# endif
# ifdef CONFIG_USART6_RS485
@ -982,8 +904,8 @@ static struct stm32_serial_s g_uart7priv =
.tx_gpio = GPIO_UART7_TX,
.rx_gpio = GPIO_UART7_RX,
# ifdef CONFIG_UART7_RXDMA
.rxdma_channel = DMAMAP_UART7_RX,
.rxfifo = g_uart7rxfifo,
.rxdma_req = GPDMA_REQ_UART7_RX,
# endif
# ifdef CONFIG_UART7_RS485
@ -1045,8 +967,8 @@ static struct stm32_serial_s g_uart8priv =
.tx_gpio = GPIO_UART8_TX,
.rx_gpio = GPIO_UART8_RX,
# ifdef CONFIG_UART8_RXDMA
.rxdma_channel = DMAMAP_UART8_RX,
.rxfifo = g_uart8rxfifo,
.rxdma_req = GPDMA_REQ_UART8_RX,
# endif
# ifdef CONFIG_UART8_RS485
@ -1108,8 +1030,8 @@ static struct stm32_serial_s g_uart9priv =
.tx_gpio = GPIO_UART9_TX,
.rx_gpio = GPIO_UART9_RX,
# ifdef CONFIG_UART9_RXDMA
.rxdma_channel = DMAMAP_UART9_RX,
.rxfifo = g_uart9rxfifo,
.rxdma_req = GPDMA_REQ_UART9_RX,
# endif
# ifdef CONFIG_UART9_RS485
@ -1171,8 +1093,8 @@ static struct stm32_serial_s g_usart10priv =
.rts_gpio = GPIO_USART10_RTS,
# endif
# ifdef CONFIG_USART10_RXDMA
.rxdma_channel = DMAMAP_USART10_RX,
.rxfifo = g_usart10rxfifo,
.rxdma_req = GPDMA_REQ_USART10_RX,
# endif
# ifdef CONFIG_USART10_RS485
@ -1234,8 +1156,8 @@ static struct stm32_serial_s g_usart11priv =
.rts_gpio = GPIO_USART11_RTS,
# endif
# ifdef CONFIG_USART11_RXDMA
.rxdma_channel = DMAMAP_USART11_RX,
.rxfifo = g_usart11rxfifo,
.rxdma_req = GPDMA_REQ_USART11_RX,
# endif
# ifdef CONFIG_USART11_RS485
@ -1297,8 +1219,8 @@ static struct stm32_serial_s g_uart12priv =
.tx_gpio = GPIO_UART12_TX,
.rx_gpio = GPIO_UART12_RX,
# ifdef CONFIG_UART12_RXDMA
.rxdma_channel = DMAMAP_UART12_RX,
.rxfifo = g_uart12rxfifo,
.rxdma_req = GPDMA_REQ_UART12_RX,
# endif
# ifdef CONFIG_UART12_RS485
@ -2166,69 +2088,88 @@ static int stm32serial_setup(struct uart_dev_s *dev)
return OK;
}
/****************************************************************************
* Name: serial_rxdmacfg
*
* Description:
* Generate the required DMA configuration structure for oneshot mode based
* on the serial configuration.
*
* Input Parameters:
* priv - serial instance structure
* cfg - DMA configuration structure
* circular - 0 = oneshot, 1 = circular
*
* Returned Value:
* None
****************************************************************************/
#ifdef SERIAL_HAVE_DMA
static void serial_rxdmacfg(struct stm32_serial_s *priv,
struct stm32_gpdma_cfg_s *cfg)
{
cfg->src_addr = priv->usartbase + STM32_USART_RDR_OFFSET;
cfg->dest_addr = (uint32_t)priv->rxfifo;
cfg->request = priv->rxdma_req;
cfg->priority = GPMDACFG_PRIO_LH;
cfg->mode = GPDMACFG_MODE_CIRC;
cfg->ntransfers = RXDMA_BUFFER_SIZE;
/* Write SDW and DDW to 0 for 8-bit beats */
cfg->tr1 = GPDMA_CXTR1_DINC; /* dest-inc, source fixed */
}
#endif
/****************************************************************************
* Name: stm32serial_dmasetup
*
* Description:
* Configure the USART baud, bits, parity, etc. This method is called the
* first time that the serial port is opened.
* Configure and start circular RX DMA for USART:
* - Allocate a GPDMA channel
* - Set up source (USART RDR), destination (RX buffer), REQSEL,
* circular mode
* - Program DMA and reset read index
* - Enable USART CR3.DMAR
* - Start DMA with half and fulltransfer callbacks
*
* Returned Value:
* OK on success; negative errno on failure.
****************************************************************************/
#ifdef SERIAL_HAVE_DMA
static int stm32serial_dmasetup(struct uart_dev_s *dev)
{
struct stm32_serial_s *priv =
(struct stm32_serial_s *)dev->priv;
int result;
uint32_t regval;
/* Do the basic UART setup first, unless we are the console */
struct stm32_serial_s *priv = (struct stm32_serial_s *)dev->priv;
struct stm32_gpdma_cfg_s dmacfg;
uint32_t regval;
int ret;
if (!dev->isconsole)
{
result = stm32serial_setup(dev);
if (result != OK)
ret = stm32serial_setup(dev);
if (ret != OK)
{
return result;
return ret;
}
}
/* Acquire the DMA channel. This should always succeed. */
priv->rxdma = stm32h5_dmachannel(priv->rxdma_channel);
#ifdef CONFIG_SERIAL_IFLOWCONTROL
if (priv->iflow)
priv->rxdma = stm32_dmachannel(GPDMA_TTYPE_P2M);
if (!priv->rxdma)
{
/* Configure for non-circular DMA reception into the RX FIFO */
stm32h5_dmasetup(priv->rxdma,
priv->usartbase + STM32_USART_RDR_OFFSET,
(uint32_t)priv->rxfifo,
RXDMA_BUFFER_SIZE,
SERIAL_DMA_IFLOW_CONTROL_WORD);
}
else
#endif
{
/* Configure for circular DMA reception into the RX FIFO */
stm32h5_dmasetup(priv->rxdma,
priv->usartbase + STM32_USART_RDR_OFFSET,
(uint32_t)priv->rxfifo,
RXDMA_BUFFER_SIZE,
SERIAL_DMA_CONTROL_WORD);
return -EBUSY;
}
/* Reset our DMA shadow pointer to match the address just
* programmed above.
*/
serial_rxdmacfg(priv, &dmacfg);
stm32_dmasetup(priv->rxdma, &dmacfg);
priv->rxdmanext = 0;
/* Enable receive DMA for the UART */
regval = stm32serial_getreg(priv, STM32_USART_CR3_OFFSET);
regval |= USART_CR3_DMAR;
stm32serial_putreg(priv, STM32_USART_CR3_OFFSET, regval);
@ -2241,8 +2182,8 @@ static int stm32serial_dmasetup(struct uart_dev_s *dev)
* in and DMA transfer is stopped.
*/
stm32h5_dmastart(priv->rxdma, stm32serial_dmarxcallback,
(void *)priv, false);
stm32_dmastart(priv->rxdma, stm32serial_dmarxcallback,
(void *)priv, false);
}
else
#endif
@ -2252,8 +2193,8 @@ static int stm32serial_dmasetup(struct uart_dev_s *dev)
* worth of time to claim bytes before they are overwritten.
*/
stm32h5_dmastart(priv->rxdma, stm32serial_dmarxcallback,
(void *)priv, true);
stm32_dmastart(priv->rxdma, stm32serial_dmarxcallback,
(void *)priv, true);
}
return OK;
@ -2347,11 +2288,13 @@ static void stm32serial_dmashutdown(struct uart_dev_s *dev)
/* Stop the DMA channel */
stm32h5_dmastop(priv->rxdma);
stm32_dmastop(priv->rxdma);
priv->rxenable = false;
/* Release the DMA channel */
stm32h5_dmafree(priv->rxdma);
stm32_dmafree(priv->rxdma);
priv->rxdma = NULL;
}
#endif
@ -3131,43 +3074,64 @@ static bool stm32serial_rxflowcontrol(struct uart_dev_s *dev,
* Name: stm32serial_dmareceive
*
* 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'.
* Retrieve one character from the RX FIFO filled by circular DMA. Also
* report any USART error flags in *status.
*
****************************************************************************/
#ifdef SERIAL_HAVE_DMA
static int stm32serial_dmareceive(struct uart_dev_s *dev,
unsigned int *status)
unsigned int *status)
{
struct stm32_serial_s *priv =
(struct stm32_serial_s *)dev->priv;
int c = 0;
unsigned int next;
int ch = -1;
uint32_t sr;
if (stm32serial_dmanextrx(priv) != priv->rxdmanext)
/* 1) Capture USART error flags */
sr = getreg32(priv->usartbase + STM32_USART_ISR_OFFSET);
*status = sr & (USART_ISR_ORE | USART_ISR_NF |
USART_ISR_FE | USART_ISR_PE);
/* 2) Where will DMA write the next byte? */
next = stm32serial_dmanextrx(priv);
/* 3) Pull one byte if available */
if (next != priv->rxdmanext)
{
c = priv->rxfifo[priv->rxdmanext];
ch = priv->rxfifo[priv->rxdmanext++];
priv->rxdmanext++;
if (priv->rxdmanext == RXDMA_BUFFER_SIZE)
/* 4) Endofbuffer wrap or flowcontrol pause */
if (priv->rxdmanext >= RXDMA_BUFFER_SIZE)
{
#ifdef CONFIG_SERIAL_IFLOWCONTROL
if (priv->iflow)
{
/* RX DMA buffer full. RX paused, RTS line pulled up to prevent
* more input data from other end.
*/
/* Pause DMA callbacks */
stm32serial_dmarxint(&priv->dev, false);
/* Assert RTS to halt sender */
(void)stm32serial_rxflowcontrol(&priv->dev,
RXDMA_BUFFER_SIZE, true);
}
else
#endif
{
/* Simply wrap to buffer start */
priv->rxdmanext = 0;
}
}
}
return c;
return ch;
}
#endif
@ -3182,28 +3146,10 @@ static int stm32serial_dmareceive(struct uart_dev_s *dev,
#if defined(SERIAL_HAVE_DMA)
static void stm32serial_dmareenable(struct stm32_serial_s *priv)
{
#ifdef CONFIG_SERIAL_IFLOWCONTROL
if (priv->iflow)
{
/* Configure for non-circular DMA reception into the RX FIFO */
struct stm32_gpdma_cfg_s dmacfg;
stm32h5_dmasetup(priv->rxdma,
priv->usartbase + STM32_USART_RDR_OFFSET,
(uint32_t)priv->rxfifo,
RXDMA_BUFFER_SIZE,
SERIAL_DMA_IFLOW_CONTROL_WORD);
}
else
#endif
{
/* Configure for circular DMA reception into the RX FIFO */
stm32h5_dmasetup(priv->rxdma,
priv->usartbase + STM32_USART_RDR_OFFSET,
(uint32_t)priv->rxfifo,
RXDMA_BUFFER_SIZE,
SERIAL_DMA_CONTROL_WORD);
}
serial_rxdmacfg(priv, &dmacfg);
stm32_dmasetup(priv->rxdma, &dmacfg);
/* Reset our DMA shadow pointer to match the address just
* programmed above.
@ -3219,7 +3165,7 @@ static void stm32serial_dmareenable(struct stm32_serial_s *priv)
* in and DMA transfer is stopped.
*/
stm32h5_dmastart(priv->rxdma, stm32serial_dmarxcallback,
stm32_dmastart(priv->rxdma, stm32serial_dmarxcallback,
(void *)priv, false);
}
else
@ -3230,7 +3176,7 @@ static void stm32serial_dmareenable(struct stm32_serial_s *priv)
* worth of time to claim bytes before they are overwritten.
*/
stm32h5_dmastart(priv->rxdma, stm32serial_dmarxcallback,
stm32_dmastart(priv->rxdma, stm32serial_dmarxcallback,
(void *)priv, true);
}
@ -3461,50 +3407,57 @@ static bool stm32serial_txready(struct uart_dev_s *dev)
* Name: stm32serial_dmarxcallback
*
* Description:
* This function checks the current DMA state and calls the generic
* serial stack when bytes appear to be available.
* DMA callback for STM32H5 USART RX. Called on half and fulltransfer
* events. Reads and clears the GPDMA status flags, notifies the NuttX
* serial core of newly arrived bytes, signals endofbuffer when a
* full transfer completes, handles RTS flow control restart, and
* clears any lingering UART error flags to keep RXDMA running.
*
* Input Parameters:
* handle - DMA channel handle returned by stm32_dmachannel()
* status - Raw status byte passed by the DMA ISR (ignored here)
* arg - Pointer to the STM32 serial driver state
* (struct stm32_serial_s)
*
* Returned Value:
* None
*
****************************************************************************/
#ifdef SERIAL_HAVE_DMA
static void stm32serial_dmarxcallback(DMA_HANDLE handle, uint8_t status,
void *arg)
static void stm32serial_dmarxcallback(DMA_HANDLE handle,
uint8_t status,
void *arg)
{
struct stm32_serial_s *priv = (struct stm32_serial_s *)arg;
struct stm32_serial_s *priv = arg;
if (priv->rxenable && stm32serial_dmarxavailable(&priv->dev))
{
uart_recvchars(&priv->dev);
/* pull whatever is in the buffer now */
#ifdef CONFIG_SERIAL_IFLOWCONTROL
if (priv->iflow)
{
/* Re-enable RX DMA. */
uart_recvchars(&priv->dev);
stm32serial_dmaiflowrestart(priv);
}
#endif
}
/* Get the masked USART status word to check and clear error flags.
*
* When wake-up from low power mode was not fast enough, UART is resumed
* too late and sometimes exactly when character was coming over UART,
* resulting to frame error.
* If error flag is not cleared, Rx DMA will be stuck. Clearing errors
* will release Rx DMA.
/* If it really was a fullbuffer event, signal “done” so the
* serial core can rearm/restart the DMA behind the scenes:
*/
priv->sr = stm32serial_getreg(priv, STM32_USART_ISR_OFFSET);
#ifdef CONFIG_SERIAL_IFLOWCONTROL
/* If you had paused the DMA on RTS flow control, restart it now */
if ((priv->sr & (USART_ISR_ORE | USART_ISR_NF | USART_ISR_FE)) != 0)
if (priv->iflow)
{
stm32serial_dmaiflowrestart(priv);
}
#endif
/* Clear any USART framing/overrun errors so RXDMA
* doesnt get stuck waiting for the UART to clear them.
*/
priv->sr = getreg32(priv->usartbase + STM32_USART_ISR_OFFSET);
if (priv->sr & (USART_ISR_ORE | USART_ISR_NF | USART_ISR_FE))
{
stm32serial_putreg(priv, STM32_USART_ICR_OFFSET,
(USART_ICR_NCF | USART_ICR_ORECF |
USART_ICR_FECF));
USART_ICR_ORECF | USART_ICR_NCF | USART_ICR_FECF);
}
}
#endif
/****************************************************************************
* Name: stm32serial_pmnotify

View file

@ -443,8 +443,7 @@
defined(CONFIG_UART8_RXDMA) || defined(CONFIG_UART9_RXDMA) || \
defined(CONFIG_USART10_RXDMA) || defined(CONFIG_USART11_RXDMA) || \
defined(CONFIG_USART12_RXDMA)
# define SERIAL_HAVE_DMA 0
# warning Serial DMA has not been implemented for STM32H5 chips.
# define SERIAL_HAVE_DMA 1
#endif
/* Is DMA used on the console UART? */