江协科技STM32学习- P23 DMA 直接存储器存取

      🚀write in front🚀  
🔎大家好,我是黄桃罐头,希望你看完之后,能对你有所帮助,不足请指正!共同学习交流
🎁欢迎各位→点赞👍 + 收藏⭐️ + 留言📝​ 

💬本系列哔哩哔哩江科大STM32的视频为主以及自己的总结梳理📚 

🚀Projeet source code🚀   

💾工程代码放在了本人的Gitee仓库:iPickCan (iPickCan) - Gitee.com

引用:

STM32入门教程-2023版 细致讲解 中文字幕_哔哩哔哩_bilibili

Keil5 MDK版 下载与安装教程(STM32单片机编程软件)_mdk528-CSDN博客

STM32之Keil5 MDK的安装与下载_keil5下载程序到单片机stm32-CSDN博客

0. 江协科技/江科大-STM32入门教程-各章节详细笔记-查阅传送门-STM32标准库开发_江协科技stm32笔记-CSDN博客

【STM32】江科大STM32学习笔记汇总(已完结)_stm32江科大笔记-CSDN博客

江科大STM32学习笔记(上)_stm32博客-CSDN博客

STM32学习笔记一(基于标准库学习)_电平输出推免-CSDN博客

STM32 MCU学习资源-CSDN博客

stm32学习笔记-作者: Vera工程师养成记

stem32江科大自学笔记-CSDN博客

术语:

英文缩写描述
GPIO:General Purpose Input Onuput通用输入输出
AFIO:Alternate Function Input Output复用输入输出
AO:Analog Output模拟输出
DO:Digital Output数字输出
内部时钟源 CK_INT:Clock Internal内部时钟源
外部时钟源 ETR:External clock 时钟源 External clock 
外部时钟源 ETR:External clock mode 1外部时钟源 Extern Input pin 时钟模式1
外部时钟源 ETR:External clock mode 2外部时钟源 Extern Trigger 时钟模式2
外部时钟源 ITRx:Internal trigger inputs外部时钟源,ITRx (Internal trigger inputs)内部触发输入
外部时钟源 TIx:external input pin 外部时钟源 TIx (external input pin)外部输入引脚
CCR:Capture/Comapre Register捕获/比较寄存器
OC:Output Compare输出比较
IC:Input Capture输入捕获
TI1FP1:TI1 Filter Polarity 1Extern Input 1 Filter Polarity 1,外部输入1滤波极性1
TI1FP2:TI1 Filter Polarity 2Extern Input 1 Filter Polarity 2,外部输入1滤波极性2
DMA:Direct Memory Access直接存储器存取

正文:

0. 概述

从 2024/06/12 定下计划开始学习下江协科技STM32课程,接下来将会按照哔站上江协科技STM32的教学视频来学习入门STM32 开发,本文是视频教程 P2 STM32简介一讲的笔记。


定时器共四个部分,分为八个小节笔记。本小节为第一部分第一节。

🌳在第一部分,是定时器的基本定时的功能:定时中断功能、内外时钟源选择

🌳在第二部分,是定时器的输出比较功能,最常见的用途是产生PWM波形,用于驱动电机等设备

🌳在第三部分,是定时器的输入捕获功能和主从触发模式,来实现测量方波频率

🌳在第四部分,是定时器的编码器接口,能够更加方便读取正交编码器的输出波形,编码电机测速


1.🚢DMA

本节我们来学习DMA,直接存储器存取。

😎DMA是一个数据转运小助手,它主要是用来协助CPU完成数据转运的工作。

2.🚢DMA的简介

DMA(Direct Memory Access)直接存储器存取,或者叫直接存储器访问;

🦄从这个DMA名字的意思来看,DMA这个外设是可以直接访问STM32内部的存储器的,包括运行内存SRAM、程序存储器flash和寄存器等等,DMA都有权限访问它们,所以DMA才能完成数据转运的工作。

🦄DMA可以提供外设和存储器或者存储器和存储器之间的高速数据传输,无须CPU干预,节省了CPU的资源

🦄这里外设指的就是外设寄存器,一般是外设的数据寄存器DR、Data、 Register。比如ADC的数据寄存器、串口的数据寄存器等等。

🦄这里存储器指的就是运行内存SRAM和程序存储器flash,是我们存储变量数组和程序代码的地方,在外设和存储器或者存储器和存储器之间进行数据转运,就可以使用DMA来完成。并且在转运的过程中,无需CPU的参与,节省了CPU的资源,CPU省下时间就可以干一些其它的更加专业的事情,搬运数据这种杂活交给DMA就行了。

🦄12个独立可配置的通道: DMA1(7个通道), DMA2(5个通道)

🦄这个通道就是数据转运的路径,从一个地方移动到另一个地方,就需要占用一个通道。如果有多个通道进行转运,那它们之间可以各转各的互不干扰,这就是DMA的通道。

🦄每个通道都支持软件触发和特定的硬件触发

