首页 > 其他分享 >DMA的巨详细配置步骤(还不懂回家种田去)

DMA的巨详细配置步骤(还不懂回家种田去)

时间:2024-09-05 16:55:02浏览次数:7  
标签:__ DMA handle struct 步骤 HandleTypeDef 种田 ADC

首先介绍我的DMA使用场景“电阻ADC转化”。

从外界读取ADC的值,然后让DMA进行搬运至自己定义的数组当中,之后读取这个数据就可以了。

先介绍一个我的ADC结构体,也就是句柄(到时候对ADC的所有控制,就是操作这个句柄)

/**
  * @brief  ADC handle Structure definition  
  */ 
typedef struct __ADC_HandleTypeDef
{
  ADC_TypeDef                   *Instance;              /*! < ADC实例                           > */

  ADC_InitTypeDef               Init;                   /*! < 配置ADC初始化参数                 > */

  DMA_HandleTypeDef             *DMA_Handle;            /*! < 直接内存访问(DMA)操作的句柄结构 > */

  HAL_LockTypeDef               Lock;                   /*! < 锁的状态                          > */
  
  __IO uint32_t                 State;                  /*! < 表示ADC状态                       > */

  __IO uint32_t                 ErrorCode;              /*! < 存储ADC错误代码的32位寄存器       > */

#if (USE_HAL_ADC_REGISTER_CALLBACKS == 1)
  void (* ConvCpltCallback)(struct __ADC_HandleTypeDef *hadc);              /*!< ADC conversion complete callback */
  void (* ConvHalfCpltCallback)(struct __ADC_HandleTypeDef *hadc);          /*!< ADC conversion DMA half-transfer callback */
  void (* LevelOutOfWindowCallback)(struct __ADC_HandleTypeDef *hadc);      /*!< ADC analog watchdog 1 callback */
  void (* ErrorCallback)(struct __ADC_HandleTypeDef *hadc);                 /*!< ADC error callback */
  void (* InjectedConvCpltCallback)(struct __ADC_HandleTypeDef *hadc);      /*!< ADC group injected conversion complete callback */       /*!< ADC end of sampling callback */
  void (* MspInitCallback)(struct __ADC_HandleTypeDef *hadc);               /*!< ADC Msp Init callback */
  void (* MspDeInitCallback)(struct __ADC_HandleTypeDef *hadc);             /*!< ADC Msp DeInit callback */
#endif /* USE_HAL_ADC_REGISTER_CALLBACKS */
}ADC_HandleTypeDef;

上面的代码中是ADC的结构体句柄,我简单写了注释(为什么简单?因为你别管,咱们重点是DMA)。

除了下面的这个元素(这TM是重点,下面仔细介绍,叫我懂王就好)

  DMA_HandleTypeDef   *DMA_Handle;  /*! < 直接内存访问(DMA)操作的句柄结构 > */

如果你要问我,下面的感觉像函数一样的东西为什么没有中文注释,那我可以回答你:

那玩意我也不懂,所以你也可以不用管,完全不影响咱们的DMA讲解!懂了吗!

懂了就好,不用谢,叫我 “装-B-王”;

---------------------------------------------------------我去你的分割线---------------------------------------------

现在我们来看我说的DMA的结构体

typedef struct __DMA_HandleTypeDef
{
  DMA_Channel_TypeDef   *Instance;    /*! < 指向 DMA 通道的寄存器基址 > */
  
  DMA_InitTypeDef       Init;        /*! < 初始化 DMA 通道的配置参数 > */ 
  
  HAL_LockTypeDef       Lock;         /*! < 锁定 DMA 通道             > */  
  
  HAL_DMA_StateTypeDef  State;         /*! < 当前 DMA 传输的状态       > */
  
  void                  *Parent;                                                      /*! < 指向父对象的状态                            > */  
  
  void                  (* XferCpltCallback)( struct __DMA_HandleTypeDef * hdma);     /*! < 回调函数指针,当 DMA 传输完成时会被调用     > */
  
  void                  (* XferHalfCpltCallback)( struct __DMA_HandleTypeDef * hdma); /*! < 回调函数指针,当 DMA 传输完成一半时会被调用 > */
  
  void                  (* XferErrorCallback)( struct __DMA_HandleTypeDef * hdma);    /*! < 回调函数指针,当 DMA 传输发生错误时会被调用 > */

  void                  (* XferAbortCallback)( struct __DMA_HandleTypeDef * hdma);    /*! < 回调函数指针,当 DMA 传输被中止时会被调用   > */  
  
  __IO uint32_t         ErrorCode;                                                    /*! < 存储 DMA 传输的错误代码                     > */

  DMA_TypeDef            *DmaBaseAddress;                                             /*! < 指向 DMA 控制器的基址                       > */
  
  uint32_t               ChannelIndex;                                                /*! < 表示 DMA 通道的索引                         > */  

} DMA_HandleTypeDef;   

