【STM32H7教程】第40章 STM32H7的BDMA基礎知識和HAL庫API


完整教程下載地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980

第40章       STM32H7的BDMA基礎知識和HAL庫API

本章節為大家講解BDMA(Basic direct memory access controller,基本直接存儲器訪問控制器),相比通用的DMA1和DMA2,BDMA功能稍弱,支持一些基本的DMA功能。

40.1 初學者重要提示

40.2 BDMA基礎知識

40.3 BDMA的HAL庫用法

40.4 源文件stm32h7xx_hal_dma.c

40.5 總結

 

 

40.1 初學者重要提示

  1.   BDMA只能操作D3域的存儲器和外設,這點比較重要,操作的時候容易被遺忘。詳情看本章2.6小節。
  2.   BDMA支持8路通道。雖然是8路,但這8路不是並行工作的,而是由BDMA的仲裁器決定當前處理哪一路。
  3.   BDMA不支持硬件FIFO,但是支持雙緩沖。
  4.   BDMA不支持突發模式。
  5.   BDMA最大傳輸次數65535次,每次傳輸單位可以是字節、半字和字。
  6.   BDMA的循環模式不可用於存儲器到存儲器模式。
  7.   HAL庫沒有配套BDMA的雙緩,當前的HAL庫V1.3.0版本沒有對雙緩沖進行支持,詳情看此貼:http://www.armbbs.cn/forum.php?mod=viewthread&tid=91149

40.2 BDMA基礎知識

BDMA的幾個關鍵知識點放在開頭說:

  •   由於總線矩陣的存在,各個主控的道路四通八達,從而可以讓DMA和CPU同時開工,但是注意一點,如果他們同時訪問的同一個外設,會有一點性能影響的。
  •   BDMA支持存儲器到外設,外設到存儲器,存儲器到存儲器和外設到外設的傳輸,其中外設到外設的傳輸,DMA1和DMA2是不支持的,這個模式在低功耗模式下比較有用。
  •   BDMA只有一個AHB總線主控,而DMA1和DMA2是有兩個的,可以分別用於源地址和目的地址的傳輸。
  •   源地址和目的地址的數據寬度可以不同,但是數據地址必須要跟其數據類型對齊。比如源地址是uint32類型的,那么此數組的地址必須4字節對齊。
  •   BDMA主要有兩種模式,一個是Normal正常模式,傳輸一次后就停止傳輸;另一種是Circular循環模式,會一直循環的傳輸下去,即使有DMA中斷,傳輸也是一直在進行的。
  •   BDMA的通道請求(Channel0 – Channel7)的優先級可編程,分為四級Very high priority,High priority,Medium priority和Low priority。通道的優先級配置相同的情況下,如果同時產生請求,會優先響應編號低的,即Channel0優先響應。

40.2.1 BDMA硬件框圖

認識一個外設,最好的方式就是看他的框圖,方便我們快速的了解BDMA的基本功能,然后再看手冊了解細節。框圖如下所示:

 

(注:ST做的DMA框圖沒有其它外設做的好,不夠詳細)

通過這個框圖,我們可以得到如下信息:

  •   bdma_tcif[0:7]接口

通道0 – 通道7的傳輸完成標志。

  •   bdma_it[0:7]接口

通道0 – 通道7的中斷觸發。                                                                                                                 

  •   bdma_req[0:7]接口

通道0 –通道7的請求信號接口。

  •   Arbiter仲裁器

用於仲裁當期要處理的DMA請求。通過這里我們可以看出雖然是8路,但這8路不是並行工作的,而是由BDMA的仲裁器決定當前處理哪一路。

  •   AHB總線接口

BDMA只有一個AHB總線主控,而DMA1和DMA2是有兩個的,可以分別用於源地址和目的地址的傳輸。

DMA1和DMA2:

 

BDMA:

 

40.2.2 BDMA傳輸

BDMA支持如下幾種傳輸模式:

  •   存儲器到外設。
  •   外設到存儲器。
  •   存儲器到存儲器。
  •   外設到外設的傳輸。

其中外設到外設的傳輸,DMA1和DMA2是不支持的,這個模式在低功耗模式下比較有用。

 

關於這幾種傳輸方式要注意以下兩個問題:

  •   源地址和目的地址的數據寬度可以不同,但是數據地址必須要跟其數據類型對齊。比如源地址是uint32類型的,那么此數組的地址必須4字節對齊。
  •   BDMA不可以操作TCM區,其它的SRAM區均可操作,在第25章專門講解過這個問題。

 

  •  拓展知識

MDK中全局變量的數據對齊問題說明:

http://www.armbbs.cn/forum.php?mod=viewthread&tid=13511

40.2.3 BDMA的循環模式和正常模式

BDMA主要有兩種模式,一個是Normal正常模式,傳輸一次后就停止傳輸;另一種是Circular循環模式,會一直循環的傳輸下去,即使有DMA中斷,傳輸也是一直在進行的。

這兩種模式各有用途。

  •   Normal正常模式

適合用於單次傳輸,比如存儲器到存儲器的數據復制粘貼,又比如串口的數據單次發送,下次還需要發送的時候,使能下即可。

  •   Circular循環模式

適合用於需要連續傳輸的場合,比如定時器觸發BDMA實現任意IO的PWM輸出。

 

另外特別注意,循環模式不可用於存儲器到存儲器模式。

40.2.4 BDMA數據封裝和解封

獨立的源和目標傳輸寬度(字節、半字、字):源和目標的數據寬度不相等時, DMA 自動封裝/解封必要的傳輸數據來優化帶寬。無需像F1系列那樣強行要求數據緩沖的4字節對齊。下面是各種源地址和目的地址數據寬度傳輸4次的效果,可以幫助大家更好的理解。

 

40.2.5 BDMA雙緩沖

BDMA也是支持雙緩沖模式的,雙緩沖的含義是源地址或者目的地址可以設置兩個緩沖區,這種方式的好處是一個緩沖區在接收或者發送數據的時候,另一個緩沖區可以動態更新數據或者處理已經接收到的數據。

當用戶開啟了BDMA傳輸完成中斷后,通過寄存器CCRx的CT位判斷當前使用的是哪個緩沖區

  •   如果CT = 1表示當前正在使用緩沖區1,即寄存器BDMA_CM1ARx記錄的地址。
  •   如果CT = 0表示當前正在使用緩沖區0,即寄存器BDMA_CM0ARx記錄的地址。

 

另外注意,存儲器到存儲器的BDMA傳輸不支持雙緩沖模式,僅可以用於存儲器到外設或者外設到存儲器。

40.2.6 BDMA可以操作的區域