🦄如果DMA进行的是存储器到存储器的数据转运。比如我们想把flash里的一批数据转运到SRAM里去,那就需要软件触发了。

🦄使用软件触发之后,DMA就会一股脑地把这批数据以最快的速度全部转运完成。这也是我们想要的效果。

🦄那如果DMA进行的是外设到存储器的数据转运,就不能一股脑地转运了。因为外设的数据是有一定时机的。所以这时我们就需要用硬件触发,比如转运ADC的数据。那就得ADC每个通道AD转换完成后,硬件触发一次DMA,之后DMA再转运,触发一次,转运一次,这样数据才是正确的,才是我们想要的效果。

🦄所以存储器到存储器的数据转运,我们一般使用软件触发,外设到存储器的数据转运我们一般使用硬件触发

🦄特定的硬件触发意思就是每个DMA的通道,它的硬件触发源是不一样的。你要使用某个外设的硬件触发源,就得使用它连接的那个通道,而不能任意选择通道

🦄STM32F103C8T6 DMA资源:DMA1(7个通道)

🦄我们这个芯片只有DMA1的七个通道,没有DMA2。

3.🚢存储器映像

既然DMA是在存储器之间进行数据转运的,那我们就应该要了解一下STM32中都有哪些存储器,这些存储器又是被安排到了哪些地址上,这就是存储器映像的内容。

计算机系统的五大组成部分是运算器、控制器、存储器、输入设备和输出设备。其中运算器和控制器一般会合在一起,叫做CPU。

所以计算机的核心关键部分就是CPU和存储器。存储器又有两个重要知识点,一个是存储器的内容,另一个就是存储器的地址。那STM32也不例外,这个表就是STM32中所有类型的存储器和它们所被安排的地址。

在这个表里,无论是flash还是SRAM,还是外设寄存器,它们都是存储器的一种。外设寄存器实际上也是存储器。我们前面这里说的是外设到存储器存储器到存储器本质上其实都是存储器之间的数据转运。说成外设的存储器,只不过是STM32特别指令可以转运外设的存储器而已。

在上表里,存储器总共分成两大类ROM和RAM。

ROM 就是只读存储器是一种非易失掉电不丢失的存储器

RAM就是随机存储器是一种易失掉电丢失的存储器

其中ROM分为了三块:

  • 第一块是程序存储器flash,也就是主闪存。它的用途就是存储C语言编译后的程序代码,也就是我们下载程序的位置,运行程序一般也是从主闪存里面开始运行的。这一块存储器STM32给它分配的起始地址是0x0800 0000。然后剩余字节的地址依次增长,每个字节都分配一个独一无二的地址。终止地址取决于它的容量编到哪里,哪里就是终止地址,这就是主闪存的地址范围。之后如果在软件里看到某个数据的地址是0x0800开头的,那就可以确定它是属于主闪存的数据。
  • 接着下面两块系统存储器和选项字节,这两块存储器也是ROM的一种,掉电不丢失。实际上它们的存储介质也是flash,只不过是我们一般说flash指的是主闪存flash,而不是指系统存储器和选项字节。它们的地址都是0x1FFF开头的,紧跟着0x2000开头的就是RAM区。

所以可以看出系统存储器和选项字节这两块存储器的位置是在ROM区的最后面。

系统存储器的用途是存储BootLoader用于串口下载程序存储的位置就被分配到BootLoaderBootLoader程序是芯片出厂自动写入的,一般也不允许我们修改。

选项字节是用于存储一些独立于程序代码的配置参数。它的位置是在ROM区的最后面。下载程序可以不刷新选项字节的内容,这样选项字节的配置就可以保持不变。选项字节里存的主要是flash的读保护写保护还有看门狗等等的配置。

然后我们看一下RAM区。

  • 首先是运行内存SRAM分配的地址是0x2000 0000,用途是存储运行过程中的临时变量也就是我们在程序中定义变量数组结构体的地方。你可以试一下定义一个变量,再取它的地址显示出来。那这个地址肯定就是0x2000开头的。类比于电脑的话运行内存就是内存条
  • 然后RAM区剩下的还有外设寄存器,它的地址是0x4000 0000这块区域,用途是存储各个外设的配置参数,也就是我们初始化各个外设最终所读写的东西。

    刚才我们说了
    外设寄存器也是存储器的一种。它的存储介质其实也是SRAM,只不过我们一般习惯把运行内存叫SRAM,外设寄存器就直接叫寄存器。
  • 内核外设寄存器地址是0xE000 0000这片区域用途是存储内核各个外设的配置参数内核外设就是NVIC和SysTick。因为内核外设和其它外设不是一个厂家设计的,所以它们的地址也是被分开了。内核外设是0xE000,其它外设是0x4000 。

以上这些就是STM32里的存储器和它们被安排的地址。

接下来我们看一下数据手册中的这张图(对应上面的表格)

