STM32 DMA直接存储器存取

news2024/10/7 4:26:20

单片机学习!

目录

文章目录

前言

一、DMA简介

1.1 DMA是什么

1.2 DMA作用

1.3 DMA通道

1.4 软硬件触发

1.5 芯片资源

二、存储器映像

2.1 存储器

2.2 STM32存储器

三、DMA框图

3.1 内核与存储器

3.2 寄存器

3.3 DMA数据转运

3.4 DMA总线作用

3.5 DMA请求

3.6 DMA结构框图总结

四、DMA基本结构

4.1 数据转运两大站点

4.2 外设和存储器的参数

4.3 传输计数器和自动重装器

4.4 DMA触发控制

4.5 开关控制

4.6 DMA转运条件

五、DMA请求

六、数据宽度与对齐

七、数据转运+DMA

八、ADC扫描模式+DMA

总结


前言

        DMA是一个转运数据小助手,它主要是用来协助CPU完成数据转运的工作。本文就介绍了DMA的基础内容。


一、DMA简介

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

1.1 DMA是什么

        DMA就是直接存储器存取或者叫直接存储器访问。DMA名字的意思就表示,DMA这个外设,是可以直接访问STM32内部的存储器的,包括运行内存SRAM、程序存储器Flash、寄存器等等,DMA都有权限访问它们。正是DMA有直接访问内部存储器的权限,DMA才能完成数据转运的工作。

1.2 DMA作用

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

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

        存储器指的就是运行内存SRAM和程序存储器Flash,是存储变量数组和程序代码的地方。

        外设和存储器或者存储器和存储器之间进行数据转运,就可以使用DMA来完成。并且在转运的过程中,无需CPU的参与。CPU省下的时间就可以干一些其他的,更加专业的事情。搬运数据这种杂活,交给DMA就行了。

1.3 DMA通道

        STM32的DMA有12个独立可配置的通道,其中DMA1有7个通道,DMA2有5个通道。这里的通道就是数据转运的路径。从一个地方到另一个地方就需要占用一个通道。如果有多个通道进行转运,那它们之间可以各转各的,互不干扰。

1.4 软硬件触发

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

        如果DMA进行的是存储器到存储器的数据转运,比如需要把Flash里的一批数据,转运到SRAM里去,那就需要软件触发。使用软件触发之后,DMA就会一股脑的把这批数据以最快的速度全部转运完成。

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

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

总结:

  • 存储器到存储器的数据转运,一般使用软件触发。
  • 外设到存储器的数据转运,一般使用硬件触发。

1.5 芯片资源

        STM32F103C8T6 的DMA资源只有DMA1的7个通道,没有DMA2.

二、存储器映像

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

2.1 存储器

        计算机系统的5大组成部分是:运算器、控制器、存储器、输入设备、输出设备。其中运算器和控制器一般会合在一起,叫做CPU。所以计算机的核心关键部分就是CPU和存储器。

        存储器有两个重要知识点:一个是存储器的内容,另一个是存储器的地址。以下内容着重从这两点入手。