根據第3章的總線互聯方式,BDMA僅可以操作:AHB4,APB4的外設以及SRAM4,Backup RAM。

實際應用的時候要特別注意,防止操作錯誤。

 

40.3 BDMA的HAL庫用法

BDMA的HAL庫用法其實就是幾個結構體變量成員的配置和使用,然后配置GPIO、時鍾,並根據需要配置NVIC、中斷和DMA。下面我們逐一展開為大家做個說明。

40.3.1 BDMA寄存器結構體

BDMA相關的寄存器是通過HAL庫中的結構體DMA_TypeDef和DMA_Stream_TypeDef定義的,在stm32h743xx.h中可以找到這個類型定義:

注:當前的HAL庫版本V1.3.0對CMAR寄存器的定義不完善,詳情看此貼:

http://www.armbbs.cn/forum.php?mod=viewthread&tid=91207

typedef struct
{
  __IO uint32_t ISR;    /*!< DMA interrupt status register,       Address offset: 0x00 */
  __IO uint32_t IFCR;   /*!< DMA interrupt flag clear register,   Address offset: 0x04 */
} BDMA_TypeDef;

typedef struct
{
  __IO uint32_t CCR; /*!< DMA channel x configuration register  Addr offset: 0x08 + 0x14 * x,x = 0 to 7 */
  __IO uint32_t CNDTR;/*!< DMA channel x number of data register Addr offset: 0x0C + 0x14 * x,x = 0 to 7 */
  __IO uint32_t CPAR; /*!< DMA channel x peripheral address register Addr offset: 0x10 + 0x14 * x, x = 0 to 7*/
  __IO uint32_t CMAR; /*!< DMA channel x memory address register, Addr offset: 0x14 + 0x14 * x, x = 0 to 7 */
} BDMA_Channel_TypeDef;

 

__IO表示volatile, 這是標准C語言中的一個修飾字,表示這個變量是非易失性的,編譯器不要將其優化掉。core_m7.h 文件定義了這個宏:

#define     __O     volatile             /*!< Defines 'write only' permissions */
#define     __IO    volatile             /*!< Defines 'read / write' permissions */

 

與其它外設的的定義方式不同,BDMA有8組通道,每個通道都有一組BDMA_Channel_TypeDef結構體所定義的寄存器。

解決這個問題的辦法就是定義一套BDMA_Channel0 - BDMA_Channel7來解決,定義在stm32h743xx.h文件。

#define PERIPH_BASE         ((uint32_t)0x40000000)
#define D3_AHB1PERIPH_BASE  (PERIPH_BASE + 0x18020000)
#define BDMA_BASE           (D3_AHB1PERIPH_BASE + 0x5400)
#define BDMA                ((BDMA_TypeDef *) BDMA_BASE)

#define BDMA_Channel0_BASE    (BDMA_BASE + 0x0008)
#define BDMA_Channel1_BASE    (BDMA_BASE + 0x001C)
#define BDMA_Channel2_BASE    (BDMA_BASE + 0x0030)
#define BDMA_Channel3_BASE    (BDMA_BASE + 0x0044)
#define BDMA_Channel4_BASE    (BDMA_BASE + 0x0058)
#define BDMA_Channel5_BASE    (BDMA_BASE + 0x006C)
#define BDMA_Channel6_BASE    (BDMA_BASE + 0x0080)
#define BDMA_Channel7_BASE    (BDMA_BASE + 0x0094)

<-----展開下面的宏定義,(BDMA_Channel_TypeDef *) 0x58025408
#define BDMA_Channel0  ((BDMA_Channel_TypeDef *) BDMA_Channel0_BASE)
#define BDMA_Channel1  ((BDMA_Channel_TypeDef *) BDMA_Channel1_BASE)
#define BDMA_Channel2  ((BDMA_Channel_TypeDef *) BDMA_Channel2_BASE)
#define BDMA_Channel3  ((BDMA_Channel_TypeDef *) BDMA_Channel3_BASE)
#define BDMA_Channel4  ((BDMA_Channel_TypeDef *) BDMA_Channel4_BASE)
#define BDMA_Channel5  ((BDMA_Channel_TypeDef *) BDMA_Channel5_BASE)
#define BDMA_Channel6  ((BDMA_Channel_TypeDef *) BDMA_Channel6_BASE)
#define BDMA_Channel7  ((BDMA_Channel_TypeDef *) BDMA_Channel7_BASE)

 

我們訪問BDMA的ISR寄存器可以采用這種形式:BDMA->ISR = 0,而訪問通道0的CCR就可以采用這種形式BDMA_Channel0->CCR = 0。

40.3.2 BDMA句柄結構體DMA_HandleTypeDef

HAL庫在DMA_TypeDef的基礎上封裝了一個結構體DMA_HandleTypeDef,定義如下:

typedef struct __DMA_HandleTypeDef
{
  void                            *Instance;                                         
  DMA_InitTypeDef                 Init;                                                       
  HAL_LockTypeDef                 Lock;                                                        
  __IO HAL_DMA_StateTypeDef       State;                                                    
  void                            *Parent;                                                       
  void                            (* XferCpltCallback)( struct __DMA_HandleTypeDef * hdma);     
  void                            (* XferHalfCpltCallback)( struct __DMA_HandleTypeDef * hdma);   
  void                            (* XferM1CpltCallback)( struct __DMA_HandleTypeDef * hdma);     
  void                            (* XferM1HalfCpltCallback)( struct __DMA_HandleTypeDef * hdma);  
  void                            (* XferErrorCallback)( struct __DMA_HandleTypeDef * hdma);      
  void                            (* XferAbortCallback)( struct __DMA_HandleTypeDef * hdma);       
 __IO uint32_t                    ErrorCode;                                                        
 uint32_t                         StreamBaseAddress;                                              
 uint32_t                         StreamIndex;                                                 
 DMAMUX_Channel_TypeDef           *DMAmuxChannel;                                                
 DMAMUX_ChannelStatus_TypeDef     *DMAmuxChannelStatus;                                         
 uint32_t                         DMAmuxChannelStatusMask;                                        
 DMAMUX_RequestGen_TypeDef        *DMAmuxRequestGen;                                              
 DMAMUX_RequestGenStatus_TypeDef  *DMAmuxRequestGenStatus;                                    
 uint32_t                         DMAmuxRequestGenStatusMask;                                 
}DMA_HandleTypeDef;

 

這里重點介紹前幾個參數,其它參數主要是HAL庫內部使用的。

  •   void  *Instance

用於BDMA,DMA1和DMA2的例化,主要是相關寄存器的操作。

