STM32F4 HAL库开发 -- DMA

一、DMA简介

DMA之前有讲过,参看:STM32开发 – DMA详解

DMA,全称为Direct Memory Access,即直接存储器访问。DMA传输方式无需CPU直接控制传输,也没有中断处理方式那样保留现场和恢复现场的过程,通过硬件为RAM与I/O设备开辟一条直接传送数据的通路,能使CPU的效率大为提高。
STM32F407最多有2个DMA控制器(DMA1和DMA2),共16个数据流(每个控制器8个),每一个DMA控制器都用于管理一个或多个外设的存储访问请求。每个数据流总共可以有多大8个通道(或称为请求)。每个数据流通道都有一个仲裁器,用于处理DMA请求间的优先级。

二、映射表

DMA1的各数据流通道映射表:
在这里插入图片描述
DMA2的各数据流通道映射表:
在这里插入图片描述

三、函数

1、使能、失能DMA时钟

DMA的时钟使能是通过AHB1ENR寄存器来控制的,这里我们要先使能时钟,才可以配置DMA相关寄存器。HAL库方法为:

__HAL_RCC_DMA2_CLK_ENABLE();//DMA2 时钟使能
__HAL_RCC_DMA1_CLK_ENABLE();//DMA1 时钟使能

__HAL_RCC_DMA1_CLK_DISABLE();//禁止 DMA1 时钟
__HAL_RCC_DMA2_CLK_DISABLE();//禁止 DMA2 时钟

2、初始化DMA2

DMA的某个数据流各种配置参数初始化是通过HAL_DMA_Init函数实现的,该函数声明为:

HAL_StatusTypeDef HAL_DMA_Init(DMA_HandleTypeDef *hdma)

该函数只有一个DMA_HandleTypeDef 结构体指针类型入口参数,结构体定义为:

typedef struct __DMA_HandleTypeDef
{
  DMA_Stream_TypeDef         *Instance;                                                        /*!< Register base address                  */

  DMA_InitTypeDef            Init;                                                             /*!< DMA communication parameters           */ 

  HAL_LockTypeDef            Lock;                                                             /*!< DMA locking object                     */  

  __IO HAL_DMA_StateTypeDef  State;                                                            /*!< DMA transfer state                     */

  void                       *Parent;                                                          /*!< Parent object state                    */ 

  void                       (* XferCpltCallback)( struct __DMA_HandleTypeDef * hdma);         /*!< DMA transfer complete callback         */

  void                       (* XferHalfCpltCallback)( struct __DMA_HandleTypeDef * hdma);     /*!< DMA Half transfer complete callback    */

  void                       (* XferM1CpltCallback)( struct __DMA_HandleTypeDef * hdma);       /*!< DMA transfer complete Memory1 callback */
  
  void                       (* XferM1HalfCpltCallback)( struct __DMA_HandleTypeDef * hdma);   /*!< DMA transfer Half complete Memory1 callback */
  
  void                       (* XferErrorCallback)( struct __DMA_HandleTypeDef * hdma);        /*!< DMA transfer error callback            */
  
  void                       (* XferAbortCallback)( struct __DMA_HandleTypeDef * hdma);        /*!< DMA transfer Abort callback            */  

  __IO uint32_t              ErrorCode;                                                        /*!< DMA Error code                          */
  
  uint32_t                   StreamBaseAddress;                                                /*!< DMA Stream Base Address                */

  uint32_t                   StreamIndex;                                                      /*!< DMA Stream Index                       */
 
}DMA_HandleTypeDef;

成员变量 Instance 是用来设置寄存器基地址,例如要设置为 DMA2 的数据流 7,那么取值为 DMA2_Stream7。
成员变量 Parent 是 HAL 库处理中间变量,用来指向 DMA 通道外设句柄。
成员变量 XferCpltCallback(传输完成回调函数) , XferHalfCpltCallback(半传输完成回调函数) , XferM1CpltCallback( Memory1 传输完成回调函数)和 XferErrorCallback(传输错误回调函数)是四个函数指针,用来指向回调函数入口地址。
成员变量 StreamBaseAddress 和 StreamIndex 是数据流基地址和索引号,这个是 HAL 库处理的时候会自动计算,用户无需设置。

其他成员变量HAL库处理过程状态标识变量,不做过多讲解。接下来我们着重介绍成员变量Init,它是DMA_InitTypeDef结构体类型,该结构体定义为:

