当前位置: 首页 > news >正文

GD32F407单片机开发入门(十九)DMA详解及ADC-DMA方式采集含源码

文章目录

    • 一.概要
    • 二.GD32F407VET6单片机DMA外设特点
    • 三.GD32单片机DMA内部结构图
    • 四.DMA各通道请求
    • 五.GD32F407VET6单片机ADC-DMA采集例程
    • 六.工程源代码下载
    • 七.小结

一.概要

基本概念:
DMA是Direct Memory Access的首字母缩写,是一种完全由硬件执行数据交换的工作方式。DMA控制器从CPU接管对总线的控制,不经过CPU直接在内存和外设之间进行批量数据交换。DMA控制器向内存发出地址和控制信号,修改地址,对传送的字的个数计数,并且以中断方式向CPU报告传送操作的结束。 DMA方式一般用于高速传送成组数据。

DMA传输的三大要素:
传输源:DMA控制器从传输源读出数据;
传输目标:DMA控制器将数据传输的目标;
触发信号:用于触发一次数据传输的动作,执行一个单位的传输源至传输目标的数据传输;可以用来控制传输的时机。

DMA的主要优点:
由于CPU根本不参加传送操作,因此就省去了CPU取指令、取数、送数等操作。在数据传送过程中,没有保存现场、恢复现场之类的工作。内存地址修改、传送字个数的计数等等,也不是由软件实现,而是用硬件线路直接实现的。所以DMA方式能满足高速I/O设备的要求,也有利于CPU效率的发挥。

二.GD32F407VET6单片机DMA外设特点

两个AHB主机接口传输数据,一个AHB从机接口配置DMA。
16个通道(每个DMA控制器有8个通道),每个通道连接8个特定的外设请求。
存储器和外设支持单一传输,4拍、8拍和16拍增量突发传输。
当外设和存储器传输数据时,支持存储器切换。
支持软件优先级(低、中、高、超高)和硬件优先级(通道号越低,优先级越高)。
存储器和外设的数据传输宽度可配置:字节,半字,字。
存储器和外设的数据传输支持固定寻址和增量式寻址。
支持循环传输模式。
支持三种传输方式:
– 存储器到外设;
– 外设到存储器;
– 存储器到存储器(仅DMA1支持);
DMA和外设均可配置为传输控制器: – DMA作为传输控制器:可配置数据传输长度,最大为65535。 – 外设作为传输控制器:数据传输的完成取决于外设的最后一个传输请求。
支持单数据传输和多数据传输模式:
– 多数据传输模式:在存储器数据宽度和外设数据宽度不同的时候,自动打包/解包数
据;
– 单数据传输模式:当且仅当FIFO空的时候从源地址读取数据,存进FIFO,然后把
FIFO 的数据写到目标地址。
每个通道有5种类型的事件标志和独立的中断,支持中断的使能和清除。

三.GD32单片机DMA内部结构图

在这里插入图片描述

DMA控制器由4部分组成:

AHB 从接口配置DMA
AHB主接口进行数据传输
仲裁器进行DMA请求的优先级管理
数据处理和计数

寄存器DMA_CHxCTL的PWIDTH和MWIDTH位域决定了外设和存储器的数据传输宽度。DMA控制器支持8位,16位和32位的数据宽度。

四.DMA各通道请求

DMA从外设读数据存储到存储器,大致流程如下图。
在这里插入图片描述
在这里插入图片描述

如下图所示,每个DMA控制器有8个通道,每个通道有多个外设请求。以ADC0为例,可以映射到DMA的Channel0。
在这里插入图片描述

DMA的传输模式:

循环模式:通过寄存器DMA_CHxCTL的CMEN位置1使能,用于处理一个环形的缓冲区,每轮传输结束时数据传输的配置会自动地更新为初始状态,DMA传输会连续不断地进行,一般采用循环模式。

普通模式:在DMA传输结束时,DMA通道被自动关闭,进一步的DMA请求将不被满足。

五.GD32F407VET6单片机ADC-DMA采集例程

STLINK接GD32F407VET6开发板,STLINK接电脑USB口。

在这里插入图片描述

GD32F407VET6开发板的PA4,PA45引脚上的进行 ADC 电压采集,杜邦线连接 PA4,PA5 引脚与 VDD(3.3V)或者GND(0V),就能读到单片机供电的电压值。

主要代码:

#include "gd32f4xx.h"
#include "gd32f4xx_libopt.h"
#include "systick.h"uint16_t adc_value[2];//ADC采样值//ADC配置,DMA配置
void ADC_config(void)
{dma_single_data_parameter_struct  dma_single_data_parameter;rcu_periph_clock_enable(RCU_GPIOA);gpio_mode_set(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_4);//PA4配置成输入gpio_mode_set(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_5);//PA5配置成输入//ADC相关时钟配置rcu_periph_clock_enable(RCU_GPIOA);rcu_periph_clock_enable(RCU_DMA1);rcu_periph_clock_enable(RCU_ADC0);adc_clock_config(ADC_ADCCK_PCLK2_DIV6);/* DMA相关配置 DMA1 CH0*/dma_deinit(DMA1, DMA_CH0);dma_single_data_parameter.periph_addr = (uint32_t)(&ADC_RDATA(ADC0));dma_single_data_parameter.periph_inc = DMA_PERIPH_INCREASE_DISABLE;dma_single_data_parameter.memory0_addr = (uint32_t)(&adc_value);dma_single_data_parameter.memory_inc = DMA_MEMORY_INCREASE_ENABLE;                         // 存储器地址是否为增量模式dma_single_data_parameter.periph_memory_width = DMA_PERIPH_WIDTH_16BIT;dma_single_data_parameter.circular_mode = DMA_CIRCULAR_MODE_ENABLE;                        // 循环模式dma_single_data_parameter.direction = DMA_PERIPH_TO_MEMORY;                                // 外设到存储器dma_single_data_parameter.number = 2;                                                      // DMA缓存大小dma_single_data_parameter.priority = DMA_PRIORITY_HIGH;dma_single_data_mode_init(DMA1,DMA_CH0,&dma_single_data_parameter);dma_channel_enable(DMA1, DMA_CH0);dma_circulation_enable(DMA1, DMA_CH0);        //ADC相关配置adc_deinit();      // 复位ADCadc_sync_mode_config(ADC_SYNC_MODE_INDEPENDENT);                         //独立模式adc_special_function_config(ADC0, ADC_SCAN_MODE, ENABLE);               // 扫描模式adc_special_function_config(ADC0, ADC_CONTINUOUS_MODE, ENABLE);         // 连续模式adc_data_alignment_config(ADC0, ADC_DATAALIGN_RIGHT);                  // 右对齐adc_channel_length_config(ADC0, ADC_REGULAR_CHANNEL, 2);              //读取2通道/* ADC regular channel config */adc_regular_channel_config(ADC0, 0, ADC_CHANNEL_4, ADC_SAMPLETIME_144);//ADC0的通道4adc_regular_channel_config(ADC0, 1, ADC_CHANNEL_5, ADC_SAMPLETIME_144);//ADC0的通道5adc_external_trigger_config(ADC0,ADC_REGULAR_CHANNEL,EXTERNAL_TRIGGER_DISABLE);adc_dma_request_after_last_enable(ADC0);adc_dma_mode_enable(ADC0);adc_enable(ADC0);adc_calibration_enable(ADC0);adc_software_trigger_enable(ADC0, ADC_REGULAR_CHANNEL);
}uint16_t Vol_Value1,Vol_Value2;//采集到的电压值
int main(void)
{systick_config();//配置系统主频168M,外部8M晶振,配置在#define __SYSTEM_CLOCK_168M_PLL_8M_HXTAL        (uint32_t)(168000000)ADC_config();	//配置ADCwhile(1){Vol_Value1=adc_value[0]*3300/4095;//转换成电压值Vol_Value2=adc_value[1]*3300/4095;//转换成电压值}
}

实验结果:
PA4接GND,PA5接3.3V,用Keil运行程序,全速运行,查看Keil调试Watch界面,如下图,PA4,PA5引脚的采样值adc_value[0]
为0,adc_value[1]为0xfff,对应的电压值为0mV与3300mV,所以ADC DMA采样成功。
在这里插入图片描述

六.工程源代码下载

源码下载链接如下:
CSDN

七.小结

使用DMA进行数据收发能够提高数据传输的效率和可靠性。其次,使用DMA进行串口数据收发可以减轻CPU的负担。

相关文章:

  • Android 动态权限申请
  • 毕业论文 | 传统特征点提取算法与匹配算法对比分析
  • 无忧AI综合插件,可实现图色识别、机器视觉、图像编辑等多种功能
  • Unity 粒子同步,FishNet
  • 【Linux安装图形化界面【欧拉】】
  • 2025年ASOC SCI2区TOP:思维创新策略TIS +一种设计和进化更新机制,深度解析+性能实测
  • 制造业行业ERP软件部署全流程指南:从选型到维护,怎么做?
  • 数据库系统综合应用与深度实践指南
  • 平衡截断(Balanced Truncation)—— MTALAB 和 Python 实现
  • 「Mac畅玩AIGC与多模态09」开发篇05 - 使用自定义天气查询插件开发智能体应用
  • 综合开发-手机APP远程控制PLC1500柱灯的亮灭
  • [Java入门]抽象类和接口
  • 低压电工理论备考精选练习题
  • ReSearch: Learning to Reason with Search for LLMs via Reinforcement Learning
  • 二叉树的路径总和问题(递归遍历,回溯算法)
  • 小米MiMo-7B大模型:解锁推理潜力的新传奇!
  • 安凯微以创新之芯,赋能万物智能互联新时代
  • 住宅代理与数据中心代理有什么区别
  • 正点原子STM32H743单片机实现ADC多通道检测
  • 0.安装两个版本的JDK8和JDK17并配置环境变量
  • 李公明︱一周书记:数字文化的乌托邦精神与……算法时代的生存指南
  • 内蒙古公开宣判144件毁林毁草刑案,单起非法占用林地逾250亩
  • 事关广大农民利益,农村集体经济组织法5月1日起施行
  • “ChatGPT严选”横空出世了,“DeepSeek严选”还要等多久?
  • 长三角铁路“五一”假期运输今启动:预计发送旅客量增6%,5月1日当天有望创新高
  • 深圳宝安区一宗涉宅用地中止出让,起始总价86.27亿元