【物联网】DMA传输原理与实现详解(超详细)

news2025/1/16 4:00:28

DMA(Direct Memory Access,直接内存访问)是一种计算机数据传输方式,允许外围设备直接访问系统内存,而无需CPU的干预。
在这里插入图片描述

文章目录

    • Part 1: DMA的工作原理
      • 配置阶段:
      • 数据传输阶段:
    • Part 2: DMA数据组成
    • Part 3: DMA传输过程的实现
    • Part 4: DMA中断处理和性能优化
      • DMA中断处理:
      • DMA性能优化:
    • Part 5: STM32实现DMA
      • 基于标准库
      • 基于HAL库

Part 1: DMA的工作原理

DMA(Direct Memory Access,直接内存访问)是一种计算机数据传输方式,允许外围设备直接访问系统内存,而无需CPU的干预。下面详细介绍DMA的工作原理:

配置阶段:

  1. 配置源地址(Source Address):通过指定源地址,DMA可以知道需要传输数据的起始位置。

  2. 配置目标地址(Destination Address):指定目标地址,将数据传输到系统内存中的相应位置。

  3. 配置数据长度(Data Length):DMA需要知道需要传输的数据长度,以便正确地读取和写入数据。

  4. 配置控制信息(Control Information):例如传输模式、中断使能等参数,用于指定传输的具体配置。

数据传输阶段:

在这里插入图片描述

  1. 外设发起传输请求:外围设备(如网络接口卡、硬盘控制器)向DMA控制器发起传输请求。

  2. DMA控制器响应请求:DMA控制器接收到传输请求后,暂停CPU的访问,并通过请求信号(如DMA请求信号)获取对系统总线的控制权。

  3. 读取数据:DMA控制器从外设读取数据,并存储在内部缓冲区中。

  4. 数据传输:DMA控制器将数据从内部缓冲区传输到系统内存中的目标地址。

  5. 传输完成通知:当数据传输完成后,DMA控制器会释放对系统总线的控制权,并发出传输完成的中断信号,通知CPU。

  6. CPU处理中断:CPU接收到传输完成的中断信号后,会执行相应的中断处理程序。

Part 2: DMA数据组成

DMA传输涉及的数据主要有以下几种组成:

  1. 源地址(Source Address):源地址表示数据传输的起始地址,即外设设备中数据缓冲区的地址。DMA将从这个地址开始读取数据。

  2. 目标地址(Destination Address):目标地址表示数据传输的目的地址,即系统内存中的指定地址。DMA将数据传输到这个地址。

  3. 数据长度(Data Length):数据长度表示需要传输的数据大小。它可以以字节、字或者其他单位进行表示。

  4. 控制信息(Control Information):控制信息包括传输模式、中断使能等参数。在传输过程中,DMA根据这些参数来控制数据的传输行为。

此外,还有一些额外的参数和寄存器与DMA相关,用于配置和控制DMA的操作,例如:

  1. DMA通道选择(DMA Channel Selection):在具有多个DMA通道的系统中,选择要使用的DMA通道。

  2. DMA传输模式(DMA Transfer Mode):指定DMA传输的模式,如单次传输模式、循环传输模式等。

  3. DMA中断使能(DMA Interrupt Enable):用于控制DMA传输完成时是否产生中断。

Part 3: DMA传输过程的实现

DMA的传输过程涉及多个步骤,包括启动DMA、请求传输、数据读取和写入等操作。
在这里插入图片描述

下面是DMA传输过程的一个简单实现示例:

  1. 配置DMA参数
    在开始DMA传输之前,需要先配置DMA相关的参数,如源地址、目标地址、数据长度和控制信息等。这些参数通常通过设置相应的寄存器来实现。
// 配置DMA
void configureDMA(uint32_t sourceAddr, uint32_t destAddr, uint32_t dataLength) {
    // 配置源地址和目标地址
    writeDMARegister(SOURCE_ADDRESS_REG, sourceAddr);
    writeDMARegister(DESTINATION_ADDRESS_REG, destAddr);
    
    // 配置数据长度
    writeDMARegister(DATA_LENGTH_REG, dataLength);
    
    // 配置控制信息,如传输模式、中断使能等
    writeDMARegister(CONTROL_INFO_REG, controlInfo);
}
  1. 启动DMA传输
    配置完成后,通过设置相应的使能寄存器,启动DMA传输。
// 启动DMA传输
void startDMA() {
    // 设置DMA使能位
    writeDMARegister(ENABLE_REG, 1);
    
    // 发送传输请求
    sendDMARequest();
}
  1. 请求传输
    外设设备发出DMA请求,请求DMA控制权,开始数据传输过程。DMA控制器收到传输请求后,暂停CPU的访问,并通过请求信号(如DMA请求信号)获取对系统总线的控制权。
