当前位置: 首页 > news >正文

HAL库DMA框架

介绍HAL库中外设如何与DMA建立连接

外设句柄结构体中包含有DMA句柄,如ADC

typedef struct __ADC_HandleTypeDef {
  // ADC_TypeDef                   *Instance;        /*!< Register base address */
  // ADC_InitTypeDef               Init;             /*!< ADC required parameters */
  DMA_HandleTypeDef             *DMA_Handle;         /*!< Pointer DMA Handler */
  // HAL_LockTypeDef               Lock;             /*!< ADC locking object */
  // __IO uint32_t                 State;            /*!< ADC communication state */
  // __IO uint32_t                 ErrorCode;        /*!< ADC Error code */
}ADC_HandleTypeDef;

DMA句柄中包含中断回调函数的函数指针接口,以及该父对象指针

typedef struct __DMA_HandleTypeDef{
  // DMA_Channel_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);    
  void   (* XferHalfCpltCallback)( struct __DMA_HandleTypeDef * hdma); 
  void   (* XferErrorCallback)( struct __DMA_HandleTypeDef * hdma);    
  void   (* XferAbortCallback)( struct __DMA_HandleTypeDef * hdma); 
  // __IO uint32_t              ErrorCode;            
  // DMA_TypeDef                *DmaBaseAddress;     
  // uint32_t                   ChannelIndex;        
} DMA_HandleTypeDef;

在外设初始化时,会对DMA进行初始化,同时将两者进行关联。这样通过外设句柄就能操作DMA句柄

#define __HAL_LINKDMA(__HANDLE__, __PPP_DMA_FIELD__, __DMA_HANDLE__) \do                                                               \
    {                                                                \
        (__HANDLE__)->__PPP_DMA_FIELD__ = &(__DMA_HANDLE__);         \
        (__DMA_HANDLE__).Parent = (__HANDLE__);                      \
    } while (0U)
                          
__HAL_LINKDMA(adcHandle,DMA_Handle,hdma_adc1);

在外设启用DMA发送或接收时,收发函数内部会对外设挂载的DMA设置回调函数,而这里使用的函数实体来自于外设预留的、关于DMA中断的回调函数。

HAL_StatusTypeDef HAL_ADC_Start_DMA(ADC_HandleTypeDef* hadc, uint32_t* pData, uint32_t Length) {// ...    /* Set the DMA transfer complete callback */
    hadc->DMA_Handle->XferCpltCallback = ADC_DMAConvCplt;
    /* Set the DMA half transfer complete callback */
    hadc->DMA_Handle->XferHalfCpltCallback = ADC_DMAHalfConvCplt;
    /* Set the DMA error callback */
    hadc->DMA_Handle->XferErrorCallback = ADC_DMAError;
    /* Start the DMA channel */
    HAL_DMA_Start_IT(hadc->DMA_Handle, (uint32_t)&hadc->Instance->DR, (uint32_t)pData, Length);
    
    // ...
}

赋值的回调函数为 ADC_DMAConvCplt ,其内部调用了 HAL_ADC_ConvCpltCallbackHAL_ADC_ConvCpltCallback 才是最后用户需要实现的。

void ADC_DMAConvCplt(DMA_HandleTypeDef *hdma) {
  /* Retrieve ADC handle corresponding to current DMA handle */
  ADC_HandleTypeDef* hadc = ( ADC_HandleTypeDef* )((DMA_HandleTypeDef* )hdma)->Parent;  /* Update state machine on conversion status if not in error state */
  if (HAL_IS_BIT_CLR(hadc->State, HAL_ADC_STATE_ERROR_INTERNAL | HAL_ADC_STATE_ERROR_DMA))
  {
    /* Update ADC state machine */
    SET_BIT(hadc->State, HAL_ADC_STATE_REG_EOC);// ...    /* Conversion complete callback */
#if (USE_HAL_ADC_REGISTER_CALLBACKS == 1)
    hadc->ConvCpltCallback(hadc);
#else
    HAL_ADC_ConvCpltCallback(hadc);
#endif /* USE_HAL_ADC_REGISTER_CALLBACKS */
  }
  else
  {
    /* Call DMA error callback */
    hadc->DMA_Handle->XferErrorCallback(hdma);
  }
}__weak void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
  UNUSED(hadc);
}