2.2 STM32存储器

        上表就是STM32中所有类型的存储器和这些存储器所被安排的地址。STM32的数据手册这里,也有存储器映像的图,上表就是从存储器图中总结。

        在表中,无论是Flash,还是SRAM,还是外设寄存器,他们都是存储器的一种。上文说的“DMA可以提供外设和存储器或者存储器和存储器之间的高速数据传输”这里本质上都是存储器之间的数据转运,因为包括外设寄存器,实际上也是存储器。外设到存储器只不过是STM32特别指定了可以转运的存储器而已。


        表中存储器分为两大类:ROMRAM

  • ROM是只读存储器,是一种非易失性,掉电不丢失的存储器。
  • RAM是随机存储器,是一种易失性,掉电丢失的存储器。

        表中ROM分为了3块:程序存储器Flash、系统存储器、选项字节。

        程序存储器Flash,也就是主闪存。它的用途就是,存储C语言编译后的代码程序,也就是下载程序的位置。运行程序一般也是从主闪存里面开始运行的。这一块存储器,STM32给它分配的地址是 0x 0800 0000. 起始地址就是第一个字节的地址是 0x 0800 0000,剩余地址依次增长,每个字节都分配一个独一无二的地址。这就像给每个住户编门牌号一样,只有分配了独一无二的门牌号,程序才能精准地访问这个存储器。最终终止地址是多少取决于存储器的容量。以后调试在软件里看到某个数据的地址是 0x 0800开头的,那就可以确定,它是属于主闪存的数据。

        系统存储器选项字节这两块存储器也是ROM的一种,掉电不丢失,实际上他们的存储介质也是Flash,只不过是一般常说的Flash指的是主闪存Flash,而不指这两块区域。它们俩的地址都是 0x 1FFF 开头的,紧跟着 0x 2000 开头的就是RAM区了。所以可以看出,这两块存储器的位置是在ROM区的最后面。

        系统存储器的用途是存储BootLoader,用于串口下载,BootLoader程序是芯片出厂自动写入的,一般不允许修改。

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

        表中RAM区也分了3块:运行内存SRAM、外设寄存器、内核外设寄存器。

        运行内存SRAM,分配的地址是 0x 2000 0000,用途是存储运行过程中的临时变量。临时变量也就是在程序中定义变量、数组、结构体的地方。当定义一个变量,再取它的地址显示出来,那这个地址肯定是 0x 2000 开头的。类比于电脑的话,运行内存就是内存条。

        外设寄存器,它的地址是 0x 4000 0000 这块区域。用途是存储各个外设的配置参数。也就是初始化各个外设,最终所读写的东西。外设寄存器也是存储器的一种,它的存储介质其实也是SRAM,只不过一般将运行内存叫做SRAM,外设寄存器就直接叫做寄存器。

        内核外设寄存器,地址是 0x E000 0000 这片区域。用途是存储内核各个外设的配置参数,内核外设就是NVIC和SysTick。内核外设和其他外设的地址是分开的,内核外设是 0x E000 0000,其他外设是 0x 4000 0000。


        再对照数据手册中的图来看,STM32中,所有的存储器都被安排到了 0x 0000 0000 ~ 0x FFFF FFFF 这个地址范围内。因为CPU是32位的,所以寻址范围就是32位的范围,32位的寻址范围非常大,最大可支持4GB容量的存储器,STM32的存储器都是KB级别的,所以4GB的寻址空间有大量的地址都是空的,地址使用率还不到1%,在上图中有灰色填充的就是Reserved区域,意思为保留区域,没有使用到的区域。

        图中灰色0区域的地址,实际上也是没有存储器的,0区域的扩展块 0x 0000 0000 ~ 0x 0800 0000 这个区域里写的是别名到Flash或者系统存储器,取决于BOOT引脚。因为程序是从0地址开始运行的,所以对照图中需要把需要执行的程序映射到0区域的地址来:

  • 如果映射在Flash区,就是从Flash执行;
  • 如果映射在系统存储器区(System memory),就是从系统存储器运行BootLoader;
  • 如果映射到SRAM,就是从SRAM启动。

以上不同方式的选择,由BOOT0和BOOT1两个引脚来决定。

        剩下的 0x 0800 0000 开始的Flash区,用于存储程序代码;

0x 1FFF F000 开始的系统存储器选项字节,在ROM区的最后面,可对照上述表格。

0x 2000 0000 开始的是SRAM

0x 4000 0000 开始的是外设寄存器区,里面内容可以展开,对应图中最右边一列。具体到每个外设,也有外设自己的起始地址。

  • TIM2的地址是 0x 4000 0000 
  • TIM3的地址是 0x 4000 0400 
  • TIM4的地址是 0x 4000 0800 
  • ......

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

0x E000 0000 开始的区域,存放的就是内核里面的外设寄存器了。

三、DMA框图


3.1 内核与存储器

        Cortex-M3内核,里面包含了CPU和内核外设等等。框图中除了Cortex-M3内核之外的所有东西,都可以把它看作是存储器。所以整个DMA框图就是CPU和存储器两个东西。

        Flash是主闪存,SRAM是运行内存,各个外设都可以看成是寄存器,也是一种SRAM存储器。


