diff --git a/Documentation/platforms/arm/samv7/index.rst b/Documentation/platforms/arm/samv7/index.rst index 644a26106f7d2..48c964b4ba071 100644 --- a/Documentation/platforms/arm/samv7/index.rst +++ b/Documentation/platforms/arm/samv7/index.rst @@ -284,10 +284,12 @@ The peripheral implements four timer counter modules, each supporting three inde Universal Synchronous Asynchronous Receiver Transceiver (USART) --------------------------------------------------------------- -The MCU supports both UART and USART controllers. USART peripheral can be used with TX and RX DMA support. -For RX DMA it is required to configure idle bus timeout value in ``CONFIG_SAMV7_SERIAL_DMA_TIMEOUT``. -This option ensures data are read from the DMA buffer even if it is not full yet. DMA support is -implemented only for USART peripheral and not for UART. +The MCU supports both UART and USART controllers. These peripheral can be used with TX and RX DMA support. +For RX DMA on USART, it is possible to configure idle bus timeout value in ``CONFIG_SAMV7_SERIAL_DMA_TIMEOUT``. +This option ensures data are read from the DMA buffer even if it is not full yet. UART peripherals do not have +this timeout support, therefore function :c:func:`sam_serial_dma_poll` should be called periodically to +flush the DMA buffers. Boards can use common :c:func:`board_uart_rxdma_poll_init` function to initialize +a timer triggering the poll. There are several modes in which USART peripheral can operate (ISO7816, IrDA, RS485, SPI, LIN and LON). Currently RS485 and SPI master are supported by NuttX. diff --git a/arch/arm/src/samv7/sam_serial.c b/arch/arm/src/samv7/sam_serial.c index a3d412f545f6e..1a97cc0412c11 100644 --- a/arch/arm/src/samv7/sam_serial.c +++ b/arch/arm/src/samv7/sam_serial.c @@ -66,35 +66,27 @@ /* DMA Configuration */ #if defined(CONFIG_USART0_RXDMA) || defined(CONFIG_USART1_RXDMA) || \ - defined(CONFIG_USART2_RXDMA) + defined(CONFIG_USART2_RXDMA) || defined(CONFIG_UART0_RXDMA) || \ + defined(CONFIG_UART1_RXDMA) || defined(CONFIG_UART2_RXDMA) || \ + defined(CONFIG_UART3_RXDMA) || defined(CONFIG_UART4_RXDMA) # define SERIAL_HAVE_RXDMA #else # undef SERIAL_HAVE_RXDMA #endif -#if defined(CONFIG_UART0_RXDMA) || defined(CONFIG_UART1_RXDMA) || \ - defined(CONFIG_UART2_RXDMA) || defined(CONFIG_UART3_RXDMA) || \ - defined(CONFIG_UART4_RXDMA) -# warning RX DMA is currently supported only for USART driver. -#endif - #if defined(SERIAL_HAVE_RXDMA) && !defined(CONFIG_SAMV7_XDMAC) # error SERIAL DMA requires CONFIG_SAMV7_XDMAC to be selected #endif #if defined(CONFIG_USART0_TXDMA) || defined(CONFIG_USART1_TXDMA) || \ - defined(CONFIG_USART2_TXDMA) + defined(CONFIG_USART2_TXDMA) || defined(CONFIG_UART0_TXDMA) || \ + defined(CONFIG_UART1_TXDMA) || defined(CONFIG_UART2_TXDMA) || \ + defined(CONFIG_UART3_TXDMA) || defined(CONFIG_UART4_TXDMA) # define SERIAL_HAVE_TXDMA #else # undef SERIAL_HAVE_TXDMA #endif -#if defined(CONFIG_UART0_TXDMA) || defined(CONFIG_UART1_TXDMA) || \ - defined(CONFIG_UART2_TXDMA) || defined(CONFIG_UART3_TXDMA) || \ - defined(CONFIG_UART4_TXDMA) -# warning TX DMA is currently supported only for USART driver. -#endif - #if defined(SERIAL_HAVE_TXDMA) && !defined(CONFIG_SAMV7_XDMAC) # error SERIAL DMA requires CONFIG_SAMV7_XDMAC to be selected #endif @@ -447,6 +439,7 @@ struct sam_dev_s #endif bool has_rxdma; /* True if RX DMA is enabled */ + bool has_rxdma_idle; bool has_txdma; bool has_rs485; /* True if RS-485 mode is enabled */ @@ -620,22 +613,47 @@ static const struct uart_ops_s g_uart_rxtxdma_ops = #if defined(CONFIG_SAMV7_UART0) && defined(CONFIG_UART0_SERIALDRIVER) static char g_uart0rxbuffer[CONFIG_UART0_RXBUFSIZE]; static char g_uart0txbuffer[CONFIG_UART0_TXBUFSIZE]; +# ifdef CONFIG_UART0_RXDMA +static uint32_t g_uart0rxbuf[2][RXDMA_BUFFER_SIZE] +aligned_data(ARMV7M_DCACHE_LINESIZE); +static struct chnext_view1_s g_uart0rxdesc[2]; +# endif #endif #if defined(CONFIG_SAMV7_UART1) && defined(CONFIG_UART1_SERIALDRIVER) static char g_uart1rxbuffer[CONFIG_UART1_RXBUFSIZE]; static char g_uart1txbuffer[CONFIG_UART1_TXBUFSIZE]; +# ifdef CONFIG_UART1_RXDMA +static uint32_t g_uart1rxbuf[2][RXDMA_BUFFER_SIZE] +aligned_data(ARMV7M_DCACHE_LINESIZE); +static struct chnext_view1_s g_uart1rxdesc[2]; +# endif #endif #if defined(CONFIG_SAMV7_UART2) && defined(CONFIG_UART2_SERIALDRIVER) static char g_uart2rxbuffer[CONFIG_UART2_RXBUFSIZE]; static char g_uart2txbuffer[CONFIG_UART2_TXBUFSIZE]; +# ifdef CONFIG_UART2_RXDMA +static uint32_t g_uart2rxbuf[2][RXDMA_BUFFER_SIZE] +aligned_data(ARMV7M_DCACHE_LINESIZE); +static struct chnext_view1_s g_uart2rxdesc[2]; +# endif #endif #if defined(CONFIG_SAMV7_UART3) && defined(CONFIG_UART3_SERIALDRIVER) static char g_uart3rxbuffer[CONFIG_UART3_RXBUFSIZE]; static char g_uart3txbuffer[CONFIG_UART3_TXBUFSIZE]; +# ifdef CONFIG_UART3_RXDMA +static uint32_t g_uart3rxbuf[2][RXDMA_BUFFER_SIZE] +aligned_data(ARMV7M_DCACHE_LINESIZE); +static struct chnext_view1_s g_uart3rxdesc[2]; +# endif #endif #if defined(CONFIG_SAMV7_UART4) && defined(CONFIG_UART4_SERIALDRIVER) static char g_uart4rxbuffer[CONFIG_UART4_RXBUFSIZE]; static char g_uart4txbuffer[CONFIG_UART4_TXBUFSIZE]; +# ifdef CONFIG_UART4_RXDMA +static uint32_t g_uart4rxbuf[2][RXDMA_BUFFER_SIZE] +aligned_data(ARMV7M_DCACHE_LINESIZE); +static struct chnext_view1_s g_uart4rxdesc[2]; +# endif #endif #if defined(CONFIG_SAMV7_USART0) && defined(CONFIG_USART0_SERIALDRIVER) static char g_usart0rxbuffer[CONFIG_USART0_RXBUFSIZE]; @@ -677,6 +695,22 @@ static struct sam_dev_s g_uart0priv = .parity = CONFIG_UART0_PARITY, .bits = CONFIG_UART0_BITS, .stopbits2 = CONFIG_UART0_2STOP, +# ifdef CONFIG_UART0_RXDMA + .buf_idx = 0, + .nextcache = 0, + .rxbuf = + { + g_uart0rxbuf[0], g_uart0rxbuf[1] + }, + .desc = + { + &g_uart0rxdesc[0], &g_uart0rxdesc[1] + }, + .has_rxdma = true, +# endif +# ifdef CONFIG_UART0_TXDMA + .has_txdma = true, +# endif }; static uart_dev_t g_uart0port = @@ -691,7 +725,15 @@ static uart_dev_t g_uart0port = .size = CONFIG_UART0_TXBUFSIZE, .buffer = g_uart0txbuffer, }, +# if defined(CONFIG_UART0_RXDMA) && defined(CONFIG_UART0_TXDMA) + .ops = &g_uart_rxtxdma_ops, +# elif defined(CONFIG_UART0_RXDMA) && !defined(CONFIG_UART0_TXDMA) + .ops = &g_uart_rxdma_ops, +# elif !defined(CONFIG_UART0_RXDMA) && defined(CONFIG_UART0_TXDMA) + .ops = &g_uart_txdma_ops, +# else .ops = &g_uart_ops, +# endif .priv = &g_uart0priv, }; #endif @@ -708,6 +750,22 @@ static struct sam_dev_s g_uart1priv = .parity = CONFIG_UART1_PARITY, .bits = CONFIG_UART1_BITS, .stopbits2 = CONFIG_UART1_2STOP, +# ifdef CONFIG_UART1_RXDMA + .buf_idx = 0, + .nextcache = 0, + .rxbuf = + { + g_uart1rxbuf[0], g_uart1rxbuf[1] + }, + .desc = + { + &g_uart1rxdesc[0], &g_uart1rxdesc[1] + }, + .has_rxdma = true, +# endif +# ifdef CONFIG_UART1_TXDMA + .has_txdma = true, +# endif }; static uart_dev_t g_uart1port = @@ -722,7 +780,15 @@ static uart_dev_t g_uart1port = .size = CONFIG_UART1_TXBUFSIZE, .buffer = g_uart1txbuffer, }, +# if defined(CONFIG_UART1_RXDMA) && defined(CONFIG_UART1_TXDMA) + .ops = &g_uart_rxtxdma_ops, +# elif defined(CONFIG_UART1_RXDMA) && !defined(CONFIG_UART1_TXDMA) + .ops = &g_uart_rxdma_ops, +# elif !defined(CONFIG_UART1_RXDMA) && defined(CONFIG_UART1_TXDMA) + .ops = &g_uart_txdma_ops, +# else .ops = &g_uart_ops, +# endif .priv = &g_uart1priv, }; #endif @@ -739,6 +805,22 @@ static struct sam_dev_s g_uart2priv = .parity = CONFIG_UART2_PARITY, .bits = CONFIG_UART2_BITS, .stopbits2 = CONFIG_UART2_2STOP, +# ifdef CONFIG_UART2_RXDMA + .buf_idx = 0, + .nextcache = 0, + .rxbuf = + { + g_uart2rxbuf[0], g_uart2rxbuf[1] + }, + .desc = + { + &g_uart2rxdesc[0], &g_uart2rxdesc[1] + }, + .has_rxdma = true, +# endif +# ifdef CONFIG_UART2_TXDMA + .has_txdma = true, +# endif }; static uart_dev_t g_uart2port = @@ -753,7 +835,15 @@ static uart_dev_t g_uart2port = .size = CONFIG_UART2_TXBUFSIZE, .buffer = g_uart2txbuffer, }, +# if defined(CONFIG_UART2_RXDMA) && defined(CONFIG_UART2_TXDMA) + .ops = &g_uart_rxtxdma_ops, +# elif defined(CONFIG_UART2_RXDMA) && !defined(CONFIG_UART2_TXDMA) + .ops = &g_uart_rxdma_ops, +# elif !defined(CONFIG_UART2_RXDMA) && defined(CONFIG_UART2_TXDMA) + .ops = &g_uart_txdma_ops, +# else .ops = &g_uart_ops, +# endif .priv = &g_uart2priv, }; #endif @@ -770,6 +860,22 @@ static struct sam_dev_s g_uart3priv = .parity = CONFIG_UART3_PARITY, .bits = CONFIG_UART3_BITS, .stopbits2 = CONFIG_UART3_2STOP, +# ifdef CONFIG_UART3_RXDMA + .buf_idx = 0, + .nextcache = 0, + .rxbuf = + { + g_uart3rxbuf[0], g_uart3rxbuf[1] + }, + .desc = + { + &g_uart3rxdesc[0], &g_uart3rxdesc[1] + }, + .has_rxdma = true, +# endif +# ifdef CONFIG_UART3_TXDMA + .has_txdma = true, +# endif }; static uart_dev_t g_uart3port = @@ -784,7 +890,15 @@ static uart_dev_t g_uart3port = .size = CONFIG_UART3_TXBUFSIZE, .buffer = g_uart3txbuffer, }, +# if defined(CONFIG_UART3_RXDMA) && defined(CONFIG_UART3_TXDMA) + .ops = &g_uart_rxtxdma_ops, +# elif defined(CONFIG_UART3_RXDMA) && !defined(CONFIG_UART3_TXDMA) + .ops = &g_uart_rxdma_ops, +# elif !defined(CONFIG_UART3_RXDMA) && defined(CONFIG_UART3_TXDMA) + .ops = &g_uart_txdma_ops, +# else .ops = &g_uart_ops, +# endif .priv = &g_uart3priv, }; #endif @@ -801,6 +915,22 @@ static struct sam_dev_s g_uart4priv = .parity = CONFIG_UART4_PARITY, .bits = CONFIG_UART4_BITS, .stopbits2 = CONFIG_UART4_2STOP, +# ifdef CONFIG_UART4_RXDMA + .buf_idx = 0, + .nextcache = 0, + .rxbuf = + { + g_uart4rxbuf[0], g_uart4rxbuf[1] + }, + .desc = + { + &g_uart4rxdesc[0], &g_uart4rxdesc[1] + }, + .has_rxdma = true, +# endif +# ifdef CONFIG_UART4_TXDMA + .has_txdma = true, +# endif }; static uart_dev_t g_uart4port = @@ -815,7 +945,15 @@ static uart_dev_t g_uart4port = .size = CONFIG_UART4_TXBUFSIZE, .buffer = g_uart4txbuffer, }, +# if defined(CONFIG_UART4_RXDMA) && defined(CONFIG_UART4_TXDMA) + .ops = &g_uart_rxtxdma_ops, +# elif defined(CONFIG_UART4_RXDMA) && !defined(CONFIG_UART4_TXDMA) + .ops = &g_uart_rxdma_ops, +# elif !defined(CONFIG_UART4_RXDMA) && defined(CONFIG_UART4_TXDMA) + .ops = &g_uart_txdma_ops, +# else .ops = &g_uart_ops, +# endif .priv = &g_uart4priv, }; #endif @@ -847,6 +985,7 @@ static struct sam_dev_s g_usart0priv = &g_usart0rxdesc[0], &g_usart0rxdesc[1] }, .has_rxdma = true, + .has_rxdma_idle = true, # endif # ifdef CONFIG_USART0_TXDMA .has_txdma = true, @@ -909,6 +1048,7 @@ static struct sam_dev_s g_usart1priv = &g_usart1rxdesc[0], &g_usart1rxdesc[1] }, .has_rxdma = true, + .has_rxdma_idle = true, # endif # ifdef CONFIG_USART1_TXDMA .has_txdma = true, @@ -971,6 +1111,7 @@ static struct sam_dev_s g_usart2priv = &g_usart2rxdesc[0], &g_usart2rxdesc[1] }, .has_rxdma = true, + .has_rxdma_idle = true, # endif # ifdef CONFIG_USART2_TXDMA .has_txdma = true, @@ -1371,11 +1512,14 @@ static int sam_dma_setup(struct uart_dev_s *dev) sam_dmastart_circular(priv->rxdma, sam_dma_rxcallback, (void *)dev); - /* Use defined timeout to check if RX bus is in idle state */ + if (priv->has_rxdma_idle) + { + /* Use defined timeout to check if RX bus is in idle state */ - sam_serialout(priv, SAM_UART_RTOR_OFFSET, - CONFIG_SAMV7_SERIAL_DMA_TIMEOUT); - sam_serialout(priv, SAM_UART_IER_OFFSET, UART_INT_TIMEOUT); + sam_serialout(priv, SAM_UART_RTOR_OFFSET, + CONFIG_SAMV7_SERIAL_DMA_TIMEOUT); + sam_serialout(priv, SAM_UART_IER_OFFSET, UART_INT_TIMEOUT); + } } #endif @@ -1608,7 +1752,7 @@ static int sam_interrupt(int irq, void *context, void *arg) #ifdef SERIAL_HAVE_RXDMA if ((pending & UART_INT_TIMEOUT) != 0) { - if (priv->has_rxdma) + if (priv->has_rxdma && priv->has_rxdma_idle) { /* We received Timeout interrupt */ @@ -2334,7 +2478,8 @@ static void sam_dma_txcallback(DMA_HANDLE handle, void *arg, int status) * * This polling also in not neccessary if CONFIG_SAMV7_SERIAL_DMA_TIMEOUT * is defined as sam_dma_rxcallback() is called each time idle bus is - * detected. + * detected. This however only applies to USART peripherals, UART has to + * be polled in any case. * ****************************************************************************/ @@ -2345,6 +2490,41 @@ void sam_serial_dma_poll(void) flags = enter_critical_section(); +#ifdef CONFIG_UART0_RXDMA + if (g_uart0priv.rxdma != NULL) + { + sam_dma_rxcallback(g_uart0priv.rxdma, &g_uart0port, 0); + } +#endif + +#ifdef CONFIG_UART1_RXDMA + if (g_uart1priv.rxdma != NULL) + { + sam_dma_rxcallback(g_uart1priv.rxdma, &g_uart1port, 0); + } +#endif + +#ifdef CONFIG_UART2_RXDMA + if (g_uart2priv.rxdma != NULL) + { + sam_dma_rxcallback(g_uart2priv.rxdma, &g_uart2port, 0); + } +#endif + +#ifdef CONFIG_UART3_RXDMA + if (g_uart3priv.rxdma != NULL) + { + sam_dma_rxcallback(g_uart3priv.rxdma, &g_uart3port, 0); + } +#endif + +#ifdef CONFIG_UART4_RXDMA + if (g_uart4priv.rxdma != NULL) + { + sam_dma_rxcallback(g_uart4priv.rxdma, &g_uart4port, 0); + } +#endif + #ifdef CONFIG_USART0_RXDMA if (g_usart0priv.rxdma != NULL) { diff --git a/arch/arm/src/samv7/sam_serial.h b/arch/arm/src/samv7/sam_serial.h index 32f3d62d555a4..8f997da8960af 100644 --- a/arch/arm/src/samv7/sam_serial.h +++ b/arch/arm/src/samv7/sam_serial.h @@ -58,6 +58,21 @@ #elif defined(CONFIG_USART2_SERIAL_CONSOLE) && \ (defined(CONFIG_USART2_RXDMA) || defined(CONFIG_USART2_TXDMA)) # define SERIAL_HAVE_CONSOLE_DMA +#elif defined(CONFIG_UART0_SERIAL_CONSOLE) && \ + (defined(CONFIG_UART0_RXDMA) || defined(CONFIG_UART0_TXDMA)) +# define SERIAL_HAVE_CONSOLE_DMA +#elif defined(CONFIG_UART1_SERIAL_CONSOLE) && \ + (defined(CONFIG_UART1_RXDMA) || defined(CONFIG_UART1_TXDMA)) +# define SERIAL_HAVE_CONSOLE_DMA +#elif defined(CONFIG_UART2_SERIAL_CONSOLE) && \ + (defined(CONFIG_UART2_RXDMA) || defined(CONFIG_UART2_TXDMA)) +# define SERIAL_HAVE_CONSOLE_DMA +#elif defined(CONFIG_UART3_SERIAL_CONSOLE) && \ + (defined(CONFIG_UART3_RXDMA) || defined(CONFIG_UART3_TXDMA)) +# define SERIAL_HAVE_CONSOLE_DMA +#elif defined(CONFIG_UART4_SERIAL_CONSOLE) && \ + (defined(CONFIG_UART4_RXDMA) || defined(CONFIG_UART4_TXDMA)) +# define SERIAL_HAVE_CONSOLE_DMA #endif /* RX/TX DMA ops */ @@ -69,6 +84,16 @@ # define SERIAL_HAVE_NORXDMA_OPS #elif !defined(CONFIG_USART2_RXDMA) && defined(CONFIG_SAMV7_USART2) # define SERIAL_HAVE_NORXDMA_OPS +#elif !defined(CONFIG_UART0_RXDMA) && defined(CONFIG_SAMV7_UART0) +# define SERIAL_HAVE_NORXDMA_OPS +#elif !defined(CONFIG_UART1_RXDMA) && defined(CONFIG_SAMV7_UART1) +# define SERIAL_HAVE_NORXDMA_OPS +#elif !defined(CONFIG_UART2_RXDMA) && defined(CONFIG_SAMV7_UART2) +# define SERIAL_HAVE_NORXDMA_OPS +#elif !defined(CONFIG_UART3_RXDMA) && defined(CONFIG_SAMV7_UART3) +# define SERIAL_HAVE_NORXDMA_OPS +#elif !defined(CONFIG_UART4_RXDMA) && defined(CONFIG_SAMV7_UART4) +# define SERIAL_HAVE_NORXDMA_OPS #endif #undef SERIAL_HAVE_NOTXDMA_OPS @@ -78,6 +103,16 @@ # define SERIAL_HAVE_NOTXDMA_OPS #elif !defined(CONFIG_USART2_TXDMA) && defined(CONFIG_SAMV7_USART2) # define SERIAL_HAVE_NOTXDMA_OPS +#elif !defined(CONFIG_UART0_TXDMA) && defined(CONFIG_SAMV7_UART0) +# define SERIAL_HAVE_NOTXDMA_OPS +#elif !defined(CONFIG_UART1_TXDMA) && defined(CONFIG_SAMV7_UART1) +# define SERIAL_HAVE_NOTXDMA_OPS +#elif !defined(CONFIG_UART2_TXDMA) && defined(CONFIG_SAMV7_UART2) +# define SERIAL_HAVE_NOTXDMA_OPS +#elif !defined(CONFIG_UART3_TXDMA) && defined(CONFIG_SAMV7_UART3) +# define SERIAL_HAVE_NOTXDMA_OPS +#elif !defined(CONFIG_UART4_TXDMA) && defined(CONFIG_SAMV7_UART4) +# define SERIAL_HAVE_NOTXDMA_OPS #endif #undef SERIAL_HAVE_RXTXDMA_OPS @@ -102,6 +137,41 @@ #elif !defined(CONFIG_USART2_TXDMA) && defined(CONFIG_USART2_RXDMA) # define SERIAL_HAVE_RXDMA_OPS #endif +#if defined(CONFIG_UART0_TXDMA) && defined(CONFIG_UART0_RXDMA) +# define SERIAL_HAVE_RXTXDMA_OPS +#elif defined(CONFIG_UART0_TXDMA) && !defined(CONFIG_UART0_RXDMA) +# define SERIAL_HAVE_TXDMA_OPS +#elif !defined(CONFIG_UART0_TXDMA) && defined(CONFIG_UART0_RXDMA) +# define SERIAL_HAVE_RXDMA_OPS +#endif +#if defined(CONFIG_UART1_TXDMA) && defined(CONFIG_UART1_RXDMA) +# define SERIAL_HAVE_RXTXDMA_OPS +#elif defined(CONFIG_UART1_TXDMA) && !defined(CONFIG_UART1_RXDMA) +# define SERIAL_HAVE_TXDMA_OPS +#elif !defined(CONFIG_UART1_TXDMA) && defined(CONFIG_UART1_RXDMA) +# define SERIAL_HAVE_RXDMA_OPS +#endif +#if defined(CONFIG_UART2_TXDMA) && defined(CONFIG_UART2_RXDMA) +# define SERIAL_HAVE_RXTXDMA_OPS +#elif defined(CONFIG_UART2_TXDMA) && !defined(CONFIG_UART2_RXDMA) +# define SERIAL_HAVE_TXDMA_OPS +#elif !defined(CONFIG_UART2_TXDMA) && defined(CONFIG_UART2_RXDMA) +# define SERIAL_HAVE_RXDMA_OPS +#endif +#if defined(CONFIG_UART0_TXDMA) && defined(CONFIG_UART3_RXDMA) +# define SERIAL_HAVE_RXTXDMA_OPS +#elif defined(CONFIG_UART3_TXDMA) && !defined(CONFIG_UART3_RXDMA) +# define SERIAL_HAVE_TXDMA_OPS +#elif !defined(CONFIG_UART3_TXDMA) && defined(CONFIG_UART3_RXDMA) +# define SERIAL_HAVE_RXDMA_OPS +#endif +#if defined(CONFIG_UART4_TXDMA) && defined(CONFIG_UART4_RXDMA) +# define SERIAL_HAVE_RXTXDMA_OPS +#elif defined(CONFIG_UART4_TXDMA) && !defined(CONFIG_UART4_RXDMA) +# define SERIAL_HAVE_TXDMA_OPS +#elif !defined(CONFIG_UART4_TXDMA) && defined(CONFIG_UART4_RXDMA) +# define SERIAL_HAVE_RXDMA_OPS +#endif /* No DMA ops */ @@ -118,27 +188,25 @@ defined(CONFIG_SAMV7_USART2) # define SERIAL_HAVE_NODMA_OPS #endif - -#if defined(CONFIG_SAMV7_UART0) +#if !defined(CONFIG_UART0_TXDMA) && !defined(CONFIG_UART0_RXDMA) && \ + defined(CONFIG_SAMV7_UART0) # define SERIAL_HAVE_NODMA_OPS -# define SERIAL_HAVE_NORXDMA_OPS -# define SERIAL_HAVE_NOTXDMA_OPS -#elif defined(CONFIG_SAMV7_UART1) +#endif +#if !defined(CONFIG_UART1_TXDMA) && !defined(CONFIG_UART1_RXDMA) && \ + defined(CONFIG_SAMV7_UART1) # define SERIAL_HAVE_NODMA_OPS -# define SERIAL_HAVE_NORXDMA_OPS -# define SERIAL_HAVE_NOTXDMA_OPS -#elif defined(CONFIG_SAMV7_UART2) +#endif +#if !defined(CONFIG_UART2_TXDMA) && !defined(CONFIG_UART2_RXDMA) && \ + defined(CONFIG_SAMV7_UART2) # define SERIAL_HAVE_NODMA_OPS -# define SERIAL_HAVE_NORXDMA_OPS -# define SERIAL_HAVE_NOTXDMA_OPS -#elif defined(CONFIG_SAMV7_UART3) +#endif +#if !defined(CONFIG_UART3_TXDMA) && !defined(CONFIG_UART3_RXDMA) && \ + defined(CONFIG_SAMV7_UART3) # define SERIAL_HAVE_NODMA_OPS -# define SERIAL_HAVE_NORXDMA_OPS -# define SERIAL_HAVE_NOTXDMA_OPS -#elif defined(CONFIG_SAMV7_UART4) +#endif +#if !defined(CONFIG_UART4_TXDMA) && !defined(CONFIG_UART4_RXDMA) && \ + defined(CONFIG_SAMV7_UART4) # define SERIAL_HAVE_NODMA_OPS -# define SERIAL_HAVE_NORXDMA_OPS -# define SERIAL_HAVE_NOTXDMA_OPS #endif /**************************************************************************** @@ -156,7 +224,7 @@ * ****************************************************************************/ -#ifdef SERIAL_HAVE_RXDMA +#if defined(SERIAL_HAVE_RXDMA_OPS) || defined(SERIAL_HAVE_RXTXDMA_OPS) void sam_serial_dma_poll(void); #endif diff --git a/boards/arm/samv7/common/Kconfig b/boards/arm/samv7/common/Kconfig index eb33f9c2ee5d6..e196d0e691d78 100644 --- a/boards/arm/samv7/common/Kconfig +++ b/boards/arm/samv7/common/Kconfig @@ -62,6 +62,37 @@ config SAMV7_HSMCI0_MOUNT_MOUNTPOINT endif # SAMV7_HSMCI0_MOUNT +config SAMV7_UART_RXDMA_POLL + bool "Enable U(S)ART RX DMA Polling" + default n + depends on UART0_RXDMA || UART1_RXDMA || UART2_RXDMA || UART3_RXDMA || \ + UART4_RXDMA || USART0_RXDMA || USART1_RXDMA || USART2_RXDMA + ---help--- + UART peripheral with RX DMA need periodic polling that checks the received + DMA buffers for received bytes that have not accumulated to the point + where the DMA interrupt has triggered. + +if SAMV7_UART_RXDMA_POLL + +config SAMV7_UART_RXDMA_POLL_TIMER + int "Timer channel to trigger polling" + default 0 + range 0 11 + ---help--- + The number of timer channel to trigger the polling. Values from 0 to 11 + are available. Be careful not to assign the same channel that is + already configured to other peripheral (ADC trigger for example). + +config SAMV7_UART_RXDMA_POLL_FREQUENCY + int "Timer frequency" + default 1000 + ---help--- + Frequency of the timer to trigger the polling. You might want to keep + this reasonably low to avoid unnecessary overhead and negate + DMA benefit. + +endif # SAMV7_UART_RXDMA_POLL + config SAMV7_PROGMEM_OTA_PARTITION bool default n diff --git a/boards/arm/samv7/common/include/board_uart_rxdma_poll.h b/boards/arm/samv7/common/include/board_uart_rxdma_poll.h new file mode 100644 index 0000000000000..94ce37102088b --- /dev/null +++ b/boards/arm/samv7/common/include/board_uart_rxdma_poll.h @@ -0,0 +1,110 @@ +/**************************************************************************** + * boards/arm/samv7/common/include/board_uart_rxdma_poll.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __BOARDS_ARM_SAMV7_COMMON_INCLUDE_BOARD_UART_RXDMA_POLL_H +#define __BOARDS_ARM_SAMV7_COMMON_INCLUDE_BOARD_UART_RXDMA_POLL_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Functions Definitions + ****************************************************************************/ + +/**************************************************************************** + * Name: board_uart_rxdma_poll_stop + * + * Description: + * This function starts the timer polling UART. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +void board_uart_rxdma_poll_start(void); + +/**************************************************************************** + * Name: board_uart_rxdma_poll_stop + * + * Description: + * This function stops the timer polling UART. No resourses are freed, + * time is just stopped and can be started again. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +void board_uart_rxdma_poll_stop(void); + +/**************************************************************************** + * Name: board_uart_rxdma_poll_init + * + * Description: + * This function initializes and starts the timer that is polling + * UART/USART peripherals with RX DMA enabled. + * + * Input Parameters: + * channel - Channel number (0-11, see TC_CHANx) + * frequency - Timer frequency + * + * Returned Value: + * 0 on success, negative value (errno) on ERROR. + * + ****************************************************************************/ + +int board_uart_rxdma_poll_init(int channel, uint32_t frequency); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __BOARDS_ARM_SAMV7_COMMON_INCLUDE_BOARD_UART_RXDMA_POLL_H */ diff --git a/boards/arm/samv7/common/src/Make.defs b/boards/arm/samv7/common/src/Make.defs index b4097a8ed9753..93ac2dc133bb1 100644 --- a/boards/arm/samv7/common/src/Make.defs +++ b/boards/arm/samv7/common/src/Make.defs @@ -46,6 +46,10 @@ ifeq ($(CONFIG_SAMV7_GPIO_ENC),y) CSRCS += sam_gpio_enc.c endif +ifeq ($(CONFIG_SAMV7_UART_RXDMA_POLL),y) +CSRCS += sam_uart_rxdma_poll.c +endif + DEPPATH += --dep-path src VPATH += :src CFLAGS += ${INCDIR_PREFIX}$(TOPDIR)$(DELIM)arch$(DELIM)$(CONFIG_ARCH)$(DELIM)src$(DELIM)board$(DELIM)src diff --git a/boards/arm/samv7/common/src/sam_uart_rxdma_poll.c b/boards/arm/samv7/common/src/sam_uart_rxdma_poll.c new file mode 100644 index 0000000000000..ded29500865e2 --- /dev/null +++ b/boards/arm/samv7/common/src/sam_uart_rxdma_poll.c @@ -0,0 +1,194 @@ +/**************************************************************************** + * boards/arm/samv7/common/src/sam_uart_rxdma_poll.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include "sam_tc.h" +#include "sam_serial.h" + +#include "board_uart_rxdma_poll.h" + +#ifdef CONFIG_SAMV7_UART_RXDMA_POLL + +static TC_HANDLE poll_tc; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: timer_handler + * + * Description: + * Timer interrupt callback. + * + * Input Parameters: + * tch - The handle that represents the timer state + * arg - An opaque argument provided when the interrupt was registered + * sr - The value of the timer interrupt status register at the time + * that the interrupt occurred. + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void timer_handler(TC_HANDLE tch, void *arg, uint32_t sr) +{ + sam_serial_dma_poll(); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: board_uart_rxdma_poll_stop + * + * Description: + * This function starts the timer polling UART. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +void board_uart_rxdma_poll_start(void) +{ + sam_tc_start(poll_tc); +} + +/**************************************************************************** + * Name: board_uart_rxdma_poll_stop + * + * Description: + * This function stops the timer polling UART. No resourses are freed, + * time is just stopped and can be started again. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +void board_uart_rxdma_poll_stop(void) +{ + sam_tc_stop(poll_tc); +} + +/**************************************************************************** + * Name: board_uart_rxdma_poll_init + * + * Description: + * This function initializes and starts the timer that is polling + * UART/USART peripherals with RX DMA enabled. + * + * Input Parameters: + * channel - Channel number (0-11, see TC_CHANx) + * frequency - Timer frequency + * + * Returned Value: + * 0 on success, negative value (errno) on ERROR. + * + ****************************************************************************/ + +int board_uart_rxdma_poll_init(int channel, uint32_t frequency) +{ + int ret; + uint32_t div; + uint32_t tcclks; + uint32_t actual; + uint32_t mode; + uint32_t fdiv; + uint32_t regval; + + if (channel < TC_CHAN0 || channel > TC_CHAN11) + { + syslog(LOG_ERR, "Invalid channel number: %d", channel); + return -1; + } + + ret = sam_tc_clockselect(frequency, &tcclks, &actual); + if (ret < 0) + { + syslog(LOG_ERR, "sam_tc_divisor failed: %d", ret); + return ret; + } + + div = BOARD_MCK_FREQUENCY / actual; + + /* Set the timer/counter waveform mode the clock input selected by + * sam_tc_clockselect() + */ + + mode = ((tcclks << TC_CMR_TCCLKS_SHIFT) | /* Use selected TCCLKS value */ + TC_CMR_WAVSEL_UPRC | /* UP mode w/ trigger on RC Compare */ + TC_CMR_WAVE); /* Wave mode */ + + /* Now allocate and configure the channel */ + + poll_tc = sam_tc_allocate(channel, mode); + if (!poll_tc) + { + syslog(LOG_ERR, "Failed to allocate channel %d mode %08" PRIx32 "\n", + channel, mode); + return -EINVAL; + } + + /* The divider returned by sam_tc_clockselect() is the reload value + * that will achieve a 1Hz rate. We need to multiply this to get the + * desired frequency. sam_tc_divisor() should have already assure + * that we can do this without overflowing a 32-bit unsigned integer. + */ + + fdiv = div * frequency; + DEBUGASSERT(div > 0 && div <= fdiv); /* Will check for integer overflow */ + + /* Calculate the actual counter value from this divider and the tc input + * frequency. + */ + + regval = BOARD_MCK_FREQUENCY / fdiv; + sam_tc_setregister(poll_tc, TC_REGC, regval); + sam_tc_attach(poll_tc, timer_handler, NULL, TC_INT_CPCS); + + /* And start the timer */ + + sam_tc_start(poll_tc); + + return 0; +} + +#endif /* SAMV7_UART_RXDMA_POLL */