HPM6750开发笔记《DMA接收和发送数据UART例程深度解析》

目录

概述:

端口设置:

代码分析:

运行现象:


概述:

DMA(Direct Memory Access)是一种计算机系统中的数据传输技术,它允许数据在不经过中央处理器(CPU)的直接控制下在内存和外设之间传输。UART(Universal Asynchronous Receiver/Transmitter)是一种串行通信协议,用于在设备之间传输数据。

在DMA接收和发送数据的情况下,DMA可以用于管理UART通信中的数据传输。具体来说:

  1. DMA接收数据:

    • 当UART接收到数据时,通常会触发中断来通知CPU。
    • 使用DMA时,DMA控制器可以直接从UART接收缓冲区中读取数据,并将其存储到内存中,而无需CPU的干预。
    • 这允许在数据到达时实现高效的数据传输,减轻了CPU的负担。
  2. DMA发送数据:

    • 当需要通过UART发送数据时,通常需要将数据写入UART的发送缓冲区,并等待发送完成。
    • 使用DMA时,DMA控制器可以直接从内存中获取要发送的数据,并将其传输到UART发送缓冲区,而无需CPU的干预。
    • 这提高了数据传输的效率,因为CPU可以继续执行其他任务而无需等待数据发送完成。

总的来说,DMA在UART通信中的应用可以提高数据传输的效率,减少对CPU的依赖,使系统能够更有效地处理数据。

端口设置:

波特率115200        1位停止位        无奇偶校验

代码分析:

包含了一些头文件,包含了与底层硬件和外设驱动相关的定义和函数声明

义了一些与UART相关的宏,如UART的基地址、时钟名、DMA请求等

声明了两个全局变量 uart_tx_dma_doneuart_rx_dma_done,用于表示UART的发送和接收DMA是否完成

#include "board.h"
#include "hpm_clock_drv.h"
#include "hpm_uart_drv.h"
#ifdef CONFIG_HAS_HPMSDK_DMAV2
#include "hpm_dmav2_drv.h"
#else
#include "hpm_dma_drv.h"
#endif
#include "hpm_dmamux_drv.h"
#include "hpm_l1c_drv.h"
#include "hpm_common.h"#define TEST_UART                   BOARD_APP_UART_BASE
#define TEST_UART_CLK_NAME          BOARD_APP_UART_CLK_NAME
#define TEST_UART_TX_DMA_REQ        BOARD_APP_UART_TX_DMA_REQ
#define TEST_UART_RX_DMA_REQ        BOARD_APP_UART_RX_DMA_REQ#define TEST_UART_DMA_CONTROLLER    BOARD_APP_HDMA
#define TEST_UART_DMAMUX_CONTROLLER BOARD_APP_DMAMUX
#define TEST_UART_TX_DMA_CHN        (0U)
#define TEST_UART_RX_DMA_CHN        (1U)
#define TEST_UART_TX_DMAMUX_CHN     DMA_SOC_CHN_TO_DMAMUX_CHN(TEST_UART_DMA_CONTROLLER, TEST_UART_TX_DMA_CHN)
#define TEST_UART_RX_DMAMUX_CHN     DMA_SOC_CHN_TO_DMAMUX_CHN(TEST_UART_DMA_CONTROLLER, TEST_UART_RX_DMA_CHN)
#define TEST_UART_DMA_IRQ           BOARD_APP_HDMA_IRQ#define TEST_BUFFER_SIZE   (16U)
ATTR_PLACE_AT_NONCACHEABLE uint8_t uart_buff[TEST_BUFFER_SIZE];volatile bool uart_tx_dma_done;
volatile bool uart_rx_dma_done;