在STM32中所有的存储器都被安排到了0~0xFFFF FFFF这个地址范围内

因为CPU是32位的,所以寻址范围就是32位的范围。32位的寻址范围是非常大的,最大可以支持4GB容量的存储器。而我们STM32的存储器都是KB级别的。所以这个4GB的寻址空间会有大量的地址都是空的,算一下地址的使用率还不到百分之一。

在这个图里,灰色填充的就是reserve的区域,也就是保留区域,没有使用到。

0地址实际上也是没有存储器的,它这里写的是别名到flash或者系统存储器取决于boot引脚。

因为程序是从0地址开始运行的,所以这里需要把我们想要执行的程序映射到零地址来。如果映射在flash区,就是从flash执行。

如果映射在系统存储器区,就是从系统存储器运行BootLoader。

如果映射到SRAM,就是从SRAM启动。

怎么选择由BOOT0和BOOT1两个引脚来决定,这就是0地址里的别名区。

剩下的0x0800开始的flash区,用于存储程序代码。

0x1FFF开始的系统存储器和选项字节是在ROM区的最后面。

0x2000开始的是SRAM区,0x4000开始的是外设寄存器

这里面可以展开,就是右边这些东西

每个外设又有它们自己的起始地址,比如TIM2的地址是0x4000 0000。

然后外设地址里面又可以具体细分到每个寄存器的地址、寄存器里每个字节的地址,最终所有字节的地址就都可以算出来了。

最后上面这里0xE000开始的区域存放在就是内核里面的外设寄存器

接下来我们来看一下DMA的框图。

4.🚢DMA框图

这个框图我们在第一节STM32的系统结构里也见过一个类似的。

左上角这里是Cortex-M3内核里面包含了CPU和内核外设等等。

剩下的所有东西都可以把它看成是存储器。

  • 🤠所以这个框图总共就是CPU和存储器两个东西。
  • 🤠flash是主闪存,SRAM是运行内存各个外设都可以看成是寄存器也是一种SRAM存储器因为寄存器是一种特殊的存储器

一方面,CPU可以对寄存器进行读写,就像读写运行内存一样。另一方面,寄存器的每一位背后都连接了一根导线,这些导线可以用于控制外设电路的状态,比如置引脚的高低电平、导通和断开开关、切换数据选择器或者多位结合起来,当做计数器,数据寄存器等等。

🤠所以寄存器是连接软件和硬件的桥梁。软件读写寄存器就相当于在控制硬件的执行所以我们可以把外设抽象成一个个寄存器,CPU控制外设本质上就是读写寄存器

既然外设就是寄存器,寄存器就是存储器,那使用DMA进行数据转运,就都可以归为一类问题了,就是从某个地址取内容再放到另一个地址去。

我们看向上面的框图,为了高效有条理的访问存储器,这里设计了一个总线矩阵。总线矩阵的左端是主动单元也就是拥有存储器的访问权。右边这些是被动单元,它们的存储器只能被左边的主动单元读写。

主动单元这块内核有DCode和系统总线可以访问右边的存储器其中DCode的总线是专门访问flash的,系统总线是访问其它东西的。

另外,由于DMA要转运数据,所以DMA也必须要有访问的主动权。那主动单元除了内核CPU,剩下的就是DMA线了。这里DMA1有一条DMA总线,DMA2也有一条DMA总线。下面还有一条是以太网外设自己私有的DMA总线,这个可以不用管。

在DMA1和DMA2里面可以看到DMA1有七个通道,,DMA2有五个通道,各个通道可以分别设置它们转移数据的原地址和目的地址。这样它们就可以各自独立的工作了。

接着下面这里有个仲裁器。这个是因为虽然多个通道可以独立转运数据,但是最终DMA总线只有一条。所以所有的通道都只能分时复用这一条DMA总线,如果产生了冲突,那就会由仲裁器根据通道的优先级决定谁先用谁后用。

另外在总线矩阵里也会有个仲裁器如果DMACPU都要访问同一个目标那么DMA就会暂停CPU的访问以防止冲突。不过总线仲裁器仍然会保证CPU得到一半的总线带宽,使CPU也能正常的工作。这就是仲裁器的作用。

后继续看下面这里是AHB从设备,也就是DMA自身的寄存器。因为DMA作为一个外设它自己也会有相应的配置寄存器这里连接在了总线右边的AHB总线上。所以,DMA既是总线矩阵的主动单元,可以读写各种存储器,也是AHB总线上的被动单元。

CPU通过这一条线路就可以对DMA进行配置了。

接着继续看,这里是DMA请求,请求就是触发的意思。这条线路右边的触发源是各个外设,所以这个DMA请求就是DMA的硬件触发源

比如ADC转换完成,串口接收到数据,需要触发DMA转运数据的时候,就会通过这条线路向DMA发出硬件触发信号。之后DMA就可以执行数据转运的工作了,这就是DMA请求的作用。

到这里,有关DMA的结构就讲的差不多了。