3.2 寄存器

        寄存器是一种特殊的存储器,

一方面CPU可以对寄存器进行读写,就像读写运行内存一样;

另一方面,寄存器的每一位背后,都连接了一根导线,这些导线可以用于控制外设电路的状态。比如:

  • 置引脚的高低电平,
  • 导通和断开开关,
  • 切换数据选择器,
  • 或者多位结合起来当作计数器、数据寄存器等等。

所以寄存器是连接软件和硬件的桥梁。软件读写寄存器就相当于在控制硬件的执行。


3.3 DMA数据转运

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

        从框图中可以看到,为了高效有条理地访问存储器,这里设计了一个总线矩阵。

  • 总线矩阵的左端是主动单元,也就是拥有存储器的访问权。
  • 总线矩阵的右端是被动单元,它们的存储器只能被左边的主动单元读写。

主动单元这里,内核有DCode和系统总线,可以访问右边的存储器。

其中DCoude总线是专门访问Flash的,系统总线是访问其它东西的。

另外由于DMA要转运数据,所以DMA也必须要有访问的主动权。


3.4 DMA总线作用

        主动单元,除了内核CPU,剩下的就是DMA总线了。

  • DMA1有一条DMA总线;
  • DMA2也有一条DMA总线;
  • 下方以太网还有一条DMA总线,这是以太网外设自己私有的DMA。

        在DMA1和DMA2里面可以看到,DMA1有7个通道;DMA2有5个通道,各个通道可以分别设置它们转运数据的源地址和目的地址。这样的设计可以使他们各自独立的工作。

        图中还有个仲裁器,仲裁器的设计是因为,虽然多个通道可以独立转运数据,但是最终DMA总线只有一条,所以所有的通道都只能分时复用这一条DMA总线,如果产生了冲突,那就会由仲裁器根据通道的优先级来决定谁先用,谁后用。另外在总线矩阵这里,也会有个仲裁器,如果DMA和CPU都要访问同一个目标,那么DMA就会暂停CPU的访问,以防止冲突。不过总线仲裁器,仍然会保证CPU得到一半的总线带宽,使CPU也能正常的工作。

        以上就是仲裁器在不同地方的作用。

        AHB从设备,也就是DMA自身的寄存器。因为DMA作为一个外设,它自己也会有相应得配置寄存器,这里被连接在了总线右边的AHB总线上,所以DMA既是总线矩阵的主动单元,可以读写各种存储器;也是AHB总线上的被动单元,CPU通过图中红线标注线路,就可以对DMA进行配置了。


3.5 DMA请求

        DMA请求,请求就是触发的意思。DMA请求线路右边的触发源是各个外设,所以DMA请求就是DMA的硬件触发源。比如ADC转换完成,串口接收到数据。

        需要触发DMA转运数据的时候,就会通过图中红线标注的线路。向DMA发出硬件触发信号之后DMA就可以执行数据转运的工作了,这就是DMA请求的作用。


3.6 DMA结构框图总结

DMA框图中主要讲述了以下内容:

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

注:

SARM是运行内存,可以任意读写;

外设寄存器,需要参考手册里面的描述,有的寄存器是只读的,有的寄存器是只写的,常用的数据寄存器是可以正常读写的;

CPU或者DMA直接访问Flash的话,是只可以读而不可以写的。

        Flash是ROM只读存储器的一种,如果通过总线直接访问的话,无论是CPU,还是DMA都是只读的,只能读取数据,而不能写入。如果DMA的目的地址,填写了Flash的区域,那转运时就会出错。当然Flash也不是绝对的不可写入,可以配置Flash接口控制器,对Flash进行写入,这个流程比较麻烦,先要对Flash按页进行擦除,再写入数据。

四、DMA基本结构

        DMA基本结构图主要体现DMA内部执行的细节,由图来分析DMA具体是怎么工作的。