hpm_stat_t uart_tx_trigger_dma(DMA_Type *dma_ptr,uint8_t ch_num,UART_Type *uart_ptr,uint32_t src,uint32_t size)
{dma_handshake_config_t config;dma_default_handshake_config(dma_ptr, &config);config.ch_index = ch_num;config.dst = (uint32_t)&uart_ptr->THR;config.dst_fixed = true;config.src = src;config.src_fixed = false;config.data_width = DMA_TRANSFER_WIDTH_BYTE;config.size_in_byte = size;return dma_setup_handshake(dma_ptr, &config, true);
}
  • 参数说明:

    • dma_ptr: DMA控制器的指针,指向用于配置和控制DMA的硬件寄存器。
    • ch_num: DMA通道号,表示要配置的DMA通道。
    • uart_ptr: UART控制器的指针,指向用于配置和控制UART的硬件寄存器。
    • src: 数据源的地址,这是UART发送数据的来源。
    • size: 要传输的数据大小,以字节为单位。
  • 函数逻辑:

    1. 创建一个 dma_handshake_config_t 类型的结构体变量 config,用于配置DMA的握手参数。
    2. 调用 dma_default_handshake_config 函数初始化 config 结构体,设置了一些默认的DMA握手参数。
    3. 设置 config 结构体的各个成员:
      • ch_index: DMA通道号。
      • dst: 目的地地址,这里是UART的传输保持寄存器(THR - Transmitter Holding Register)的地址。
      • dst_fixed: 目的地地址是否固定,这里设置为 true,表示目的地地址不变。
      • src: 数据源地址,即要发送的数据的地址。
      • src_fixed: 数据源地址是否固定,这里设置为 false,表示数据源地址可能变化。
      • data_width: 数据传输宽度,这里设置为字节宽度。
      • size_in_byte: 要传输的数据大小。
  • 返回值:

    • 调用 dma_setup_handshake 函数,根据配置好的参数设置DMA握手,并返回相应的状态。
  • 注意事项:

    • 该函数通过设置DMA的握手参数,将UART的发送数据配置到DMA通道中,并返回相应的状态,用于后续判断是否配置成功。

这个函数的作用是通过DMA实现UART的发送数据,配置了DMA握手参数,确保数据正确地传输到UART传输保持寄存器中。


hpm_stat_t uart_rx_trigger_dma(DMA_Type *dma_ptr,uint8_t ch_num,UART_Type *uart_ptr,uint32_t dst,uint32_t size)
{dma_handshake_config_t config;dma_default_handshake_config(dma_ptr, &config);config.ch_index = ch_num;config.dst = dst;config.dst_fixed = false;config.src = (uint32_t)&uart_ptr->RBR;config.src_fixed = true;config.data_width = DMA_TRANSFER_WIDTH_BYTE;config.size_in_byte = size;return dma_setup_handshake(dma_ptr, &config, true);
}
  • 参数说明:

    • dma_ptr: DMA控制器的指针,指向用于配置和控制DMA的硬件寄存器。
    • ch_num: DMA通道号,表示要配置的DMA通道。
    • uart_ptr: UART控制器的指针,指向用于配置和控制UART的硬件寄存器。
    • dst: 数据目的地的地址,这是用于存储UART接收数据的缓冲区的地址。
    • size: 要传输的数据大小,以字节为单位。
  • 函数逻辑:

    1. 创建一个 dma_handshake_config_t 类型的结构体变量 config,用于配置DMA的握手参数。
    2. 调用 dma_default_handshake_config 函数初始化 config 结构体,设置了一些默认的DMA握手参数。
    3. 设置 config 结构体的各个成员:
      • ch_index: DMA通道号。
      • dst: 目的地地址,即UART接收数据的缓冲区地址。
      • dst_fixed: 目的地地址是否固定,这里设置为 false,表示目的地地址可能变化。
      • src: 数据源地址,这里是UART的接收保持寄存器(RBR - Receiver Buffer Register)的地址。
      • src_fixed: 数据源地址是否固定,这里设置为 true,表示数据源地址不变。
      • data_width: 数据传输宽度,这里设置为字节宽度。
      • size_in_byte: 要传输的数据大小。
  • 返回值:

    • 调用 dma_setup_handshake 函数,根据配置好的参数设置DMA握手,并返回相应的状态。
  • 注意事项:

    • 该函数通过设置DMA的握手参数,将UART的接收数据配置到DMA通道中,并返回相应的状态,用于后续判断是否配置成功。

这个函数的作用是通过DMA实现UART的接收数据,配置了DMA握手参数,确保UART接收到的数据传输到指定的缓冲区中。