总结DMA的结构其中包括:

  • 🤠用于访问各个存储器的DMA总线
  • 🤠内部的多个通道可以进行独立的数据转运;
  • 🤠仲裁器用于调度各个通道,防止产冲突;
  • 🤠AHB从设备用于配置DMA参数;
  • 🤠DMA请求用于硬件触发DMA的数据转移。

这就是这个DMA的各个部分和作用。

最后再额外说一个问题,就是这里的flash它是ROM只读存储器的一种,如果通过总线直接访问的话,无论是CPU还是DMA,都是只读的,只能读取数据而不能写入如果你DMA的目的地址填写在flash的区域那转运时就会出错。这个注意一下。

当然flash也不是绝对的不可写入,我们可以配置这个flash接口控制器对flash进行写入,这个流程就比较麻烦了,要先对flash按页进行擦除,再写入数据。不过这是另一个课题了,这里就不再讨论。

总之就是CPU或者DMA直接访问flash的话是只可以读而不可以写的。

SRAM是运行内存可以任意读写。

外设寄存器得看参考手册里面的描述,有的寄存器是只读的,有的寄存器是只写的。不过我们主要用的是数据寄存器,数据寄存器都是可以正常读写的。

5.🚢DMA基本结构图

刚才的框图只是一个笼统的结构图,对于DMA内部的执行细节,它还是没体现出来。如果想编写代码,实际去控制DMA的话,就按下图来。

图中这两部分就是数据转运的两大站点,左边是外设寄存器站点,右边是存储器站点包括flash和SRAM。

STM32手册里所说的存储器一般是特指flash和SRAM,不包含外设寄存器。外设寄存器一般直接称作外设所以就是外设到存储器存储器到存储器这样来描述。虽然我们刚才说了,寄存器也是存储器的一种,但是STM32还是使用了外设和存储器来作为区分,注意一下描述方法的不同。

看图中的箭头方向就知道DMA的数据转运可以是从外设到存储器,也是可以从存储器到外设,具体是向左还是向右,有一个方向的参数可以进行控制。

另外还有一种转运方式,就是存储器到存储器,比如flash到SRAM或者SRAM到SRAM这两种方式。

由于flash是只读的所以DMA不可以进行SRAM到flash或者flash到flash的转移操作。

然后我们继续看这两边的参数,既然要进行数据转运,那肯定就要指定从哪里转到哪里,具体怎么转,所以外设和存储器两个站点就都有三个参数。

  • 🤠第一个是起始地址,有外设端的起始地址和存储器端的起始地址,这两个参数决定了数据是从哪里来到哪里去的。 
  • 🤠第二个参数是数据宽度,这个参数的作用是指定一次转运要按多大的数据宽度来进行。它可以选择字节Byte、半字HalfWord和字word。字节就是八位,也就是一次转用一个uint8_t这么大的数据;半字是十六位,就是一次转用一个uint16_t;字是32位,就是一次转用uint32_t。比如转运ADC的数据,ADC的结果是uint16_t这么大,所以这个参数就要选择半字一次转运。

  • 第三个参数是地址是否自增,这个参数的作用是指定一次转运完成后,下一次转运是不是要把地址移动到下一个位置去,这就相当于是指针p++这个意思,比如ADC扫描模式,用DMA进行数据转运。外设地址是ADC_DR寄存器,寄存器这边显然地址是不用自增的,如果自增,那下一次转运就跑到别的寄存器那里去了。存储器这边地址就需要指针,每转运一个数据后,就往后挪个坑,要不然下次再转,就把上次的覆盖掉了,这就是地址是否自增的作用,就是指定是不是叫转运一次挪个坑这个意思。

如果要进行存储器到存储器的数据转运那我们就需要把其中一个存储器的地址放在外设的这个这样就能进行存储器到存储器的转运了。

只要在外设起始地址里写flash或者SRAM的地址,那它就会去flash或SRAM找数据。

这个站点虽然叫外设存储器,但是它就只是个名字而已。并不是说这个地址只能写寄存器的地址。如果写flash的地址,那它就会去flash里,找写SRAM,它就会去SRAM里找,这个没有限制。甚至你可以在外设站点写存储器的地址,存储器站点写外设的地址,然后方向参数给反过来,这样也是可以的,只是ST公司给它起的这样的名字而已。你也可以把它叫做站点A,站点B,不必拘泥于它写的外设站点和存储器站点这个名字。

接着往下面看,这里有个东西叫做传输计数这个东西就是用来指定我总共需要转运几次的。这个传输计器是一个自减计数比如给它写个5,那DMA就只能进行5次数据转运。转运过程中,每转运一次,计数器的数就会减1。当传输计数器减到零之后,DMA就不会再进行数据转运了。

另外0之后之前自增的地址也会恢复到起始地址的位置以方便之后DMA开始新一轮的转换。