因為DMA1,DMA2和BDMA都使用的這個結構體句柄,而DMA1,DMA2與BDMA的寄存器結構體封裝是不同的,這里的定義比較巧妙, 定義為void *空類型后,就可以直接使用DMA1,DMA2和BDMA的結構體定義了。

比如操作DMA1 Stream1的寄存器CR:

DMA_HandleTypeDef DMA_Handle;

DMA_Handle.Instance = DMA1_Stream1;

((DMA_Stream_TypeDef   *) DMA_Handle ->Instance)->CR =0;

又比如操作BDMA Channel1的寄存器CCR:

DMA_HandleTypeDef BDMA_Handle;

BDMA_Handle.Instance = BDMA_Channel1;

((BDMA_Channel_TypeDef *) DMA_Handle ->Instance)->CCR =0;

  •   DMA_InitTypeDef  Init;  

這個參數是用戶接觸最多的,用於配置BDMA的基本參數。

DMA_InitTypeDef結構體的定義如下:

typedef struct
{
  uint32_t Request;        
  uint32_t Direction;            
  uint32_t PeriphInc;            
  uint32_t MemInc;               
  uint32_t PeriphDataAlignment;  
  uint32_t MemDataAlignment;     
  uint32_t Mode;                 
  uint32_t Priority;             
  uint32_t FIFOMode;            
  uint32_t FIFOThreshold;       
  uint32_t MemBurst;            
  uint32_t PeriphBurst;          
}DMA_InitTypeDef;

 

  成員Request

用於設置支持的DMA請求,對於BDAM來說,主要來自DMAMUX2。

/* D3 Domain : DMAMUX2 requests */
#define BDMA_REQUEST_MEM2MEM          0U  /*!< memory to memory transfer   */
#define BDMA_REQUEST_GENERATOR0       1U  /*!< DMAMUX2 request generator 0 */
#define BDMA_REQUEST_GENERATOR1       2U  /*!< DMAMUX2 request generator 1 */
#define BDMA_REQUEST_GENERATOR2       3U  /*!< DMAMUX2 request generator 2 */
#define BDMA_REQUEST_GENERATOR3       4U  /*!< DMAMUX2 request generator 3 */
#define BDMA_REQUEST_GENERATOR4       5U  /*!< DMAMUX2 request generator 4 */
#define BDMA_REQUEST_GENERATOR5       6U  /*!< DMAMUX2 request generator 5 */
#define BDMA_REQUEST_GENERATOR6       7U  /*!< DMAMUX2 request generator 6 */
#define BDMA_REQUEST_GENERATOR7       8U  /*!< DMAMUX2 request generator 7 */
#define BDMA_REQUEST_LPUART1_RX       9U  /*!< DMAMUX2 LP_UART1_RX request */
#define BDMA_REQUEST_LPUART1_TX      10U  /*!< DMAMUX2 LP_UART1_TX request */
#define BDMA_REQUEST_SPI6_RX         11U  /*!< DMAMUX2 SPI6 RX request     */
#define BDMA_REQUEST_SPI6_TX         12U  /*!< DMAMUX2 SPI6 TX request     */
#define BDMA_REQUEST_I2C4_RX         13U  /*!< DMAMUX2 I2C4 RX request     */
#define BDMA_REQUEST_I2C4_TX         14U  /*!< DMAMUX2 I2C4 TX request     */
#define BDMA_REQUEST_SAI4_A          15U  /*!< DMAMUX2 SAI4 A request      */
#define BDMA_REQUEST_SAI4_B          16U  /*!< DMAMUX2 SAI4 B request      */
#define BDMA_REQUEST_ADC3            17U  /*!< DMAMUX2 ADC3 request        */

 

  成員Direction

用於設置傳輸方向,外設到存儲器、存儲器到外設或者存儲器到存儲器,具體支持的參數如下:

#define DMA_PERIPH_TO_MEMORY         ((uint32_t)0x00000000U)     /*!< Peripheral to memory direction */
#define DMA_MEMORY_TO_PERIPH         ((uint32_t)DMA_SxCR_DIR_0)  /*!< Memory to peripheral direction */
#define DMA_MEMORY_TO_MEMORY         ((uint32_t)DMA_SxCR_DIR_1)  /*!< Memory to memory direction     */

 

  成員PeriphInc

用於設置外設地址是否使能遞增,即每完成一次傳輸,外設地址自增,增加的大小由參數PeriphDataAlignment決定。具體支持的參數如下:

#define DMA_PINC_ENABLE        ((uint32_t)DMA_SxCR_PINC)  /*!< Peripheral increment mode enable  */
#define DMA_PINC_DISABLE       ((uint32_t)0x00000000U)    /*!< Peripheral increment mode disable */

 

  成員MemInc

用於設置存儲器地址是否使能遞增,即每完成一次傳輸,存儲器地址自增,增加的大小由參數MemDataAlignment決定。具體支持的參數如下:

#define DMA_MINC_ENABLE         ((uint32_t)DMA_SxCR_MINC)  /*!< Memory increment mode enable  */
#define DMA_MINC_DISABLE        ((uint32_t)0x00000000U)    /*!< Memory increment mode disable */

 

  成員PeriphDataAlignment

用於設置外設支持的數據寬度,可以選擇字節、半字和字進行傳輸。

#define DMA_PDATAALIGN_BYTE     ((uint32_t)0x00000000U)      /*!< Peripheral data alignment: Byte     */
#define DMA_PDATAALIGN_HALFWORD (uint32_t)DMA_SxCR_PSIZE_0)  /*!< Peripheral data alignment: HalfWord */
#define DMA_PDATAALIGN_WORD     ((uint32_t)DMA_SxCR_PSIZE_1) /*!< Peripheral data alignment: Word     */

 

  成員MemDataAlignment

用於設置存儲器支持的數據寬度,可以選擇字節、半字和字進行傳輸。

#define DMA_MDATAALIGN_BYTE          ((uint32_t)0x00000000U)       /*!< Memory data alignment: Byte     */
#define DMA_MDATAALIGN_HALFWORD      ((uint32_t)DMA_SxCR_MSIZE_0)  /*!< Memory data alignment: HalfWord */
#define DMA_MDATAALIGN_WORD          ((uint32_t)DMA_SxCR_MSIZE_1)  /*!< Memory data alignment: Word     */ 

 

 成員Mode

用於設置正常模式、循環模式和流控制,對於BDMA而言,僅支持正常模式和循環模式。