void dma_isr(void)
{volatile hpm_stat_t stat_rx_chn, stat_tx_chn;stat_rx_chn = dma_check_transfer_status(TEST_UART_DMA_CONTROLLER, TEST_UART_RX_DMA_CHN);if (stat_rx_chn & DMA_CHANNEL_STATUS_TC) {uart_rx_dma_done = true;}stat_tx_chn = dma_check_transfer_status(TEST_UART_DMA_CONTROLLER, TEST_UART_TX_DMA_CHN);if (stat_tx_chn & DMA_CHANNEL_STATUS_TC) {uart_tx_dma_done = true;}
}
SDK_DECLARE_EXT_ISR_M(TEST_UART_DMA_IRQ, dma_isr)
  • 函数逻辑:

    1. 定义两个局部变量 stat_rx_chnstat_tx_chn,用于保存DMA通道的传输状态。
    2. 调用 dma_check_transfer_status 函数检查UART接收和发送的DMA通道的传输状态。
    3. 如果接收通道的传输状态中包含 DMA_CHANNEL_STATUS_TC(传输完成),则将 uart_rx_dma_done 置为 true,表示UART接收DMA完成。
    4. 如果发送通道的传输状态中包含 DMA_CHANNEL_STATUS_TC,则将 uart_tx_dma_done 置为 true,表示UART发送DMA完成。
  • 注意事项:

    • volatile 修饰 stat_rx_chnstat_tx_chn,表示这两个变量可能在中断服务例程之外被修改,确保编译器不会对它们进行优化。
    • 中断处理函数通过检查DMA通道的传输状态来确定DMA是否完成,从而设置相应的标志位。
  • SDK_DECLARE_EXT_ISR_M

    • 该宏用于声明外部中断服务例程。在这里,使用该宏声明了中断服务例程 dma_isr 并关联到 TEST_UART_DMA_IRQ 所指定的中断。

这个中断服务例程的作用是在DMA传输完成时被调用,检查相应的DMA通道状态,并设置标志位以通知主程序相应的DMA传输已完成。


int main(void)
{hpm_stat_t stat;uart_config_t config = {0};board_init();printf("UART DMA \n");printf("UART will send back received characters, echo every %d bytes\n", TEST_BUFFER_SIZE);/* if TEST_UART is same as BOARD_CONSOLE_BASE, it has been initialized in board_init(); */board_init_uart(TEST_UART);uart_default_config(TEST_UART, &config);config.fifo_enable = true;config.dma_enable = true;config.src_freq_in_hz = clock_get_frequency(TEST_UART_CLK_NAME);config.tx_fifo_level = uart_tx_fifo_trg_not_full;config.rx_fifo_level = uart_rx_fifo_trg_not_empty;stat = uart_init(TEST_UART, &config);if (stat != status_success) {printf("failed to initialize uart\n");while (1) {}}intc_m_enable_irq_with_priority(TEST_UART_DMA_IRQ, 1);dmamux_config(TEST_UART_DMAMUX_CONTROLLER, TEST_UART_RX_DMAMUX_CHN, TEST_UART_RX_DMA_REQ, true);dmamux_config(TEST_UART_DMAMUX_CONTROLLER, TEST_UART_TX_DMAMUX_CHN, TEST_UART_TX_DMA_REQ, true);while (1) {/* config rx dma transfer */stat = uart_rx_trigger_dma(TEST_UART_DMA_CONTROLLER,TEST_UART_RX_DMA_CHN,TEST_UART,core_local_mem_to_sys_address(BOARD_RUNNING_CORE, (uint32_t)uart_buff),TEST_BUFFER_SIZE);if (stat != status_success) {printf("uart rx trigger dma failed\n");break;}while (!uart_rx_dma_done) {__asm("nop");}uart_rx_dma_done = false;/* config tx dma transfer */stat = uart_tx_trigger_dma(TEST_UART_DMA_CONTROLLER,TEST_UART_TX_DMA_CHN,TEST_UART,core_local_mem_to_sys_address(BOARD_RUNNING_CORE, (uint32_t)uart_buff),TEST_BUFFER_SIZE);if (stat != status_success) {printf("uart tx trigger dma failed\n");break;}while (!uart_tx_dma_done) {__asm("nop");}uart_tx_dma_done = false;}while (1) {__asm("nop");}return 0;
}

  • 代码逻辑:
    1. 调用 board_init 初始化板子。
    2. 输出一些提示信息,包括 "UART DMA" 和 UART 将返回接收到的字符,每次回显的字节数。
    3. 如果 TEST_UARTBOARD_CONSOLE_BASE 相同,说明UART已在 board_init 中初始化。
    4. 调用 board_init_uart 初始化UART。
    5. 初始化UART配置,包括使能FIFO、DMA,设置传输频率等。
    6. 调用 uart_init 初始化UART,检查初始化是否成功。
    7. 启用DMA中断,并配置UART的DMA传输请求。
    8. 进入主循环,循环中:
      • 配置UART接收的DMA传输。
      • 等待UART接收DMA完成。
      • 配置UART发送的DMA传输。
      • 等待UART发送DMA完成。
    9. 如果在DMA配置过程中发生错误,输出相应的错误信息,并跳出主循环。
    10. 主循环最后有一个空操作,用于保持程序运行。

该主函数的主要任务是配置并执行UART的DMA传输,实现了UART接收到的数据的回显。