4.1 数据转运两大站点

        数据转运的两大站点是,外设寄存器站点存储器站点,存储器站点包括FlashSRAM

        在STM32手册中所说的存储器一般是特指Flash和SRAM,不包含外设寄存器,外设寄存器一般直接称作外设。所以就是外设到存储器,存储器到存储器这样来描述的。虽然外设寄存器也是存储器的一种,但是STM32还是使用了外设寄存器和存储器来作为区分。

        图中可以看到,DMA的数据转运,可以是从外设到存储器,也可以从存储器到外设,具体是从哪到哪,有一个方向的参数,可以进行控制。

        除了外设和寄存器之间的数据转运,还有一种转运方式,就是存储器到存储器。比如Flash到SRAM或者SRAM到SRAM这两种方式。由于Flash是只读的,所以DMA不可以进行SRAM到Flash,或者Flash到Flash的转运操作。

4.2 外设和存储器的参数

        既然要进行数据转运,那肯定就要指定从哪里转到哪里,具体怎么转了。所以外设和存储器两个站点就都有3个参数来配置数据转运:

        第一个是起始地址,有外设端的起始地址和存储器端的起始地址,这两个参数决定了数据是从哪里来到哪里去的。

        第二个是数据宽度,这个参数的作用是,指定一次转运要按多大的数据宽度来进行。可以选择字节Byte、半字HalfWord和字Word。

  • 字节是8位,也就是一次转运一个 unit8_t 这么大的数据。
  • 半字是16位,也就是一次转运一个 unit16_t 这么大的数据。
  • 字是32位,也就是一次转运一个 unit32_t 这么大的数据。

比如转运ADC的数据,ADC的结果是 unit16_t 这么大,所以这个参数就要选择半字,一次转运一个 unit16_t 这么大的数据才可以。

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

        以上就是外设站点和存储器站点各自的3个参数了。如果要进行存储器到存储器的数据转运,那就需要把其中一个存储器的地址,放在外设的这个站点,这样就能进行存储器到存储器的数据转运了。只要在外设起始地址里写Flash或者SRAM的地址,那程序就会去Flash或SRAM找数据。

        站点名字虽然叫外设寄存器,但它就只是个名字而已,并不能说这个地址只能写外设寄存器的地址。如果写Flash的地址,那程序就会去Flash里找;如果写SRAM的地址,那程序就会去SRAM里找,这个没有限制。

        甚至在进行外设到存储器的数据转运时,可以在外设站点写存储器的地址,存储器站点写外设的地址,只要把方向参数给反过来,这样也是可以的。外设站点和存储器站点只是ST公司给它起了这样的名字而已,DMA基本结构图中是按照名字来设计的。可以理解为站点A和站点B,从A到B或者B到A转运数据。不必拘泥于外设站点和存储器站点这两个名字。

4.3 传输计数器和自动重装器

        传输计数器,是用来指定总共需要转运几次的。这个传输计数器是一个自减计数器,比如给传输计数器写一个5,那DMA就只能进行5次数据转运,转运过程中,每转运一次,计数器的数就会减1.当传输计数器减到0之后,DMA就不会再进行数据转运了。另外,传输计数器减到0之后,之前自增的地址,也会恢复到起始地址的位置。以方便之后DMA开始新一轮的转运。

        自动重装器,在传输计数器的右边就是自动重装器,作用就是传输计数器减到0之后,是否要自动恢复到最初的值。

  • 如果不使用自动重装器,那转运5次后,DMA就结束了;
  • 如果使用自动重装器,那转运5次,计数器减到0后,就会立即重装到初始值5.

        自动重装器决定了转运的模式:

  • 如果不重装,就是正常的单次模式;
  • 如果重装,就是循环模式。

        举例:

  • 如果需要转运一个数组,那一般就是单次模式,转运一轮就结束了;
  • 如果是ADC扫描模式+连续转换,那为了配合ADC,DMA也需要使用循环模式。

这个循环模式和ADC的连续模式差不多。都是指定一轮工作后,是不是立即开始下一轮工作。