typedef struct
{
uint32_t Channel; //通道,例如: DMA_CHANNEL_4
uint32_t Direction;//传输方向,例如存储器到外设 DMA_MEMORY_TO_PERIPH
uint32_t PeriphInc;//外设(非)增量模式,非增量模式 DMA_PINC_DISABLE
uint32_t MemInc;//存储器(非)增量模式,增量模式 DMA_MINC_ENABLE
uint32_t PeriphDataAlignment; //外设数据大小: 8/16/32 位。
uint32_t MemDataAlignment; //存储器数据大小: 8/16/32 位。
uint32_t Mode;//模式:外设流控模式/循环模式/普通模式
uint32_t Priority; //DMA 优先级:低/中/高/非常高
uint32_t FIFOMode;//FIFO 模式开启或者禁止
uint32_t FIFOThreshold; //FIFO 阈值选择:
uint32_t MemBurst; //存储器突发模式:单次/4 个节拍/8 个节拍/16 个节拍
uint32_t PeriphBurst; //外设突发模式:单次/4 个节拍/8 个节拍/16 个节拍
}DMA_InitTypeDef;

具体usart使用DMA的配置如下:

    /* USART1_TX Init */
    hdma_usart1_tx.Instance = DMA2_Stream7;
    hdma_usart1_tx.Init.Channel = DMA_CHANNEL_4;
    hdma_usart1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
    hdma_usart1_tx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_usart1_tx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_usart1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_usart1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_usart1_tx.Init.Mode = DMA_NORMAL;
    hdma_usart1_tx.Init.Priority = DMA_PRIORITY_VERY_HIGH;
    hdma_usart1_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
    if (HAL_DMA_Init(&hdma_usart1_tx) != HAL_OK)
    {
      Error_Handler();
    }

    __HAL_LINKDMA(uartHandle,hdmatx,hdma_usart1_tx);

这里大家要注意,HAL库为了处理各类外设的DMA请求,在调用相关函数之前,需要调用一个宏定义标识符,来连接DMA和外设句柄。例如上面的要使用串口DMA发送,所以方式为:

__HAL_LINKDMA(uartHandle,hdmatx,hdma_usart1_tx);

3、使能串口的DMA发送

HAL库提供了对串口的DMA发送的停止,暂停,继续等操作函数。

HAL_StatusTypeDef HAL_UART_DMAStop(UART_HandleTypeDef *huart); //停止
HAL_StatusTypeDef HAL_UART_DMAPause(UART_HandleTypeDef *huart); //暂停
HAL_StatusTypeDef HAL_UART_DMAResume(UART_HandleTypeDef *huart);//恢复

4、使能DMA数据流

使能DMA数据流的函数为:

HAL_StatusTypeDef HAL_DMA_Start(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength)

5、查询DMA传输状态

查询DMA传输通道的状态:

__HAL_DMA_GET_FLAG(&UART1TxDMA_Handler,DMA_FLAG_TCIF3_7);

获取当前传输剩余数据量:

__HAL_DMA_GET_COUNTER(&UART1TxDMA_Handler);

设置对应DMA数据流传输的数据量大小:

__HAL_DMA_SET_COUNTER(&UART1TxDMA_Handler,1000);

6、DMA中断使用方法

DMA 中断对于每个流都有一个中断服务函数,比如 DMA2_Stream7 的中断服务函数为DMA2_Stream7_IRQHandler 。 同样 , HAL 库 也 提 供 了一 个通 用的 DMA 中 断处 理函 数HAL_DMA_IRQHandler,在该函数内部,会对 DMA 传输状态进行分析,然后调用相应的中断处理回调函数:

void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart);//发送完成回调函数
void HAL_UART_TxHalfCpltCallback(UART_HandleTypeDef *huart);/发送一半回调函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart);//接收完成回调函数
void HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart);//接收一半回调函数
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart);//传输出错回调函数

对于串口 DMA 开启,使能数据流,启动传输,这些步骤,如果使用了中断,可以直接调用 HAL 库函数 HAL_USART_Transmit_DMA,该函数声明如下:

HAL_StatusTypeDef HAL_USART_Transmit_DMA(USART_HandleTypeDef *husart,
uint8_t *pTxData, uint16_t Size);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

聚优致成

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值