#define DMA_NORMAL         ((uint32_t)0x00000000U)       /*!< Normal mode                  */
#define DMA_CIRCULAR       ((uint32_t)DMA_SxCR_CIRC)    /*!< Circular mode                */
#define DMA_PFCTRL         ((uint32_t)DMA_SxCR_PFCTRL)  /*!< Peripheral flow control mode */

 

  成員Priority

用於BDMA通道進行傳輸時的優先級設置,控制多通道同時請求時優先響應誰。支持四種優先級設置。

#define DMA_PRIORITY_LOW             ((uint32_t)0x00000000U)    /*!< Priority level: Low       */
#define DMA_PRIORITY_MEDIUM          ((uint32_t)DMA_SxCR_PL_0)  /*!< Priority level: Medium    */
#define DMA_PRIORITY_HIGH            ((uint32_t)DMA_SxCR_PL_1)  /*!< Priority level: High      */
#define DMA_PRIORITY_VERY_HIGH       ((uint32_t)DMA_SxCR_PL)    /*!< Priority level: Very High */

 

  成員FIFOMode

BDMA不支持FIFO。

  成員FIFOThreshold

FIFO閥值設置,BDMA不支持此參數。

  成員MemBurst

存儲器突發配置,BDMA不支持此參數。

  成員PeriphBurst

外設突發配置,BDMA不支持此參數。

 

  •      HAL_LockTypeDef   Lock

__IO HAL_DMA_StateTypeDef  State

這兩個變量主要供函數內部使用。Lock用於設置鎖狀態,而State用於設置DMA狀態。

  •      void     (* XferCpltCallback)( struct __DMA_HandleTypeDef * hdma);    

void     (* XferHalfCpltCallback)( struct __DMA_HandleTypeDef * hdma);  

void     (* XferM1CpltCallback)( struct __DMA_HandleTypeDef * hdma);    

void     (* XferM1HalfCpltCallback)( struct __DMA_HandleTypeDef * hdma); 

void     (* XferErrorCallback)( struct __DMA_HandleTypeDef * hdma);     

void     (* XferAbortCallback)( struct __DMA_HandleTypeDef * hdma);    

這里是定義了六個回調函數指針,分別用於配置傳輸完成回調,半傳輸完成回調,Memory1傳輸完成回調,Memory1半傳輸完成回調,傳輸錯誤回調和傳輸終止回調。

40.3.3 BDMA的狀態標志清除問題

下面我們介紹__HAL_DMA_GET_FLAG函數。這個函數用來檢查BDMA標志位是否被設置。

/**
  * @brief  Get the DMA Stream pending flags.
  * @param  __HANDLE__: DMA handle
  * @param  __FLAG__: Get the specified flag.
  *          This parameter can be any combination of the following values:
  *            @arg DMA_FLAG_TCIFx: Transfer complete flag.
  *            @arg DMA_FLAG_HTIFx: Half transfer complete flag.
  *            @arg DMA_FLAG_TEIFx: Transfer error flag.
  *            @arg DMA_FLAG_DMEIFx: Direct mode error flag.
  *            @arg DMA_FLAG_FEIFx: FIFO error flag.
  *         Where x can be 0_4, 1_5, 2_6 or 3_7 to select the DMA Stream flag.
  * @retval The state of FLAG (SET or RESET).
  */
#define __HAL_DMA_GET_FLAG(__HANDLE__, __FLAG__)\
(((uint32_t)((__HANDLE__)->Instance) > (uint32_t)DMA2_Stream7)? (BDMA->ISR & (__FLAG__))  :\
 ((uint32_t)((__HANDLE__)->Instance) > (uint32_t)DMA2_Stream3)? (DMA2->HISR & (__FLAG__)) :\
 ((uint32_t)((__HANDLE__)->Instance) > (uint32_t)DMA1_Stream7)? (DMA2->LISR & (__FLAG__)) :\
 ((uint32_t)((__HANDLE__)->Instance) > (uint32_t)DMA1_Stream3)? (DMA1->HISR & (__FLAG__)) : (DMA1->LISR &
 (__FLAG__)))

 

對於BDMA,主要是前三個中斷標志。

  •   DMA_FLAG_TCIFx

傳輸完成標志。

  •   DMA_FLAG_HTIFx

半傳輸完成標志。

  •   DMA_FLAG_TEIFx

傳輸錯誤標志。

  •   DMA_FLAG_DMEIFx

直接模式錯誤標志。

  •   DMA_FLAG_FEIFx

FIFO錯誤標志。

 

BDMA支持的標志參數如下:

/** @defgroup BDMA_flag_definitions BDMA flag definitions
  * @brief    BDMA flag definitions
  * @{
  */
#define BDMA_FLAG_GL0                      ((uint32_t)0x00000001)
#define BDMA_FLAG_TC0                      ((uint32_t)0x00000002)
#define BDMA_FLAG_HT0                      ((uint32_t)0x00000004)
#define BDMA_FLAG_TE0                      ((uint32_t)0x00000008)
#define BDMA_FLAG_GL1                      ((uint32_t)0x00000010)
#define BDMA_FLAG_TC1                      ((uint32_t)0x00000020)
#define BDMA_FLAG_HT1                      ((uint32_t)0x00000040)
#define BDMA_FLAG_TE1                      ((uint32_t)0x00000080)
#define BDMA_FLAG_GL2                      ((uint32_t)0x00000100)
#define BDMA_FLAG_TC2                      ((uint32_t)0x00000200)
#define BDMA_FLAG_HT2                      ((uint32_t)0x00000400)
#define BDMA_FLAG_TE2                      ((uint32_t)0x00000800)
#define BDMA_FLAG_GL3                      ((uint32_t)0x00001000)
#define BDMA_FLAG_TC3                      ((uint32_t)0x00002000)
#define BDMA_FLAG_HT3                      ((uint32_t)0x00004000)
#define BDMA_FLAG_TE3                      ((uint32_t)0x00008000)
#define BDMA_FLAG_GL4                      ((uint32_t)0x00010000)
#define BDMA_FLAG_TC4                      ((uint32_t)0x00020000)
#define BDMA_FLAG_HT4                      ((uint32_t)0x00040000)
#define BDMA_FLAG_TE4                      ((uint32_t)0x00080000)
#define BDMA_FLAG_GL5                      ((uint32_t)0x00100000)
#define BDMA_FLAG_TC5                      ((uint32_t)0x00200000)
#define BDMA_FLAG_HT5                      ((uint32_t)0x00400000)
#define BDMA_FLAG_TE5                      ((uint32_t)0x00800000)
#define BDMA_FLAG_GL6                      ((uint32_t)0x01000000)
#define BDMA_FLAG_TC6                      ((uint32_t)0x02000000)
#define BDMA_FLAG_HT6                      ((uint32_t)0x04000000)
#define BDMA_FLAG_TE6                      ((uint32_t)0x08000000)
#define BDMA_FLAG_GL7                      ((uint32_t)0x10000000)
#define BDMA_FLAG_TC7                      ((uint32_t)0x20000000)
#define BDMA_FLAG_HT7                      ((uint32_t)0x40000000)
#define BDMA_FLAG_TE7                      ((uint32_t)0x80000000)

 