在传输计数器的右边有一个自动重装器,这个自动重装器的作用就是传输计数器减到零之后是否要自动恢复到最初的值比如最初传输计数器给5,如果不使用自动重装器,那转用5次后DMA就结束了。如果使用自动重装器,那转运5次计数器减到0后,就会立即重装到初始值5。

自动重装器决定了转运的模式如果不重装,就是正常的单次模式如果重装就是循环模式,比如如果想转运一个数组,那一般就是单次模式,转运一轮就结束了。如果是ADC扫描模式加连续转换,那为了配合ADC,DMA也需要使用循环模式。所以这个循环模式和ADC的连续模式差不多,都是指定一轮工作完成后,是不是立即开始下一轮工作

 然后继续往下看,这一块就是DMA的触发控制。

触发就是决定DMA需要在什么时机进行转运的。触发源硬件触发和软件触发具体选择哪个由M2M这个参数决定M2M就是memory to memory存储器到存储器的意思。

  • 当我们给M2M位1时,DMA就会选择软件触发,应用在存储器到存储器转运的情况。
  • 这个软件触发并不是调用某个函数一次触发一次,这个软件触发的执行逻辑是以最快的速度连续不断的触发DMA争取早日把传输计数器清零,完成这一轮的转换。所以这里的软件触发和我们之前外部中断和ADC的软件触发可能不太一样,可以把它理解成连续触发。

 💯💯注意:这个软件触发和循环模式不能同时用,因为软件触发就是想把传输计数器清零,循环模式是清零后自动重装。如果同时用的话,那DMA就停不下来了。

软件触发一般适用于存储器到存储器的转运。因为存储器到存储器的转运是软件启动,不需要时机,并且想尽快完成的任务。

M2M位给0,就是硬件触发硬件触发源可以选择ADC、串口、定时器等等。使用硬件触发的转运一般都是与外设有关的转运。这些转运需要一定的时机,比如ADC转换完成、串口收到数据、定时时间到等等,所以需要使用硬件触发,在硬件达到这些时机时,传个信号过来触发DMA进行转运。

最后就是开关控制,也就是DMA_Cmd函数,当DMA使能后,DMA就准备就绪可以进行转运了。

DMA进行转运有几个条件:

  • 😎第一就是开关控制,DMA_Cmd必须使能;
  • 😎第二就是传输计数器必须大于零;
  • 😎第三就是触发源必须有触发信号,触发一次转运一次,传输计数器自减一次,当传输计数器等于0且没有自动重装时,这时无论是否触发,DMA都不会再进行转运,此时就需要DMA_Cmd给disable关闭DMA。当传输计数器写一个大于零的时候,DMA_Cmd给ENable开启DMA,DMA才能继续工作。

⚠️⚠️⚠️注意:写传输计数器时,必须要先关闭DMA再进行不能在DMA开启时写传输计数这是手册里的规定。

接下来我们再看几个细节的问题:

6.🚢DMA请求 

这张图是DMA1的请求映象

这张图表示的就是结构图中这部分结构,DMA触发的部分:

请求映像图中可以看到DMA的七个通道,每个通道都有一个数据选择器,可以选择硬件触发或软件触发。EN决定这个数据选择器要不要工作,EN等于0数据选择器不工作,EN等于1数据选择器工作,然后软件触发后面跟个M2M的意思应该是当M2M等于1时选择软件触发。

图中左边的硬件触发源,是外设请求信号,可以看到每个通道的硬件触发源都是不同的。如果需要用ADC1来触发的话,那就必须选择通道1。如果需要定时器二的更新事件来触发的话,那就必须选择通道二,剩下的也是同理。因为每个通道的硬件触发源都不同,所以如果想使用某个硬件触发源的话,就必须使用它所在的通道,这就是硬件触发的注意事项。

而如果使用软件触发的话通道就可以任意选择。因为每个通道的软件触发都是一样的。这就是最开始DMA的简介那部分所讲的每个通道都支持软件触发和特定的硬件触发,这就是特定的意思,即选择硬件触发是要看通道的。

再看,比如通道1硬件触发ADC1、定时器2是通道3,定时器4是通道1那到底是选择哪个触发

这个是对应的外设是否开启了DMA输出来决定的。比如要使用ADC1,会有个库函数ADC_DMACmd,必须使用这个库函数开启ADC1的这一路输出,它才有效。如果想选择定时器二的通道三,那也会有个TIM_DMACmd函数用来进行DMA输出控制。

所以这三个触发源具体使用哪个,取决于把哪个外设的DMA输出开启了,如果三个都开启了,那这边是一个或门,理论上三个硬件都可以进行触发,不过一般情况下,我们都是开启其中一个。

七个触发进入到仲裁器经优先级判断最终产生内部的DMA1请求。这个优先级的判断类似于中断的优先级默认优先级是通道号越小优先级越高。当然也可以在程序中配置优先级,这个其实影响并不是很大,大家了解一下就行了。

7.🚢数据宽度与对齐

