文章目录

  • DMA
  • DMA的概念&作用
  • 如何作用
  • STM32 & DMA
  • STM32 (F1) DMA特性🐾
  • STM32的DMA原理及其配置
  • STM32的DMA原理
  • STM32之DMA的配置步骤
  • DMA与外设建立连接
  • DMA三种工作模式的选用
  • 串口通信 | DMA实例
  • 修改说明:
  • 思考
  • DMA

    DMA的概念&作用

    DMA(Direct Memory Access,直接内存访问) .

    DMA既可以指内存和外设直接存取数据这种内存访问的计算机技术,又可以指实现该技术的硬件模块(对于通用计算机PC而言,DMA控制逻辑由CPU和DMA控制接口逻辑芯片共同组成,嵌入式系统的DMA控制器内建在处理器芯片内部,一般称为 DMA控制器,DMAC)。

    🤔为啥用到DMA?

    ​ 在无须CPU干预的情况下,提供外设与存储器之间或者存储器与存储器之间的高速数据传输. 既节省了CPU的资源,又提高数据传输的快速性,因为不需要通过代码实施数据传输过程。👍

    如何作用

    只要CPU将DMA初始化后,内存和外设的数据传输只需要进过DMA就可以很方便进行(绕开CPU)

    STM32 & DMA

    例如需要传送100个8位的数据到外设,如果用CPU来做一般是:

    for(i=0;i<100;i++) { 数据转移 }
    

    这样CPU要履行100次for循环,如果用DMA方式只要把数据的个数和数据的起始地址给DMA,接着CPU可以执行其他操作了。🤘

    STM32单片机可有两个DMA控制器,共12个通道,其中DMA1有7个通道,DMA2有5个通道。 每个通道专门用来管理来自于一个或多个外设对存储器访问的请求。DMA控制器中还有一个仲裁器,专门协调各个DMA请求的优先权。

    STM32 (F1) DMA特性🐾

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

    1. 每个通道都支持软件触发,可通过软件配置
    2. 在同一个DMA模块上,多个请求的优先权可以通过软件编程设置
      1. 共有四级:很高、高、中等和低
      2. 优先权设置相等时由硬件决定(较低编号的通道比较高编号的通道有较高的优先权,比如通道2优先于通道4

    在大容量产品和互联型产品中,DMA1控制器拥有高于DMA2控制器的优先级

    1. 独立数据(取数据的地方)和目标数据区(放数据的地方)的传输宽度有字节(8位)、半字(16位)、全字(32位,字,不是字节)三种可选

      1. 和目标地址必须按数据传输宽度对齐
      2. 支持循环的缓冲器管理—传输完数据又从数据头传输,可反复进行(参考手册10.3.3)
    2. 每个通道都有3个事件标志(DMA半传输、DMA传输完成和DMA传输出错)

      1. 这3个事件标志逻辑相“或”成为一个单独的中断请求,即任何一个事件均可触发中断

        事件标志位是只读的,使能控制位是可读可写的(所以就是中断之后,只有使能了才能触发中断(?))

    3. DMA传输的数据量是可编程的,最小为1,最大达到65535。包含要传输的数据项数量的寄存器,在每次传输后递减。DMA_CCRx

    STM32的DMA原理及其配置

    STM32的DMA原理

    1. 在发生一个事件后,外设发送一个请求信号到DMA控制器
    2. DMA控制器根据通道的优先权处理请求
    3. 当DMA控制器开始访问外设的时候,DMA 控制器立即发送给外设一个应答信号
    4. 当外设释放了这个请求,DMA控制器同时撤销应答信号

    可以在DMA传输过半、传输完成和传输错误时产生中断,每个DMA传送由3个操作组成:

    1. 从外设数据寄存器或者从DMA_CMARx寄存器指定地址的存储器单元执行加载操作
    2. 存数据到外设数据寄存器或者存数据到DMA_CMARx寄存器指定地址的存储器单元
    3. 执行一次DMA_CNDTRx寄存器的递减操作.该寄存器包含未完成的操作数目

    STM32之DMA的配置步骤

    进行DMA配置前,在RCC设置中使能DMA时钟

    ​ STM32的DMA控制器挂在AHB总线上

    配置DMA通道x的过程(x代表通道号)主要包括6个方面:

  • 在DMA_CPARx寄存器中设置外设寄存器的地址。发生外设数据传输请求时,这个地址将是数据传输的源或目标.
  • 在DMA_CMARx寄存器中设置数据存储器的地址。发生外设数据传输请求时,传输的数据将从这个地址读出或写入这个地址.
  • 在DMA_CNDTRx寄存器中设置要传输的数据量。每传输一个数据,这个数值被递减.
  • 在DMA_CCRx寄存器的PL[1:0]位中设置通道的优先级.
  • 在DMA_CCRx寄存器中设置数据传输的方向、循环模式、外设和存储器的增量模式、外设和存储器的数据宽度、选择传输一半产生中断或传输完成产生中断的中断方式.
  • 设置DMA_CCRx寄存器的ENABLE位,启动该通道。一旦启动了DMA 通道,它即可响应连到该通道上的外设的DMA请求。当传输一半的数据后, 半传输标志(HTIF)被置1,当设置了允许半传输中断位(HTIE)时,将 产生一个中断请求。在数据传输结束后,传输完成标志(TCIF)被置1,当 设置了允许传输完成中断位(TCIE)时,将产生一个中断请求.
  • 🤔注意:

    DMA与外设建立连接

    要使DMA与外设建立有效连接,这不是DMA自身的事情,是各个外设的事情,每个外设都有一个xxx_DMACmd(XXXx,Enable )函数,如果使 DMA与ADC建立有效联系,就使用以下函数:

    ADC_DMACmd(ADC1,Enable)
    
    DMA三种工作模式的选用

    DMA有三种工作模式:循环模式、非循环模式、存储器到存储器模式

    1. 非循环模式—DMA_Mode_Normal
      1. 即正常模式,当一次DMA数据传输完后,停止DMA传送。需要重组设置传送数量和启动后,才能进行下一次DMA数据传输。
    2. 循环模式—DMA_Mode_Circular
      1. 用于处理循环缓冲区和连续的数据传输(如ADC的扫描模式) 在DMA_CCRx寄存器中的“CIRC”位可开启这一功能。当启动了循环模式, 数据传输的数目变为0时,将会自动地被恢复成配置通道时设置的初值,DMA 操作将会继续进行.
    3. 存储器到存储器模式—DMA_M2M_Enable
      1. 存储器数据以DMA方式复制到另一地址存储

    串口通信 | DMA实例

    程序源码>>标准例程-HAL库函数版本>>实验17 DMA实验>>HARDWARE>>dma.c

    void MYDMA_Config(DMA_Channel_TypeDef *chx) {  __HAL_RCC_DMA1_CLK_ENABLE(); __HAL_LINKDMA(&UART1_Handler,hdmatx,UART1TxDMA_Handler);     UART1TxDMA_Handler.Instance=chx;                             UART1TxDMA_Handler.Init.Direction=DMA_MEMORY_TO_PERIPH;  UART1TxDMA_Handler.Init.PeriphInc=DMA_PINC_DISABLE;  UART1TxDMA_Handler.Init.MemInc=DMA_MINC_ENABLE;  UART1TxDMA_Handler.Init.PeriphDataAlignment=DMA_PDATAALIGN_BYTE;  UART1TxDMA_Handler.Init.MemDataAlignment=DMA_MDATAALIGN_BYTE;  UART1TxDMA_Handler.Init.Mode=DMA_NORMAL; UART1TxDMA_Handler.Init.Priority=DMA_PRIORITY_MEDIUM;  HAL_DMA_DeInit(&UART1TxDMA_Handler);    HAL_DMA_Init(&UART1TxDMA_Handler); }  
    

    阅读并修改以上代码配置,实现SPI1 DMA接收: 1. chx的值应该为什么?请直接在代码上修改; 2. 修改代码,实现DMA传输为循环模式、优先级为高。

    1. chx的值需要设为用于SPI1接收的正确DMA通道。通常在STM32中,SPI1使用的DMA通道为DMA1_Channel2或DMA1_Channel3,具体取决于您的STM32变体和DMA通道映射。本例中我们假设使用的是DMA1_Channel2,请根据您的硬件调整。

    2. 修改DMA配置为循环模式,并将优先级设置为

    以下是修改后的代码:

    void MYDMA_Config(DMA_Channel_TypeDef *chx) 
    { 
        __HAL_RCC_DMA1_CLK_ENABLE();
        __HAL_LINKDMA(&UART1_Handler, hdmatx, UART1TxDMA_Handler);
        
        // 将chx设置为SPI1接收对应的DMA通道
        UART1TxDMA_Handler.Instance = DMA1_Channel2; // 根据具体的硬件调整DMA通道
    
        UART1TxDMA_Handler.Init.Direction = DMA_PERIPH_TO_MEMORY; // 改为从外设到内存,接收数据
        UART1TxDMA_Handler.Init.PeriphInc = DMA_PINC_DISABLE; 
        UART1TxDMA_Handler.Init.MemInc = DMA_MINC_ENABLE; 
        UART1TxDMA_Handler.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; 
        UART1TxDMA_Handler.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; 
        UART1TxDMA_Handler.Init.Mode = DMA_CIRCULAR; // 将模式设置为循环模式
        UART1TxDMA_Handler.Init.Priority = DMA_PRIORITY_HIGH; // 设置优先级为高
        
        HAL_DMA_DeInit(&UART1TxDMA_Handler);   
        HAL_DMA_Init(&UART1TxDMA_Handler);
    }
    

    修改说明:

    1. DMA通道:将UART1TxDMA_Handler.Instance设置为DMA1_Channel2
    2. 方向:将方向从DMA_MEMORY_TO_PERIPH改为DMA_PERIPH_TO_MEMORY,以处理接收数据。
    3. 模式:将UART1TxDMA_Handler.Init.Mode设置为DMA_CIRCULAR,以启用循环模式。
    4. 优先级:将UART1TxDMA_Handler.Init.Priority改为DMA_PRIORITY_HIGH

    思考

    DMA的作用是什么?为什么STM32中要加入DMA功能?

    在配置STM32的DMA时,主要有哪几个步骤?

    作者:ZHEN_021

    物联沃分享整理
    物联沃-IOTWORD物联网 » STM32复习笔记 | DMA

    发表回复