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

STM32标准库学习笔记-9.DMA 直接存储器存取

参考教程:【STM32入门教程-2023版 细致讲解 中文字幕】

DMA(Direct Memory Access)

  • DMA(Direct Memory Access)直接存储器存取
  • DMA可以提供外设和存储器或者存储器和存储器之间的高速数据传输,无须CPU干预,节省了CPU的资源
  • 12个独立可配置的通道: DMA1(7个通道), DMA2(5个通道)
  • 每个通道都支持软件触发和特定的硬件触发
  • STM32F103C8T6 DMA资源:DMA1(7个通道)
STM32存储器映射

        通俗的讲映射就是一种特殊的对应关系

        Cortex‐M3 支持4GiB 存储空间。整块4G存储器开始地址标为0x00000000,结束地址为0xFFFFFFFF,地址的位数是32位,那么2^32=4,294,967,296。

        这4GiB的空间指的是地址空间,每个地址对应一个具体的设备。CPU通过地址,然后对应到地址存储单元或者寄存器,进行读取或者写入数据即可。4GiB是它最大支持的地址数目,但是实际可能没有使用那么多。

类型

起始地址

存储器

用途

ROM

0x0800 0000

程序存储器Flash

存储C语言编译后的程序代码

0x1FFF F000

系统存储器

存储BootLoader,用于串口下载

0x1FFF F800

选项字节

存储一些独立于程序代码的配置参数

RAM

0x2000 0000

运行内存SRAM

存储运行过程中的临时变量

0x4000 0000

外设寄存器

存储各个外设的配置参数

0xE000 0000

内核外设寄存器

存储内核各个外设的配置参数

DMA框图

DMA2仅存在于大容量产品和互联型产品。

DMA简化结构图

DMA请求

数据宽度与对齐

数据转运+DMA示意图

ADC扫描模式+DMA