这个结构体就是需要你配置的东西,就是DMA的句柄,到时候所有的操作就是要操作这个结构体的对象(不是男女对象,想什么呢,注意点),对象不用我教你怎么定义了吧(结构体名 xx),别定义什么稀奇古怪的名字,求你了。

现在来详细介绍每一个元素:

(我靠,怎么就2个元素,其他的被我吃了,其他的不用配,最后直接初始化,tm的最后报错我把电脑吃了)

  DMA_Channel_TypeDef   *Instance;    这个元素就是(DMA1 还是 DMA2)
  
  DMA_InitTypeDef       Init;      (一个结构体),下面是他的细分(去他的细分,模糊求生模式)
  

typedef struct
{
  uint32_t Direction;                 /*!< Specifies if the data will be transferred from memory to peripheral, 
                                           from memory to memory or from peripheral to memory.
                                           This parameter can be a value of @ref DMA_Data_transfer_direction */

  uint32_t PeriphInc;                 /*!< Specifies whether the Peripheral address register should be incremented or not.
                                           This parameter can be a value of @ref DMA_Peripheral_incremented_mode */

  uint32_t MemInc;                    /*!< Specifies whether the memory address register should be incremented or not.
                                           This parameter can be a value of @ref DMA_Memory_incremented_mode */

  uint32_t PeriphDataAlignment;       /*!< Specifies the Peripheral data width.
                                           This parameter can be a value of @ref DMA_Peripheral_data_size */

  uint32_t MemDataAlignment;          /*!< Specifies the Memory data width.
                                           This parameter can be a value of @ref DMA_Memory_data_size */

  uint32_t Mode;                      /*!< Specifies the operation mode of the DMAy Channelx.
                                           This parameter can be a value of @ref DMA_mode
                                           @note The circular buffer mode cannot be used if the memory-to-memory
                                                 data transfer is configured on the selected Channel */

  uint32_t Priority;                  /*!< Specifies the software priority for the DMAy Channelx.
                                           This parameter can be a value of @ref DMA_Priority_level */
}DMA_InitTypeDef;

你肯定想说:我靠,怎么那么多英文,老Z要看中文,不要急,下面我就给你讲中文,Hold住

__HAL_RCC_DMA1_CLK_ENABLE();                                   //开启DMA1的时钟
dma1_handle.Instance                 = DMA1_Channel1;           //使用的DMA通道1
dma1_handle.Init.Direction           = DMA_PERIPH_TO_MEMORY;    //外存到内设
dma1_handle.Init.PeriphInc           = DMA_PINC_DISABLE;        //外设地址寄存器不递增--固定
dma1_handle.Init.MemInc              = DMA_MINC_ENABLE;         //内存地址寄存器自动递增,不递增的话若有新数据来就会直接在这个基础上直接覆盖
dma1_handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; //外设数据宽度--半字dma1_handle.Init.MemDataAlignment    = DMA_MDATAALIGN_HALFWORD; //内存数据宽度--半字
dma1_handle.Init.Mode                = DMA_NORMAL ;             //正常模式
dma1_handle.Init.Priority            = DMA_PRIORITY_MEDIUM;     //优先级--中等	
	 
 HAL_DMA_Init(&dma1_handle);
	
__HAL_LINKDMA(&adc1_handle,DMA_Handle,dma1_handle);             //ADC-DMA关联函数(三个参数分别为:adc句柄,adc结构体内dma名称,dma句柄)

上面的代码就是配置的具体过程,你只看结构体里面就是一坨大便,咱们具体来讲。

1. 要先开启时钟(时钟是什么破玩意?),就是钱,没钱咋改装车,你说是吧。

2.instance,就是选择DMA的通道,那么通道可以随便选择吗?你选1,选2,选到天王老子都没关系,但别重复哈。

3.Direction的情况:外设到内存,内存到外设(你就看这两种情况就行了)

4.PeriphInc:就是外设的地址变不变呢?大哥,你变了你还怎么读这个地方的ADC值,隔山打牛读吗,上面的DISABLE是啥意思不用我说了。

5.MemInc:是我内存的地址,也就是说我的数据来了放在哪里呢?如果你不ENABLE,好比你现在有100个水缸,一个水缸已经满了,你还要一直往里面注水(就是传数据),溢出来了大哥,你不自增我算你是条汉子

6.PeriphDataAlignment和MemDataAlignment,这两个就是数字大小,字节还是字,你自己选,但是要一致。

7.Mode:正常模式和循环模式,正常的情况DMA只搬一次,你打死他不会再搬,如果你的ADC一直在变,你想让他一直搬,那你就要用连续模式

