Skip to content

Commit

Permalink
boards/samv7/common: add support for UART RX DMA polling
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
michallenc committed Jan 29, 2025
1 parent 8e58b0f commit db38122
Show file tree
Hide file tree
Showing 4 changed files with 339 additions and 0 deletions.
31 changes: 31 additions & 0 deletions boards/arm/samv7/common/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
110 changes: 110 additions & 0 deletions boards/arm/samv7/common/include/board_uart_rxdma_poll.h
Original file line number Diff line number Diff line change
@@ -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 */
4 changes: 4 additions & 0 deletions boards/arm/samv7/common/src/Make.defs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
194 changes: 194 additions & 0 deletions boards/arm/samv7/common/src/sam_uart_rxdma_poll.c
Original file line number Diff line number Diff line change
@@ -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 <nuttx/config.h>

#include <nuttx/arch.h>
#include <nuttx/board.h>
#include <arch/board/board.h>

#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 */

0 comments on commit db38122

Please sign in to comment.