DMA教程代码实例:
#include "stm32f10x.h"                  // Device headeruint16_t MyDMA_Size;					//定义全局变量,用于记住Init函数的Size,供Transfer函数使用/*** 函    数:DMA初始化* 参    数:AddrA 原数组的首地址* 参    数:AddrB 目的数组的首地址* 参    数:Size 转运的数据大小(转运次数)* 返 回 值:无*/
void MyDMA_Init(uint32_t AddrA, uint32_t AddrB, uint16_t Size)
{MyDMA_Size = Size;					//将Size写入到全局变量,记住参数Size/*开启时钟*/RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);						//开启DMA的时钟/*DMA初始化*/DMA_InitTypeDef DMA_InitStructure;										//定义结构体变量DMA_InitStructure.DMA_PeripheralBaseAddr = AddrA;						//外设基地址,给定形参AddrADMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;	//外设数据宽度,选择字节DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable;			//外设地址自增,选择使能DMA_InitStructure.DMA_MemoryBaseAddr = AddrB;							//存储器基地址,给定形参AddrBDMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;			//存储器数据宽度,选择字节DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;					//存储器地址自增,选择使能DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;						//数据传输方向,选择由外设到存储器DMA_InitStructure.DMA_BufferSize = Size;								//转运的数据大小(转运次数)DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;							//模式,选择正常模式DMA_InitStructure.DMA_M2M = DMA_M2M_Enable;								//存储器到存储器,选择使能DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;					//优先级,选择中等DMA_Init(DMA1_Channel1, &DMA_InitStructure);							//将结构体变量交给DMA_Init,配置DMA1的通道1/*DMA使能*/DMA_Cmd(DMA1_Channel1, DISABLE);	//这里先不给使能,初始化后不会立刻工作,等后续调用Transfer后,再开始
}/*** 函    数:启动DMA数据转运* 参    数:无* 返 回 值:无*/
void MyDMA_Transfer(void)
{DMA_Cmd(DMA1_Channel1, DISABLE);					//DMA失能,在写入传输计数器之前,需要DMA暂停工作DMA_SetCurrDataCounter(DMA1_Channel1, MyDMA_Size);	//写入传输计数器,指定将要转运的次数DMA_Cmd(DMA1_Channel1, ENABLE);						//DMA使能,开始工作while (DMA_GetFlagStatus(DMA1_FLAG_TC1) == RESET);	//等待DMA工作完成DMA_ClearFlag(DMA1_FLAG_TC1);						//清除工作完成标志位
}
AD+DMA教程代码实例:
#include "stm32f10x.h"                  // Device headeruint16_t AD_Value[4];					//定义用于存放AD转换结果的全局数组/*** 函    数:AD初始化* 参    数:无* 返 回 值:无*/
void AD_Init(void)
{/*开启时钟*/RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);	//开启ADC1的时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	//开启GPIOA的时钟RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);		//开启DMA1的时钟/*设置ADC时钟*/RCC_ADCCLKConfig(RCC_PCLK2_Div6);						//选择时钟6分频,ADCCLK = 72MHz / 6 = 12MHz/*GPIO初始化*/GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);					//将PA0、PA1、PA2和PA3引脚初始化为模拟输入/*规则组通道配置*/ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);	//规则组序列1的位置,配置为通道0ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_55Cycles5);	//规则组序列2的位置,配置为通道1ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_55Cycles5);	//规则组序列3的位置,配置为通道2ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 4, ADC_SampleTime_55Cycles5);	//规则组序列4的位置,配置为通道3/*ADC初始化*/ADC_InitTypeDef ADC_InitStructure;											//定义结构体变量ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;							//模式,选择独立模式,即单独使用ADC1ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;						//数据对齐,选择右对齐ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;			//外部触发,使用软件触发,不需要外部触发ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;							//连续转换,使能,每转换一次规则组序列后立刻开始下一次转换ADC_InitStructure.ADC_ScanConvMode = ENABLE;								//扫描模式,使能,扫描规则组的序列,扫描数量由ADC_NbrOfChannel确定ADC_InitStructure.ADC_NbrOfChannel = 4;										//通道数,为4,扫描规则组的前4个通道ADC_Init(ADC1, &ADC_InitStructure);											//将结构体变量交给ADC_Init,配置ADC1/*DMA初始化*/DMA_InitTypeDef DMA_InitStructure;											//定义结构体变量DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;				//外设基地址,给定形参AddrADMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;	//外设数据宽度,选择半字,对应16为的ADC数据寄存器DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;			//外设地址自增,选择失能,始终以ADC数据寄存器为源DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)AD_Value;					//存储器基地址,给定存放AD转换结果的全局数组AD_ValueDMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;			//存储器数据宽度,选择半字,与源数据宽度对应DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;						//存储器地址自增,选择使能,每次转运后,数组移到下一个位置DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;							//数据传输方向,选择由外设到存储器,ADC数据寄存器转到数组DMA_InitStructure.DMA_BufferSize = 4;										//转运的数据大小(转运次数),与ADC通道数一致DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;								//模式,选择循环模式,与ADC的连续转换一致DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;								//存储器到存储器,选择失能,数据由ADC外设触发转运到存储器DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;						//优先级,选择中等DMA_Init(DMA1_Channel1, &DMA_InitStructure);								//将结构体变量交给DMA_Init,配置DMA1的通道1/*DMA和ADC使能*/DMA_Cmd(DMA1_Channel1, ENABLE);							//DMA1的通道1使能ADC_DMACmd(ADC1, ENABLE);								//ADC1触发DMA1的信号使能ADC_Cmd(ADC1, ENABLE);									//ADC1使能/*ADC校准*/ADC_ResetCalibration(ADC1);								//固定流程,内部有电路会自动执行校准while (ADC_GetResetCalibrationStatus(ADC1) == SET);ADC_StartCalibration(ADC1);while (ADC_GetCalibrationStatus(ADC1) == SET);/*ADC触发*/ADC_SoftwareStartConvCmd(ADC1, ENABLE);	//软件触发ADC开始工作,由于ADC处于连续转换模式,故触发一次后ADC就可以一直连续不断地工作
}


http://www.mrgr.cn/news/451.html

相关文章:

  • 二、前后端分离通用权限系统(2)
  • 笑出腹肌!Ubuntu:如果连猫都会用,那你呢?‍
  • Java语言程序设计——篇十五(1)
  • Python实现人脸轮廓提取
  • AWS 注册是否必须提供信用卡号?
  • Qt/QML学习-StackView
  • 【笔试题面试题】(网络编程类1)知识点汇总,常用概念
  • Vue 3 + 天地图 + D3.js 绘制行政区划
  • 4.vue中引入axios
  • 关于鸿蒙开发中装饰器@Extend、@Styles、@Builder的介绍
  • Linux - 权限
  • PostgreSQL的walwriter进程
  • 【SpringBoot】SpringBoot项目中实现数据缓存
  • 家里养有宠物,宠物空气净化器真的能除毛除臭吗?
  • 使用PowerShell自动化Windows系统管理任务
  • Squish 8.0现已发布
  • 用“文心一言”写的文章,看看AI写得怎么样?
  • PHP中英文企业官网系统应用插件
  • pyexiv2库 EXIF信息读取、写入
  • FFmpeg源码:av_log2函数分析