4.4 DMA触发控制

        上图红色框框起来的一块就是DMA的触发控制。

        触发就是决定DMA需要在什么时机进行转运的。

        触发源硬件触发软件触发,具体选择选择哪个,由M2M这个参数决定。

        M2M就是 Memory to Memory,因为数字2的英文 two 和 to 同音,所以 M2M 就是 M to M,存储器到存储器的意思。

        M2M位给1时,DMA就会选择软件触发,这里的软件触发并不是调用某个函数一次,触发一次。这里软件触发执行逻辑是,以最快的速度,连续不断地触发DMA,争取早日把传输计数器清零,完成这一轮的转换。DMA的软件触发和外部中断与ADC的软件触发不太一样,可以把DMA的软件触发理解为连续触发。

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

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

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

DMA触发控制总结:

        M2M位给1,就是使用软件触发,就是应用在存储器到存储器转运的情况;

        M2M位给0,就是使用硬件触发,一般都是与外设有关的转运。

4.5 开关控制

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

4.6 DMA转运条件

DMA进行转运有几个条件:

  • 第一,开关控制,DMA_Cmd函数必须使能。
  • 第二,传输计数器必须大于0.
  • 第三,触发源必须有触发信号。

        触发信号触发一次,转运一次,传输计数器自减一次。当传输计数器等于0,且没有自动重装器时,这时无论是否触发,DMA都不会再进行转运了。此时就需要DMA_Cmd函数配置DISABLE,关闭DMA。然后再为传输计数器写入一个大于0的数。再对DMA_Cmd函数配置ENABLE,开启DMA,DMA才能继续工作。

注意:

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

五、DMA请求

        下图表示的就是上文“4.4 DMA触发控制”这一部分。

        DMA1的请求映像,有DMA的7个通道,每个通道都有一个数据选择器,可以选择硬件触发或软件触发。

        每个通道的数据选择器下边都有一个EN位,这里的EN位并不是数据选择器的控制位,而是决定这个数据选择器要不要工作的位。

  • 当EN位=0时,数据选择器不工作;
  • 当EN位=1时,数据选择器工作。

        每个通道的数据选择器左边的软件触发(MEM2MEM位)的意思是,当M2M位=1时,DMA选择软件触发。

        硬件触发源看图中最左边的外设请求信号,通道1~通道7的硬件触发源都是不同的:

  • 如果需要ADC1来触发的话,那就必须选择通道1;
  • 如果需要定时器2的更新事件(TIM2_UP)来触发的话,那就必须选择通道2;
  • .........

        因为每个通道的硬件触发源都不同,所以如果需要使用某个硬件触发源的话,就必须使用它所在的通道,这就是硬件触发的注意事项。而如果使用软件触发的话,通道就可以任意选择了。因为每个通道的软件触发都是一样的。这也就是“DMA每个通道都支持软件触发和特定的硬件触发”这句话中“特定”的意思,选择硬件触发需要看是哪个通道的。

        通道1的硬件触发是ADC1、定时器2的通道3(TIM2_CH3)、定时器4的通道1(TIM4_CH1)这三个,要选择哪个触发源,是对应的外设是否开启了DMA输出来决定的:

  • 如果需要使用ADC1,那会使用库函数ADC_DMACmd来开启ADC1这一路输出,ADC1才有效; 
  • 如果想选择定时器2的通道3,那会使用库函数TIM_DMACmd来开启TIM2_CH3这一路输出,TIM2_CH3才有效。

如果三个都开启了,图中标识的是一个或门,意思是三个硬件都可以进行触发。但是一般操作时,都是只开启其中一个硬件触发源。

        不同触发源通过7个通道进入到仲裁器,仲裁器用于进行优先级判断,排好先后最终产生内部的DMA1请求。

        仲裁器优先级的判断类似于中断的优先级,默认优先级是通道号越小,优先级越高。当然也可以在程序中配置优先级。