如果数据宽度都一样那就是正常的一个个转运。如果数据宽度不一样那会怎么处理

这个表就是来说明这个问题的:

第一列是源端宽度,第二列是目标宽度,第三列是传输数目。

当源端和目标宽度都是八位时,转运第一步是在源端的0位置读数据B0,在目标的零位置写数据B0,就是把这个B0从左边挪到右边。之后的步骤就是把B1从左边挪到右边,接着B2,B3,这是源端和目标都是八位的情况。

当源端是8位,目标是16位,那它的操作就是在源端读B0,在目标写00B0。之后读B1写00B1。这个意思就是如果你目标的数据宽度比源端的数据宽度大,那就在目标数据前面多出来的空位补零。

 八位转运到32位也是一样的处理,前面空出来的都补零。

当目标数据宽度比源端数据宽度小时比如由十六位转到八位就是读B1、B0只写入B0。读B3、B2只写入B2,也就是把多出来的高位舍弃掉。

之后那些也都是类似的操作。

总之这个表的意思就是如果把小的数据转到大的里面去,高位就会补零。如果把大的数据转到小的里面去,高位就会舍弃掉。如果数据宽度一样,那就没事。就是跟uint8_t uint16_t和uint32_t变量之间相互赋值一样。不够就补零,超了就舍弃高位。 

最后我们再来看两个例子,看看在这些实际的任务下,DMA是如何工作的。

8.🚢实例 

第一个例子就是数据转运+DMA,第二个例子是ADC扫描模式+DMA。这两个例子将和我们演示的两个程序是对应的。

8.1数据转运+DMA

先看第一个例子,这个例子的任务是将SRAM里的数组DataA转运到另一个数组DataB中。我们看一下这种情况下,这个基本结构里的各个参数,该如何配置。

首先是外设站点和存储器站点的起始地址、数据宽度、地址是否自增这三个参数。

在这个任务里,外设地址显然应该填DataA数组的首地址,存储器地址给DataB数组的首地址,然后数据宽度两个数组的类型都是uint8_t,所以数据宽度都是按八位的字节传输。关于地址是否自增,我们想要的效果是DataA[0]转到DataB[0],DataA[1]转到DataB[1]等等,两个数组的位置一一对应。所以转运完DataA[0]和DataB[0]之后,两个站点的地址都应该自增,都移动到下一个数据的位置,继续转运DataA[1]和DataB[1]这样来进行。如果左边不自增,右边自增,效果就是这样的,转运完成后,DataB的所有数据都会等于DataA[0]

如果左边自增,右边不自增,那效果就是这样的,转运完成后DataB[0]等于DataA的最后一个数DataB,其它的数不变

如果左右都不自增,那就一直是DataA[0]转到DataB[0],其它的数据不变,这就是地址是否自增的效果。

方向参数显然就是外设站点转运到存储机站点。如果想把DataB的数据转运到DataA,那可以把方向参数换过来,这样就是反向转运。

然后是传输计数器和是否要自动重装,在这里显然要转运7次,所以传输计数器给7,自动重装暂时不需要。

触发选择部分这里我们要使用软件触发,因为这是存储器到存储器的数据转运,是不需要等待硬件时机的,尽快转运完成就行了。

最后调用DMA_Cmd给DMA使能,这样数据就会从DataA转运到DataB了。

转运7次之后,传输计数器自减到0,DMA停止,转运完成。

这里的数据转运是一种复制转运。转运完成后,DataA的数据并不会消失。这个过程相当于是把DataA的数据复制到了DataB的位置。这就是第一个任务,存储器到存储器的数据转移。

8.2ADC扫描模式+DMA

接着看第二个任务ADC扫描模式+DMA

左边是ADC扫描模式的执行流程,在这里有七个通道,触发一次后七个通道依次进行AD转换,然后转换结果都放到ADC_DR数据寄存器里面。

那我们要做的就是在每个单独的通道转换完成后,进行一次DMA数据转运,并且目的地址进行自增,这样数据就不会被覆盖了。所以在这里,DMA的配置就是外设地址写入ADC_DR这个寄存器的地址,存储器的地址可以在SRAM中定一个数组ADvalue,然后把ADvalue的地址当做存储器的地址。

之后数据宽度,因为ADC_DR和SRAM数组我们要的都是uint16_t的数据,所以数据宽度都是十六位的半字传输。

地址是否自增,从这个图里显然是外设地址不自增,存储器地址自增。

传输方向是外设站点到存储器站点。

传输计数器,这里通道有七个,所以计数七次。

计数器是否自动重装,ADC如果是单次扫描,那DMA的传输计数器可以不自动重装,转换一轮就停止。如果ADC是连续扫描,那DMA就可以使用自动重装,在ADC启动下一轮转换的时候,DMA也启动下一轮的转运,ADC和DMA同步工作。

