STM32-第十节-DMA直接存储器存取

一、DMA:

1.简介:

DMA,直接存储区存取

DMA可以提供外设和存储器或存储器与存储器见的高速数据传输,无需CPU干预。

12个通道:DMA1(7个通道),DMA2(5个通道)

每个通道支持软件触发,和特定硬件触发(每个外设有固定通道)。

本芯片只有DMA1。

2.存储器映像:

3.功能图:

外设寄存器Flash和SRAM(存储器)为两大数据存储地点。

转运数据由两个结构体决定,每个包含三个参数:
起始地址,数据宽度,地址是否自增(一次转运完成后,指针是否挪到下个地址)。
(ps:这两个结构体其实是完全相同的,并非外设结构体只能放外设地址等等)

传输计数器:触发后,进行数据转运的次数,在传输完成后,两个结构体的指针回到初始地址。

自动重装器:决定了是否循环传输,在传输完成后,传输寄存器恢复到自动重装器的值,配合上面结构体指针回到初始地址,可以做到对对同一块地址数据循环传输。

M2M:决定触发逻辑,为1则软件触发,为0硬件触发(MtoM名称意义为存储器到存储器)

软件触发:与前面不同的是,并非由一个函数触发,而是不断连续触发DMA,直到将传输计数器清零,完成传输,即使能DMA就自动开始转运。(软件触发和循环模式不能同时使用)

硬件触发:就是外设给出信号触发

开关控制:给DMA使能,写传输计数器时,需要将DMA关闭。

4.ADC与DMA:

前文介绍了ADC的功能,ADC有一个扫描模式,可以同时转换多个通道的值,但在规则组中,却只有一个寄存器存放结果,就需要DMA,在一次转换完成后,就将寄存器的数据转运到存储器中,这样就不会被下一个通道的结果覆盖而丢失。

二、实战:DMA数据转运

DMA.c

#include "stm32f10x.h"                  // Device headeruint16_t MyDMA_Size;					//定义全局变量,用于记住Init函数的Size,供Transfer函数使用/*** 函    数:DMA初始化* 参    数:AddrA 原数组的首地址* 参    数:AddrB 目的数组的首地址* 参    数:Size 转运的数据大小(转运次数),1代表字节* 返 回 值:无*/
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);						//清除工作完成标志位
}

三、实战:DMA+AD多通道

问:如何访问外设寄存器?

答:无需具体地址,可通过结构体来访问,如想访问ADC1的DR寄存器,直接ADC1->DR即可。

新AD.c

#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(只能是通道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.pswp.cn/news/915689.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/915689.shtml

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

相关文章

服务器设置国外IP无法访问对防御攻击有用吗?

将服务器设置为仅允许国外 IP 访问,限制国内 IP 访问,确实可以在某些特定场景下提高服务器的抗攻击能力,但这并不能完全防御攻击。以下是对这种方法的分析、优缺点以及其他防御攻击的补充措施。1. 仅允许国外 IP 访问是否有用?1.1…

八大作业票(一) 动火安全作业证

动火安全作业证 执行标准:GB30871 GSDH——2200001 申报单位 申请人 作业申请时间 年 月 日 时 分 动火内容 动火方式 动火地点 动火类别 特级动火□ 一级动火□ 二级动火□ 作业负责人 监护人 动火…

NumPy库使用教学,简单详细。

NumPy 使用教学NumPy 是 Python 中用于科学计算的基础库,它提供了高性能的多维数组对象以及用于处理这些数组的工具。下面将结合多个代码文件,详细介绍 NumPy 的各种用法。1. 创建数组1.1 从列表创建数组import numpy as np# 一维数组 list1 [1,2,3,4,5…

vue3:十八、内容管理-实现行内图片的预览、审核功能

一、实现效果 实现图片的显示,大图预览;审核部分的待审核的审核功能 二、图片预览实现 1、参考官网 官网-图片预览 2、图片预览插槽设置 {row,index} 插槽中获取row行信息、index索引信息(指定行图片预览需要用到) style 设置基本样式宽width高height src 设置图片的路径…

Go后端配置文件教程

注:本文为博主,首次接触项目时的入门级配置实操在 Go 后端中,使用配置文件管理参数(如数据库连接、服务端口等)是必备技能。Viper 是 Go 生态中最流行的配置管理库。支持多种配置文件、环境变量、命令行参数等&#xf…

ubuntu24.04安装CUDA、VLLM、Pytorch等并部署Qwen3-8B-AWQ【50系显卡通用】

1. 系统更新与依赖安装 sudo apt update && sudo apt upgrade -y sudo apt install -y python3-pip python3-venv build-essential git nvidia-driver-575注:RTX 5070 Ti 推荐驱动 ≥550 版本 我是直接官网安装最新的驱动了,反正向上兼容,驱动安装教程可以参考我以…