// 发送DMA传输请求
void sendDMARequest() {
    // 发送DMA请求信号给DMA控制器
    setDMARequestSignal();
}
  1. 数据读取和写入
    DMA控制器根据配置的参数,从外设设备中读取数据,并将其写入系统内存中的目标地址。
// 读取数据并写入内存
void transferData() {
    // 从外设读取数据
    uint32_t data = readDataFromPeripheral();
    
    // 写入内存
    writeDataToMemory(data);
}
  1. 传输完成通知
    当数据传输完成后,DMA控制器会释放对系统总线的控制权,并发送传输完成的中断信号,通知CPU。
// DMA中断处理函数
void handleDMAInterrupt() {
    // 处理传输完成的中断信号
    // ...
}

Part 4: DMA中断处理和性能优化

DMA中断处理:

在DMA传输完成时,DMA控制器可以触发一个中断,通知CPU传输已完成。CPU可以相应地执行中断处理程序,进行必要的操作。

  1. 中断使能设置:
    在配置DMA参数时,通过设置相应的控制信息,可以选择是否使能DMA传输完成中断。如果使能了中断,DMA传输完成时会产生中断请求信号。否则,传输完成后不会触发中断。

  2. 中断处理程序:
    在CPU侧,需要编写中断处理程序来处理DMA传输完成中断。中断处理程序负责执行相应的操作,如处理传输完成的数据、清除中断标志等。

DMA性能优化:

为了提高DMA传输的效率和性能,可以采取以下优化技术:

  1. 数据对齐(Data Alignment):
    尽可能地对齐数据可以提高DMA的传输效率。许多硬件平台在DMA传输时对数据对齐有限制,所以确保数据在传输过程中的对齐是重要的。

  2. 数据块传输(Block Transfer):
    DMA支持以块为单位的数据传输,逐次传输多个数据块,并在传输完成后给出一个中断通知。这种方式比每次传输一个数据更高效,减少了中断的开销和系统总线访问的次数。

  3. 通道优先级(Channel Priority):
    在具有多个DMA通道的系统中,可以通过设置不同的通道优先级,来决定DMA通道之间的数据传输优先级。这样可以在多个外设设备同时请求传输时,对优先级较高的设备进行优先处理。

  4. 多重缓冲区(Double Buffering):
    使用多个缓冲区来存储数据可以提高DMA传输效率。当DMA从一个缓冲区传输数据时,CPU可以同时向另一个缓冲区写入新的数据,从而实现并行操作。

Part 5: STM32实现DMA

基于标准库

示例代码:

#include "stm32f10x.h"

#define BUFFER_SIZE 100

uint32_t sourceBuffer[BUFFER_SIZE];
uint32_t destinationBuffer[BUFFER_SIZE];

void DMA_Configuration(void) {
    DMA_InitTypeDef DMA_InitStructure;
    
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
    
    DMA_DeInit(DMA1_Channel1);
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(ADC1->DR);
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)destinationBuffer;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
    DMA_InitStructure.DMA_BufferSize = BUFFER_SIZE;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
    
    DMA_Init(DMA1_Channel1, &DMA_InitStructure);
    
    DMA_Cmd(DMA1_Channel1, ENABLE);
}

int main() {
    // 初始化源缓冲区
    for (int i = 0; i < BUFFER_SIZE; i++) {
        sourceBuffer[i] = i;
    }
    
    // 配置DMA
    DMA_Configuration();
    
    while (1) {
        // 等待DMA传输完成
        while (!DMA_GetFlagStatus(DMA1_FLAG_TC1));
        
        // 处理传输完成的数据
        for (int i = 0; i < BUFFER_SIZE; i++) {
            // 处理destinationBuffer中的数据
            // ...
        }
        
        // 清除DMA传输完成标志位
        DMA_ClearFlag(DMA1_FLAG_TC1);
    }
}

在这个示例代码中,首先通过DMA_Configuration函数进行DMA的配置。然后在主循环中等待DMA传输完成的标志位,处理传输完成的数据,并清除传输完成标志位。

基于HAL库

示例代码:

#include "stm32f1xx_hal.h"

#define BUFFER_SIZE 100

DMA_HandleTypeDef hdma_adc1;

uint32_t sourceBuffer[BUFFER_SIZE];
uint32_t destinationBuffer[BUFFER_SIZE];

void DMA_Configuration(void) {
    __HAL_RCC_DMA1_CLK_ENABLE();
    
    hdma_adc1.Instance = DMA1_Channel1;
    hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;
    hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_adc1.Init.MemInc = DMA_MINC_ENABLE;
    hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
    hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
    hdma_adc1.Init.Mode = DMA_CIRCULAR;
    hdma_adc1.Init.Priority = DMA_PRIORITY_HIGH;
    
    HAL_DMA_Init(&hdma_adc1);
    
    __HAL_LINKDMA(&hadc1, DMA_Handle, hdma_adc1);
    
    HAL_DMA_Start(&hdma_adc1, (uint32_t)&(ADC1->DR), (uint32_t)destinationBuffer, BUFFER_SIZE);
}

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) {
    // 处理传输完成的数据
    for (int i = 0; i < BUFFER_SIZE; i++) {
        // 处理destinationBuffer中的数据
        // ...
    }
}