触发选择,这里ADC_DR的值是在ADC单个通道转换完成后才会有效,所以DMA转运的时机需要和ADC单个通道转换完成同步,因此DMA的触发要选择ADC的硬件触发。

⚠️⚠️注意:ADC扫描模式在每个单独的通道转换完成后,没有任何标志位也不会触发中断。所以我们程序不太好判断某一个通道转换完成的时机是什么时候。但是,虽然单个通道转换完成后,不产生任何标志位和中断,但是它应该会产生DMA请求去触发DMA转运。这部分内容手册里并没有详细描述,根据实际实验,单个通道的DMA请求肯定是有的。

一般来说,DMA最常见的用途就是配合ADC的扫描模式因为ADC扫描模式有个数据覆盖的特征,或者可以说这个数据覆盖的问题是ADC固有的缺陷。这个缺陷使ADC和DMA成了最常见的伙伴。ADC对DMA的需求是非常强烈的,而其它的一些外设使用DMAA可以提高效率是锦上添花的操作,但是不使用也是可以的,顶多是损失一些性能。但是这个ADC的扫描模式如果不使用DMA功能都会受到很大的限制。所以ADC和DMA的结合最为常见。

最后补充一下手册中的一个知识点,详情可以去手册上看看。

存储器包含两个位段区域,这两个位段区映射的外设寄存器和SRAM中全部的位。这个位段区就相当于是位寻址,它把外设寄存器和SRAM中所有的位都分配了地址,你操作这个新的地址就相当于操作其中某一个位。因为32位的地址有99%都是空的,所以地址空间很充足,即使把每一位都单独编码,那也毫无压力。所以就存在了这样一个位段,用于单独操作寄存器或SRAM的某一位,位段区是另早那一个地方开辟了一段地址区域。其中SRAM位段区是2200开头的区域,外设寄存器的位段区是4200开头的区域。

9.🚢嵌入式闪存

闪存被分为了很多页,它们的地址都是0800开头的。在闪存区的最后就是系统存储器和选项字节,这两个区域统称为信息块。下面这是闪存接口寄存器,这是外设的一部分,这个外设可以对闪存进行读写。

10.🚢启动配置

配置BOOT0和BOOT1两个引脚来来选择程序从哪里启动

本节的内容到这里就结束了,下节来开始写代码。

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

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

相关文章

数据结构与算法(二叉树)

树 树的概念与结构 1. 树是⼀种非线性的数据结构,它是由 n 个有限结点组成的⼀个具有层次关系的集合。 2. 之所以把它叫做树,是因为它看起来像⼀棵倒挂的树,也就是说它是根朝上,而叶朝下。 2. 有⼀个特殊的结点,称为根…

HarmonyOS应用开发者基础认证——初级闯关习题参考答案大全

相关文章 HarmonyOS应用开发者中级认证——中级闯关习题参考答案大全 HarmonyOS应用开发者高级认证——高级闯关习题参考答案大全 文章目录 HarmonyOS第一课 HarmonyOS介绍判断题单选题多选题 HarmonyOS第一课 DevEco Studio的使用判断题单选题多选题 HarmonyOS第一课 ArkTS语法…

浅析Android View绘制过程中的Surface

前言 在《浅析Android中View的测量布局流程》中我们对VSYNC信号到达App进程之后开启的View布局过程进行了分析,经过对整个App界面的View树进行遍历完成了测量和布局,确定了View的大小以及在屏幕中所处的位置。但是,如果想让用户在屏幕上看到…

使用 FastGPT 工作流实现 AI 赛博算卦,一键生成卦象图

最近那个男人写的汉语新解火遍了全网,那个男人叫李继刚,国内玩 AI 的同学如果不知道这个名字,可以去面壁思过了。 这个汉语新解的神奇之处就在于它只是一段几百字的提示词,效果却顶得上几千行代码写出来的应用程序。 这段提示词…

面试域——岗位职责以及工作流程

摘要 介绍互联网岗位的职责以及开发流程。在岗位职责方面,详细阐述了产品经理、前端开发工程师、后端开发工程师、测试工程师、运维工程师等的具体工作内容。产品经理负责需求收集、产品规划等;前端专注界面开发与交互;后端涉及系统架构与业…

【STM32-HAL库】火焰传感器(STM32F407ZGT6)(附带工程下载链接)

一、TEMT6000光照强度传感器 火焰传感器是一种能够检测火焰的传感器,它通过检测空气中的特定波长的光线来检测火焰的存在,并输出一个信号来通知系统发生了火灾 工作原理 火焰传感器的工作原理基于光学检测技术。当火焰燃烧时,会产生一些特…

Python 实现 excel 数据过滤(从入门到exe)

一、场景分析 假设有如下一份 excel 数据 shop.xlsx, 写一段 python 程序,实现对于车牌的分组数据过滤。 并以车牌为文件名,把店名输出到 车牌.txt 文件中。 比如 闽A.txt 文件内容为: 小林书店福州店1 小林书店福州店2 二、依赖安装 程序依…