以下是上述代码的主要运行流程:

  1. 初始化:

    • 初始化嵌入式系统板。
    • 打印一些信息,包括 "UART DMA" 和一条关于将接收到的字符发送回去的消息。
    • 初始化 UART 模块,包括配置 UART 的基本参数和启用 DMA。
  2. 设置中断和DMA多路复用:

    • 启用 UART DMA 中断并设置中断优先级。
    • 配置 DMA 多路复用,将 RX 和 TX DMA 通道与 UART 的相应请求关联。
  3. 主循环:

    • 进入一个无限循环,该循环执行以下操作:
      • 配置 RX DMA 传输:设置 UART 接收的 DMA 传输,将接收到的数据存储在 uart_buff 缓冲区中。
      • 等待 RX DMA 传输完成:通过轮询等待 uart_rx_dma_done 标志。
      • 在数据前添加 "send" 前缀:将 "send" 字符串复制到 uart_buff 的开头。
      • 配置 TX DMA 传输:设置 UART 发送的 DMA 传输,发送整个 uart_buff 缓冲区的数据。
      • 等待 TX DMA 传输完成:通过轮询等待 uart_tx_dma_done 标志。
  4. 结束:

    • 由于主循环是一个无限循环,因此在实际应用中可能需要添加适当的终止条件。
    • 在实际应用中,可能还需要在主循环中添加对接收到的数据的处理逻辑。

总体而言,该代码通过 DMA 实现了 UART 数据的异步传输。接收到的数据被存储在 uart_buff 缓冲区中,并在发送之前添加了 "send" 前缀。此过程一直在一个无限循环中进行,确保持续接收和发送数据。


运行现象:

当工程正确运行后,通过串口手动输入字符串,如 ‘1234567887654321’,则串口终端会收到如下信息:

UART DMA example
UART will send back received characters, echo every 16 bytes
1234567887654321

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/233575.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MYSQL篇--索引高频面试题

mysql索引 1什么是索引? 索引说白了就是一种数据结构,可以协助快速查询数据,以及更新数据库表中的数据,更通俗的来说索引其实就是目录,通过对数据建立索引形成目录,便于去查询数据,而mysql索引…

cmd命令启动C# windows服务程序

因为Process.Manage.Service.exe程序为Windows服务程序,不能直接双击打开,所以需要借助windows系统自带InstallUtil.exe程序来启动它。 以管理员身份运行cmd命令控制台窗口 输入命令进入到InstallUtil.exe程序所在的文件夹 cd C:\Windows\Microsoft.NET…

软件测试|Python中的变量与关键字详解

简介 在Python编程中,变量和关键字是非常重要的概念。它们是构建和控制程序的基本要素。本文将深入介绍Python中的变量和关键字,包括它们的定义、使用方法以及一些常见注意事项。 变量 变量的定义 变量是用于存储数据值的名称。在Python中&#xff0…

洗地机什么牌子好?目前口碑最好的洗地机

如今,人们的生活中,洗地机已经成为了越来越受欢迎的清洁工具,洗地机能迅速而有效地清理地板、地毯以及其他硬表面,为用户提供更加方便快捷的洗地机体验。那么,洗地机什么牌子好?我们一起来看看目前口碑最好的洗地机有…

数据分析基础之《pandas(1)—pandas介绍》

一、pandas介绍 1、2008年Wes McKinney(韦斯麦金尼)开发出的库 2、专门用于数据分析的开源python库 3、以numpy为基础,借力numpy模块在计算方面性能高的优势 4、基于matplotlib能够简便的画图 5、独特的数据结构 6、也是三个单词组合而…

【REST2SQL】02 GO连接Oracle数据库

【REST2SQL】01RDB关系型数据库REST初设计 Oracle数据库我用的最多,先研究Oracle,Go连接Oracle并实现REST和SQL服务。 1 Oracle数据库的安装 我这里安装使用的是Oracle 11g , 安装过程省略5217字。 2 安装Go-ora依赖 go get github.com/sijms/go-ora/v2 安装成功…

华为认证 | 这门HCIE认证正式发布!

华为认证openEuler专家HCIE-openEuler V1.0(中文版)自2023年12月29日起,正式在中国区发布。 01 发布概述 基于“平台生态”战略,围绕“云-管-端”协同的新ICT技术架构,华为公司打造了覆盖ICT领域的认证体系&#xff0…

dnSpy调试工具二次开发1-新增菜单