DMA 中断被启动,并且挂载回调函数后,会在中断中自动运行。

void HAL_DMA_IRQHandler(DMA_HandleTypeDef *hdma)
{
  uint32_t flag_it = hdma->DmaBaseAddress->ISR;
  uint32_t source_it = hdma->Instance->CCR;  /* Half Transfer Complete Interrupt management ******************************/
  if (((flag_it & (DMA_FLAG_HT1 << hdma->ChannelIndex)) != RESET) && ((source_it & DMA_IT_HT) != RESET))
  {// ...
    if(hdma->XferHalfCpltCallback != NULL) {
      hdma->XferHalfCpltCallback(hdma); /* Half transfer callback */
    }
  }  /* Transfer Complete Interrupt management ***********************************/
  else if (((flag_it & (DMA_FLAG_TC1 << hdma->ChannelIndex)) != RESET) && ((source_it & DMA_IT_TC) != RESET))
  {
    // ...
    if(hdma->XferCpltCallback != NULL) {
      hdma->XferCpltCallback(hdma);/* Transfer complete callback */
    }
  }  /* Transfer Error Interrupt management **************************************/
  else if (( RESET != (flag_it & (DMA_FLAG_TE1 << hdma->ChannelIndex))) && (RESET != (source_it & DMA_IT_TE)))
  {// ...
    if (hdma->XferErrorCallback != NULL) {
      hdma->XferErrorCallback(hdma);/* Transfer error callback */
    }
  }
  return;
}void DMA1_Channel1_IRQHandler(void)
{
  HAL_DMA_IRQHandler(&hdma_adc1);
}
http://www.gsyq.cn/news/40183.html

相关文章:

  • 2025 年 11 月电线电缆厂家推荐排行榜,电力电缆,控制电缆,通信电缆,阻燃电缆,高压电缆公司推荐
  • 2025 年 11 月回信器厂家推荐排行榜,隔爆回信器,阀门回信器,防爆回信器,限位开关回信器,气动阀回信器,气动回信器公司推荐
  • 数据分析流程
  • 2025 年 11 月锅炉厂家推荐排行榜,有机热载体锅炉,导热油锅炉,生物质锅炉,蒸汽锅炉,燃天然气锅炉,热水锅炉公司推荐
  • 9.22 未完成的情感投射
  • 2025 年 11 月电磁阀厂家推荐排行榜,高压电磁阀,防爆电磁阀,比例电磁阀,汽车电磁阀,ABS电磁阀,ESP电磁阀,车用ESC电磁阀公司推荐
  • 请求库的封装
  • 用户登录系统
  • Java 内存模型(JMM)中 volatile 的作用与限制
  • 论文导读:从 TSMC ISSCC 看 SRAM 存算发展
  • edge chromium浏览器copilot图标消失处理
  • AI - 自然语言处理(NLP) - part 2 - 词向量 - 教程
  • 洛谷 P4577
  • [linux-mint] Surface Pro4 安装linux驱动
  • [B] AGC VP 记录
  • 2025年河南工业大学2025新生周赛(2)
  • Reflections on Trusting Trust by Ken Thompson
  • [Agent] ACE(Agentic Context Engineering)源码阅读笔记---(1)基础模块
  • 顺序结构及选择结构
  • 洛谷 P10894
  • 服务器取证基本知识学习
  • 实用指南:【18】C实战篇——C语言 文件读写【fputc、fgetc、fputs、fgets】
  • L09_ java内注解反射的简单理解(作为小白,菜鸟的理解)
  • 20232323 2024-2025-1《网络与系统攻防技术》实验4实验报告
  • 直播带货话术不会写?这个AI指令帮你搞定
  • Java数组——数组的使用
  • NOIP2025加训
  • 20232427 2025-2026-1 《网络与系统攻防技术》实验四实验报告
  • Windows 系统下通过 VMware 17 安装 macOS 的教程
  • 2025.11.4 - A