乘云而上,OceanBase再越山峰

一座山峰都是一个挑战,每一次攀登都是一次超越。 商业数据库时代,面对国外数据库巨头这座大山,实现市场突破一直都是中国数据库产业多年夙愿,而OceanBase在金融核心系统等领域的攻坚克难,为产业突破交出一副令人信服的…

消防应急救援系留照明无人机技术详解

消防应急救援系留照明无人机技术是一种专门用于消防应急救援场景,通过系留技术实现长时间悬停并提供高效照明服务的高科技解决方案。以下是对该技术的详细解析: 一、系统组成 消防应急救援系留照明无人机系统主要由无人机平台、LED照明灯组、系留供电系…

PowerBI 根据条件选择获得不同的表格 因为IF和SWITCH只能返回标量而不能返回表格 Power BI

PowerBI 根据条件选择返回不同的表格 因为IF和SWITCH只能返回标量而不能返回表格 Power BI 自定义日期筛选套件 根据条件得到不同的表格 背景 在设置自定义对比日期时,需要根据选择的内容返回不同的表格作为CALCULATE的表格参数进行计算。 图1:Power …

2024年10款好用的图纸加密软件推荐|企业CAD图纸加密指南!

在当今数字化时代,企业的 CAD 图纸等重要设计文件面临着日益严峻的安全风险。为了保护企业的核心知识产权和商业机密,选择一款可靠的图纸加密软件至关重要。下面为大家推荐 2024 年 10 款好用的图纸加密软件,为企业提供 CAD 图纸加密指南。 一…

设计资讯 | 塑造数字交互未来的 Sol Reader

虚拟现实 (VR) 在过去几年中不断创新和发展。它真正突破了沉浸式体验的极限。VR 技术目前正在提高视觉保真度,甚至融入其他感官,从而彻底改变我们与数字世界的互动方式。 来看看世界上第一款 VR 电子书阅读器——Sol Reader。它为狂热的读者提供了一种独…

Linux下MySQL8.x的编译安装与使用

Linux下MySQL的安装与配置 1. 安装环境初始化 1.1 查看是否安装过MySQL 如果使用rpm安装, 检查一下RPM PACKAGE rpm -qa | grep -i mysql # -i 忽略大小写 # 或者 yum list installed | grep mysql如果存在mysql-libs的旧版本包,显示如下 #存在 [rootlocalhost ~]…

一文解决单调栈的应用

单调栈的定义: 单调栈是栈的一中特殊形式,在栈中的元素必须满足单调性(一定是单调上升或单调下降等等的规律)。 单调栈的性质: 单调栈解决的问题 单调栈解决的常见问题:给定一个序列,求每个位置…

.NET 8 中的 Mini WebApi

介绍 .NET 8 中的极简 API 隆重登场,重新定义了我们构建 Web 服务的方式。如果您想知道极简 API 的工作原理以及它们如何简化您的开发流程,让我们通过一些引人入胜的示例来深入了解一下。 .NET 极简主义的诞生 想想我们曾经不得不为一个简单的 Web 服务…

Linux——常见指令及其权限理解(正在更新中)

1.指令 1.1 快速了解指令 pwd 首次登录,默认所处的路径 whoami 当前所用的用户的名称 ls 显示当前路径下,文件名称 mkdir 在当前目录下,创建一个文件夹/目录 cd 进入一个目录 touch 新建一个文…

esp32 GPIO 分别用5种中断类型控制LED

下面程序分别用ANYEDGE POSEDGE NEGEDGE HIGH_LEVEL LOW_LEVEL 中断类型控制GPIO 0 脚的电平。此程序的重点是用延时消除按键产生的无用中断信号 硬件 1. led 接0脚和地 2. 按钮接gpio 1脚 和地或3.3v 脚 图片 程序 #include "driver/gpio.h" #incl…

ansible开局配置-openEuler

ansible干啥用的就不多介绍了,这篇文章主要在说ansible的安装、开局配置、免密登录。 ansible安装 查看系统版本 cat /etc/openEuler-latest输出内容如下: openeulerversionopenEuler-24.03-LTS compiletime2024-05-27-21-31-28 gccversion12.3.1-30.…

金蝶云星空采购退料单集成易仓出库单实现高效数据对接

金蝶云星空采购退料单集成易仓出库单实现高效数据对接 Done-金蝶-采购退料单——>易仓-出库单:高效数据集成方案解析 在企业的日常运营中,数据的准确传递和实时处理至关重要。本文将聚焦于一个具体的系统对接集成案例:如何将金蝶云星空中…

基于Ubuntu24.04,下载并编译Android12系统源码 (二)

1. 前言 上篇文章,我们基于Ubuntu24.04,已经成功下载下来了Android12的源码,这篇文章我们会接着上文,基于Ubuntu24.04来编译Android源码。 2. 编译源码 2.1 了解源码编译的名词 Makefile : Android平台的一个编译系…