8.Priority:这个随便你怎么弄,优先级而已

配置以后,     HAL_DMA_Init(&dma1_handle);

这个语句才是真的初始化成功了,你创的不算,你是老大还是编译器是老大。

然后:    __HAL_DMA_ENABLE(&dma1_handle);        //只是使能DMA(没有运输)

这句话的意思是,我的DMA电源开了,还没开始搬哈,一个语句你还想干两件事,想得美

标签:__,DMA,handle,struct,步骤,HandleTypeDef,种田,ADC
From: https://blog.csdn.net/CC_Biu/article/details/141932839

相关文章

  • 仿真软件Comsol下载:附安装包+详细安装步骤
    Comsol多物理场仿真软件给大家提供了一个方便易用的多物理场耦合仿真平台,事实上,这是一个支持多种语言的图形化操作界面,其中包括简体中文。Comsol6.2版本比较常用,它提供大量的用于电气、机械、流体流动和化工等应用领域的物理场接口,可以无缝地耦合任意数量的模块来处理极具挑......
  • YOLOv8改进:CA注意力机制【注意力系列篇】(附详细的修改步骤,以及代码,CA目标检测效果由
    如果实验环境尚未搭建成功,可以参考这篇文章->【YOLOv8超详细环境搭建以及模型训练(GPU版本)】文章链接为:http://t.csdnimg.cn/8ZmAm---------------------------------------------------------------------------​------------------------------------------------------1......
  • 话费充值API接口的关键步骤与考虑因素
    话费充值API接口通常是由电信运营商或第三方支付平台提供的一种服务,允许开发者将话费充值功能集成到自己的应用程序或网站中。通过这种接口,用户可以方便地为他们的手机账户充值。以下是实现话费充值API接口可能涉及的一些关键步骤和考虑因素:关键步骤:选择服务提供商:选择一个......
  • DMA——STM32F407ZGT6
    DMA简介DMA(DirectMemoryAccess)直接存储器存取DMA可以提供外设和存储器或者存储器和存储器之间的高速数据传输,无须CPU干预,节省了CPU的资源。DMA的作用就是解决大量数据转移过度消耗CPU资源的问题,有了DMA得CPU可以更加专注的实用的的操作——计算、控制等。外围设备可以通过......
  • 解决podman: ERRO[0000] running newuidmap: write to uid_map failed: Invalid argum
    报错ERRO[0000]running/usr/bin/newuidmap27115520100011100000655366553710000065537:newuidmap:writetouid_mapfailed:InvalidargumentError:cannotsetupnamespaceusing"/usr/bin/newuidmap":shouldhavesetuidorhavefilecapssetu......
  • 《安装Windows 11 系统详细步骤》
    以下是安装Windows11系统的详细步骤: 准备工作: 1. 检查电脑是否满足Windows11的系统要求,包括处理器、内存、存储、TPM等。2. 备份重要的数据,因为安装过程中可能会导致数据丢失。3. 准备一个8GB或以上容量的U盘,并将其格式化为FAT32格式。4. 从微软官方......
  • Java 单元测试:保障代码质量的关键步骤
    Java单元测试:保障代码质量的关键步骤大家好,我是微赚淘客返利系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!一、单元测试的定义和重要性单元测试是针对程序中最小的可测试部分进行的测试。在Java中,这通常意味着对单个方法或类进行测试。单元测试是保障代码质量的关键步骤,它有......
  • OpenCV与AI深度学习 | 实战 | OpenCV传统方法实现密集圆形分割与计数(详细步骤 + 代码
    本文来源公众号“OpenCV与AI深度学习”,仅用于学术分享,侵权删,干货满满。原文链接:实战|OpenCV传统方法实现密集圆形分割与计数(详细步骤+代码)导 读    本文主要介绍基于OpenCV传统方法实现密集圆形分割与计数应用,并给详细步骤和代码。 背景介绍  实例图片来......
  • 流式dma和一致性dma的区别
    流式DMA(StreamingDMA)和一致性DMA(ConsistentDMA)是两种不同的内存映射模式,用于DMA(直接内存访问)操作。它们的主要区别在于缓存一致性、性能和使用场景。以下是这两者的详细区别:1.流式DMA(StreamingDMA)缓存一致性:流式DMA不保证缓存的一致性。在进行DMA操作前,需要显式......
  • aws waf logs日志分析步骤
    1.waf设置AWSWAF----WebACLs----选择地区和规则--->Loggingandmetrics2.设置日志存放在s3中Editlogging---S3bucket----选择一个桶---save 3.在s3另外一个桶中新建目录waflogs4.修改官方配置官方配置:https://docs.aws.amazon.com/athena/latest/ug/create-waf-tab......