From db381228aae38674adb71bd2bbcee59ce1851ec5 Mon Sep 17 00:00:00 2001 From: Michal Lenc Date: Wed, 29 Jan 2025 10:48:33 +0100 Subject: [PATCH] boards/samv7/common: add support for UART RX DMA polling This adds the support for RX DMA polling. The board initializes timer channel SAMV7_UART_RXDMA_POLL_TIMER with frequency SAMV7_UART_RXDMA_POLL_FREQUENCY that triggers DMA polling function. Signed-off-by: Michal Lenc --- boards/arm/samv7/common/Kconfig | 31 +++ .../common/include/board_uart_rxdma_poll.h | 110 ++++++++++ boards/arm/samv7/common/src/Make.defs | 4 + .../samv7/common/src/sam_uart_rxdma_poll.c | 194 ++++++++++++++++++ 4 files changed, 339 insertions(+) create mode 100644 boards/arm/samv7/common/include/board_uart_rxdma_poll.h create mode 100644 boards/arm/samv7/common/src/sam_uart_rxdma_poll.c 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 */