六、数据宽度与对齐

        外设和存储器的参数中有一个参数是数据宽度。如果外设和存储器的数据宽度都一样,那就是正常的一个一个转运。如果外设和存储器的数据宽度不一样,那就需要参考下表的内容。

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

  • 当源端宽度和目标宽度都是8位时。转运的第一步:在源端的0位置,读数据B0;在目标的0位置,写入数据B0。就是把B0从源端地址挪到目标地址。下一步就是挪B1,接着B2、B3。
  • 当源端宽度是8位,目标宽度是16位。转运的第一步:在源端的0位置,读数据B0;在目标的0位置,写入数据00B0.下一步读B1,写00B1;读B2,写00B2;读B3,写00B3.
  • 当源端宽度是16位,目标宽度是8位。转运的第一步:在源端的0位置,读数据B1B0;在目标的0位置,只写入数据B0.下一步读B3B2,写B2;读B5B4,写B4;读B7B6,写B6.
  1. 当目标的数据宽度比源端的数据宽度相等时,就是把源端数据挪给目标数据。源端8位转目标8位、源端16位转目标16位、源端32位转目标32位都是一样的处理,数据不变
  2. 当目标的数据宽度比源端的数据宽度时,那就在目标的数据前面多出来的空位补0。源端8位转目标16位、源端8位转目标32位、源端16位转目标32位都是一样的处理,前面多出的空位都补0.
  3. 当目标的数据宽度比源端的数据宽度时,就把多出来的高位舍弃掉。源端16位转目标8位、源端32位转目标16位、源端32位转目标8位都是一样的处理,舍弃多余的高位。

        数据宽度的对齐就和 uint8_t、uint16_t、uint32_t 变量之间相互赋值一样,不够就补0,超了就舍弃高位,是一个逻辑。

七、数据转运+DMA

        下图对应一个任务,是将SRAM里的数组DataA转运到另一个数组DataB中。在这个任务下,分析DMA基本结构里的各个参数该如何配置。

        DMA基本结构参数配置:

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

  1. 外设地址应该填DataA数组的首地址,存储器地址应该给DataB数组的首地址;
  2. 数据宽度,两个数组的类型都是uint8_t,所以数据宽度都是按8位的字节传输;
  3. 地址是否自增,应该外设地址和存储器地址都自增。

        任务图展示的要求是 DataA[0] 转到 DataB[0] 、DataA[1] 转到 DataB[1] 、DataA[2] 转到 DataB[2] ...... DataA[6] 转到 DataB[6] ,两个数组的位置一一对应。所以转运完DataA[0] 和 DataB[0] 之后,两个站点的地址都应该自增,都移动到下一个数据的位置,继续转运DataA[1] 和 DataB[1] ,这样来进行。

  • 如果外设地址不自增,存储器地址自增,效果就会是在转运完成后,DataB的所有数据都会等于DataA[0];
  • 如果外设地址自增,存储器地址不自增,效果就会是在转运完成后,DataB[0]就会等于DataA的最后一个数,DataB其它数不变。
  • 如果外设地址和存储器地址都不自增,那就一直会是DataA[0]转到DataB[0],其它数据不变。

第二方向参数,根据任务图,显然就是外设站点转运到存储器站点了。

        如果需要把 DataB 的数据转运到 DataA ,那可以把方向参数换一下,这样就是反向转运了。

第三传输计数器是否要自动重装。根据任务图,显然要转运7次,所以传输计数器给7。自动重装暂时不需要。

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

最后,给DMA使能,调用DMA_Cmd函数之后,数据就会从 DataA 转运到 DataB 了。转运7次之后,传输计数器自减到0,DMA停止,转运完成。

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

八、ADC扫描模式+DMA

        下图对应的任务是ADC扫描模式+DMA。图左边是ADC扫描模式的执行流程,有7个通道,触发一次后,7个通道依次进行AD转换。然后转换结果都放到ADC_DR数据寄存器里面。DMA要做的就是,在每个单独的通道转换完成后,进行一个DMA数据转运,并且目的地址进行自增。这样数据就不会被覆盖了。

        DMA基本结构参数配置:

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

  1. 外设地址应该写入 ADC_DR 这个寄存器地址,存储器地址可以在 SRAM 中定义一个数组 ADValue ,然后把 ADValue 的地址当作存储器的地址;
  2. 数据宽度,因为 ADC_DR 和 SRAM 数组需要的数据类型都是uint16_t,所以数据宽度都是16位的半字传输;
  3. 地址是否自增,应该是外设地址不自增,存储器地址自增。

第二方向参数,根据任务图,应该是外设站点转运到存储器站点了。

第三传输计数器是否要自动重装

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

        计数器是否自动重装,这需要看ADC的配置。