與標志獲取函數__HAL_DMA_GET_FLAG對應的清除函數是__HAL_DMA_CLEAR_FLAG:

/**
  * @brief  Clear the DMA Stream pending flags.
  * @param  __HANDLE__: DMA handle
  * @param  __FLAG__: specifies the flag to clear.
  *          This parameter can be any combination of the following values:
  *            @arg DMA_FLAG_TCIFx: Transfer complete flag.
  *            @arg DMA_FLAG_HTIFx: Half transfer complete flag.
  *            @arg DMA_FLAG_TEIFx: Transfer error flag.
  *            @arg DMA_FLAG_DMEIFx: Direct mode error flag.
  *            @arg DMA_FLAG_FEIFx: FIFO error flag.
  *         Where x can be 0_4, 1_5, 2_6 or 3_7 to select the DMA Stream flag.
  * @retval None
  */
#define __HAL_DMA_CLEAR_FLAG(__HANDLE__, __FLAG__) \
(((uint32_t)((__HANDLE__)->Instance) > (uint32_t)DMA2_Stream7)? (BDMA->IFCR = (__FLAG__))  :\
 ((uint32_t)((__HANDLE__)->Instance) > (uint32_t)DMA2_Stream3)? (DMA2->HIFCR = (__FLAG__)) :\
 ((uint32_t)((__HANDLE__)->Instance) > (uint32_t)DMA1_Stream7)? (DMA2->LIFCR = (__FLAG__)) :\
 ((uint32_t)((__HANDLE__)->Instance) > (uint32_t)DMA1_Stream3)? (DMA1->HIFCR = (__FLAG__)) : (DMA1->LIFCR = (__FLAG__)))

 

清除標志函數所支持的參數跟獲取函數是一 一對應的。除了這兩個函數,還有BDMA的中斷開啟和中斷關閉函數,有時候也要用到。                                                                                                                                                   

/**
  * @brief  Enable the specified DMA Stream interrupts.
  * @param  __HANDLE__: DMA handle
  * @param  __INTERRUPT__: specifies the DMA interrupt sources to be enabled or disabled.
  *        This parameter can be one of the following values:
  *           @arg DMA_IT_TC: Transfer complete interrupt mask.
  *           @arg DMA_IT_HT: Half transfer complete interrupt mask.
  *           @arg DMA_IT_TE: Transfer error interrupt mask.
  *           @arg DMA_IT_FE: FIFO error interrupt mask.
  *           @arg DMA_IT_DME: Direct mode error interrupt.
  * @retval None
  */
#define __HAL_DMA_ENABLE_IT(__HANDLE__, __INTERRUPT__) ((IS_D2_DMA_INSTANCE(__HANDLE__))?\
                                                        (__HAL_DMA_D2_ENABLE_IT((__HANDLE__), (__INTERRUPT__))) :\
                                                        (__HAL_DMA_D3_ENABLE_IT((__HANDLE__), (__INTERRUPT__))))

/**
  * @brief  Disable the specified DMA Stream interrupts.
  * @param  __HANDLE__: DMA handle
  * @param  __INTERRUPT__: specifies the DMA interrupt sources to be enabled or disabled.
  *         This parameter can be one of the following values:
  *            @arg DMA_IT_TC: Transfer complete interrupt mask.
  *            @arg DMA_IT_HT: Half transfer complete interrupt mask.
  *            @arg DMA_IT_TE: Transfer error interrupt mask.
  *            @arg DMA_IT_FE: FIFO error interrupt mask.
  *            @arg DMA_IT_DME: Direct mode error interrupt.
  * @retval None
  */
#define __HAL_DMA_DISABLE_IT(__HANDLE__, __INTERRUPT__) ((IS_D2_DMA_INSTANCE(__HANDLE__))?\
                                                         (__HAL_DMA_D2_DISABLE_IT((__HANDLE__), (__INTERRUPT__))) :\
                                                         (__HAL_DMA_D3_DISABLE_IT((__HANDLE__), (__INTERRUPT__))))

注意:操作DMA的寄存器不限制必須要用HAL庫提供的API,比如要操作寄存器ISR,直接調用BDMA->ISR操作即可。

40.3.4 BDMA初始化流程總結

使用方法由HAL庫提供:

  第1步:通過函數HAL_DMA_Init配置各項參數。

 

  第2步:BDMA查詢方式。

  •   配置了源地址、目的地址和數據長度后,調用函數HAL_DMA_Start()啟動傳輸。
  •   使用函數HAL_DMA_PollForTransfer()查詢當前傳輸是否結束,用戶還可以給此函數配置超時等待時間。

 

  第3步:BDMA中斷方式。

  •   使用函數HAL_NVIC_SetPriority配置BDMA優先級。
  •   使用函數HAL_NVIC_EnableIRQ使能BDMA中斷。
  •   配置了源地址、目的地址和數據長度后,調用函數HAL_DMA_Start_IT()可以啟動傳輸(注,此函數會使能BDMA中斷)。
  •   將函數HAL_DMA_IRQHandler()填到中斷服務程序BDMA_Channelx_IRQHandler里面。
  •   傳輸結束后會調用函數HAL_DMA_IRQHandler(),此函數里面會執行回調函數,即用戶需要為XferCpltCallback,XferErrorCallback等函數配置實體(如果用到的話)。

 

  第4步:使用函數 HAL_DMA_GetState()可以獲得DMA狀態,函數HAL_DMA_GetError()獲取錯誤類型。

 

  第5步:使用函數HAL_DMA_Abort()可以終止DMA傳輸。

  •   存儲器到存儲器方式,不支持循環模式。
  •   DMA FIFO的作用是降低對總線的需求和源地址,目的地址不同數據寬度的傳輸。
  •   當FIFO禁止后,不允許配置源數據和目的數據寬度不同,此時將統一使用外設數據寬度。

 

  第6步:下面是幾個常用的DMA宏定義。

  •   __HAL_DMA_ENABLE:  使能指定的DMA Stream
  •   __HAL_DMA_DISABLE: 禁止指定的DMA Stream
  •   __HAL_DMA_GET_FS:  返回當前DMA Stream FIFO填充情況
  •   __HAL_DMA_ENABLE_IT: 使能指定的DMA Stream中斷
  •   __HAL_DMA_DISABLE_IT: 禁止指定的DMA Stream中斷
  •   __HAL_DMA_GET_IT_SOURCE: 檢查指定的DMA Stream中斷是否使能

 