Azure可靠性架构指南:构建云时代的高可用系统

随着企业加速拥抱数字化转型,云服务的可靠性已成为业务连续性的核心命题。Microsoft Azure凭借其"可靠性即核心"的设计理念,为企业技术决策者与架构师提供了一个可信赖的数字化底座。本文将系统解析Azure如何通过技术架构、工具链与方法论&…

linux 驱动 - v4l2 驱动框架

文章目录一、/dev/videoX1. 查询设备能力2. 获取当前视频格式3. 设置视频格式4. 申请缓冲区1) mmap 方式2) user 分配5. 查询缓冲区信息6. 将缓冲区放入队1) fill_vb2_buffer2) buf_prepare3) get_userptr4) buf_init5) attach_dmabuf 和 map_dmabuf6) start_streaming7) 总结7…

windows内核研究(驱动开发-0环与3环的通信)

驱动开发0环与3环的通信 设备对象 在之前开发窗口程序时,消息都是被封装成一个结构体(MSG),在内核开发时,消息被封装成另外一个结构体:IRP(I/O Request Package) 在窗口程序中&#…

ASP.NET Core Web API 内存缓存(IMemoryCache)入门指南

在 Web API 开发中,频繁访问数据库或第三方服务可能会带来性能瓶颈。为了提升接口响应速度并减轻后端压力,使用缓存是非常有效的优化手段。本文将带你快速上手 ASP.NET Core 提供的内存缓存(IMemoryCache),无需安装额外…

Axios Token 设置示例

以下是一个完整的 Axios Token 设置示例,涵盖全局配置、请求拦截器和单次请求设置三种方式:1. 基础配置(推荐方案)javascript复制代码import axios from axios;// 创建 Axios 实例 const apiClient axios.create({baseURL: https…

Excel数据合并工具:零门槛快速整理

软件介绍 在数据处理工作中,合并Excel同类数据是一项常见但繁琐的任务。今天为大家推荐一款专为简化此类操作设计的工具,它能快速完成工作表内多行同类数据的合并整理,大幅提升数据处理效率。 零门槛操作体验 相比Excel自带的数据透视…

深度学习 -- 梯度计算及上下文控制

深度学习 – 梯度计算及上下文控制 文章目录深度学习 -- 梯度计算及上下文控制一,自动微分1.1 基础概念1.2 计算梯度1.2.1 计算标量梯度1.2.2 计算向量梯度1.2.3 多标量梯度计算1.2.4 多向量梯度计算二,梯度上下文控制2.1 控制梯度计算2.2 累计梯度2.3 梯…

Redisson RLocalCachedMap 核心参数详解

🧑 博主简介:CSDN博客专家,历代文学网(PC端可以访问:https://literature.sinhy.com/#/?__c1000,移动端可微信小程序搜索“历代文学”)总架构师,15年工作经验,精通Java编…

【Unity3D实例-功能-移动】角色移动-通过WSAD(Rigidbody方式)

你是否曾梦想在虚拟世界中自由翱翔,像海豚一样在海洋自由穿梭,或者像宇航员一样在宇宙中尽情探索?今天,我们就来聊聊如何在Unity中使用Rigidbody来实现角色移动。 废话不多说,走,让我们马上来一探究竟&…

Vue接口平台学习十一——业务流测试

效果图及简单说明 与之前的用例列表相似布局,也分左右,左边用于显示测试流程的名称,右边用于显示流程相关信息。 左侧点击添加,直接增加一个新的业务流。 右侧是点击的业务流详情,展示名称,名称的编辑保存&…

碳化硅缺陷分类与原因

01一、碳化硅晶体材料中的缺陷到底是什么?碳化硅晶体材料中的缺陷是指在晶体生长、加工或使用过程中出现的不完美结构。这些缺陷可能表现为晶体内部的裂纹、表面的凹坑、原子排列的错误等。虽然缺陷看起来微不足道,但它们却可能对晶体的电学、热学和机械…

Jenkins 实现项目的构建和发布

作者:小凯 沉淀、分享、成长,让自己和他人都能有所收获! 本文的宗旨在于通过简单干净实践的方式教会读者,如何在 Docker 中部署 Jenkins,并通过 Jenkins 完成对项目的打包构建并在 Docker 容器中部署。 Jenkins 的主要…

Django接口自动化平台实现(三)

3.2 后台 admin 添加数据 1)注册模型类到 admin: 1 from django.contrib import admin2 from . import models3 4 5 class ProjectAdmin(admin.ModelAdmin):6 list_display ("id", "name", "proj_owner", "tes…

CentOS 7 配置环境变量常见的4种方式

✨博客主页: https://blog.csdn.net/m0_63815035?typeblog 💗《博客内容》:.NET、Java.测试开发、Python、Android、Go、Node、Android前端小程序等相关领域知识 📢博客专栏: https://blog.csdn.net/m0_63815035/cat…