ADC如果是单次扫描,那DMA的传输计数器可以不自动重装,转换一轮就停止;

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

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

        硬件触发这里需要说明一下。在ADC扫描模式下,每个单独的通道转换完成后,没有任何标志位,也不会触发中断,所以程序不太好判断某一个通道转换完成的时机是什么时候。这里虽然单个通道转换完成后,不产生任何标志位和中断,但是应该会产生DMA请求,去触发DMA转运。

最后,给DMA使能,调用DMA_Cmd函数之后,数据就会从 ADC_DR 数据寄存器转运到 SRAM 数组了。

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


总结

        以上就是今天要讲的内容,本文仅仅简单介绍了DMA的基本结构,并举例了数据转运+DMA和ADC扫描模式+DMA的两个任务,来具体分析DMA基本结构中的参数配置。

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

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

相关文章

Flutter笔记:Widgets Easier组件库(3)使用按钮组件

Flutter笔记 Widgets Easier组件库(3):使用按钮组件 - 文章信息 - Author: 李俊才 (jcLee95) Visit me at CSDN: https://jclee95.blog.csdn.netMy WebSite:http://thispage.tech/Email: 291148484163.com. Shenzhen ChinaAddre…

数字旅游以科技创新为核心:推动旅游服务的智能化、精准化、个性化,为游客提供更加贴心、专业、高效的旅游服务

目录 一、引言 二、数字旅游以科技创新推动旅游服务智能化 1、智能化技术的应用 2、提升旅游服务的效率和质量 三、数字旅游以科技创新推动旅游服务精准化 1、精准化需求的识别与满足 2、精准化营销与推广 四、数字旅游以科技创新推动旅游服务个性化 1、个性化服务的创…

Cloudflare高级防御规则 看看我的网站如何用防御的

网站已趋于稳定,并且经过nginx调优。我想先分享一下Cloudflare的WAF规则,因为这是最有效的防御之一,可以抵御大量恶意攻击流量,我已经验证了数月。 对于海外独立站电商网站,Cloudflare的CDN服务是首选,它强…

File contains parsing errors: file:///etc/yum.repos.d/nginx.repo报错解决,文件配置出现问题

