mirror of
https://github.com/RT-Thread/rt-thread.git
synced 2026-02-06 00:45:22 +08:00
bsp: k230: add pdma driver support
This commit introduces the PDMA (Peripheral DMA) driver for K230 SoC, providing essential DMA capabilities for peripheral data transfers. Key features implemented: 1. PDMA channel request/release management 2. Channel start/stop control 3. Interrupt callback registration 4. Data transfer between device ports and DDR memory The driver includes: - Core driver implementation (drv_pdma.c/h) - Build system support (SConscript) - Basic test cases (test_pdma.c) Tested with: - PDMA channel request/release - DDR to UART TX FIFO transfers - UART RX FIFO to DDR transfers Signed-off-by: eatvector <2302147681@qq.com>
This commit is contained in:
@@ -228,6 +228,7 @@ CONFIG_FINSH_THREAD_PRIORITY=20
|
||||
CONFIG_FINSH_THREAD_STACK_SIZE=8192
|
||||
CONFIG_FINSH_USING_HISTORY=y
|
||||
CONFIG_FINSH_HISTORY_LINES=5
|
||||
# CONFIG_FINSH_USING_WORD_OPERATION is not set
|
||||
CONFIG_FINSH_USING_SYMTAB=y
|
||||
CONFIG_FINSH_CMD_SIZE=80
|
||||
CONFIG_MSH_USING_BUILT_IN_COMMANDS=y
|
||||
@@ -710,6 +711,7 @@ CONFIG_RT_USING_VDSO=y
|
||||
# CONFIG_PKG_USING_QMODBUS is not set
|
||||
# CONFIG_PKG_USING_PNET is not set
|
||||
# CONFIG_PKG_USING_OPENER is not set
|
||||
# CONFIG_PKG_USING_FREEMQTT is not set
|
||||
# end of IoT - internet of things
|
||||
|
||||
#
|
||||
@@ -937,6 +939,7 @@ CONFIG_RT_USING_VDSO=y
|
||||
# CONFIG_PKG_USING_RMP is not set
|
||||
# CONFIG_PKG_USING_R_RHEALSTONE is not set
|
||||
# CONFIG_PKG_USING_HEARTBEAT is not set
|
||||
# CONFIG_PKG_USING_MICRO_ROS_RTTHREAD_PACKAGE is not set
|
||||
# end of system packages
|
||||
|
||||
#
|
||||
@@ -1061,6 +1064,8 @@ CONFIG_RT_USING_VDSO=y
|
||||
#
|
||||
# HC32 DDL Drivers
|
||||
#
|
||||
# CONFIG_PKG_USING_HC32F4_CMSIS_DRIVER is not set
|
||||
# CONFIG_PKG_USING_HC32F4_SERIES_DRIVER is not set
|
||||
# end of HC32 DDL Drivers
|
||||
|
||||
#
|
||||
@@ -1074,6 +1079,21 @@ CONFIG_RT_USING_VDSO=y
|
||||
# CONFIG_PKG_USING_NXP_IMX6UL_DRIVER is not set
|
||||
# CONFIG_PKG_USING_NXP_IMXRT_DRIVER is not set
|
||||
# end of NXP HAL & SDK Drivers
|
||||
|
||||
#
|
||||
# NUVOTON Drivers
|
||||
#
|
||||
# CONFIG_PKG_USING_NUVOTON_CMSIS_DRIVER is not set
|
||||
# CONFIG_PKG_USING_NUVOTON_SERIES_DRIVER is not set
|
||||
# CONFIG_PKG_USING_NUVOTON_ARM926_LIB is not set
|
||||
# end of NUVOTON Drivers
|
||||
|
||||
#
|
||||
# GD32 Drivers
|
||||
#
|
||||
# CONFIG_PKG_USING_GD32_ARM_CMSIS_DRIVER is not set
|
||||
# CONFIG_PKG_USING_GD32_ARM_SERIES_DRIVER is not set
|
||||
# end of GD32 Drivers
|
||||
# end of HAL & SDK Drivers
|
||||
|
||||
#
|
||||
@@ -1149,6 +1169,7 @@ CONFIG_RT_USING_VDSO=y
|
||||
# CONFIG_PKG_USING_STHS34PF80 is not set
|
||||
# CONFIG_PKG_USING_P3T1755 is not set
|
||||
# CONFIG_PKG_USING_QMI8658 is not set
|
||||
# CONFIG_PKG_USING_ICM20948 is not set
|
||||
# end of sensors drivers
|
||||
|
||||
#
|
||||
@@ -1243,6 +1264,7 @@ CONFIG_RT_USING_VDSO=y
|
||||
# CONFIG_PKG_USING_SERVO is not set
|
||||
# CONFIG_PKG_USING_SEAN_WS2812B is not set
|
||||
# CONFIG_PKG_USING_IC74HC165 is not set
|
||||
# CONFIG_PKG_USING_IST8310 is not set
|
||||
# CONFIG_PKG_USING_SPI_TOOLS is not set
|
||||
# end of peripheral libraries and drivers
|
||||
|
||||
@@ -1601,6 +1623,7 @@ CONFIG_BSP_USING_SDIO0=y
|
||||
CONFIG_BSP_SD_MNT_DEVNAME="sd0p1"
|
||||
# CONFIG_BSP_USING_TIMERS is not set
|
||||
# CONFIG_BSP_USING_WDT is not set
|
||||
# CONFIG_BSP_USING_PDMA is not set
|
||||
# CONFIG_BSP_UTEST_DRIVERS is not set
|
||||
# end of Drivers Configuration
|
||||
|
||||
|
||||
@@ -107,6 +107,45 @@ menu "Drivers Configuration"
|
||||
|
||||
endif
|
||||
|
||||
menuconfig BSP_USING_PDMA
|
||||
bool "Enable PDMA"
|
||||
select RT_USING_PDMA
|
||||
default n
|
||||
|
||||
if BSP_USING_PDMA
|
||||
config BSP_USING_PDMA_CHANNEL0
|
||||
bool "Enable PDMA Channel 0"
|
||||
default n
|
||||
|
||||
config BSP_USING_PDMA_CHANNEL1
|
||||
bool "Enable PDMA Channel 1"
|
||||
default n
|
||||
|
||||
config BSP_USING_PDMA_CHANNEL2
|
||||
bool "Enable PDMA Channel 2"
|
||||
default n
|
||||
|
||||
config BSP_USING_PDMA_CHANNEL3
|
||||
bool "Enable PDMA Channel 3"
|
||||
default n
|
||||
|
||||
config BSP_USING_PDMA_CHANNEL4
|
||||
bool "Enable PDMA Channel 4"
|
||||
default n
|
||||
|
||||
config BSP_USING_PDMA_CHANNEL5
|
||||
bool "Enable PDMA Channel 5"
|
||||
default n
|
||||
|
||||
config BSP_USING_PDMA_CHANNEL6
|
||||
bool "Enable PDMA Channel 6"
|
||||
default n
|
||||
|
||||
config BSP_USING_PDMA_CHANNEL7
|
||||
bool "Enable PDMA Channel 7"
|
||||
default n
|
||||
endif
|
||||
|
||||
config BSP_UTEST_DRIVERS
|
||||
bool "Enable drivers utest"
|
||||
select RT_USING_UTEST
|
||||
|
||||
12
bsp/k230/drivers/interdrv/pdma/SConscript
Normal file
12
bsp/k230/drivers/interdrv/pdma/SConscript
Normal file
@@ -0,0 +1,12 @@
|
||||
# RT-Thread building script for component
|
||||
|
||||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = Glob('*.c')
|
||||
CPPPATH = [cwd]
|
||||
|
||||
group = DefineGroup('PDMA', src, depend = [''], CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
||||
|
||||
887
bsp/k230/drivers/interdrv/pdma/drv_pdma.c
Normal file
887
bsp/k230/drivers/interdrv/pdma/drv_pdma.c
Normal file
File diff suppressed because it is too large
Load Diff
334
bsp/k230/drivers/interdrv/pdma/drv_pdma.h
Normal file
334
bsp/k230/drivers/interdrv/pdma/drv_pdma.h
Normal file
@@ -0,0 +1,334 @@
|
||||
/* Copyright (c) 2023, Canaan Bright Sight Co., Ltd
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2006-2025 RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef DRV_PDMA_H_
|
||||
#define DRV_PDMA_H_
|
||||
|
||||
#include <rtdef.h>
|
||||
|
||||
/**
|
||||
* @brief PDMA channel enumeration
|
||||
*/
|
||||
typedef enum pdma_ch {
|
||||
PDMA_CH_0 = 0, /**< Channel 0 */
|
||||
PDMA_CH_1 = 1, /**< Channel 1 */
|
||||
PDMA_CH_2 = 2, /**< Channel 2 */
|
||||
PDMA_CH_3 = 3, /**< Channel 3 */
|
||||
PDMA_CH_4 = 4, /**< Channel 4 */
|
||||
PDMA_CH_5 = 5, /**< Channel 5 */
|
||||
PDMA_CH_6 = 6, /**< Channel 6 */
|
||||
PDMA_CH_7 = 7, /**< Channel 7 */
|
||||
PDMA_CH_MAX, /**< Maximum channel count */
|
||||
} pdma_ch_e;
|
||||
|
||||
/* PDMA Register Access Macros */
|
||||
#define pdma_write32(addr, val) writel((val), (volatile void *)(addr))
|
||||
#define pdma_read32(addr) readl((volatile void *)(addr))
|
||||
|
||||
/* PDMA Configuration Constants */
|
||||
#define PDMA_MAX_WAIT_MS 2000 /* Maximum wait time in milliseconds */
|
||||
#define PDMA_MAX_LINE_SIZE 64 /* Maximum data block size per transfer */
|
||||
|
||||
/**
|
||||
* @brief PDMA Interrupt Mask Definitions
|
||||
*
|
||||
* These macros define the bitmask values for different PDMA interrupt types.
|
||||
* Each interrupt type is represented by a unique bit in the interrupt status register.
|
||||
*/
|
||||
#define PDMA_PDONE_INT 0x00000001 /**< Transfer Done interrupt mask */
|
||||
#define PDMA_PITEM_INT 0x00000100 /**< Item Done interrupt mask */
|
||||
#define PDMA_PPAUSE_INT 0x00010000 /**< Transfer Paused interrupt mask */
|
||||
#define PDMA_PTOUT_INT 0x01000000 /**< Transfer Timeout interrupt mask */
|
||||
|
||||
/* Combined interrupt masks */
|
||||
#define PDMA_ALL_INTS (PDMA_PDONE_INT | PDMA_PITEM_INT | PDMA_PPAUSE_INT | PDMA_PTOUT_INT) /**< All PDMA interrupts mask */
|
||||
|
||||
#define PDMA_IRQ_OFFSET 16
|
||||
|
||||
/**
|
||||
* @brief PDMA channel interrupt numbers
|
||||
* @note These values equal (manual_specified_IRQ + PDMA_IRQ_OFFSET)
|
||||
*/
|
||||
#define PDMA_CHANNEL0_IRQn (123 + PDMA_IRQ_OFFSET) /**< Channel 0 IRQ number */
|
||||
#define PDMA_CHANNEL1_IRQn (180 + PDMA_IRQ_OFFSET) /**< Channel 1 IRQ number */
|
||||
#define PDMA_CHANNEL2_IRQn (181 + PDMA_IRQ_OFFSET) /**< Channel 2 IRQ number */
|
||||
#define PDMA_CHANNEL3_IRQn (182 + PDMA_IRQ_OFFSET) /**< Channel 3 IRQ number */
|
||||
#define PDMA_CHANNEL4_IRQn (183 + PDMA_IRQ_OFFSET) /**< Channel 4 IRQ number */
|
||||
#define PDMA_CHANNEL5_IRQn (184 + PDMA_IRQ_OFFSET) /**< Channel 5 IRQ number */
|
||||
#define PDMA_CHANNEL6_IRQn (185 + PDMA_IRQ_OFFSET) /**< Channel 6 IRQ number */
|
||||
#define PDMA_CHANNEL7_IRQn (186 + PDMA_IRQ_OFFSET) /**< Channel 7 IRQ number */
|
||||
|
||||
/**
|
||||
* @brief PDMA channel state enumeration
|
||||
*/
|
||||
typedef enum {
|
||||
PDMA_STATE_BUSY = 0x1, /**< Channel is busy transferring */
|
||||
PDMA_STATE_PAUSE = 0x2, /**< Channel is paused */
|
||||
} pdma_state_e;
|
||||
|
||||
/**
|
||||
* @brief PDMA control command enumeration
|
||||
*/
|
||||
typedef enum {
|
||||
PDMA_CMD_START = 0x1, /**< Start DMA transfer command */
|
||||
PDMA_CMD_STOP = 0x2, /**< Stop DMA transfer command */
|
||||
PDMA_CMD_RESUME = 0x4, /**< Resume paused transfer command */
|
||||
} pdma_cmd_e;
|
||||
|
||||
/**
|
||||
* @brief PDMA data transfer direction enumeration
|
||||
*
|
||||
* @param TX Transmit direction: Data flows from system memory to peripheral device
|
||||
* @param RX Receive direction: Data flows from peripheral device to system memory
|
||||
*/
|
||||
typedef enum pdma_rxtx {
|
||||
TX = 0,
|
||||
RX = 1,
|
||||
} pdma_rxtx_e;
|
||||
|
||||
/**
|
||||
* @brief PDMA burst length configuration
|
||||
*/
|
||||
typedef enum pdma_burst_len {
|
||||
PBURST_LEN_1 = 0,
|
||||
PBURST_LEN_2 = 1,
|
||||
PBURST_LEN_3 = 2,
|
||||
PBURST_LEN_4 = 3,
|
||||
PBURST_LEN_5 = 4,
|
||||
PBURST_LEN_6 = 5,
|
||||
PBURST_LEN_7 = 6,
|
||||
PBURST_LEN_8 = 7,
|
||||
PBURST_LEN_9 = 8,
|
||||
PBURST_LEN_10 = 9,
|
||||
PBURST_LEN_11 = 10,
|
||||
PBURST_LEN_12 = 11,
|
||||
PBURST_LEN_13 = 12,
|
||||
PBURST_LEN_14 = 13,
|
||||
PBURST_LEN_15 = 14,
|
||||
PBURST_LEN_16 = 15,
|
||||
} pdma_burst_len_e;
|
||||
|
||||
/**
|
||||
* @brief Peripheral device selection for PDMA
|
||||
*/
|
||||
typedef enum device_sel {
|
||||
UART0_TX = 0,
|
||||
UART0_RX = 1,
|
||||
UART1_TX = 2,
|
||||
UART1_RX = 3,
|
||||
UART2_TX = 4,
|
||||
UART2_RX = 5,
|
||||
UART3_TX = 6,
|
||||
UART3_RX = 7,
|
||||
UART4_TX = 8,
|
||||
UART4_RX = 9,
|
||||
I2C0_TX = 10,
|
||||
I2C0_RX = 11,
|
||||
I2C1_TX = 12,
|
||||
I2C1_RX = 13,
|
||||
I2C2_TX = 14,
|
||||
I2C2_RX = 15,
|
||||
I2C3_TX = 16,
|
||||
I2C3_RX = 17,
|
||||
I2C4_TX = 18,
|
||||
I2C4_RX = 19,
|
||||
AUDIO_TX = 20,
|
||||
AUDIO_RX = 21,
|
||||
JAMLINK0_TX = 22,
|
||||
JAMLINK0_RX = 23,
|
||||
JAMLINK1_TX = 24,
|
||||
JAMLINK1_RX = 25,
|
||||
JAMLINK2_TX = 26,
|
||||
JAMLINK2_RX = 27,
|
||||
JAMLINK3_TX = 28,
|
||||
JAMLINK3_RX = 29,
|
||||
ADC0 = 30,
|
||||
ADC1 = 31,
|
||||
ADC2 = 32,
|
||||
PDM_IN = 33,
|
||||
} device_sel_e;
|
||||
|
||||
/**
|
||||
* @brief Data endianness configuration
|
||||
*/
|
||||
typedef enum pendian {
|
||||
PDEFAULT,
|
||||
PBYTE2,
|
||||
PBYTE4,
|
||||
PBYTE8,
|
||||
} pendian_e;
|
||||
|
||||
/**
|
||||
* @brief Data transfer size configuration
|
||||
*/
|
||||
typedef enum hsize {
|
||||
PSBYTE1,
|
||||
PSBYTE2,
|
||||
PSBYTE4,
|
||||
} hsize_e;
|
||||
|
||||
/**
|
||||
* @brief Source address behavior configuration
|
||||
*/
|
||||
typedef enum src_type {
|
||||
CONTINUE,
|
||||
FIXED,
|
||||
} src_type_e;
|
||||
|
||||
/**
|
||||
* @brief PDMA channel configuration structure
|
||||
*/
|
||||
typedef struct pdma_ch_cfg {
|
||||
volatile rt_uint32_t ch_src_type : 1;
|
||||
volatile rt_uint32_t ch_dev_hsize : 2;
|
||||
volatile rt_uint32_t reserved0 : 1;
|
||||
volatile rt_uint32_t ch_dat_endian : 2;
|
||||
volatile rt_uint32_t reserved1 : 2;
|
||||
volatile rt_uint32_t ch_dev_blen : 4;
|
||||
volatile rt_uint32_t ch_priority : 4;
|
||||
volatile rt_uint32_t ch_dev_tout : 12;
|
||||
volatile rt_uint32_t reserved2 : 4;
|
||||
} pdma_ch_cfg_t;
|
||||
|
||||
/**
|
||||
* @brief PDMA channel register structure
|
||||
*/
|
||||
typedef struct pdma_ch_reg {
|
||||
volatile rt_uint32_t ch_ctl;
|
||||
volatile rt_uint32_t ch_status;
|
||||
volatile pdma_ch_cfg_t ch_cfg;
|
||||
volatile rt_uint32_t ch_llt_saddr;
|
||||
volatile rt_uint32_t reserved[4];
|
||||
} pdma_ch_reg_t;
|
||||
|
||||
/**
|
||||
* @brief PDMA controller register structure
|
||||
*/
|
||||
typedef struct pdma_reg {
|
||||
volatile rt_uint32_t pdma_ch_en;
|
||||
volatile rt_uint32_t dma_int_mask;
|
||||
volatile rt_uint32_t dma_int_stat;
|
||||
volatile rt_uint32_t reserved[5];
|
||||
volatile pdma_ch_reg_t pdma_ch_reg[8];
|
||||
volatile rt_uint32_t ch_peri_dev_sel[8];
|
||||
} pdma_reg_t;
|
||||
|
||||
/**
|
||||
* @brief PDMA Linked List Transfer (LLT) node structure
|
||||
*/
|
||||
typedef struct pdma_llt {
|
||||
rt_uint32_t line_size : 30; /**< Transfer length in bytes */
|
||||
rt_uint32_t pause : 1; /**< Pause control flag */
|
||||
rt_uint32_t node_intr : 1; /**< Node completion interrupt enable */
|
||||
rt_uint32_t src_addr; /**< Source address */
|
||||
rt_uint32_t dst_addr; /**< Destination address */
|
||||
rt_uint32_t next_llt_addr; /**< Next LLT node address */
|
||||
} pdma_llt_t;
|
||||
|
||||
/**
|
||||
* @brief User PDMA configuration structure
|
||||
*/
|
||||
typedef struct usr_pdma_cfg {
|
||||
device_sel_e device; /**< Peripheral device selection */
|
||||
rt_uint8_t *src_addr; /**< Source address pointer */
|
||||
rt_uint8_t *dst_addr; /**< Destination address pointer */
|
||||
rt_uint32_t line_size; /**< Transfer block size */
|
||||
pdma_ch_cfg_t pdma_ch_cfg; /**< Channel configuration */
|
||||
} usr_pdma_cfg_t;
|
||||
|
||||
/**
|
||||
* @brief DMA transfer event callback function type
|
||||
* @param ch DMA channel number where event occurred
|
||||
* @param is_done Event type indicator:
|
||||
* - RT_TRUE: Transfer completed successfully
|
||||
* - RT_FALSE: Transfer terminated due to timeout
|
||||
* @note This callback will be invoked for both successful completion
|
||||
* and timeout conditions. The is_done parameter distinguishes
|
||||
* between these cases.
|
||||
*/
|
||||
typedef void (*k230_pdma_callback_t)(rt_uint8_t ch, rt_bool_t is_done);
|
||||
|
||||
/**
|
||||
* @brief DMA channel callback structure
|
||||
* Contains callback function for DMA channel events
|
||||
*/
|
||||
typedef struct {
|
||||
k230_pdma_callback_t callback; /* Callback function pointer */
|
||||
} k230_pdma_chan_cb_t;
|
||||
|
||||
/**
|
||||
* @brief PDMA controller structure
|
||||
*/
|
||||
typedef struct {
|
||||
rt_int32_t hardlock; /**< Hardware lock for critical sections */
|
||||
volatile pdma_reg_t *reg; /**< PDMA register base address */
|
||||
|
||||
struct {
|
||||
rt_uint32_t irq_num; /**< Interrupt number for this channel */
|
||||
void *llt_va; /**< Virtual address of LLT memory (NULL if not allocated) */
|
||||
rt_size_t page_size; /**< Page size for each channel */
|
||||
k230_pdma_chan_cb_t cb; /**< Channel callback functions */
|
||||
rt_bool_t is_hw_configured; /**< Hardware config flag (must set via k230_pdma_config() before start to avoid BUSY lock) */
|
||||
rt_bool_t menuconfig_enabled;/**< Channel enabled in menuconfig */
|
||||
} chan[PDMA_CH_MAX]; /**< Channel configuration array */
|
||||
} pdma_controller_t;
|
||||
|
||||
/**
|
||||
* @brief Set PDMA callback function for specified channel
|
||||
*/
|
||||
rt_err_t k230_pdma_set_callback(rt_uint8_t ch, k230_pdma_callback_t func);
|
||||
|
||||
/**
|
||||
* @brief Request an available PDMA channel
|
||||
*/
|
||||
rt_err_t k230_pdma_request_channel(rt_uint8_t *ch);
|
||||
|
||||
/**
|
||||
* @brief Release allocated PDMA channel
|
||||
*/
|
||||
rt_err_t k230_pdma_release_channel(rt_uint8_t ch);
|
||||
|
||||
/**
|
||||
* @brief Start PDMA transfer on specified channel
|
||||
*/
|
||||
rt_err_t k230_pdma_start(rt_uint8_t ch);
|
||||
|
||||
/**
|
||||
* @brief Stop PDMA transfer on specified channel
|
||||
*/
|
||||
rt_err_t k230_pdma_stop(rt_uint8_t ch);
|
||||
|
||||
/**
|
||||
* @brief Configure PDMA channel parameters
|
||||
*/
|
||||
rt_err_t k230_pdma_config(rt_uint8_t ch, usr_pdma_cfg_t *ucfg);
|
||||
|
||||
#endif /* DRV_PDMA_H_ */
|
||||
@@ -17,7 +17,10 @@ if GetDepend('RT_UTEST_USING_ALL_CASES') or GetDepend('BSP_UTEST_DRIVERS'):
|
||||
|
||||
if GetDepend('BSP_USING_PWM'):
|
||||
src += ['test_pwm.c']
|
||||
|
||||
|
||||
if GetDepend('BSP_USING_PDMA'):
|
||||
src += ['test_pdma.c']
|
||||
|
||||
group = DefineGroup('utestcases', src, depend = [''])
|
||||
|
||||
Return('group')
|
||||
299
bsp/k230/drivers/utest/test_pdma.c
Normal file
299
bsp/k230/drivers/utest/test_pdma.c
Normal file
@@ -0,0 +1,299 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2025, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/*
|
||||
* Refer to PDMA driver implementation and hardware specifications
|
||||
* This is a PDMA (Peripheral DMA) device test routine. The program tests:
|
||||
* - Channel allocation/release functionality
|
||||
* - DMA transfer from DDR to UART (TX)
|
||||
* - DMA transfer from UART to DDR (RX)
|
||||
*
|
||||
* "test_pdma_tx" tests DDR-to-UART transmission:
|
||||
* - Should display 3 identical rows of data on screen
|
||||
* - Each row consists of 62 'x' characters
|
||||
* - Total output should contain exactly 186 'x' characters
|
||||
* - Data is transferred from DDR to UART0 TX FIFO via PDMA
|
||||
*
|
||||
* "test_pdma_rx" tests UART-to-DDR reception:
|
||||
* - After "Send test data by keyboard input within 2 seconds" prompt appears:
|
||||
* - User has 2 seconds to input data via keyboard
|
||||
* - Input will be captured via UART0 RX FIFO to DDR through PDMA
|
||||
* - Test will display first 16 bytes of received DDR data
|
||||
* - Verify output matches partial input data
|
||||
*/
|
||||
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
#include "utest.h"
|
||||
#include <mmu.h>
|
||||
#include "board.h"
|
||||
#include "drv_pdma.h"
|
||||
|
||||
#define UART0_IRQ 0x10
|
||||
|
||||
#define CACHE_LINE_SIZE 64
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TEST_PDMA_EVENT_NONE,
|
||||
TEST_PDMA_EVENT_COMPLETE,
|
||||
TEST_PDMA_EVENT_TIMEOUT
|
||||
} test_pdma_event_t;
|
||||
|
||||
static rt_event_t test_pdma_event = RT_NULL;
|
||||
|
||||
void test_pdma_call_back(rt_uint8_t ch, rt_bool_t is_done)
|
||||
{
|
||||
/* Send completion or timeout event based on callback status */
|
||||
test_pdma_event_t event_type = is_done ? TEST_PDMA_EVENT_COMPLETE : TEST_PDMA_EVENT_TIMEOUT;
|
||||
rt_event_send(test_pdma_event, event_type);
|
||||
}
|
||||
|
||||
void test_pdma_request()
|
||||
{
|
||||
rt_uint8_t ch;
|
||||
rt_err_t err;
|
||||
|
||||
/* Test channel allocation for all available channels */
|
||||
for (rt_uint8_t i = 0; i < PDMA_CH_MAX; i++)
|
||||
{
|
||||
err = k230_pdma_request_channel(&ch);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
}
|
||||
|
||||
/* Should fail when all channels are allocated */
|
||||
err = k230_pdma_request_channel(&ch);
|
||||
uassert_int_equal(err, -RT_EBUSY);
|
||||
|
||||
/* Release channel 0 and test re-allocation */
|
||||
err = k230_pdma_release_channel(0);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
err = k230_pdma_request_channel(&ch);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
/* Cleanup: release all channels */
|
||||
for (rt_uint8_t i = 0; i < PDMA_CH_MAX; i++)
|
||||
{
|
||||
err = k230_pdma_release_channel(i);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
}
|
||||
}
|
||||
|
||||
/* Test DMA transfer from DDR to UART output */
|
||||
void test_pdma_tx()
|
||||
{
|
||||
rt_uint8_t ch;
|
||||
rt_err_t err;
|
||||
rt_uint32_t recv_event;
|
||||
rt_uint32_t len = 192;
|
||||
|
||||
/* For software-managed DMA cache coherency, ensure buffer start address and size are cache-line aligned */
|
||||
uint8_t *buf = rt_malloc_align(len, CACHE_LINE_SIZE);
|
||||
void *buf_pa = rt_kmem_v2p(buf);
|
||||
|
||||
for (int i = 0; i < 192; i++)
|
||||
{
|
||||
if ((i + 2) % 64 == 0)
|
||||
{
|
||||
buf[i] = '\r';
|
||||
}
|
||||
else if ((i + 1) % 64 == 0)
|
||||
{
|
||||
buf[i] = '\n';
|
||||
}
|
||||
else
|
||||
{
|
||||
buf[i] = 'x';
|
||||
}
|
||||
}
|
||||
|
||||
rt_event_control(test_pdma_event, RT_IPC_CMD_RESET, NULL);
|
||||
|
||||
/* Configure DMA transfer */
|
||||
err = k230_pdma_request_channel(&ch);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
usr_pdma_cfg_t pdma_cfg;
|
||||
/* Configure DMA parameters */
|
||||
pdma_cfg.device = UART0_TX;
|
||||
pdma_cfg.src_addr = buf_pa;
|
||||
pdma_cfg.dst_addr = (rt_uint8_t *)UART0_BASE_ADDR;
|
||||
pdma_cfg.line_size = len;
|
||||
|
||||
/* Set channel configuration */
|
||||
pdma_cfg.pdma_ch_cfg.ch_src_type = CONTINUE;
|
||||
pdma_cfg.pdma_ch_cfg.ch_dev_hsize = PSBYTE1;
|
||||
pdma_cfg.pdma_ch_cfg.ch_dat_endian = PDEFAULT;
|
||||
pdma_cfg.pdma_ch_cfg.ch_dev_blen = PBURST_LEN_16;
|
||||
pdma_cfg.pdma_ch_cfg.ch_priority = 7;
|
||||
pdma_cfg.pdma_ch_cfg.ch_dev_tout = 0xFFF;
|
||||
|
||||
err = k230_pdma_set_callback(ch, test_pdma_call_back);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
err = k230_pdma_config(ch, &pdma_cfg);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
/* Start transfer and wait for completion */
|
||||
err = k230_pdma_start(ch);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
err = rt_event_recv(test_pdma_event,
|
||||
TEST_PDMA_EVENT_COMPLETE | TEST_PDMA_EVENT_TIMEOUT,
|
||||
RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR,
|
||||
RT_WAITING_FOREVER,
|
||||
&recv_event);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
uassert_int_equal(recv_event, TEST_PDMA_EVENT_COMPLETE);
|
||||
|
||||
/* Cleanup */
|
||||
err = k230_pdma_stop(ch);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
err = k230_pdma_release_channel(ch);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
rt_free_align(buf);
|
||||
LOG_I("PDMA TX test completed successfully");
|
||||
}
|
||||
|
||||
/* Test DMA transfer from UART RX FIFO to DDR */
|
||||
void test_pdma_rx()
|
||||
{
|
||||
rt_uint8_t ch;
|
||||
rt_err_t err;
|
||||
rt_uint32_t recv_event;
|
||||
rt_uint32_t len = 16;
|
||||
|
||||
uint8_t *buf = rt_malloc_align(64, CACHE_LINE_SIZE);
|
||||
void *buf_pa = rt_kmem_v2p(buf);
|
||||
|
||||
/* Reset event before starting test */
|
||||
rt_event_control(test_pdma_event, RT_IPC_CMD_RESET, NULL);
|
||||
|
||||
/* Request DMA channel */
|
||||
err = k230_pdma_request_channel(&ch);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
/* Configure DMA parameters */
|
||||
usr_pdma_cfg_t pdma_cfg;
|
||||
pdma_cfg.device = UART0_RX;
|
||||
pdma_cfg.src_addr = (rt_uint8_t *)UART0_BASE_ADDR;
|
||||
pdma_cfg.dst_addr = buf_pa;
|
||||
pdma_cfg.line_size = len;
|
||||
|
||||
/* Set channel configuration */
|
||||
pdma_cfg.pdma_ch_cfg.ch_src_type = FIXED;
|
||||
pdma_cfg.pdma_ch_cfg.ch_dev_hsize = PSBYTE1;
|
||||
pdma_cfg.pdma_ch_cfg.ch_dat_endian = PDEFAULT;
|
||||
pdma_cfg.pdma_ch_cfg.ch_dev_blen = PBURST_LEN_16;
|
||||
pdma_cfg.pdma_ch_cfg.ch_priority = 7;
|
||||
pdma_cfg.pdma_ch_cfg.ch_dev_tout = 0xFFF;
|
||||
|
||||
/* Set callback and configure DMA */
|
||||
err = k230_pdma_set_callback(ch, test_pdma_call_back);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
err = k230_pdma_config(ch, &pdma_cfg);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
LOG_I("Send test data by keyboard input within 2 seconds (to UART receive buffer)");
|
||||
|
||||
/* Setup 2 second timeout */
|
||||
rt_tick_t timeout = RT_TICK_PER_SECOND * 2;
|
||||
rt_tick_t start_tick = rt_tick_get();
|
||||
|
||||
/* Mask UART0 interrupt to prevent FIFO access by ISR */
|
||||
rt_hw_interrupt_mask(UART0_IRQ);
|
||||
|
||||
/* Wait for timeout period */
|
||||
while (RT_TRUE)
|
||||
{
|
||||
if (rt_tick_get_delta(start_tick) >= timeout)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Start DMA transfer */
|
||||
k230_pdma_start(ch);
|
||||
|
||||
/* Wait for transfer completion event */
|
||||
err = rt_event_recv(test_pdma_event,
|
||||
TEST_PDMA_EVENT_COMPLETE | TEST_PDMA_EVENT_TIMEOUT,
|
||||
RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR,
|
||||
RT_WAITING_FOREVER,
|
||||
&recv_event);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
uassert_int_equal(recv_event, TEST_PDMA_EVENT_COMPLETE);
|
||||
|
||||
rt_hw_interrupt_umask(UART0_IRQ);
|
||||
|
||||
err = k230_pdma_stop(ch);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
err = k230_pdma_release_channel(ch);
|
||||
uassert_int_equal(err, RT_EOK);
|
||||
|
||||
LOG_I("Got: %.*s", len, buf);
|
||||
|
||||
rt_free_align(buf);
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_init(void)
|
||||
{
|
||||
test_pdma_event = (rt_event_t)rt_malloc(sizeof(struct rt_event));
|
||||
if (test_pdma_event == RT_NULL)
|
||||
{
|
||||
LOG_E("Failed to allocate memory for pdma_event!");
|
||||
return -RT_ENOMEM;
|
||||
}
|
||||
|
||||
if (rt_event_init(test_pdma_event, "pdma_event", RT_IPC_FLAG_FIFO) != RT_EOK)
|
||||
{
|
||||
LOG_E("Failed to init pdma_event!");
|
||||
rt_free(test_pdma_event);
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
LOG_I("PDMA event initialized successfully!");
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t utest_tc_cleanup(void)
|
||||
{
|
||||
rt_free(test_pdma_event);
|
||||
|
||||
/* Check and release all DMA channels */
|
||||
for (rt_uint8_t ch = 0; ch < PDMA_CH_MAX; ch++)
|
||||
{
|
||||
rt_err_t err = k230_pdma_release_channel(ch);
|
||||
|
||||
/* Channel was successfully released now - means it wasn't properly released in test case */
|
||||
if (err == RT_EOK)
|
||||
{
|
||||
LOG_W("PDMA channel %d was not released in test case!", ch);
|
||||
}
|
||||
/* Channel release failed with error other than -RT_EINVAL (unexpected error) */
|
||||
else if (err != -RT_EINVAL)
|
||||
{
|
||||
LOG_I("PDMA channel %d release failed: %d", ch, err);
|
||||
}
|
||||
/* -RT_EINVAL means channel was already released (normal case) - no action needed */
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
void test_pdma()
|
||||
{
|
||||
UTEST_UNIT_RUN(test_pdma_request);
|
||||
UTEST_UNIT_RUN(test_pdma_tx);
|
||||
UTEST_UNIT_RUN(test_pdma_rx);
|
||||
}
|
||||
|
||||
UTEST_TC_EXPORT(test_pdma, "pdma", utest_tc_init, utest_tc_cleanup, 10);
|
||||
@@ -494,6 +494,14 @@
|
||||
/* NXP HAL & SDK Drivers */
|
||||
|
||||
/* end of NXP HAL & SDK Drivers */
|
||||
|
||||
/* NUVOTON Drivers */
|
||||
|
||||
/* end of NUVOTON Drivers */
|
||||
|
||||
/* GD32 Drivers */
|
||||
|
||||
/* end of GD32 Drivers */
|
||||
/* end of HAL & SDK Drivers */
|
||||
|
||||
/* sensors drivers */
|
||||
|
||||
Reference in New Issue
Block a user