Implement high level DMA infrastructure for serial devices
This commit is contained in:
parent
ef59f83a38
commit
d54a39832a
@ -11084,4 +11084,7 @@
|
|||||||
* drivers/mtd/mtd_progmem.c: Add an upper half MTD device that can
|
* drivers/mtd/mtd_progmem.c: Add an upper half MTD device that can
|
||||||
use the interfaces defined in included/nuttx/progmem.h to provide
|
use the interfaces defined in included/nuttx/progmem.h to provide
|
||||||
a standard MTD interface (2015-11-12).
|
a standard MTD interface (2015-11-12).
|
||||||
|
* drivers/serial/serial.c, serialirq.c and include/nuttx/serial/serial.h:
|
||||||
|
Implement high level DMA infrastructure for serial devices. From
|
||||||
|
Max Neklyudov (2015-11-12).
|
||||||
|
|
||||||
|
2
configs
2
configs
@ -1 +1 @@
|
|||||||
Subproject commit 758aa6d23647d98fb1a6064175a8abd6c9cc28b2
|
Subproject commit 4d23ce39bf6bbf3ca0161ff6247fc9fe1610890f
|
@ -540,6 +540,10 @@ config SERIAL_OFLOWCONTROL
|
|||||||
bool
|
bool
|
||||||
default n
|
default n
|
||||||
|
|
||||||
|
config SERIAL_DMA
|
||||||
|
bool
|
||||||
|
default n
|
||||||
|
|
||||||
config SERIAL_IFLOWCONTROL_WATERMARKS
|
config SERIAL_IFLOWCONTROL_WATERMARKS
|
||||||
bool "RX flow control watermarks"
|
bool "RX flow control watermarks"
|
||||||
default n
|
default n
|
||||||
@ -762,6 +766,13 @@ config UART_OFLOWCONTROL
|
|||||||
---help---
|
---help---
|
||||||
Enable UART CTS flow control
|
Enable UART CTS flow control
|
||||||
|
|
||||||
|
config UART_DMA
|
||||||
|
bool "UART DMA support"
|
||||||
|
default n
|
||||||
|
select SERIAL_DMA
|
||||||
|
---help---
|
||||||
|
Enable DMA transfers on UART
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
|
||||||
menu "UART0 Configuration"
|
menu "UART0 Configuration"
|
||||||
@ -820,6 +831,13 @@ config UART0_OFLOWCONTROL
|
|||||||
---help---
|
---help---
|
||||||
Enable UART0 CTS flow control
|
Enable UART0 CTS flow control
|
||||||
|
|
||||||
|
config UART0_DMA
|
||||||
|
bool "UART0 DMA support"
|
||||||
|
default n
|
||||||
|
select SERIAL_DMA
|
||||||
|
---help---
|
||||||
|
Enable DMA transfers on UART0
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
|
||||||
menu "USART0 Configuration"
|
menu "USART0 Configuration"
|
||||||
@ -878,6 +896,13 @@ config USART0_OFLOWCONTROL
|
|||||||
---help---
|
---help---
|
||||||
Enable USART0 CTS flow control
|
Enable USART0 CTS flow control
|
||||||
|
|
||||||
|
config USART0_DMA
|
||||||
|
bool "USART0 DMA support"
|
||||||
|
default n
|
||||||
|
select SERIAL_DMA
|
||||||
|
---help---
|
||||||
|
Enable DMA transfers on USART0
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
|
||||||
menu "UART1 Configuration"
|
menu "UART1 Configuration"
|
||||||
@ -936,6 +961,13 @@ config UART1_OFLOWCONTROL
|
|||||||
---help---
|
---help---
|
||||||
Enable UART1 CTS flow control
|
Enable UART1 CTS flow control
|
||||||
|
|
||||||
|
config UART1_DMA
|
||||||
|
bool "UART1 DMA support"
|
||||||
|
default n
|
||||||
|
select SERIAL_DMA
|
||||||
|
---help---
|
||||||
|
Enable DMA transfers on UART1
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
|
||||||
menu "USART1 Configuration"
|
menu "USART1 Configuration"
|
||||||
@ -994,6 +1026,13 @@ config USART1_OFLOWCONTROL
|
|||||||
---help---
|
---help---
|
||||||
Enable USART1 CTS flow control
|
Enable USART1 CTS flow control
|
||||||
|
|
||||||
|
config USART1_DMA
|
||||||
|
bool "USART1 DMA support"
|
||||||
|
default n
|
||||||
|
select SERIAL_DMA
|
||||||
|
---help---
|
||||||
|
Enable DMA transfers on USART1
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
|
||||||
menu "UART2 Configuration"
|
menu "UART2 Configuration"
|
||||||
@ -1052,6 +1091,13 @@ config UART2_OFLOWCONTROL
|
|||||||
---help---
|
---help---
|
||||||
Enable UART2 CTS flow control
|
Enable UART2 CTS flow control
|
||||||
|
|
||||||
|
config UART2_DMA
|
||||||
|
bool "UART2 DMA support"
|
||||||
|
default n
|
||||||
|
select SERIAL_DMA
|
||||||
|
---help---
|
||||||
|
Enable DMA transfers on UART2
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
|
||||||
menu "USART2 Configuration"
|
menu "USART2 Configuration"
|
||||||
@ -1110,6 +1156,12 @@ config USART2_OFLOWCONTROL
|
|||||||
---help---
|
---help---
|
||||||
Enable USART2 CTS flow control
|
Enable USART2 CTS flow control
|
||||||
|
|
||||||
|
config USART2_DMA
|
||||||
|
bool "USART2 DMA support"
|
||||||
|
default n
|
||||||
|
select SERIAL_DMA
|
||||||
|
---help---
|
||||||
|
Enable DMA transfers on USART2
|
||||||
endmenu
|
endmenu
|
||||||
|
|
||||||
menu "UART3 Configuration"
|
menu "UART3 Configuration"
|
||||||
@ -1168,6 +1220,13 @@ config UART3_OFLOWCONTROL
|
|||||||
---help---
|
---help---
|
||||||
Enable UART3 CTS flow control
|
Enable UART3 CTS flow control
|
||||||
|
|
||||||
|
config UART3_DMA
|
||||||
|
bool "UART3 DMA support"
|
||||||
|
default n
|
||||||
|
select SERIAL_DMA
|
||||||
|
---help---
|
||||||
|
Enable DMA transfers on UART3
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
|
||||||
menu "USART3 Configuration"
|
menu "USART3 Configuration"
|
||||||
@ -1226,6 +1285,13 @@ config USART3_OFLOWCONTROL
|
|||||||
---help---
|
---help---
|
||||||
Enable USART3 CTS flow control
|
Enable USART3 CTS flow control
|
||||||
|
|
||||||
|
config USART3_DMA
|
||||||
|
bool "USART3 DMA support"
|
||||||
|
default n
|
||||||
|
select SERIAL_DMA
|
||||||
|
---help---
|
||||||
|
Enable DMA transfers on USART3
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
|
||||||
menu "UART4 Configuration"
|
menu "UART4 Configuration"
|
||||||
@ -1284,6 +1350,13 @@ config UART4_OFLOWCONTROL
|
|||||||
---help---
|
---help---
|
||||||
Enable UART4 CTS flow control
|
Enable UART4 CTS flow control
|
||||||
|
|
||||||
|
config UART4_DMA
|
||||||
|
bool "UART4 DMA support"
|
||||||
|
default n
|
||||||
|
select SERIAL_DMA
|
||||||
|
---help---
|
||||||
|
Enable DMA transfers on UART4
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
|
||||||
menu "USART4 Configuration"
|
menu "USART4 Configuration"
|
||||||
@ -1342,6 +1415,13 @@ config USART4_OFLOWCONTROL
|
|||||||
---help---
|
---help---
|
||||||
Enable USART4 CTS flow control
|
Enable USART4 CTS flow control
|
||||||
|
|
||||||
|
config USART4_DMA
|
||||||
|
bool "USART4 DMA support"
|
||||||
|
default n
|
||||||
|
select SERIAL_DMA
|
||||||
|
---help---
|
||||||
|
Enable DMA transfers on USART4
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
|
||||||
menu "UART5 Configuration"
|
menu "UART5 Configuration"
|
||||||
@ -1400,6 +1480,13 @@ config UART5_OFLOWCONTROL
|
|||||||
---help---
|
---help---
|
||||||
Enable UART5 CTS flow control
|
Enable UART5 CTS flow control
|
||||||
|
|
||||||
|
config UART5_DMA
|
||||||
|
bool "UART5 DMA support"
|
||||||
|
default n
|
||||||
|
select SERIAL_DMA
|
||||||
|
---help---
|
||||||
|
Enable DMA transfers on UART5
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
|
||||||
menu "USART5 Configuration"
|
menu "USART5 Configuration"
|
||||||
@ -1458,6 +1545,13 @@ config USART5_OFLOWCONTROL
|
|||||||
---help---
|
---help---
|
||||||
Enable USART5 CTS flow control
|
Enable USART5 CTS flow control
|
||||||
|
|
||||||
|
config USART5_DMA
|
||||||
|
bool "USART5 DMA support"
|
||||||
|
default n
|
||||||
|
select SERIAL_DMA
|
||||||
|
---help---
|
||||||
|
Enable DMA transfers on USART5
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
|
||||||
menu "USART6 Configuration"
|
menu "USART6 Configuration"
|
||||||
@ -1516,6 +1610,13 @@ config USART6_OFLOWCONTROL
|
|||||||
---help---
|
---help---
|
||||||
Enable USART6 CTS flow control
|
Enable USART6 CTS flow control
|
||||||
|
|
||||||
|
config USART6_DMA
|
||||||
|
bool "USART6 DMA support"
|
||||||
|
default n
|
||||||
|
select SERIAL_DMA
|
||||||
|
---help---
|
||||||
|
Enable DMA transfers on USART6
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
|
||||||
menu "UART6 Configuration"
|
menu "UART6 Configuration"
|
||||||
@ -1574,6 +1675,13 @@ config UART6_OFLOWCONTROL
|
|||||||
---help---
|
---help---
|
||||||
Enable UART6 CTS flow control
|
Enable UART6 CTS flow control
|
||||||
|
|
||||||
|
config UART6_DMA
|
||||||
|
bool "UART6 DMA support"
|
||||||
|
default n
|
||||||
|
select SERIAL_DMA
|
||||||
|
---help---
|
||||||
|
Enable DMA transfers on UART6
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
|
||||||
menu "USART7 Configuration"
|
menu "USART7 Configuration"
|
||||||
@ -1632,6 +1740,13 @@ config USART7_OFLOWCONTROL
|
|||||||
---help---
|
---help---
|
||||||
Enable USART7 CTS flow control
|
Enable USART7 CTS flow control
|
||||||
|
|
||||||
|
config USART7_DMA
|
||||||
|
bool "USART7 DMA support"
|
||||||
|
default n
|
||||||
|
select SERIAL_DMA
|
||||||
|
---help---
|
||||||
|
Enable DMA transfers on USART7
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
|
||||||
menu "UART7 Configuration"
|
menu "UART7 Configuration"
|
||||||
@ -1690,6 +1805,13 @@ config UART7_OFLOWCONTROL
|
|||||||
---help---
|
---help---
|
||||||
Enable UART7 CTS flow control
|
Enable UART7 CTS flow control
|
||||||
|
|
||||||
|
config UART7_DMA
|
||||||
|
bool "UART7 DMA support"
|
||||||
|
default n
|
||||||
|
select SERIAL_DMA
|
||||||
|
---help---
|
||||||
|
Enable DMA transfers on UART7
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
|
||||||
menu "USART8 Configuration"
|
menu "USART8 Configuration"
|
||||||
@ -1748,6 +1870,13 @@ config USART8_OFLOWCONTROL
|
|||||||
---help---
|
---help---
|
||||||
Enable USART8 CTS flow control
|
Enable USART8 CTS flow control
|
||||||
|
|
||||||
|
config USART8_DMA
|
||||||
|
bool "USART8 DMA support"
|
||||||
|
default n
|
||||||
|
select SERIAL_DMA
|
||||||
|
---help---
|
||||||
|
Enable DMA transfers on USART8
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
|
||||||
menu "UART8 Configuration"
|
menu "UART8 Configuration"
|
||||||
@ -1806,6 +1935,13 @@ config UART8_OFLOWCONTROL
|
|||||||
---help---
|
---help---
|
||||||
Enable UART8 CTS flow control
|
Enable UART8 CTS flow control
|
||||||
|
|
||||||
|
config UART8_DMA
|
||||||
|
bool "UART8 DMA support"
|
||||||
|
default n
|
||||||
|
select SERIAL_DMA
|
||||||
|
---help---
|
||||||
|
Enable DMA transfers on UART8
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
|
||||||
menu "SCI0 Configuration"
|
menu "SCI0 Configuration"
|
||||||
|
@ -249,6 +249,9 @@ static int uart_putxmitchar(FAR uart_dev_t *dev, int ch, bool oktoblock)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
dev->xmitwaiting = true;
|
dev->xmitwaiting = true;
|
||||||
|
#ifdef CONFIG_SERIAL_DMA
|
||||||
|
uart_dmatxavail(dev);
|
||||||
|
#endif
|
||||||
uart_enabletxint(dev);
|
uart_enabletxint(dev);
|
||||||
ret = uart_takesem(&dev->xmitsem, true);
|
ret = uart_takesem(&dev->xmitsem, true);
|
||||||
uart_disabletxint(dev);
|
uart_disabletxint(dev);
|
||||||
@ -507,6 +510,9 @@ static ssize_t uart_write(FAR struct file *filep, FAR const char *buffer,
|
|||||||
|
|
||||||
if (dev->xmit.head != dev->xmit.tail)
|
if (dev->xmit.head != dev->xmit.tail)
|
||||||
{
|
{
|
||||||
|
#ifdef CONFIG_SERIAL_DMA
|
||||||
|
uart_dmatxavail(dev);
|
||||||
|
#endif
|
||||||
uart_enabletxint(dev);
|
uart_enabletxint(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -707,6 +713,20 @@ static ssize_t uart_read(FAR struct file *filep, FAR char *buffer, size_t buflen
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
flags = irqsave();
|
flags = irqsave();
|
||||||
|
|
||||||
|
#ifdef CONFIG_SERIAL_DMA
|
||||||
|
/* If RX buffer is empty move tail and head to zero position */
|
||||||
|
|
||||||
|
if (rxbuf->head == rxbuf->tail)
|
||||||
|
{
|
||||||
|
rxbuf->head = rxbuf->tail = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Notify DMA that there is free space in the RX buffer */
|
||||||
|
|
||||||
|
uart_dmarxfree(dev);
|
||||||
|
#endif
|
||||||
|
|
||||||
uart_enablerxint(dev);
|
uart_enablerxint(dev);
|
||||||
|
|
||||||
#ifdef CONFIG_SERIAL_REMOVABLE
|
#ifdef CONFIG_SERIAL_REMOVABLE
|
||||||
@ -778,6 +798,27 @@ static ssize_t uart_read(FAR struct file *filep, FAR char *buffer, size_t buflen
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_SERIAL_DMA
|
||||||
|
flags = irqsave();
|
||||||
|
|
||||||
|
/* If RX buffer is empty move tail and head to zero position */
|
||||||
|
|
||||||
|
if (rxbuf->head == rxbuf->tail)
|
||||||
|
{
|
||||||
|
rxbuf->head = rxbuf->tail = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
irqrestore(flags);
|
||||||
|
|
||||||
|
/* Notify DMA that there is free space in the RX buffer */
|
||||||
|
|
||||||
|
uart_dmarxfree(dev);
|
||||||
|
|
||||||
|
/* RX interrupt could be disabled by RX buffer overflow. Enable it now. */
|
||||||
|
|
||||||
|
uart_enablerxint(dev);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_SERIAL_IFLOWCONTROL
|
#ifdef CONFIG_SERIAL_IFLOWCONTROL
|
||||||
#ifdef CONFIG_SERIAL_IFLOWCONTROL_WATERMARKS
|
#ifdef CONFIG_SERIAL_IFLOWCONTROL_WATERMARKS
|
||||||
/* How many bytes are now buffered */
|
/* How many bytes are now buffered */
|
||||||
@ -1281,6 +1322,12 @@ static int uart_open(FAR struct file *filep)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_SERIAL_DMA
|
||||||
|
/* Notify DMA that there is free space in the RX buffer */
|
||||||
|
|
||||||
|
uart_dmarxfree(dev);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Enable the RX interrupt */
|
/* Enable the RX interrupt */
|
||||||
|
|
||||||
uart_enablerxint(dev);
|
uart_enablerxint(dev);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/************************************************************************************
|
/************************************************************************************
|
||||||
* drivers/serial/serialirq.c
|
* drivers/serial/serialirq.c
|
||||||
*
|
*
|
||||||
* Copyright (C) 2007-2009, 2011 Gregory Nutt. All rights reserved.
|
* Copyright (C) 2007-2009, 2011, 2015 Gregory Nutt. All rights reserved.
|
||||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -65,10 +65,269 @@
|
|||||||
* Private Functions
|
* Private Functions
|
||||||
************************************************************************************/
|
************************************************************************************/
|
||||||
|
|
||||||
|
/************************************************************************************
|
||||||
|
* Name: uart_dorxflowcontrol
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Handle RX flow control using watermark levels or not
|
||||||
|
*
|
||||||
|
************************************************************************************/
|
||||||
|
|
||||||
|
#ifdef CONFIG_SERIAL_IFLOWCONTROL
|
||||||
|
#ifdef CONFIG_SERIAL_IFLOWCONTROL_WATERMARKS
|
||||||
|
static inline bool uart_dorxflowcontrol(FAR uart_dev_t *dev,
|
||||||
|
FAR struct uart_buffer_s *rxbuf,
|
||||||
|
unsigned int watermark)
|
||||||
|
{
|
||||||
|
unsigned int nbuffered;
|
||||||
|
|
||||||
|
/* How many bytes are buffered */
|
||||||
|
|
||||||
|
if (rxbuf->head >= rxbuf->tail)
|
||||||
|
{
|
||||||
|
nbuffered = rxbuf->head - rxbuf->tail;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nbuffered = rxbuf->size - rxbuf->tail + rxbuf->head;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Is the level now above the watermark level that we need to report? */
|
||||||
|
|
||||||
|
if (nbuffered >= watermark)
|
||||||
|
{
|
||||||
|
/* Let the lower level driver know that the watermark level has been
|
||||||
|
* crossed. It will probably activate RX flow control.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (uart_rxflowcontrol(dev, nbuffered, true))
|
||||||
|
{
|
||||||
|
/* Low-level driver activated RX flow control, exit loop now. */
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static inline bool uart_dorxflowcontrol(FAR uart_dev_t *dev,
|
||||||
|
FAR struct uart_buffer_s *rxbuf,
|
||||||
|
bool is_full)
|
||||||
|
{
|
||||||
|
/* Check if RX buffer is full and allow serial low-level driver to pause
|
||||||
|
* processing. This allows proper utilization of hardware flow control.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (is_full)
|
||||||
|
{
|
||||||
|
if (uart_rxflowcontrol(dev, rxbuf->size, true))
|
||||||
|
{
|
||||||
|
/* Low-level driver activated RX flow control, exit loop now. */
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
/************************************************************************************
|
/************************************************************************************
|
||||||
* Public Functions
|
* Public Functions
|
||||||
************************************************************************************/
|
************************************************************************************/
|
||||||
|
|
||||||
|
/************************************************************************************
|
||||||
|
* Name: uart_xmitchars_dma
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Set up to transfer bytes from the TX circular buffer using DMA
|
||||||
|
*
|
||||||
|
************************************************************************************/
|
||||||
|
|
||||||
|
#ifdef CONFIG_SERIAL_DMA
|
||||||
|
void uart_xmitchars_dma(FAR uart_dev_t *dev)
|
||||||
|
{
|
||||||
|
FAR struct uart_dmaxfer_s *xfer = &dev->dmatx;
|
||||||
|
|
||||||
|
if (dev->xmit.head == dev->xmit.tail)
|
||||||
|
{
|
||||||
|
/* No data to transfer. */
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dev->xmit.tail < dev->xmit.head)
|
||||||
|
{
|
||||||
|
xfer->buffer = &dev->xmit.buffer[dev->xmit.tail];
|
||||||
|
xfer->length = dev->xmit.head - dev->xmit.tail;
|
||||||
|
xfer->nbuffer = NULL;
|
||||||
|
xfer->nlength = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
xfer->buffer = &dev->xmit.buffer[dev->xmit.tail];
|
||||||
|
xfer->length = dev->xmit.size - dev->xmit.tail;
|
||||||
|
xfer->nbuffer = dev->xmit.buffer;
|
||||||
|
xfer->nlength = dev->xmit.head;
|
||||||
|
}
|
||||||
|
|
||||||
|
uart_dmasend(dev);
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_SERIAL_DMA */
|
||||||
|
|
||||||
|
/************************************************************************************
|
||||||
|
* Name: uart_xmitchars_done
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Perform operations necessary at the complete of DMA including adjusting the
|
||||||
|
* TX circular buffer indices and waking up of any threads that may have been
|
||||||
|
* waiting for space to become available in the TX circular buffer.
|
||||||
|
*
|
||||||
|
************************************************************************************/
|
||||||
|
|
||||||
|
#ifdef CONFIG_SERIAL_DMA
|
||||||
|
void uart_xmitchars_done(FAR uart_dev_t *dev)
|
||||||
|
{
|
||||||
|
FAR struct uart_dmaxfer_s *xfer = &dev->dmatx;
|
||||||
|
size_t nbytes = xfer->nbytes;
|
||||||
|
struct uart_buffer_s *txbuf = &dev->xmit;
|
||||||
|
|
||||||
|
/* Move tail for nbytes. */
|
||||||
|
|
||||||
|
txbuf->tail = (txbuf->tail + nbytes) % txbuf->size;
|
||||||
|
xfer->nbytes = 0;
|
||||||
|
xfer->length = xfer->nlength = 0;
|
||||||
|
|
||||||
|
/* If any bytes were removed from the buffer, inform any waiters there there is
|
||||||
|
* space available.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (nbytes)
|
||||||
|
{
|
||||||
|
uart_datasent(dev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_SERIAL_DMA */
|
||||||
|
|
||||||
|
/************************************************************************************
|
||||||
|
* Name: uart_recvchars_dma
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Set up to receive bytes into the RX circular buffer using DMA
|
||||||
|
*
|
||||||
|
************************************************************************************/
|
||||||
|
|
||||||
|
#ifdef CONFIG_SERIAL_DMA
|
||||||
|
void uart_recvchars_dma(FAR uart_dev_t *dev)
|
||||||
|
{
|
||||||
|
FAR struct uart_dmaxfer_s *xfer = &dev->dmarx;
|
||||||
|
FAR struct uart_buffer_s *rxbuf = &dev->recv;
|
||||||
|
#ifdef CONFIG_SERIAL_IFLOWCONTROL_WATERMARKS
|
||||||
|
unsigned int watermark;
|
||||||
|
#endif
|
||||||
|
bool is_full;
|
||||||
|
int nexthead = rxbuf->head + 1;
|
||||||
|
|
||||||
|
if (nexthead >= rxbuf->size)
|
||||||
|
{
|
||||||
|
nexthead = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
is_full = nexthead == rxbuf->tail;
|
||||||
|
|
||||||
|
#ifdef CONFIG_SERIAL_IFLOWCONTROL_WATERMARKS
|
||||||
|
/* Pre-calcuate the watermark level that we will need to test against. */
|
||||||
|
|
||||||
|
watermark = (CONFIG_SERIAL_IFLOWCONTROL_UPPER_WATERMARK * rxbuf->size) / 100;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_SERIAL_IFLOWCONTROL
|
||||||
|
#ifdef CONFIG_SERIAL_IFLOWCONTROL_WATERMARKS
|
||||||
|
if (uart_dorxflowcontrol(dev, rxbuf, watermark))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (uart_dorxflowcontrol(dev, rxbuf, is_full))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (is_full)
|
||||||
|
{
|
||||||
|
/* If there is no free space in receive buffer we cannot start DMA
|
||||||
|
* transfer.
|
||||||
|
*/
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rxbuf->tail <= rxbuf->head)
|
||||||
|
{
|
||||||
|
xfer->buffer = &rxbuf->buffer[rxbuf->head];
|
||||||
|
xfer->nbuffer = rxbuf->buffer;
|
||||||
|
|
||||||
|
if (rxbuf->tail > 0)
|
||||||
|
{
|
||||||
|
xfer->length = rxbuf->size - rxbuf->head;
|
||||||
|
xfer->nlength = rxbuf->tail - 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
xfer->length = rxbuf->size - rxbuf->head - 1;
|
||||||
|
xfer->nlength = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
xfer->buffer = &rxbuf->buffer[rxbuf->head];
|
||||||
|
xfer->length = rxbuf->tail - rxbuf->head - 1;
|
||||||
|
xfer->nbuffer = NULL;
|
||||||
|
xfer->nlength = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uart_dmareceive(dev);
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_SERIAL_DMA */
|
||||||
|
|
||||||
|
/************************************************************************************
|
||||||
|
* Name: uart_recvchars_done
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Perform operations necessary at the complete of DMA including adjusting the
|
||||||
|
* RX circular buffer indices and waking up of any threads that may have been
|
||||||
|
* waiting for new data to become available in the RX circular buffer.
|
||||||
|
*
|
||||||
|
************************************************************************************/
|
||||||
|
|
||||||
|
#ifdef CONFIG_SERIAL_DMA
|
||||||
|
void uart_recvchars_done(FAR uart_dev_t *dev)
|
||||||
|
{
|
||||||
|
FAR struct uart_dmaxfer_s *xfer = &dev->dmarx;
|
||||||
|
FAR struct uart_buffer_s *rxbuf = &dev->recv;
|
||||||
|
size_t nbytes = xfer->nbytes;
|
||||||
|
|
||||||
|
/* Move head for nbytes. */
|
||||||
|
|
||||||
|
rxbuf->head = (rxbuf->head + nbytes) % rxbuf->size;
|
||||||
|
xfer->nbytes = 0;
|
||||||
|
xfer->length = xfer->nlength = 0;
|
||||||
|
|
||||||
|
/* If any bytes were added to the buffer, inform any waiters there is new
|
||||||
|
* incoming data available.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (nbytes)
|
||||||
|
{
|
||||||
|
uart_datareceived(dev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_SERIAL_DMA */
|
||||||
|
|
||||||
/************************************************************************************
|
/************************************************************************************
|
||||||
* Name: uart_xmitchars
|
* Name: uart_xmitchars
|
||||||
*
|
*
|
||||||
@ -145,6 +404,7 @@ void uart_recvchars(FAR uart_dev_t *dev)
|
|||||||
unsigned int status;
|
unsigned int status;
|
||||||
int nexthead = rxbuf->head + 1;
|
int nexthead = rxbuf->head + 1;
|
||||||
uint16_t nbytes = 0;
|
uint16_t nbytes = 0;
|
||||||
|
bool is_full;
|
||||||
|
|
||||||
if (nexthead >= rxbuf->size)
|
if (nexthead >= rxbuf->size)
|
||||||
{
|
{
|
||||||
@ -163,52 +423,19 @@ void uart_recvchars(FAR uart_dev_t *dev)
|
|||||||
|
|
||||||
while (uart_rxavailable(dev))
|
while (uart_rxavailable(dev))
|
||||||
{
|
{
|
||||||
bool is_full = (nexthead == rxbuf->tail);
|
is_full = (nexthead == rxbuf->tail);
|
||||||
char ch;
|
char ch;
|
||||||
|
|
||||||
#ifdef CONFIG_SERIAL_IFLOWCONTROL
|
#ifdef CONFIG_SERIAL_IFLOWCONTROL
|
||||||
#ifdef CONFIG_SERIAL_IFLOWCONTROL_WATERMARKS
|
#ifdef CONFIG_SERIAL_IFLOWCONTROL_WATERMARKS
|
||||||
unsigned int nbuffered;
|
if (uart_dorxflowcontrol(dev, rxbuf, watermark))
|
||||||
|
|
||||||
/* How many bytes are buffered */
|
|
||||||
|
|
||||||
if (rxbuf->head >= rxbuf->tail)
|
|
||||||
{
|
{
|
||||||
nbuffered = rxbuf->head - rxbuf->tail;
|
break;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
nbuffered = rxbuf->size - rxbuf->tail + rxbuf->head;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Is the level now above the watermark level that we need to report? */
|
|
||||||
|
|
||||||
if (nbuffered >= watermark)
|
|
||||||
{
|
|
||||||
/* Let the lower level driver know that the watermark level has been
|
|
||||||
* crossed. It will probably activate RX flow control.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (uart_rxflowcontrol(dev, nbuffered, true))
|
|
||||||
{
|
|
||||||
/* Low-level driver activated RX flow control, exit loop now. */
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
/* Check if RX buffer is full and allow serial low-level driver to pause
|
if (uart_dorxflowcontrol(dev, rxbuf, is_full))
|
||||||
* processing. This allows proper utilization of hardware flow control.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (is_full)
|
|
||||||
{
|
{
|
||||||
if (uart_rxflowcontrol(dev, rxbuf->size, true))
|
break;
|
||||||
{
|
|
||||||
/* Low-level driver activated RX flow control, exit loop now. */
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
@ -240,7 +467,7 @@ void uart_recvchars(FAR uart_dev_t *dev)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If any bytes were added to the buffer, inform any waiters there there is new
|
/* If any bytes were added to the buffer, inform any waiters there is new
|
||||||
* incoming data available.
|
* incoming data available.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/************************************************************************************
|
/************************************************************************************
|
||||||
* include/nuttx/serial/serial.h
|
* include/nuttx/serial/serial.h
|
||||||
*
|
*
|
||||||
* Copyright (C) 2007-2008, 2012-2014 Gregory Nutt. All rights reserved.
|
* Copyright (C) 2007-2008, 2012-2015 Gregory Nutt. All rights reserved.
|
||||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -104,9 +104,16 @@
|
|||||||
#define uart_send(dev,ch) dev->ops->send(dev,ch)
|
#define uart_send(dev,ch) dev->ops->send(dev,ch)
|
||||||
#define uart_receive(dev,s) dev->ops->receive(dev,s)
|
#define uart_receive(dev,s) dev->ops->receive(dev,s)
|
||||||
|
|
||||||
|
#ifdef CONFIG_SERIAL_DMA
|
||||||
|
# define uart_dmasend(dev) dev->ops->dmasend(dev)
|
||||||
|
# define uart_dmareceive(dev) dev->ops->dmareceive(dev)
|
||||||
|
# define uart_dmarxfree(dev) dev->ops->dmarxfree(dev)
|
||||||
|
# define uart_dmatxavail(dev) dev->ops->dmatxavail(dev)
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_SERIAL_IFLOWCONTROL
|
#ifdef CONFIG_SERIAL_IFLOWCONTROL
|
||||||
#define uart_rxflowcontrol(dev,n,u) \
|
# define uart_rxflowcontrol(dev,n,u) \
|
||||||
(dev->ops->rxflowcontrol && dev->ops->rxflowcontrol(dev,n,u))
|
(dev->ops->rxflowcontrol && dev->ops->rxflowcontrol(dev,n,u))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/************************************************************************************
|
/************************************************************************************
|
||||||
@ -127,6 +134,17 @@ struct uart_buffer_s
|
|||||||
FAR char *buffer; /* Pointer to the allocated buffer memory */
|
FAR char *buffer; /* Pointer to the allocated buffer memory */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef CONFIG_SERIAL_DMA
|
||||||
|
struct uart_dmaxfer_s
|
||||||
|
{
|
||||||
|
FAR char *buffer; /* First DMA buffer */
|
||||||
|
FAR char *nbuffer; /* Next DMA buffer */
|
||||||
|
size_t length; /* Length of first DMA buffer */
|
||||||
|
size_t nlength; /* Length of next DMA buffer */
|
||||||
|
size_t nbytes; /* Bytes actually transferred by DMA from both buffers */
|
||||||
|
};
|
||||||
|
#endif /* CONFIG_SERIAL_DMA */
|
||||||
|
|
||||||
/* This structure defines all of the operations providd by the architecture specific
|
/* This structure defines all of the operations providd by the architecture specific
|
||||||
* logic. All fields must be provided with non-NULL function pointers by the
|
* logic. All fields must be provided with non-NULL function pointers by the
|
||||||
* caller of uart_register().
|
* caller of uart_register().
|
||||||
@ -199,6 +217,24 @@ struct uart_ops_s
|
|||||||
unsigned int nbuffered, bool upper);
|
unsigned int nbuffered, bool upper);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_SERIAL_DMA
|
||||||
|
/* Start transfer bytes from the TX circular buffer using DMA */
|
||||||
|
|
||||||
|
CODE void (*dmasend)(FAR struct uart_dev_s *dev);
|
||||||
|
|
||||||
|
/* Start transfer bytes from the TX circular buffer using DMA */
|
||||||
|
|
||||||
|
CODE void (*dmareceive)(FAR struct uart_dev_s *dev);
|
||||||
|
|
||||||
|
/* Notify DMA that there is free space in the RX buffer */
|
||||||
|
|
||||||
|
CODE void (*dmarxfree)(FAR struct uart_dev_s *dev);
|
||||||
|
|
||||||
|
/* Notify DMA that there is data to be transferred in the TX buffer */
|
||||||
|
|
||||||
|
CODE void (*dmatxavail)(FAR struct uart_dev_s *dev);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* This method will send one byte on the UART */
|
/* This method will send one byte on the UART */
|
||||||
|
|
||||||
CODE void (*send)(FAR struct uart_dev_s *dev, int ch);
|
CODE void (*send)(FAR struct uart_dev_s *dev, int ch);
|
||||||
@ -266,6 +302,14 @@ struct uart_dev_s
|
|||||||
struct uart_buffer_s xmit; /* Describes transmit buffer */
|
struct uart_buffer_s xmit; /* Describes transmit buffer */
|
||||||
struct uart_buffer_s recv; /* Describes receive buffer */
|
struct uart_buffer_s recv; /* Describes receive buffer */
|
||||||
|
|
||||||
|
#ifdef CONFIG_SERIAL_DMA
|
||||||
|
|
||||||
|
/* DMA transfers */
|
||||||
|
|
||||||
|
struct uart_dmaxfer_s dmatx; /* Describes transmit DMA transfer */
|
||||||
|
struct uart_dmaxfer_s dmarx; /* Describes receive DMA transfer */
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Driver interface */
|
/* Driver interface */
|
||||||
|
|
||||||
FAR const struct uart_ops_s *ops; /* Arch-specific operations */
|
FAR const struct uart_ops_s *ops; /* Arch-specific operations */
|
||||||
@ -385,6 +429,58 @@ void uart_datasent(FAR uart_dev_t *dev);
|
|||||||
void uart_connected(FAR uart_dev_t *dev, bool connected);
|
void uart_connected(FAR uart_dev_t *dev, bool connected);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/************************************************************************************
|
||||||
|
* Name: uart_xmitchars_dma
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Set up to transfer bytes from the TX circular buffer using DMA
|
||||||
|
*
|
||||||
|
************************************************************************************/
|
||||||
|
|
||||||
|
#ifdef CONFIG_SERIAL_DMA
|
||||||
|
void uart_xmitchars_dma(FAR uart_dev_t *dev);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/************************************************************************************
|
||||||
|
* Name: uart_xmitchars_done
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Perform operations necessary at the complete of DMA including adjusting the
|
||||||
|
* TX circular buffer indices and waking up of any threads that may have been
|
||||||
|
* waiting for space to become available in the TX circular buffer.
|
||||||
|
*
|
||||||
|
************************************************************************************/
|
||||||
|
|
||||||
|
#ifdef CONFIG_SERIAL_DMA
|
||||||
|
void uart_xmitchars_done(FAR uart_dev_t *dev);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/************************************************************************************
|
||||||
|
* Name: uart_recvchars_dma
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Set up to receive bytes into the RX circular buffer using DMA
|
||||||
|
*
|
||||||
|
************************************************************************************/
|
||||||
|
|
||||||
|
#ifdef CONFIG_SERIAL_DMA
|
||||||
|
void uart_recvchars_dma(FAR uart_dev_t *dev);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/************************************************************************************
|
||||||
|
* Name: uart_recvchars_done
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Perform operations necessary at the complete of DMA including adjusting the
|
||||||
|
* RX circular buffer indices and waking up of any threads that may have been
|
||||||
|
* waiting for new data to become available in the RX circular buffer.
|
||||||
|
*
|
||||||
|
************************************************************************************/
|
||||||
|
|
||||||
|
#ifdef CONFIG_SERIAL_DMA
|
||||||
|
void uart_recvchars_done(FAR uart_dev_t *dev);
|
||||||
|
#endif
|
||||||
|
|
||||||
#undef EXTERN
|
#undef EXTERN
|
||||||
#if defined(__cplusplus)
|
#if defined(__cplusplus)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user