40.4 源文件stm32h7xx_hal_dma.c

此文件涉及到的函數比較多,這里把我們幾個常用的函數做個說明:

  •   HAL_DMA_Init
  •   HAL_DMA_Start
  •   HAL_DMA_Start_IT

40.4.1 函數HAL_DMA_Init

函數原型:

HAL_StatusTypeDef HAL_DMA_Init(DMA_HandleTypeDef *hdma)
{
  uint32_t registerValue = 0U;
  uint32_t tickstart = HAL_GetTick();
  DMA_Base_Registers *regs = NULL;

   /* 省略 */

  /* DMA1或者DMA2的初始化 */
  if(IS_D2_DMA_INSTANCE(hdma) != RESET) 
  {
     /* 省略 */
  }
  
  /* BDMA的初始 */
else if(IS_D3_DMA_INSTANCE(hdma) != RESET) /*<BDMA channel , D3 domain*/
  {
     /* 省略 */
  }
  else
  {
    hdma->ErrorCode = HAL_DMA_ERROR_PARAM;
    hdma->State     = HAL_DMA_STATE_ERROR;

    return HAL_ERROR;
  }

  /* 初始化DMAMUX */
  DMA_CalcDMAMUXChannelBaseAndMask(hdma);

  if(hdma->Init.Direction == DMA_MEMORY_TO_MEMORY)
  {
     /* 如果是內存到內存模式,強制使用請求DMA_REQUEST_MEM2MEM */
     hdma->Init.Request = DMA_REQUEST_MEM2MEM;
  }


  /* 設置外設請求 */
  hdma->DMAmuxChannel->CCR = (hdma->Init.Request & DMAMUX_CxCR_DMAREQ_ID);

  /* 清除DMAMUX同步溢出標志 */
  hdma->DMAmuxChannelStatus->CFR = hdma->DMAmuxChannelStatusMask;

  /* 如果請求類型是DMA_REQUEST_GENERATOR0 到 DMA_REQUEST_GENERATOR7,那么設置請求發生器 */
  if((hdma->Init.Request >= DMA_REQUEST_GENERATOR0) && (hdma->Init.Request <= DMA_REQUEST_GENERATOR7))
  {
    /* 省略 */
  }
  else
  {
    hdma->DMAmuxRequestGen = 0U;
    hdma->DMAmuxRequestGenStatus = 0U;
    hdma->DMAmuxRequestGenStatusMask = 0U;
  }

  /* 無錯誤 */
  hdma->ErrorCode = HAL_DMA_ERROR_NONE;

  /* 設置DMA就緒 */
  hdma->State = HAL_DMA_STATE_READY;

  return HAL_OK;
}

 

函數描述:

此函數用於初始化DMA1,DMA2和BDMA。

函數參數:

  •   第1個參數是DMA_HandleTypeDef類型結構體指針變量,用於配置要初始化的參數。結構體變量成員的詳細介紹看本章3.2小節。
  •   返回值,返回HAL_ERROR表示配置失敗,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示時間溢出。

注意事項:

  1. 第1個參數的結構體成員介紹在本章的3.2小節進行了詳細說明。

使用舉例:

DMA_HandleTypeDef DMA_Handle = {0};

DMA_Handle.Instance                 = BDMA_Channel0;           /* 使用的BDMA通道0 */
DMA_Handle.Init.Request             = BDMA_REQUEST_GENERATOR0; /* 請求類型采用的DMAMUX請求發生器通道0 */  
DMA_Handle.Init.Direction           = DMA_MEMORY_TO_PERIPH;    /* 傳輸方向是從存儲器到外設 */  
DMA_Handle.Init.PeriphInc           = DMA_PINC_DISABLE;        /* 外設地址自增禁止 */  
DMA_Handle.Init.MemInc              = DMA_MINC_ENABLE;         /* 存儲器地址自增使能 */  
DMA_Handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;     /* 外設數據傳輸位寬選擇字,即32bit */     
DMA_Handle.Init.MemDataAlignment    = DMA_MDATAALIGN_WORD;     /* 存儲器數據傳輸位寬選擇字,即32bit */    
DMA_Handle.Init.Mode                = DMA_CIRCULAR;            /* 循環模式 */   
DMA_Handle.Init.Priority            = DMA_PRIORITY_LOW;        /* 優先級低 */  
DMA_Handle.Init.FIFOMode            = DMA_FIFOMODE_DISABLE;    /* BDMA不支持FIFO */ 
DMA_Handle.Init.FIFOThreshold       = DMA_FIFO_THRESHOLD_FULL; /* BDMA不支持FIFO閥值設置 */ 
DMA_Handle.Init.MemBurst            = DMA_MBURST_SINGLE;       /* BDMA不支持存儲器突發 */ 
DMA_Handle.Init.PeriphBurst         = DMA_PBURST_SINGLE;       /* BDMA不支持外設突發 */ 

HAL_DMA_Init(&DMA_Handle);

 

40.4.2 函數HAL_DMA_Start

函數原型:

HAL_StatusTypeDef HAL_DMA_Start(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength)
{
  HAL_StatusTypeDef status = HAL_OK;

  /* 檢測參數 */
  assert_param(IS_DMA_BUFFER_SIZE(DataLength));

  /* 檢測句柄 */
  if(hdma == NULL)
  {
    return HAL_ERROR;
  }

  /* 上鎖 */
  __HAL_LOCK(hdma);

  if(HAL_DMA_STATE_READY == hdma->State)
  {
    /* 設置DMA狀態 */
    hdma->State = HAL_DMA_STATE_BUSY;

    /* 無錯誤 */
    hdma->ErrorCode = HAL_DMA_ERROR_NONE;

    /* 禁止DMA */
    __HAL_DMA_DISABLE(hdma);

    /* 配置源地址,目的地址和數據長度 */
    DMA_SetConfig(hdma, SrcAddress, DstAddress, DataLength);

    /* 使能DMA */
    __HAL_DMA_ENABLE(hdma);
  }
  else
  {
    /* 解鎖 */
    __HAL_UNLOCK(hdma);

    /* 設置忙 */
    hdma->ErrorCode = HAL_DMA_ERROR_BUSY;

    /* 返回HAL_ERROR */
    status = HAL_ERROR;
  }
  return status;
}

 

函數描述:

調用函數HAL_DMA_Init配置了基礎功能后,就可以調用此函數啟動BDMA了。DMA1,DMA2和BDMA都是用的這個函數。