执行yum指令出现以下错误: 解决方案:yum的配置文件出现问题, 先删除yum.repos.d目录下所有文件 rm -f /etc/yum.repos.d/* 然后重新下载阿里的资源 wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.…

VPX双路***至强高性能服务器模块

VPX双路***至强高性能服务器模块 1 产品介绍 1.1 产品概述 是一款基于Intel Xeon Gold系列处理器设计的双至强VPX模块,连接器采用VPX规范的高速连接器,专为高性能全加固服务器设计,具有贴片内存颗粒128GB DDR4内存,并提供了丰富…

翻译: 什么是ChatGPT 通过图形化的方式来理解 Transformer 架构 深度学习三

合集 ChatGPT 通过图形化的方式来理解 Transformer 架构 翻译: 什么是ChatGPT 通过图形化的方式来理解 Transformer 架构 深度学习一翻译: 什么是ChatGPT 通过图形化的方式来理解 Transformer 架构 深度学习二翻译: 什么是ChatGPT 通过图形化的方式来理解 Transformer 架构 深…

图像处理:乘法滤波器(Multiplying Filter)和逆FFT位移

一、乘法滤波器(Multiplying Filter) 乘法滤波器是一种以像素值为权重的滤波器,它通过将滤波器的权重与图像的像素值相乘,来获得滤波后的像素值。具体地,假设乘法滤波器的权重为h(i,j),图像的像素值为f(m,…

【氮化镓】GaN器件在航天器高可靠正向转换器中应用

文章是发表在《IEEE Journal of Emerging and Selected Topics in Power Electronics》2022年10月第10卷第5期上的一篇关于GaN(氮化镓)器件在航天器高可靠性正向转换器中应用的研究。文章的作者是匹兹堡大学电气与计算机工程系的Aidan Phillips, Thomas Cook和Brandon M. Gra…

code-server容器webpack的ws无法连接解决方法

TLDR 通过指定client的wsrul去连接ws devServer.client.webSocketURL ‘wss://<Forwarded uri>/ws’ 拓扑 1、code-server: 用于编写代码、启动webpack dev-server 服务&#xff1b;[https://<domain>:8001] 2、webpack: 用于浏览dev-server服务&#xff1b;[ht…

【计算机网络】网络层总结

目录 知识梗概 IP地址 子网划分 IP包头格式 路由 网络层协议 ARP病毒/ARP欺骗 知识梗概 IP地址 IP相关介绍&#xff1a;机器之间需要交流&#xff0c;必须要一个地址才能找到对应的主机&#xff0c;IP地址是主机的一种表示&#xff0c;保证主机之间的正常通信&#xff…

农牧渔农业信息网整站源码优化版

下载地址&#xff1a;农牧渔农业信息网整站源码优化版.zip 适合做农产品、农业物资、农活用人信息平台

记录一次恢复假卡750ti的过程

有一张卡&#xff0c;一直上不了144hz我就很纳闷&#xff0c;下载了一个gpuz查看了一下 了解了一下gf116是550ti或者gts450.我到挺希望他是550ti的。 很坑

【STM32F407+CUBEMX+FreeRTOS+lwIP netconn UDP TCP记录】

STM32F407CUBEMXFreeRTOSlwIP netconn UDP TCP记录 注意UDPUDP1UDP2 TCPTCP clientTCP server图片 注意 1、超时 #include “lwipopts.h” #define LWIP_SO_RCVTIMEO 12、先保证能ping通 3、关于工程创建可参考 【STM32F407CUBEMXFreeRTOSlwIP之UDP记录】 4、…

NLP 笔记:TF-IDF

TF-IDF&#xff08;Term Frequency-Inverse Document Frequency&#xff0c;词频-逆文档频率&#xff09;是一种用于信息检索和文本挖掘的统计方法&#xff0c;用来评估一个词在一组文档中的重要性。TF-IDF的基本思想是&#xff0c;如果某个词在一篇文档中出现频率高&#xff0…

使用Python的Tkinter库创建你的第一个桌面应用程序

文章目录 准备工作创建窗口和按钮代码解释运行你的应用程序结论 在本教程中&#xff0c;我们将介绍如何使用Python的Tkinter库创建一个简单的桌面应用程序。我们将会创建一个包含一个按钮的窗口&#xff0c;点击按钮时会在窗口上显示一条消息。 准备工作 首先&#xff0c;确保…

图片懒加载:提升网页性能的秘诀

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

Python-Socket编程实现tcp-udp通信

本文章是记录我准备大创项目时学的socket编程的用法&#xff0c;纯属记录生活&#xff0c;没有教学意义&#xff0c;视频我是看b站up主王铭东学的&#xff0c;讲的很详细&#xff0c;我只粗略学了个大概&#xff0c;我想要通过tcp&#xff0c;udp传输yolo目标检测中的物体坐标信…

QT:按钮类控件

文章目录 PushButton快捷键Radio Buttion PushButton 这个类继承自QAbstractButton&#xff0c;是所有按钮的父类 创建一个带有图标的按钮&#xff1a; 假设这个图片是这个 那么我们就可以创建按钮并进行设置了&#xff1a; #include "widget.h" #include "u…

net lambda 、 匿名函数 以及集合(实现IEnumerable的 如数组 、list等)

匿名函数&#xff1a;》》》 Action a1 delegate(int i) { Console.WriteLine(i); }; Lambda:>>> Aciont a1 (int i) > { Console.WriteLine(i); }; 可以简写 &#xff08;编译器会自动根据委托类型 推断&#xff09; Action a1 &#xff08;i&#xff09;> {…

图像处理的一些操作(1)

图像处理 1.安装PIL&#xff0c;skimage库1.1导入skimage库中的oi模块和data模块 2.读取图像文件2.1读取图像文件2.2 以灰度模式读取图像2.3 查看示例图像的目录路径2.4 读取chelsea图片2.5 加载示例图片并保存2.6 获得加载图片的信息2.6.1 输出图片类型2.6.2 输出图片尺寸2.6.…