测试环境: window 10 visual studio 2019 版本号:16.11.15 .net framework 4.8 开发者工具包 下载 .NET Framework 4.8 | 免费官方下载 .net 5开发者工具包 下载 .NET 5.0 (Linux、macOS 和 Windows) 利用git拉取代码(源码地址:Gi…

20240108移远的4G模块EC20在Firefly的AIO-3399J开发板的Android11下调通的步骤

20240108移远的4G模块EC20在Firefly的AIO-3399J开发板的Android11下调通的步骤 2024/1/8 17:50 缘起:使用友善之臂的Android11可以让EC20上网,但是同样的修改步骤,Toybrick的Android11不能让EC20上网。最后确认是selinux的问题! …

MySQL-体系结构

第一层:连接层 接收客户端的连接,完成一些连接的处理,认证授权(校验我们的用户密码)的相关操作,相关的一些安全方案,检查是否超过最大连接数等。 第二层:服务层 :主要完成大多数的核心服务功能&…

代码随想录算法训练营第20天 | 654.最大二叉树 617.合并二叉树 700.二叉搜索树中的搜索 98.验证二叉搜索树

目录 654.最大二叉树 💡解题思路 💻实现代码 617.合并二叉树 💡解题思路 递归 💻实现代码 700.二叉搜索树中的搜索 💡解题思路 递归法 迭代法 💻实现代码 98.验证二叉搜索树 💡解题…

代码随想录算法训练营第二十四天 | 回溯算法

理论基础 代码随想录原文 什么是回溯法 回溯也可以叫做回溯搜索法,它是一种搜索的方式。 回溯是递归的副产品,只要有递归就会有回溯。 回溯法的效率 虽然回溯法很难,不好理解,但是回溯法并不是什么高效的算法。因为回溯的本…

在Kubernetes中优雅地导出和清理Ingress资源

引言 Kubernetes的Ingress资源是定义外部访问集群服务的规则。随着微服务架构和容器化技术的普及,Ingress作为路由流量的关键组件变得愈发重要。当我们需要在环境之间迁移Ingress资源或者备份当前的配置时,就会用到导出功能。然而,直接使用k…

计算机毕业设计----SSM BBS论坛

项目介绍 本项目包含前后台,前台为普通用户登录,后台为管理员登录; 管理员角色包含以下功能: 管理员登录,删除或者编辑用户的帖子,后台管理,友情链接管理,用户管理,版块管理,网站设置,用户设置,版块主题管理等功能。 用户角色…

【linux学习】linux概述

1. linux概述 操作系统主要的功能有两个部分,一是更有效率的控制计算机硬件资源(主要通过核心来控制),二是为程序设计师提供更容易开发软件的环境(系统呼叫提供软件开发环境)。linux就是一套操作系统&…

在Windows上使用VScode阅读kernel源码

有一说一,在Windows上使用Source Inside阅读kernel源码真的很舒服,但是有时候带着轻薄本出去,又不想往轻薄本上安装很多的软件,就使用VS code临时阅读kernel源码。如果不能进行跳转,阅读kernel源码就很难受&#xff0c…

安全测试之SSRF请求伪造

前言 SSRF漏洞是一种在未能获取服务器权限时,利用服务器漏洞,由攻击者构造请求,服务器端发起请求的安全漏洞,攻击者可以利用该漏洞诱使服务器端应用程序向攻击者选择的任意域发出HTTP请求。 很多Web应用都提供了从其他的服务器上…

vue项目中的录屏插件recordrtc且带声音

vue项目中的录屏插件recordrtc且带声音 一、效果图二、安装插件三、直接上代码 一、效果图 其中窗口录屏不带声音&#xff0c;chrome标签和整个屏幕的录屏是带声音的 二、安装插件 npm i recordrtc 三、直接上代码 <template><div class"record-page">…

VMware Workstation——修改虚拟机配置和设置网络

目录 一、修改配置 1、点击需要修改配置的虚拟机&#xff0c;然后点击编辑虚拟机配置 2、修改内存、CPU、硬盘配置 二、设置网络 1、从虚拟机配置中进入到网络适配器设置 2、选择网络连接模式 一、修改配置 1、点击需要修改配置的虚拟机&#xff0c;然后点击编辑虚拟机配…

Packet Tracer - Configure AAA Authentication on Cisco Routers

Packet Tracer - 在思科路由器上配置 AAA 认证 地址表 目标 在R1上配置本地用户账户&#xff0c;并使用本地AAA进行控制台和vty线路的身份验证。从R1控制台和PC-A客户端验证本地AAA身份验证功能。配置基于服务器的AAA身份验证&#xff0c;采用TACACS协议。从PC-B客户端验证基…