函數參數:

  •   第1個參數是DMA_HandleTypeDef類型結構體指針變量。
  •   第2個參數是BDMA傳輸的源地址。
  •   第3個參數是BDMA傳輸的目的地址。
  •   第4個參數是傳輸的數據長度。
  •   返回值,返回HAL_ERROR表示配置失敗,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示時間溢出。

注意事項:

  1. 第1個參數的結構體成員介紹在本章的3.2小節進行了詳細說明。

使用舉例:

/*
*********************************************************************************************************
*    函 數 名: bsp_InitTimBDMA
*    功能說明: 配置DMAMUX的定時器觸+DMA控制任意IO做PWM和脈沖數控制
*    形    參: 無
*    返 回 值: 無
*********************************************************************************************************
*/
void bsp_InitTimBDMA(void)
{
    GPIO_InitTypeDef  GPIO_InitStruct;
    DMA_HandleTypeDef DMA_Handle = {0};
    HAL_DMA_MuxRequestGeneratorConfigTypeDef dmamux_ReqGenParams ={0};

    
     /*##-1- 配置PB1用於PWM輸出######################################*/ 
    __HAL_RCC_GPIOB_CLK_ENABLE();
      
    GPIO_InitStruct.Pin = GPIO_PIN_1;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
    
  
    /*##-2- 配置DMA ##################################################*/
    __HAL_RCC_BDMA_CLK_ENABLE();

    DMA_Handle.Instance                 = BDMA_Channel0;           /* 使用的BDMA通道0 */
    DMA_Handle.Init.Request             = BDMA_REQUEST_GENERATOR0; /* 請求類型采用的DMAMUX請求發生器通道0 */  
    DMA_Handle.Init.Direction           = DMA_MEMORY_TO_PERIPH;    /* 傳輸方向是從存儲器到外設 */  
    DMA_Handle.Init.PeriphInc           = DMA_PINC_DISABLE;        /* 外設地址自增禁止 */  
    DMA_Handle.Init.MemInc              = DMA_MINC_ENABLE;         /* 存儲器地址自增使能 */  
    DMA_Handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;     /* 外設數據傳輸位寬選擇字,即32bit */     
    DMA_Handle.Init.MemDataAlignment    = DMA_MDATAALIGN_WORD;     /* 存儲器數據傳輸位寬選擇字,即32bit */    
    DMA_Handle.Init.Mode                = DMA_CIRCULAR;            /* 循環模式 */   
    DMA_Handle.Init.Priority            = DMA_PRIORITY_LOW;        /* 優先級低 */  
    DMA_Handle.Init.FIFOMode            = DMA_FIFOMODE_DISABLE;    /* BDMA不支持FIFO */ 
    DMA_Handle.Init.FIFOThreshold       = DMA_FIFO_THRESHOLD_FULL; /* BDMA不支持FIFO閥值設置 */ 
    DMA_Handle.Init.MemBurst            = DMA_MBURST_SINGLE;       /* BDMA不支持存儲器突發 */ 
    DMA_Handle.Init.PeriphBurst         = DMA_PBURST_SINGLE;       /* BDMA不支持外設突發 */ 
    
    HAL_DMA_Init(&DMA_Handle);

    /* 開啟BDMA Channel0的中斷 */
    HAL_NVIC_SetPriority(BDMA_Channel0_IRQn, 2, 0);
    HAL_NVIC_EnableIRQ(BDMA_Channel0_IRQn); 

    /*##-3- 配置DMAMUX #########################################################*/
dmamux_ReqGenParams.SignalID  = HAL_DMAMUX2_REQ_GEN_LPTIM2_OUT;    /* 請求觸發器選擇LPTIM2_OUT */
dmamux_ReqGenParams.Polarity  = HAL_DMAMUX_REQ_GEN_RISING_FALLING; /* LPTIM2輸出的上升沿和下降沿均可觸
發  */
    dmamux_ReqGenParams.RequestNumber = 1;                             /* 觸發后,傳輸進行1次DMA傳輸 */
    HAL_DMAEx_ConfigMuxRequestGenerator(&DMA_Handle, &dmamux_ReqGenParams); /* 配置DMAMUX */
    HAL_DMAEx_EnableMuxRequestGenerator (&DMA_Handle);                /* 使能DMAMUX請求發生器 */        
      
    /*##-4- 啟動DMA傳輸 ################################################*/
    HAL_DMA_Start(&DMA_Handle, (uint32_t)IO_Toggle, (uint32_t)&GPIOB->BSRRL, 8);
}

 

40.4.3 函數HAL_DMA_Start_IT

函數原型:

HAL_StatusTypeDef HAL_DMA_Start_IT(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength)
{
  HAL_StatusTypeDef status = HAL_OK;

  /* 檢測參數 */
  assert_param(IS_DMA_BUFFER_SIZE(DataLength));

  /* 檢測句柄 */
  if(hdma == NULL)
  {
    return HAL_ERROR;
  }

  /* 上鎖  */
  __HAL_LOCK(hdma);

  if(HAL_DMA_STATE_READY == hdma->State)
  {
    /* 設置DMA忙 */
    hdma->State = HAL_DMA_STATE_BUSY;

    /* 設置無錯誤 */
    hdma->ErrorCode = HAL_DMA_ERROR_NONE;

    /* 禁止DMA */
    __HAL_DMA_DISABLE(hdma);

    /* 配置DMA源地址,目的地址和數據長度 */
    DMA_SetConfig(hdma, SrcAddress, DstAddress, DataLength);

    /* DMA1和DMA2配置 */
    if(IS_D2_DMA_INSTANCE(hdma) != RESET) 
    {
      /* 使能TC,TE和DME中斷 */
      MODIFY_REG(((DMA_Stream_TypeDef   *)hdma->Instance)->CR, (DMA_IT_TC | DMA_IT_TE | DMA_IT_DME |
 DMA_IT_HT), (DMA_IT_TC | DMA_IT_TE | DMA_IT_DME));
      ((DMA_Stream_TypeDef   *)hdma->Instance)->FCR |= DMA_IT_FE;

      if(hdma->XferHalfCpltCallback != NULL)
      {
        /* 如何設置了半傳輸回調函數,同時開啟半傳輸中斷 */
        ((DMA_Stream_TypeDef   *)hdma->Instance)->CR  |= DMA_IT_HT;
      }
    }
    else /* BDMA配置 */
    {
      /* 使能TC和TC中斷 */
      MODIFY_REG(((BDMA_Channel_TypeDef   *)hdma->Instance)->CCR, (BDMA_CCR_TCIE | BDMA_CCR_HTIE | 
BDMA_CCR_TEIE), (BDMA_CCR_TCIE | BDMA_CCR_TEIE));

      if(hdma->XferHalfCpltCallback != NULL)
      {
         /* 如何設置了半傳輸回調函數,同時開啟半傳輸中斷 */
        ((BDMA_Channel_TypeDef   *)hdma->Instance)->CCR  |= BDMA_CCR_HTIE;
      }
    }

    /* 檢測是否使能DMAMUX同步傳輸 */
    if((hdma->DMAmuxChannel->CCR & DMAMUX_CxCR_SE) != 0U)
    {
      /* 使能了的話,開啟同步溢出中斷 */
      hdma->DMAmuxChannel->CCR |= DMAMUX_CxCR_SOIE;
    }

    if(hdma->DMAmuxRequestGen != 0U)
    {
      /* 如果使用了DMAMUX請求發生器,使能請求發生器溢出中斷 */
      hdma->DMAmuxRequestGen->RGCR |= DMAMUX_RGxCR_OIE;

    }

    /* 使能DMA */
    __HAL_DMA_ENABLE(hdma);
  }
  else
  {
    /* 解鎖 */
    __HAL_UNLOCK(hdma);

    /* 設置DMA忙 */
    hdma->ErrorCode = HAL_DMA_ERROR_BUSY;

    /* 返回HAL_ERROR */
    status = HAL_ERROR;
  }

  return status;
}

 