int main() {
    // 初始化源缓冲区
    for (int i = 0; i < BUFFER_SIZE; i++) {
        sourceBuffer[i] = i;
    }
    
    // 配置DMA
    DMA_Configuration();
    
    // 启动ADC转换
    HAL_ADC_Start_DMA(&hadc1, (uint32_t*)sourceBuffer, BUFFER_SIZE);
    
    while (1) {
        // 主循环中不需要额外的处理
        
        // 在需要使用CPU的其他任务中加入适当的延时或等待DMA传输完成的标志位
        // ...
    }
}

这个示例使用了STM32Cube HAL库提供的HAL库函数进行DMA的配置和控制。在DMA_Configuration函数中,使用HAL_DMA_Init函数进行DMA的初始化,并且通过__HAL_LINKDMA宏将DMA与ADC关联起来。在HAL_ADC_ConvCpltCallback函数中,处理传输完成的数据。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

java读写properties文件和xml文件,解决中文乱码问题

文章目录 前言一、properties文件1.1properties格式介绍1.2读取项目resource/templates下面properties并处理中文乱码问题1.3读取本地properties并处理中文乱码问题1.4修改properties文件 二、XML文件2.1xml文件格式2.2读取xml文件2.3写xml文件 前言 在开发当中我们经常需要用…

【NX】NX二次开发中拉伸曲线完整范例

之前做项目测试用到的代码&#xff0c;开发的版本是NX8.5的32位版本&#xff0c;这个代码实现起来也不难&#xff0c;其实就是调用了UG的API而已。 那么我在这里提供完整的代码&#xff1a; //author&#xff1a;autumoon //邮箱&#xff1a;9506163.com //日期&#xff1a;20…

spring AOP学习

概念 面向切面编程横向扩展动态代理 相关术语 动态代理 spring在运行期&#xff0c;生成动态代理对象&#xff0c;不需要特殊的编译器 Spring AOP的底层就是通过JDK动态代理或者CGLIb动态代理技术为目标Bean执行横向织入 目标对象实现了接口&#xff0c;spring使用JDK的ja…

利用微软Bing AI语言大模型辅助提高写代码、阅读代码、解bug的效率

目录 1 怎么才能使用Bing AI 2 Bing AI使用举例 2.1 代码没看懂&#xff0c;可以问Bing AI 2.2 当你不确定你程序理解的是否正确时&#xff0c;可以问Bing AI 2.3 程序编译出现bug&#xff0c;可以问Bing AI 1 怎么才能使用Bing AI 要想使用Bing AI&#xff0c;必须用微软…

【学会动态规划】剑指 Offer II 091. 粉刷房子(14)

目录 动态规划怎么学&#xff1f; 1. 题目解析 2. 算法原理 1. 状态表示 2. 状态转移方程 3. 初始化 4. 填表顺序 5. 返回值 3. 代码编写 写在最后&#xff1a; 动态规划怎么学&#xff1f; 学习一个算法没有捷径&#xff0c;更何况是学习动态规划&#xff0c; 跟我…

arm交叉编译lmbench

一、下载lmbench www.bitmover.com/lmbench 官网下载&#xff0c;http://www.bitmover.com/lmbench/lmbench3.tar.gz 我没有下载下来&#xff0c;找的别人的百度云下载 链接: https://pan.baidu.com/s/1tGo1clCqY-jQPN8G1eWSsg 提取码: f6jd 二、修改makefile 修改三个文件…

CrossOver2023虚拟机下载及如何安装软件教程

在当今数字化时代&#xff0c;虚拟机技术被广泛应用于软件开发、系统测试、网络安全等领域。虚拟机提供了一个隔离的虚拟环境&#xff0c;使得我们能够在一台物理计算机上同时运行多个操作系统和应用程序。下面我们就来看虚拟机软件怎么安装&#xff0c;虚拟机怎么使用吧&#…

浅析:单板静态数据分析功能在足底压力步态测量分析系统的应用

时代在不断进步&#xff0c;健康成为了现代人最重要的追求之一。而在我们繁忙的生活中&#xff0c;您是否关注过自己的足部健康&#xff1f;它不仅影响着我们的行走姿态、脊椎健康&#xff0c;还影响着我们的整体健康状态。 足底压力测量分析系统A30是一项采集人体足底压力的装…

【并发专题】单例模式的线程安全(进阶理解篇)

