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

【STM32-学习笔记-6-】DMA

文章目录

  • DMA
    • Ⅰ、DMA框图
    • Ⅱ、DMA基本结构
    • Ⅲ、不同外设的DMA请求
    • Ⅳ、DMA函数
    • Ⅴ、DMA_InitTypeDef结构体参数
      • ①、DMA_PeripheralBaseAddr
      • ②、DMA_PeripheralDataSize
      • ③、DMA_PeripheralInc
      • ④、DMA_MemoryBaseAddr
      • ⑤、DMA_MemoryDataSize
      • ⑥、DMA_MemoryInc
      • ⑦、DMA_DIR
      • ⑧、DMA_BufferSize
      • ⑨、DMA_Mode
      • ⑩、DMA_M2M
      • ①①、DMA_Priority
    • Ⅵ、DMA配置示例
      • DMA+AD多通道
        • 1. ADC单次扫描+DMA数据转运
        • 2. ADC连续扫描+DMA循环转运

DMA

Ⅰ、DMA框图

image-20241227112815688

Ⅱ、DMA基本结构

image-20241227112841087

Ⅲ、不同外设的DMA请求

image-20241227113057979

Ⅳ、DMA函数

// 重置指定的DMA通道寄存器为默认值
void DMA_DeInit(DMA_Channel_TypeDef* DMAy_Channelx);

// 初始化指定的DMA通道,根据初始化结构体配置参数
void DMA_Init(DMA_Channel_TypeDef* DMAy_Channelx, DMA_InitTypeDef* DMA_InitStruct);

// 初始化DMA初始化结构体的默认值
void DMA_StructInit(DMA_InitTypeDef* DMA_InitStruct);

// 开启或关闭指定的DMA通道
void DMA_Cmd(DMA_Channel_TypeDef* DMAy_Channelx, FunctionalState NewState);

// 开启或关闭DMA通道的中断
void DMA_ITConfig(DMA_Channel_TypeDef* DMAy_Channelx, uint32_t DMA_IT, FunctionalState NewState);

// 设置DMA当前数据计数器的值
void DMA_SetCurrDataCounter(DMA_Channel_TypeDef* DMAy_Channelx, uint16_t DataNumber); 

// 获取DMA当前数据计数器的值
uint16_t DMA_GetCurrDataCounter(DMA_Channel_TypeDef* DMAy_Channelx);

// 获取DMA标志状态
FlagStatus DMA_GetFlagStatus(uint32_t DMAy_FLAG);
// 清除DMA标志
void DMA_ClearFlag(uint32_t DMAy_FLAG);

// 获取DMA中断状态	
ITStatus DMA_GetITStatus(uint32_t DMAy_IT);
// 清除DMA中断待处理位
void DMA_ClearITPendingBit(uint32_t DMAy_IT);

Ⅴ、DMA_InitTypeDef结构体参数

①、DMA_PeripheralBaseAddr

指定DMA通道的外设基地址外设寄存器-起始地址

    • 类型uint32_t
    • 取值范围:任意有效的外设地址
    • 作用:这是DMA操作的外设端的起始地址,例如ADC、USART等外设的数据寄存器地址

②、DMA_PeripheralDataSize

指定外设寄存器的数据宽度配置DMA传输时外设数据的大小

  • 该参数可以是@ref DMA_peripheral_data_size

    • 宏定义解释

      1. DMA_PeripheralDataSize_Byte
        • 描述:表示外设数据大小为1字节(8位)
          • 每次DMA传输的数据大小为1字节
      2. DMA_PeripheralDataSize_HalfWord
        • 描述:表示外设数据大小为半字(16位)
          • 每次DMA传输的数据大小为2字节
      3. DMA_PeripheralDataSize_Word
        • 描述:表示外设数据大小为1字(32位)
          • 每次DMA传输的数据大小为4字节

      宏函数

      1. IS_DMA_PERIPHERAL_DATA_SIZE(SIZE)
        • 描述:检查给定的外设数据大小设置是否有效
        • 参数SIZE,代表DMA的外设数据大小
        • 功能:检查SIZE是否等于DMA_PeripheralDataSize_ByteDMA_PeripheralDataSize_HalfWordDMA_PeripheralDataSize_Word中的任一个。
        • 返回值:如果SIZE有效,返回1(真),否则返回0(假)

③、DMA_PeripheralInc

指定外设地址寄存器是否递增

    • 类型uint32_t
    • 取值范围
      • DMA_PeripheralInc_Disable:外设地址不递增
      • DMA_PeripheralInc_Enable:外设地址递增
    • 作用:控制外设地址在每次数据传输后是否递增

④、DMA_MemoryBaseAddr

指定DMA通道的内存基地址存储器-起始地址

    • 类型uint32_t
    • 取值范围:任意有效的内存地址
    • 作用:这是DMA操作的内存端的起始地址,例如一个缓冲区的起始地址

⑤、DMA_MemoryDataSize

指定内存数据宽度存储器-数据宽度

    • 类型uint32_t
    • 取值范围
      • DMA_MemoryDataSize_Byte:数据宽度为8位
      • DMA_MemoryDataSize_HalfWord:数据宽度为16位
      • DMA_MemoryDataSize_Word:数据宽度为32位
    • 作用:确定内存数据的大小

⑥、DMA_MemoryInc

指定内存地址寄存器是否递增指定存储器-是否递增

    • 类型uint32_t
    • 取值范围
      • DMA_MemoryInc_Disable:内存地址不递增
      • DMA_MemoryInc_Enable:内存地址递增
    • 作用:控制内存地址在每次数据传输后是否递增

⑦、DMA_DIR

指定数据传输方向,即外设是数据源还是数据目标指定外设站点是源还是目标

    • 类型uint32_t
    • 取值范围
      • DMA_DIR_PeripheralSRC外设是数据源,内存是数据目标
      • DMA_DIR_PeripheralDST:外设是数据目标,内存是数据源
    • 作用:确定数据传输的方向

⑧、DMA_BufferSize

指定DMA通道的缓冲区大小,以数据单元为单位

  • DMA_InitStruct.DMA_BufferSize = Size; 传递Size个大小为<数据宽度>的数据

    • 类型uint32_t
    • 取值范围:0到65535
    • 作用:确定要传输的数据量。数据单元的大小取决于DMA_PeripheralDataSizeDMA_MemoryDataSize的配置,具体取决于传输方向

⑨、DMA_Mode

指定DMAy通道的工作模式是否要自动重装

    • 类型uint32_t
    • 取值范围
      • DMA_Mode_Normal正常模式,传输完成后停止
      • DMA_Mode_Circular:循环模式(自动重装),传输完成后从头开始
    • 作用:确定DMA传输的模式。循环模式不适用于内存到内存的传输

⑩、DMA_M2M

是否使用软件触发存储器到存储器

    • 类型uint32_t
    • 描述:指定DMA通道是否用于内存到内存的传输
    • 取值范围
      • DMA_M2M_Disable不使用内存到内存传输
      • DMA_M2M_Enable使用内存到内存传输
    • 作用:确定DMA通道是否用于内存到内存的传输

①①、DMA_Priority

指定DMA通道的软件优先级

  • 按需求配置

    • 类型uint32_t
    • 取值范围
      • DMA_Priority_Low低优先级
      • DMA_Priority_Medium中优先级
      • DMA_Priority_High高优先级
      • DMA_Priority_VeryHigh非常高优先级
    • 作用:确定DMA通道的优先级,影响多个DMA请求的处理顺序

Ⅵ、DMA配置示例

#include "stm32f10x.h"                  // Device header

uint32_t Temp_Size;//存储数据计数器的值

void MyDMA_Init(uint32_t Source, uint32_t Dest, uint32_t Size)//参数需为两个数组的数组名
{
	Temp_Size = Size;
	
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
	
	DMA_InitTypeDef DMA_InitStruct;
	DMA_InitStruct.DMA_PeripheralBaseAddr = Source;//外设寄存器-起始地址
	DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//外设寄存器-数据宽度(此处为1byte)
	DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Enable;//指定外设地址寄存器-是否递增
	DMA_InitStruct.DMA_MemoryBaseAddr = Dest;//存储器-起始地址
	DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;//存储器-数据宽度
	DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;//指定存储器-是否递增
	DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC;//指定外设站点是源还是目标
	DMA_InitStruct.DMA_BufferSize = Size;//传递Size个大小为<数据宽度>的数据
	DMA_InitStruct.DMA_Mode = DMA_Mode_Normal;//指定DMAy通道的工作模式(是否要自动重装)
	DMA_InitStruct.DMA_M2M = DMA_M2M_Enable;//是否使用软件触发(存储器到存储器)
	DMA_InitStruct.DMA_Priority = DMA_Priority_Medium;//指定DMAy通道的软件优先级
	DMA_Init(DMA1_Channel1, &DMA_InitStruct);
	
	DMA_Cmd(DMA1_Channel1, DISABLE);//使能或失能DMA
}

void MyDMA_Transfer(void)//调用函数则开始转运
{
	DMA_Cmd(DMA1_Channel1, DISABLE);//失能DMA
	DMA_SetCurrDataCounter(DMA1_Channel1, Temp_Size);//设置DMA当前数据计数器的值
	DMA_Cmd(DMA1_Channel1, ENABLE);//使能DMA
	
	while(DMA_GetFlagStatus(DMA1_FLAG_TC1) == RESET)//获取DMA标志状态(等待转运完成)
	DMA_ClearFlag(DMA1_FLAG_TC1);//清除DMA标志位
}

DMA+AD多通道

1. ADC单次扫描+DMA数据转运
#include "stm32f10x.h"                  // Device header
//模拟量转换为数字量
//AD多通道(ADC扫描模式+DMA数据转运)

uint16_t Dest_Data[4];

void AD_Init(void)
{	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//开启GPIO时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);//开启ADC时钟
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);//开启DMA时钟
	
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);//配置ADC时钟(72MHz/6=12MHz)
	
	//配置GPIO
	GPIO_InitTypeDef GPIO_InitStruct;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AIN;//模拟输入
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStruct);

	ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_41Cycles5);//配置ADC常规通道
	ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_41Cycles5);//配置ADC常规通道
	ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_41Cycles5);//配置ADC常规通道
	ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 4, ADC_SampleTime_41Cycles5);//配置ADC常规通道
	
	//配置ADC
	ADC_InitTypeDef ADC_InitStruct;
	ADC_InitStruct.ADC_Mode = ADC_Mode_Independent;//将ADC配置为独立或操作双模式
	ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;//数据右对齐
	ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//不使用外部触发
	ADC_InitStruct.ADC_ContinuousConvMode = DISABLE;//单次转换or连续转换
	ADC_InitStruct.ADC_ScanConvMode = ENABLE;//非扫描模式or扫描模式
	ADC_InitStruct.ADC_NbrOfChannel = 4;//指定要转换的ADC通道的数量
	ADC_Init(ADC1, &ADC_InitStruct);

	//配置DMA	
	DMA_InitTypeDef DMA_InitStruct;
	DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;//外设寄存器-起始地址
	DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;//外设寄存器-数据宽度(此处为1byte)
	DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//指定外设地址寄存器-是否递增
	DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)Dest_Data;//存储器-起始地址
	DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;//存储器-数据宽度
	DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;//指定存储器-是否递增
	DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC;//指定外设站点是源还是目标
	DMA_InitStruct.DMA_BufferSize = 4;//传递Size个大小为<数据宽度>的数据
	DMA_InitStruct.DMA_Mode = DMA_Mode_Normal;//指定DMAy通道的工作模式(是否要自动重装)
	DMA_InitStruct.DMA_M2M = DMA_M2M_Disable;//是否使用软件触发(存储器到存储器)
	DMA_InitStruct.DMA_Priority = DMA_Priority_Medium;//指定DMAy通道的软件优先级
	DMA_Init(DMA1_Channel1, &DMA_InitStruct);
	
	
	ADC_DMACmd(ADC1, ENABLE);//开启ADC的DMA功能
	DMA_Cmd(DMA1_Channel1, ENABLE);//使能或失能DMA
	ADC_Cmd(ADC1, ENABLE);//开启ADC
	
	//ADC复位+校准
	ADC_ResetCalibration(ADC1);//重置ADC校准,准备进行校准操作
	while(ADC_GetResetCalibrationStatus(ADC1) == SET);//获取ADC重置校准状态,检查是否完成
	ADC_StartCalibration(ADC1);//开始ADC校准
	while(ADC_GetCalibrationStatus(ADC1) == SET);//获取ADC校准状态,检查是否完成
}

void AD_GetValue(void)//获取模拟值
{
	//选择不同的通道或取ADC值
	DMA_Cmd(DMA1_Channel1, DISABLE);//失能DMA
	DMA_SetCurrDataCounter(DMA1_Channel1, 4);//设置DMA当前数据计数器的值
	DMA_Cmd(DMA1_Channel1, ENABLE);//使能DMA
	
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);//开启软件启动ADC转换,用于软件触发转换--启动
	
	while(DMA_GetFlagStatus(DMA1_FLAG_TC1) == RESET)//获取DMA标志状态(等待转运完成)
	DMA_ClearFlag(DMA1_FLAG_TC1);//清除DMA标志位

}
2. ADC连续扫描+DMA循环转运
#include "stm32f10x.h"                  // Device header
//模拟量转换为数字量
//AD多通道(ADC连续扫描+DMA循环转运)

uint16_t Dest_Data[4];