函數描述:

調用函數HAL_DMA_Init配置了基礎功能后,就可以調用此函數啟動BDMA了,采用的中斷方式。DMA1,DMA2和BDMA都是用的這個函數。

函數參數:

  •   第1個參數是LPTIM_HandleTypeDef類型結構體指針變量。
  •   第2個參數是BDMA傳輸的源地址。
  •   第3個參數是BDMA傳輸的目的地址。
  •   第4個參數是傳輸的數據長度。
  •   返回值,返回HAL_ERROR表示配置失敗,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示時間溢出。

注意事項:

  1. 第1個參數的結構體成員介紹在本章的3.2小節進行了詳細說明。
  2. 對於DMA1和DMA2,這個函數會開啟TC,TE和MDE中斷,如果注冊了半傳輸完成回調函數,還會開啟半傳輸中斷。
  3. 對於BDMA,這個函數會開始TC和TE中斷,如果注冊了半傳輸完成回調函數,還會開啟半傳輸中斷。

使用舉例:

/*
*********************************************************************************************************
*    函 數 名: bsp_InitTimBDMA
*    功能說明: 配置DMAMUX的定時器觸+DMA控制任意IO做PWM和脈沖數控制
*    形    參: 無
*    返 回 值: 無
*********************************************************************************************************
*/
void bsp_InitTimBDMA(void)
{
    GPIO_InitTypeDef  GPIO_InitStruct;
    DMA_HandleTypeDef DMA_Handle = {0};
    HAL_DMA_MuxRequestGeneratorConfigTypeDef dmamux_ReqGenParams ={0};

    
     /*##-1- 配置PB1用於PWM輸出######################################*/ 
    __HAL_RCC_GPIOB_CLK_ENABLE();
      
    GPIO_InitStruct.Pin = GPIO_PIN_1;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
    
  
    /*##-2- 配置DMA ##################################################*/
    __HAL_RCC_BDMA_CLK_ENABLE();

    DMA_Handle.Instance                 = BDMA_Channel0;           /* 使用的BDMA通道0 */
    DMA_Handle.Init.Request             = BDMA_REQUEST_GENERATOR0; /* 請求類型采用的DMAMUX請求發生器通道0 */  
    DMA_Handle.Init.Direction           = DMA_MEMORY_TO_PERIPH;    /* 傳輸方向是從存儲器到外設 */  
    DMA_Handle.Init.PeriphInc           = DMA_PINC_DISABLE;        /* 外設地址自增禁止 */  
    DMA_Handle.Init.MemInc              = DMA_MINC_ENABLE;         /* 存儲器地址自增使能 */  
    DMA_Handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;     /* 外設數據傳輸位寬選擇字,即32bit */     
    DMA_Handle.Init.MemDataAlignment    = DMA_MDATAALIGN_WORD;     /* 存儲器數據傳輸位寬選擇字,即32bit */    
    DMA_Handle.Init.Mode                = DMA_CIRCULAR;            /* 循環模式 */   
    DMA_Handle.Init.Priority            = DMA_PRIORITY_LOW;        /* 優先級低 */  
    DMA_Handle.Init.FIFOMode            = DMA_FIFOMODE_DISABLE;    /* BDMA不支持FIFO */ 
    DMA_Handle.Init.FIFOThreshold       = DMA_FIFO_THRESHOLD_FULL; /* BDMA不支持FIFO閥值設置 */ 
    DMA_Handle.Init.MemBurst            = DMA_MBURST_SINGLE;       /* BDMA不支持存儲器突發 */ 
    DMA_Handle.Init.PeriphBurst         = DMA_PBURST_SINGLE;       /* BDMA不支持外設突發 */ 
    
    HAL_DMA_Init(&DMA_Handle);

    /* 開啟BDMA Channel0的中斷 */
    HAL_NVIC_SetPriority(BDMA_Channel0_IRQn, 2, 0);
    HAL_NVIC_EnableIRQ(BDMA_Channel0_IRQn); 

    /*##-3- 配置DMAMUX #########################################################*/
dmamux_ReqGenParams.SignalID  = HAL_DMAMUX2_REQ_GEN_LPTIM2_OUT;    /* 請求觸發器選擇LPTIM2_OUT */
dmamux_ReqGenParams.Polarity  = HAL_DMAMUX_REQ_GEN_RISING_FALLING; /* LPTIM2輸出的上升沿和下降沿均可觸
發  */
    dmamux_ReqGenParams.RequestNumber = 1;                             /* 觸發后,傳輸進行1次DMA傳輸 */
    HAL_DMAEx_ConfigMuxRequestGenerator(&DMA_Handle, &dmamux_ReqGenParams); /* 配置DMAMUX */
    HAL_DMAEx_EnableMuxRequestGenerator (&DMA_Handle);                /* 使能DMAMUX請求發生器 */        
      
    /*##-4- 啟動DMA傳輸 ################################################*/
    HAL_DMA_Start_IT(&DMA_Handle, (uint32_t)IO_Toggle, (uint32_t)&GPIOB->BSRRL, 8);
}

 

40.5 總結

本章節就為大家講解這么多,BDMA作為一個重要的外設,務必要熟練掌握。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM