STM32G474xx HAL用户手册
stm32g4xx_hal_dma.c
转到该文件的文档。
00001 /**
00002   ******************************************************************************
00003   * @file    stm32g4xx_hal_dma.c
00004   * @author  MCD Application Team
00005   * @brief   DMA HAL模块驱动程序。
00006   *         本文件提供固件功能以管理直接内存访问(DMA)外设的以下功能:
00007   *           + 初始化和反初始化函数
00008   *           + IO操作函数
00009   *           + 外设状态和错误函数
00010   *
00011   ******************************************************************************
00012   * @attention
00013   *
00014   * Copyright (c) 2019 STMicroelectronics.
00015   * All rights reserved.
00016   *
00017   * This software is licensed under terms that can be found in the LICENSE file
00018   * in the root directory of this software component.
00019   * If no LICENSE file comes with this software, it is provided AS-IS.
00020   *
00021   ******************************************************************************
00022   @verbatim
00023   ==============================================================================
00024                         ##### 如何使用此驱动程序 #####
00025   ==============================================================================
00026   [..]
00027    (#) 启用并配置要连接到DMA通道的外设
00028        (内部SRAM/FLASH存储器除外:无需初始化)。
00029        请参阅参考手册中外设与DMA请求之间的连接。
00030 
00031    (#) 对于给定通道,通过以下参数编程所需配置:
00032        通道请求、传输方向、源和目标数据格式、
00033        循环或正常模式、通道优先级、源和目标递增模式
00034        使用HAL_DMA_Init()函数。
00035 
00036        在HAL_DMA_Init之前,应为DMA和DMAMUX启用外设时钟:
00037       (##) DMA1或DMA2: __HAL_RCC_DMA1_CLK_ENABLE()或 __HAL_RCC_DMA2_CLK_ENABLE();
00038       (##) DMAMUX1:      __HAL_RCC_DMAMUX1_CLK_ENABLE();
00039 
00040    (#) 使用HAL_DMA_GetState()函数返回DMA状态,并在发生错误时使用HAL_DMA_GetError()进行错误检测。
00041 
00042    (#) 使用HAL_DMA_Abort()函数中止当前传输
00043 
00044      -@-   在内存到内存传输模式下,不允许使用循环模式。
00045 
00046      *** 轮询模式IO操作 ***
00047      =================================
00048     [..]
00049           (+) 使用HAL_DMA_Start()在配置源地址、目标地址和要传输的数据长度后启动DMA传输
00050           (+) 使用HAL_DMA_PollForTransfer()轮询当前传输的结束,在这种情况下
00051               用户可以根据其应用配置固定的超时时间。
00052 
00053      *** 中断模式IO操作 ***
00054      ===================================
00055     [..]
00056           (+) 使用HAL_NVIC_SetPriority()配置DMA中断优先级
00057           (+) 使用HAL_NVIC_EnableIRQ()启用DMA IRQ处理程序
00058           (+) 使用HAL_DMA_Start_IT()在配置源地址、目标地址和要传输的数据长度后启动DMA传输。
00059               在这种情况下,DMA中断已被配置
00060           (+) 在DMA_IRQHandler()中断子程序中调用HAL_DMA_IRQHandler()
00061           (+) 在数据传输结束时执行HAL_DMA_IRQHandler()函数,用户可以通过HAL_DMA_RegisterCallback()注册自己的回调函数。
00062 
00063      *** DMA HAL驱动程序宏列表 ***
00064      =============================================
00065       [..]
00066        以下是DMA HAL驱动程序中的宏列表。
00067 
00068        (+) __HAL_DMA_ENABLE:启用指定的DMA通道。
00069        (+) __HAL_DMA_DISABLE:禁用指定的DMA通道。
00070        (+) __HAL_DMA_GET_FLAG:获取DMA通道待处理标志。
00071        (+) __HAL_DMA_CLEAR_FLAG:清除DMA通道待处理标志。
00072        (+) __HAL_DMA_ENABLE_IT:启用指定的DMA通道中断。
00073        (+) __HAL_DMA_DISABLE_IT:禁用指定的DMA通道中断。
00074        (+) __HAL_DMA_GET_IT_SOURCE:检查指定的DMA通道中断是否已发生。
00075 
00076      [..]
00077       (@) 您可以参阅DMA HAL驱动程序头文件以获取更多有用的宏
00078 
00079   @endverbatim
00080   */
00081 
00082 /* Includes ------------------------------------------------------------------*/
00083 #include "stm32g4xx_hal.h"
00084 
00085 /** @addtogroup STM32G4xx_HAL_Driver
00086   * @{
00087   */
00088 
00089 /** @defgroup DMA DMA
00090   * @brief DMA HAL模块驱动程序
00091   * @{
00092   */
00093 
00094 #ifdef HAL_DMA_MODULE_ENABLED
00095 
00096 /* Private typedef -----------------------------------------------------------*/
00097 /* Private define ------------------------------------------------------------*/
00098 /* Private macro -------------------------------------------------------------*/
00099 /* Private variables ---------------------------------------------------------*/
00100 /* Private function prototypes -----------------------------------------------*/
00101 /** @defgroup DMA_Private_Functions DMA私有函数
00102   * @{
00103   */
00104 static void DMA_SetConfig(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength);
00105 static void DMA_CalcDMAMUXChannelBaseAndMask(DMA_HandleTypeDef *hdma);
00106 static void DMA_CalcDMAMUXRequestGenBaseAndMask(DMA_HandleTypeDef *hdma);
00107 
00108 /**
00109   * @}
00110   */
00111 
00112 /* Exported functions ---------------------------------------------------------*/
00113 
00114 /** @defgroup DMA_Exported_Functions DMA导出函数
00115   * @{
00116   */
00117 
00118 /** @defgroup DMA_Exported_Functions_Group1 初始化和反初始化函数
00119   *  @brief   初始化和反初始化函数
00120   *
00121 @verbatim
00122  ===============================================================================
00123              ##### 初始化和反初始化函数  #####
00124  ===============================================================================
00125     [..]
00126     本节提供允许初始化DMA通道源和目标地址、递增和数据大小、传输方向、
00127     循环/正常模式选择、内存到内存模式选择以及通道优先级值的函数。
00128     [..]
00129     HAL_DMA_Init()函数遵循参考手册中描述的DMA配置过程。
00130 
00131 @endverbatim
00132   * @{
00133   */
00134 
00135 /**
00136   * @brief  根据DMA_InitTypeDef中的指定参数初始化DMA,并初始化相关的句柄。
00137   * @param  hdma 指向DMA_HandleTypeDef结构的指针,该结构包含
00138   *               指定DMA通道的配置信息。
00139   * @retval HAL状态
00140   */
00141 HAL_StatusTypeDef HAL_DMA_Init(DMA_HandleTypeDef *hdma)
00142 {
00143   uint32_t tmp;
00144 
00145 /* 检查DMA句柄分配 */
00146   if (hdma == NULL)
00147   {
00148     return HAL_ERROR;
00149   }
00150 
00151   /* 检查参数 */
00152   assert_param(IS_DMA_ALL_INSTANCE(hdma->Instance));
00153   assert_param(IS_DMA_DIRECTION(hdma->Init.Direction));
00154   assert_param(IS_DMA_PERIPHERAL_INC_STATE(hdma->Init.PeriphInc));
00155   assert_param(IS_DMA_MEMORY_INC_STATE(hdma->Init.MemInc));
00156   assert_param(IS_DMA_PERIPHERAL_DATA_SIZE(hdma->Init.PeriphDataAlignment));
00157   assert_param(IS_DMA_MEMORY_DATA_SIZE(hdma->Init.MemDataAlignment));
00158   assert_param(IS_DMA_MODE(hdma->Init.Mode));
00159   assert_param(IS_DMA_PRIORITY(hdma->Init.Priority));
00160 
00161   assert_param(IS_DMA_ALL_REQUEST(hdma->Init.Request));
00162 
00163 /* 计算通道索引 */
00164   if ((uint32_t)(hdma->Instance) < (uint32_t)(DMA2_Channel1))
00165   {
00166     /* DMA1 */
00167     hdma->ChannelIndex = (((uint32_t)hdma->Instance - (uint32_t)DMA1_Channel1) / ((uint32_t)DMA1_Channel2 - (uint32_t)DMA1_Channel1)) << 2;
00168     hdma->DmaBaseAddress = DMA1;
00169   }
00170   else
00171   {
00172     /* DMA2 */
00173     hdma->ChannelIndex = (((uint32_t)hdma->Instance - (uint32_t)DMA2_Channel1) / ((uint32_t)DMA2_Channel2 - (uint32_t)DMA2_Channel1)) << 2;
00174     hdma->DmaBaseAddress = DMA2;
00175   }