目录 背景前置知识类加载运行全过程 单例模式的实现方式一、饿汉式基本介绍源码分析 二、懒汉式基本介绍源码分析改进 三、懒汉式单例终极解决方案&#xff08;静态内部类&#xff09;&#xff08;推荐使用方案&#xff09;基本介绍源码分析 感谢 背景 最近学习了JVM之后&…

【HMS Core】位置服务逆地理编码请求错误问题

【关键字】 HMS、位置服务、逆地理编码 【问题描述】 有开发者反馈在集成位置服务-逆地理编码时&#xff0c;出现了请求报错的问题。 后端请求逆地理编码 错误 { "returnCode": "010010", "returnDesc": "INVALID_REQUEST" } 【问…

【雕爷学编程】Arduino动手做(181)---Maixduino AI开发板9

37款传感器与执行器的提法&#xff0c;在网络上广泛流传&#xff0c;其实Arduino能够兼容的传感器模块肯定是不止这37种的。鉴于本人手头积累了一些传感器和执行器模块&#xff0c;依照实践出真知&#xff08;一定要动手做&#xff09;的理念&#xff0c;以学习和交流为目的&am…

rest-apiV2.0.0升级为simplest-api开源框架生态之simplest-jpa发布

什么是 simplest simplest 追求存粹简单和极致。 旨在为项目快速开发提供一系列的基础能力&#xff0c;方便用户根据项目需求快速进行功能拓展 不在去关心一些繁琐。重复工作&#xff0c;而是把重点聚焦到业务。 前言 程序 10 年。作为一个多年程序。深知每个项目和程序&a…

最令跨境电商信服的六个电子商务营销策略

自从人们开始适应“新常态”以来&#xff0c;电子商务销售额一直在快速增长。进入智能手机和平板电脑时代&#xff0c;在线购物有望成为未来几年每个品牌的关键增长引擎。 数字零售格局的持续转型&#xff0c;您不得不考虑放弃一些利润较低的实体店&#xff0c;并进军电子商务&…

为什么说数字时代的品牌就是体验?

​ 在数字时代&#xff0c;品牌通常被称为“体验”&#xff0c;因为消费者现在以比以往更加动态和身临其境的方式与品牌互动。传统上&#xff0c;品牌主要侧重于创建独特的视觉形象并通过广告和其他营销渠道传达一致的信息。尽管这些方面仍然很重要&#xff0c;但数字环境已经…

应用案例|基于高精度3D视觉引导压缩机抓取定位应用

Part.1 行业现状 3D机器视觉是一种新兴的人工智能技术&#xff0c;它在机器视觉和机器学习领域中发挥着重要的作用。在工业领域&#xff0c;3D视觉技术被广泛应用于引导工业机器人进行抓取和定位操作。使用显扬科技的技术可以实现识别和定位压缩机。 Part.2 如何识别和定位压缩…

appium自动爬取数据

爬取类容&#xff1a;推荐知识点中所有的题目 爬取方式&#xff1a;appium模拟操作获取前端数据 入门级简单实现&#xff0c;针对题目和答案是文字内容的没有提取出来 适用场景;数据不多&#xff0c;参数加密&#xff0c;反爬严格等场景 from appium import webdriver impor…

小程序开发:开发框架与工具的使用指南

引言 本文以微信小程序为例介绍了小程序开发框架与工具的使用&#xff0c;通过本文的阅读&#xff0c;相信大家能够简单了解小程序开发的基本流程和常用工具&#xff0c;从而快速上手小程序开发。 文章目录 引言一、小程序开发框架与工具简介1.1 小程序开发框架1.2 小程序开发工…

百度文心大模型,彻底火了!丨IDCF

IDC报告显示&#xff0c;百度稳居中国深度学习平台市场综合份额第一。 根据中国信通院发布的《深度学习平台报告(2022)》&#xff0c;飞桨是中国深度学习市场应用规模第一的深度学习框架和赋能平台。通过飞桨与文心协同优化&#xff0c;文心大模型3.5&#xff0c;在14个参评模…

CSS 滚动条

一、滚动条样式属性 ::-webkit-scrollbar {width: 6px; /* 竖向滚动条宽度 */height: 6px; /* 横向滚动条高度 */ }::-webkit-scrollbar-thumb {border-radius: 10px; /* 滚动条样式 */-webkit-box-shadow: inset 0 0 3px red; /* 内阴影 */background-color: blue; /* 滚动条…

SpringBoot使用RestTemplate发送http请求(实操版)

前言 查看此文章前强烈建议先看这篇文章&#xff1a;Java江湖路 | 专栏目录 该文章纪录的是SpringBoot使用RestTemplate发送http请求&#xff0c;每一步都有记录&#xff0c;争取每一位看该文章的小伙伴都能操作成功。达到自己想要的效果~ 文章目录 前言1、SpringBoot调用外部…