void AD_Init(void)
{	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//开启GPIO时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);//开启ADC时钟
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);//开启DMA时钟
	
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);//配置ADC时钟(72MHz/6=12MHz)
	
	//配置GPIO
	GPIO_InitTypeDef GPIO_InitStruct;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AIN;//模拟输入
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStruct);

	ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_41Cycles5);//配置ADC常规通道
	ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_41Cycles5);//配置ADC常规通道
	ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_41Cycles5);//配置ADC常规通道
	ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 4, ADC_SampleTime_41Cycles5);//配置ADC常规通道
	
	//配置ADC
	ADC_InitTypeDef ADC_InitStruct;
	ADC_InitStruct.ADC_Mode = ADC_Mode_Independent;//将ADC配置为独立或操作双模式
	ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;//数据右对齐
	ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//不使用外部触发
	ADC_InitStruct.ADC_ContinuousConvMode = ENABLE;//单次转换or连续转换**********************************************
	ADC_InitStruct.ADC_ScanConvMode = ENABLE;//非扫描模式or扫描模式
	ADC_InitStruct.ADC_NbrOfChannel = 4;//指定要转换的ADC通道的数量
	ADC_Init(ADC1, &ADC_InitStruct);

	//配置DMA	
	DMA_InitTypeDef DMA_InitStruct;
	DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;//外设寄存器-起始地址
	DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;//外设寄存器-数据宽度(此处为1byte)
	DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//指定外设地址寄存器-是否递增
	DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)Dest_Data;//存储器-起始地址
	DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;//存储器-数据宽度
	DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;//指定存储器-是否递增
	DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC;//指定外设站点是源还是目标
	DMA_InitStruct.DMA_BufferSize = 4;//传递Size个大小为<数据宽度>的数据
	DMA_InitStruct.DMA_Mode = DMA_Mode_Circular;//指定DMAy通道的工作模式(是否要自动重装)******************************
	DMA_InitStruct.DMA_M2M = DMA_M2M_Disable;//是否使用软件触发(存储器到存储器)
	DMA_InitStruct.DMA_Priority = DMA_Priority_Medium;//指定DMAy通道的软件优先级
	DMA_Init(DMA1_Channel1, &DMA_InitStruct);
	
	ADC_DMACmd(ADC1, ENABLE);//开启ADC的DMA功能
	DMA_Cmd(DMA1_Channel1, ENABLE);//使能或失能DMA
	ADC_Cmd(ADC1, ENABLE);//开启ADC
	
	//ADC复位+校准
	ADC_ResetCalibration(ADC1);//重置ADC校准,准备进行校准操作
	while(ADC_GetResetCalibrationStatus(ADC1) == SET);//获取ADC重置校准状态,检查是否完成
	ADC_StartCalibration(ADC1);//开始ADC校准
	while(ADC_GetCalibrationStatus(ADC1) == SET);//获取ADC校准状态,检查是否完成

	ADC_SoftwareStartConvCmd(ADC1, ENABLE);//开启软件启动ADC转换,用于软件触发转换--启动********************************
}
//*****************************************************************************************

http://www.kler.cn/a/502985.html

相关文章:

  • ASP.NET Core - 日志记录系统(二)
  • 零基础 监控数据可视化 Spring Boot 2.x(Actuator + Prometheus + Grafana手把手) (上)
  • Spring Boot 应用开发入门
  • 【fly-iot飞凡物联】(19):开源飞凡物联项目重启,使用go重写后端代码,感兴趣的小伙伴可以一起参加,使用apache协议开源,招募感兴趣的小伙伴!!
  • 虚拟拨号技术(GOIP|VOIP)【基于IP的语音传输转换给不法分子的境外来电披上一层外衣】: Voice over Internet Protocol
  • git——merge和rebase
  • 探索网络安全:浅析文件上传漏洞
  • Mysql--运维篇--备份和恢复(逻辑备份,mysqldump,物理备份,热备份,温备份,冷备份,二进制文件备份和恢复等)
  • python+pymysql
  • HarmonyOS:@LocalBuilder装饰器: 维持组件父子关系
  • Android Dex VMP 动态加载加密指令流
  • ucharts写的小程序如何解决Y轴小数点问题
  • 《机器学习》之K-means聚类
  • Docker数据管理与网络
  • 科研绘图系列:R语言绘制Y轴截断分组柱状图(y-axis break bar plot)
  • Tox,Python 测试环境的自动化管理器,一个高效操作的 Python 工具!
  • RabbitMQ-延迟交换器
  • 【C】初阶数据结构2 -- 顺序表
  • Chromium 132 编译指南 Windows 篇 - 配置核心环境变量 (三)
  • 【前端】自学基础算法 -- 21.图的广度优先搜索