STM32F4 HAL库DMA学习

     用了一段时间HAL库,不知道是不是用外设固件库时间长一点的原因,个人感觉没有固件库来的直接。看DMA部分看的有点乱,捋一下。

DMA的使用方法及细节直接看官方的手册就可以了,注意的是如果原地址和目的地址的数据长度不一样的话只能使用FIFO模式,直接模式下原地址和目的地址的数据长度必须一致。

主要是简单整理一下使用DMA的初始化过程,以串口发送使用DMA为例:

            (1)  定义一个外设的句柄,对外设的基本参数、IO、时钟、中断等进行初始化。

	    UART_HandleTypeDef UART1_Handler; 

	               ....
	    HAL_UART_Init(&UART1_Handler);	
                             调用外设的初始化函数完成对外设的初始化

    (2)  定义一个 DMA的句柄,对DMA的数据流、通道、传输方向、数据长度等基本参数进行初始化

 	    DMA_HandleTypeDef     UART1TxDMA_Handler; 

                      ....
	    HAL_DMA_Init(&UART1TxDMA_Handler);
                 调用初始化函数完成对句柄的填充。
      (3)  使用HAL库中对DMA的一个宏定义完成外设发送DMAT或者接收DMAR和第二步的DMA句柄进行关联

		__HAL_LINKDMA(&UART1_Handler,hdmatx,UART1TxDMA_Handler);           
  每个外设的句柄结构体中都一个该外设关于DMA相关的设置:

               DMA_HandleTypeDef      *hdmatx;          UART TX 的DMA句柄参数
 	       DMA_HandleTypeDef      *hdmarx;          UART RX 的DMA句柄参数
 使用__HAL_LINKDMA 宏定义的作用就是将第二步初始化的DMA句柄赋值给外设的发送或者接收DMA句          柄,并且外设的句柄(第一步定义的)赋给DMA结构体中的.parent 参数,调用DMA的函数都会间接调用 
              UART1TxDMA_Handler.parent->hdmatx  
                对DMA的个别寄存器的参数进行填充,比如调用 HAL_DMA_Start()函数就会调用DMA_SetConfig()函数配置数据个数、源地址、目的地址等。 而hdmatx 和第二步的DMA句柄是一模一样的,感觉最后转了一圈又转回会来了。。。

  (4)  外设初始化、DMA初始化、外设和DMA进行关联、外设使能DMA发送或者接收、DMA调用函数开始发送或者接收。

             个人感觉有时候HAL库的确有些冗余了,这时候可能就需要部分进行寄存器操作了。

二、使用过程总结

1、传输数据数目设置

       注意传输数据的个数的设置:如果源的数据宽度和目标数据宽度不一样,即PSIZE、MSIZE不相等时,DMA_SXNDTR寄存器配置要传输的数据项数目的宽度等于外设总线的宽度(和传输方向无关)。例如外设的宽度设置为字,存储器的宽度设置为半字,假如要传输100个字节的数据,NDTR寄存器配置要传输的数据数目 100/4.外设宽度是字=4个字节。

2、DMA初始化

    HAL_DMA_Init() ;   初始化函数中会使能所有的中断,如果不想用中断,可以在初始化之后关闭。初始化完成后会自动使能流的DMA。 


三、调试过程问题解决

      1、直接模式中出现FIFO溢出错误,可能是DMA的源地址或者目的地址设置有问题。









你可能感兴趣的:(STM32F4)