完整教程下載地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980
第39章 STM32H7的DMAMUX基礎知識(重要)
本章教程為大家講解DMAMUX(Direct memory access request multiplexer,直接存儲器訪問請求復用器),本章知識點非常重要,是掌握好DMA1,DMA2和BDMA的關鍵一步。
39.1 初學者重要提示
39.2 DMAMUX基礎知識
39.3 DMAMUX的HAL庫用法
39.4 源文件stm32h7xx_hal_dma_ex.c
39.5 總結
39.1 初學者重要提示
- DMAMUX其實就是DMA控制器前一級的多路選擇器,有了這個選擇器就不用再像F1,F4系列那樣每個通道(數據流)要固定選擇指定的外設,有了多路選擇器就可以任意選擇,外設使用DMA方式時無需再選擇指定的DMA通道(數據流),任意通道(數據流)都可以。
39.2 DMAMUX基礎知識
當前STM32H7有兩路DMAMUX,分別是DMAMUX1和DMAMUX2,其中DMAMUX1負責DMA1和DMA2,而DMAMUX2負責BDMA。
39.2.1 DMAMUX和DMA的連接關系
認識一個外設,最好的方式就是看它的框圖,方便我們快速的了解DMAMUX的基本功能,然后再看手冊了解細節。首先來看下DMAMUX與DMA之間的連接方式,從整體上把握下,可以更好的理解DMAMUX的作用。
DMAMUX1有16個輸出通道,前8個通道分別連接DMA1 Stream0到Stream7,而后8個通道分別連接DMA2 Stream0到Stream7。上面DMAMUX1的前8路接到DMA1的8路數據流通道Stream0到Stream7中。
DMAMUX2有8個輸出通道,連接BDMA的8個輸入通道:
39.2.2 DMAMUX的硬件框圖
這個框圖對於理解DMAMUX至關重要。
通過這個框圖,我們可以得到如下信息:
- DMA requests from peripherals接口
對於DMAMUX1來說,這個接口支持107個DMA外設請求,供DMA1和DMA2的數據流使用:
#define DMA_REQUEST_ADC1 9U /*!< DMAMUX1 ADC1 request */ #define DMA_REQUEST_ADC2 10U /*!< DMAMUX1 ADC2 request */ #define DMA_REQUEST_TIM1_CH1 11U /*!< DMAMUX1 TIM1 CH1 request */ #define DMA_REQUEST_TIM1_CH2 12U /*!< DMAMUX1 TIM1 CH2 request */ #define DMA_REQUEST_TIM1_CH3 13U /*!< DMAMUX1 TIM1 CH3 request */ #define DMA_REQUEST_TIM1_CH4 14U /*!< DMAMUX1 TIM1 CH4 request */ #define DMA_REQUEST_TIM1_UP 15U /*!< DMAMUX1 TIM1 UP request */ #define DMA_REQUEST_TIM1_TRIG 16U /*!< DMAMUX1 TIM1 TRIG request */ #define DMA_REQUEST_TIM1_COM 17U /*!< DMAMUX1 TIM1 COM request */ 中間部分省略未寫 #define DMA_REQUEST_TIM16_CH1 109U /*!< DMAMUX1 TIM16 CH1 request */ #define DMA_REQUEST_TIM16_UP 110U /*!< DMAMUX1 TIM16 UP request */ #define DMA_REQUEST_TIM17_CH1 111U /*!< DMAMUX1 TIM17 CH1 request */ #define DMA_REQUEST_TIM17_UP 112U /*!< DMAMUX1 TIM17 UP request */ #define DMA_REQUEST_SAI3_A 113U /*!< DMAMUX1 SAI3 A request */ #define DMA_REQUEST_SAI3_B 114U /*!< DMAMUX1 SAI3 B request */ #define DMA_REQUEST_ADC3 115U /*!< DMAMUX1 ADC3 request */
對於DMAMUX2來說,這個接口支持9個DMA外設請求,供BDMA通道使用:
#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 */
這里特別注意一點,DMA1,DMA2和BDMA都支持存儲區到存儲區的傳輸。
- Trigger inputs接口
除了正常的DMA請求可以輸入到DMAMUX里面,通過設置觸發條件也可以生成DMA觸發請求。這樣就比較靈活了,不支持DMA的外設也可以通過Trigger inputs接口觸發DMA傳輸,比如我們可以將RAM中的數據通過定時器觸發直接輸出到GPIO,這樣就可以產生各種脈沖效果。
DMAMUX1支持8種觸發輸入,供DMA1和DMA2使用:
#define HAL_DMAMUX1_REQ_GEN_DMAMUX1_CH0_EVT 0U #define HAL_DMAMUX1_REQ_GEN_DMAMUX1_CH1_EVT 1U #define HAL_DMAMUX1_REQ_GEN_DMAMUX1_CH2_EVT 2U #define HAL_DMAMUX1_REQ_GEN_LPTIM1_OUT 3U #define HAL_DMAMUX1_REQ_GEN_LPTIM2_OUT 4U #define HAL_DMAMUX1_REQ_GEN_LPTIM3_OUT 5U #define HAL_DMAMUX1_REQ_GEN_EXTI0 6U #define HAL_DMAMUX1_REQ_GEN_TIM12_TRGO 7U
DMAMUX2支持的30種觸發輸入,供BDMA使用:
#define HAL_DMAMUX2_REQ_GEN_DMAMUX2_CH0_EVT 0U #define HAL_DMAMUX2_REQ_GEN_DMAMUX2_CH1_EVT 1U #define HAL_DMAMUX2_REQ_GEN_DMAMUX2_CH2_EVT 2U #define HAL_DMAMUX2_REQ_GEN_DMAMUX2_CH3_EVT 3U #define HAL_DMAMUX2_REQ_GEN_DMAMUX2_CH4_EVT 4U #define HAL_DMAMUX2_REQ_GEN_DMAMUX2_CH5_EVT 5U #define HAL_DMAMUX2_REQ_GEN_DMAMUX2_CH6_EVT 6U #define HAL_DMAMUX2_REQ_GEN_LPUART1_RX_WKUP 7U #define HAL_DMAMUX2_REQ_GEN_LPUART1_TX_WKUP 8U #define HAL_DMAMUX2_REQ_GEN_LPTIM2_WKUP 9U #define HAL_DMAMUX2_REQ_GEN_LPTIM2_OUT 10U #define HAL_DMAMUX2_REQ_GEN_LPTIM3_WKUP 11U #define HAL_DMAMUX2_REQ_GEN_LPTIM3_OUT 12U #define HAL_DMAMUX2_REQ_GEN_LPTIM4_WKUP 13U #define HAL_DMAMUX2_REQ_GEN_LPTIM5_WKUP 14U #define HAL_DMAMUX2_REQ_GEN_I2C4_WKUP 15U #define HAL_DMAMUX2_REQ_GEN_SPI6_WKUP 16U #define HAL_DMAMUX2_REQ_GEN_COMP1_OUT 17U #define HAL_DMAMUX2_REQ_GEN_COMP2_OUT 18U #define HAL_DMAMUX2_REQ_GEN_RTC_WKUP 19U #define HAL_DMAMUX2_REQ_GEN_EXTI0 20U #define HAL_DMAMUX2_REQ_GEN_EXTI2 21U #define HAL_DMAMUX2_REQ_GEN_I2C4_IT_EVT 22U #define HAL_DMAMUX2_REQ_GEN_SPI6_IT 23U #define HAL_DMAMUX2_REQ_GEN_LPUART1_TX_IT 24U #define HAL_DMAMUX2_REQ_GEN_LPUART1_RX_IT 25U #define HAL_DMAMUX2_REQ_GEN_ADC3_IT 26U #define HAL_DMAMUX2_REQ_GEN_ADC3_AWD1_OUT 27U #define HAL_DMAMUX2_REQ_GEN_BDMA_CH0_IT 28U #define HAL_DMAMUX2_REQ_GEN_BDMA_CH1_IT 29U
- Interrupt接口
用於觸發中斷。
- Synchronization inputs接口
同步輸入接口可以用來控制DMAMUX的輸入端的DMA外設請求到輸出端的同步控制,其實就是控制何時輸出。
DMAMUX1支持的8種同步輸入,供DMA1和DMA2使用:
#define HAL_DMAMUX1_SYNC_DMAMUX1_CH0_EVT 0U #define HAL_DMAMUX1_SYNC_DMAMUX1_CH1_EVT 1U #define HAL_DMAMUX1_SYNC_DMAMUX1_CH2_EVT 2U #define HAL_DMAMUX1_SYNC_LPTIM1_OUT 3U #define HAL_DMAMUX1_SYNC_LPTIM2_OUT 4U #define HAL_DMAMUX1_SYNC_LPTIM3_OUT 5U #define HAL_DMAMUX1_SYNC_EXTI0 6U #define HAL_DMAMUX1_SYNC_TIM12_TRGO 7U
DMAMUX2支持的16種同步輸入,供BDMA使用:
#define HAL_DMAMUX2_SYNC_DMAMUX2_CH0_EVT 0U #define HAL_DMAMUX2_SYNC_DMAMUX2_CH1_EVT 1U #define HAL_DMAMUX2_SYNC_DMAMUX2_CH2_EVT 2U #define HAL_DMAMUX2_SYNC_DMAMUX2_CH3_EVT 3U #define HAL_DMAMUX2_SYNC_DMAMUX2_CH4_EVT 4U #define HAL_DMAMUX2_SYNC_DMAMUX2_CH5_EVT 5U #define HAL_DMAMUX2_SYNC_LPUART1_RX_WKUP 6U #define HAL_DMAMUX2_SYNC_LPUART1_TX_WKUP 7U #define HAL_DMAMUX2_SYNC_LPTIM2_OUT 8U #define HAL_DMAMUX2_SYNC_LPTIM3_OUT 9U #define HAL_DMAMUX2_SYNC_I2C4_WKUP 10U #define HAL_DMAMUX2_SYNC_SPI6_WKUP 11U #define HAL_DMAMUX2_SYNC_COMP1_OUT 12U #define HAL_DMAMUX2_SYNC_RTC_WKUP 13U #define HAL_DMAMUX2_SYNC_EXTI0 14U #define HAL_DMAMUX2_SYNC_EXTI2 15U
- DMA Channels event接口
DMAMUX的事件輸出。
- DMA requests to DMA controllers接口
DMAMUX的輸出,發往DMA1,DMA2或者BDMA。
39.2.3 請求發生器(Request Generator)
請求觸發器最大的優勢就是可以讓不支持DMA傳輸的外設也可以通過Trigger inputs接口觸發DMA傳輸,比如我們可以將RAM中的數據通過定時器觸發直接輸出到GPIO,這樣就可以產生各種脈沖效果,這樣就比較靈活了。
這里我們再進一步的認識下請求發生器,通過下面框圖可以看出請求發生器有n個通道,並且每個通道都支持t個觸發。這里有一個關鍵知識點,所有這些通道可以選擇同一個觸發源。
了解了這些之后,我們要對它的工作過程有一個簡單的認識,看下面的時序圖:
- dmamux_req_gen信號請求發生器生成的DMA請求。
- dmamux_req_out信號是DMAMUX的輸出,供DMA1,DMA2或者BDMA使用。
- Request generator counter這個計數器比較重要,它的意思是一次dmamux_trg觸發信號,可以連續執行的DMA請求,最大32次。這里是以DMA可以執行的最快速度進行響應的。每執行一次,計數器減1,減到0后自動加載用戶設置的最大次數,等待下次觸發,依次進行。如果計數器還沒有減到0就再次觸發,請求發生器的中斷狀態寄存器DMAMUX_RGSR的標志將被置位,如果使能了中斷,將會被觸發。
- dmamux_trg信號是觸發源。
39.2.4 同步觸發和請求復用器(Request multiplexer)
同步輸入接口可以用來控制DMAMUX的輸入端的DMA外設請求到輸出端的同步控制,其實就是控制何時輸出。
這里我們再進一步的認識下請求復用器,從下面的框圖中可以看出請求發生器有m個通道,並且每個通道都支持n+p+2個DMA請求,但是每個通道不可以選擇相同的DMA請求。
特別注意紅色方框的地方,請求發生器的n個DMA請求和p個DMA外設請求全都匯集於此,可供這里的多路選擇器選擇。
了解了這些之后,我們要對它的工作過程有一個簡單的認識,看下面的時序圖:
下面連續同步三次的效果,每次產生4次DMA請求:
- dmamux_reqx信號是請求復用器的輸入端。
- dmamux_syncx是同步觸發信號。
- dmamux_req_outx信號是DMAMUX的輸出,供DMA1,DMA2或者BDMA使用。
- DMA request counter這個計數器比較重要,他的意思是一次dmamux_syncx觸發信號,可以連續執行的DMA請求,最大32次。這里是以DMA請求可以執行的最快速度進行響應的。每執行一次,計數器減1,減到0后自動加載用戶設置的最大次數,等待下次觸發,依次進行。如果計數器還沒有減到0就再次觸發,請求發生器的中斷狀態寄存器DMAMUX_CSR的標志將被置位,如果使能了中斷,將會被觸發。
- dmamux_evt信號是輸出事件。
39.2.5 正常的DMA請求方式
除了前面說的請求發生器產生的DMA請求和同步觸發產生的DMA請求,關閉了這兩種方式后也可以通過DMAMUX正常發出DMA請求的,這種情況和之前使用F1和F4系列是一樣的。
39.3 DMAMUX的HAL庫用法
DMAMUX的HAL庫用法其實就是幾個結構體變量成員的配置和使用,然后配置GPIO、時鍾,並根據需要配置NVIC、中斷和DMA。下面我們逐一展開為大家做個說明。
39.3.1 請求發生器結構體HAL_DMA_MuxRequestGeneratorConfigTypeDef
HAL_DMA_MuxRequestGeneratorConfigTypeDef的定義如下:
typedef struct { uint32_t SignalID; /*!< Specifies the ID of the signal used for DMAMUX request generator This parameter can be a value of @ref DMAEx_MUX_SignalGeneratorID_selection */ uint32_t Polarity; /*!< Specifies the polarity of the signal on which the request is generated. This parameter can be a value of @ref DMAEx_MUX_RequestGeneneratorPolarity_selection */ uint32_t RequestNumber; /*!< Specifies the number of DMA request that will be generated after a signal event. This parameters can be in the range 1 to 32 */ }HAL_DMA_MuxRequestGeneratorConfigTypeDef;
下面將這三個結構體成員一 一為大家做個說明。
- SingnalID
請求發生器的觸發源ID選擇,DMAMUX1可以選擇的觸發源ID如下:
#define HAL_DMAMUX1_REQ_GEN_DMAMUX1_CH0_EVT 0U #define HAL_DMAMUX1_REQ_GEN_DMAMUX1_CH1_EVT 1U #define HAL_DMAMUX1_REQ_GEN_DMAMUX1_CH2_EVT 2U #define HAL_DMAMUX1_REQ_GEN_LPTIM1_OUT 3U #define HAL_DMAMUX1_REQ_GEN_LPTIM2_OUT 4U #define HAL_DMAMUX1_REQ_GEN_LPTIM3_OUT 5U #define HAL_DMAMUX1_REQ_GEN_EXTI0 6U #define HAL_DMAMUX1_REQ_GEN_TIM12_TRGO 7U
DMAMUX2可以選擇的觸發源ID如下:
#define HAL_DMAMUX2_REQ_GEN_DMAMUX2_CH0_EVT 0U #define HAL_DMAMUX2_REQ_GEN_DMAMUX2_CH1_EVT 1U #define HAL_DMAMUX2_REQ_GEN_DMAMUX2_CH2_EVT 2U #define HAL_DMAMUX2_REQ_GEN_DMAMUX2_CH3_EVT 3U #define HAL_DMAMUX2_REQ_GEN_DMAMUX2_CH4_EVT 4U #define HAL_DMAMUX2_REQ_GEN_DMAMUX2_CH5_EVT 5U #define HAL_DMAMUX2_REQ_GEN_DMAMUX2_CH6_EVT 6U #define HAL_DMAMUX2_REQ_GEN_LPUART1_RX_WKUP 7U #define HAL_DMAMUX2_REQ_GEN_LPUART1_TX_WKUP 8U #define HAL_DMAMUX2_REQ_GEN_LPTIM2_WKUP 9U #define HAL_DMAMUX2_REQ_GEN_LPTIM2_OUT 10U #define HAL_DMAMUX2_REQ_GEN_LPTIM3_WKUP 11U #define HAL_DMAMUX2_REQ_GEN_LPTIM3_OUT 12U #define HAL_DMAMUX2_REQ_GEN_LPTIM4_WKUP 13U #define HAL_DMAMUX2_REQ_GEN_LPTIM5_WKUP 14U #define HAL_DMAMUX2_REQ_GEN_I2C4_WKUP 15U #define HAL_DMAMUX2_REQ_GEN_SPI6_WKUP 16U #define HAL_DMAMUX2_REQ_GEN_COMP1_OUT 17U #define HAL_DMAMUX2_REQ_GEN_COMP2_OUT 18U #define HAL_DMAMUX2_REQ_GEN_RTC_WKUP 19U #define HAL_DMAMUX2_REQ_GEN_EXTI0 20U #define HAL_DMAMUX2_REQ_GEN_EXTI2 21U #define HAL_DMAMUX2_REQ_GEN_I2C4_IT_EVT 22U #define HAL_DMAMUX2_REQ_GEN_SPI6_IT 23U #define HAL_DMAMUX2_REQ_GEN_LPUART1_TX_IT 24U #define HAL_DMAMUX2_REQ_GEN_LPUART1_RX_IT 25U #define HAL_DMAMUX2_REQ_GEN_ADC3_IT 26U #define HAL_DMAMUX2_REQ_GEN_ADC3_AWD1_OUT 27U #define HAL_DMAMUX2_REQ_GEN_BDMA_CH0_IT 28U #define HAL_DMAMUX2_REQ_GEN_BDMA_CH1_IT 29U
- Polarity
觸發信號的極性設置,可以是上升沿觸發、下降沿觸發或者雙沿觸發。
#define HAL_DMAMUX_REQ_GEN_NO_EVENT 0x00000000U #define HAL_DMAMUX_REQ_GEN_RISING DMAMUX_RGxCR_GPOL_0 #define HAL_DMAMUX_REQ_GEN_FALLING DMAMUX_RGxCR_GPOL_1 #define HAL_DMAMUX_REQ_GEN_RISING_FALLING DMAMUX_RGxCR_GPOL
- RequestNumber
每次觸發信號后,可以執行的DMA請求次數,這個在本章的2.3小節已經進行了詳細說明。
39.3.2 同步觸發結構體HAL_DMA_MuxSyncConfigTypeDef
HAL_DMA_MuxSyncConfigTypeDef的定義如下::
typedef struct { uint32_t SyncSignalID; uint32_t SyncPolarity; FunctionalState SyncEnable; FunctionalState EventEnable; uint32_t RequestNumber; }HAL_DMA_MuxSyncConfigTypeDef;
下面將這五個結構體成員一 一為大家做個說明。
- SyncSingnalID
同步觸發源的ID選擇,DMAMUX1可以選擇的觸發源ID如下:
#define HAL_DMAMUX1_SYNC_DMAMUX1_CH0_EVT 0U #define HAL_DMAMUX1_SYNC_DMAMUX1_CH1_EVT 1U #define HAL_DMAMUX1_SYNC_DMAMUX1_CH2_EVT 2U #define HAL_DMAMUX1_SYNC_LPTIM1_OUT 3U #define HAL_DMAMUX1_SYNC_LP TIM2_OUT 4U #define HAL_DMAMUX1_SYNC_LPTIM3_OUT 5U #define HAL_DMAMUX1_SYNC_EXTI0 6U #define HAL_DMAMUX1_SYNC_TIM12_TRGO 7U
DMAMUX2可以選擇的觸發源ID如下:
#define HAL_DMAMUX2_SYNC_DMAMUX2_CH0_EVT 0U #define HAL_DMAMUX2_SYNC_DMAMUX2_CH1_EVT 1U #define HAL_DMAMUX2_SYNC_DMAMUX2_CH2_EVT 2U #define HAL_DMAMUX2_SYNC_DMAMUX2_CH3_EVT 3U #define HAL_DMAMUX2_SYNC_DMAMUX2_CH4_EVT 4U #define HAL_DMAMUX2_SYNC_DMAMUX2_CH5_EVT 5U #define HAL_DMAMUX2_SYNC_LPUART1_RX_WKUP 6U #define HAL_DMAMUX2_SYNC_LPUART1_TX_WKUP 7U #define HAL_DMAMUX2_SYNC_LPTIM2_OUT 8U #define HAL_DMAMUX2_SYNC_LPTIM3_OUT 9U #define HAL_DMAMUX2_SYNC_I2C4_WKUP 10U #define HAL_DMAMUX2_SYNC_SPI6_WKUP 11U #define HAL_DMAMUX2_SYNC_COMP1_OUT 12U #define HAL_DMAMUX2_SYNC_RTC_WKUP 13U #define HAL_DMAMUX2_SYNC_EXTI0 14U #define HAL_DMAMUX2_SYNC_EXTI2 15U
- SyncPolarity
同步觸發信號的極性設置,可以是上升沿觸發、下降沿觸發或者雙沿觸發。
#define HAL_DMAMUX_SYNC_NO_EVENT 0x00000000U #define HAL_DMAMUX_SYNC_RISING DMAMUX_CxCR_SPOL_0 #define HAL_DMAMUX_SYNC_FALLING DMAMUX_CxCR_SPOL_1 #define HAL_DMAMUX_SYNC_RISING_FALLING DMAMUX_CxCR_SPOL
- SyncEnable
用於使能同步觸發,參數可以是ENABLE 或者 DISABLE。
- EventEnable
同步觸發事件輸出使能,當參數RequestNumber的數值減到0的時候才會輸出。
- RequestNumber
每次同步觸發信號后,可以執行的DMA請求次數,這個在本章的2.4小節已經進行了詳細說明。
39.3.3 DMAMUX的狀態標志清除問題
DMAMUX有兩個中斷,一個是請求復用器通道發生同步事件溢出,另一個是請求發生器通道發生觸發事件溢出。
當用戶調用了函數HAL_DMA_Start_IT,程序代碼中會根據用戶是否使能了請求復用器或者請求發生器通道來使能這兩個中斷。
HAL_StatusTypeDef HAL_DMA_Start_IT(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength) { /* 省略未寫 */ if((hdma->DMAmuxChannel->CCR & DMAMUX_CxCR_SE) != 0U) { /* 使能同步溢出中斷 */ hdma->DMAmuxChannel->CCR |= DMAMUX_CxCR_SOIE; } if(hdma->DMAmuxRequestGen != 0U) { /* 使能請求發生器的溢出中斷 */ hdma->DMAmuxRequestGen->RGCR |= DMAMUX_RGxCR_OIE; } /* 省略未寫 */ }
這兩個中斷產生的中斷標志是在函數HAL_DMAEx_MUX_IRQHandler里面做的清除,如果大家不使用HAL庫提供的這個中斷處理函數,就需要自己編寫代碼清除。
void HAL_DMAEx_MUX_IRQHandler(DMA_HandleTypeDef *hdma) { /* 檢測DMAMUX同步溢出 */ if((hdma->DMAmuxChannelStatus->CSR & hdma->DMAmuxChannelStatusMask) != 0U) { /* 禁止同步溢出中斷 */ hdma->DMAmuxChannel->CCR &= ~DMAMUX_CxCR_SOIE; /* 清除DMAMUX同步溢出標志 */ hdma->DMAmuxChannelStatus->CFR = hdma->DMAmuxChannelStatusMask; /* Update error code */ hdma->ErrorCode |= HAL_DMA_ERROR_SYNC; if(hdma->XferErrorCallback != NULL) { /* 回調函數 */ hdma->XferErrorCallback(hdma); } } if(hdma->DMAmuxRequestGen != 0) { /* 檢測請求發生器溢出 */ if((hdma->DMAmuxRequestGenStatus->RGSR & hdma->DMAmuxRequestGenStatusMask) != 0U) { /* 禁止請求發生器溢出中斷 */ hdma->DMAmuxRequestGen->RGCR &= ~DMAMUX_RGxCR_OIE; /* 清除DMAMUX請求發生器溢出標志 */ hdma->DMAmuxRequestGenStatus->RGCFR = hdma->DMAmuxRequestGenStatusMask; /* 更新錯誤代碼標識 */ hdma->ErrorCode |= HAL_DMA_ERROR_REQGEN; if(hdma->XferErrorCallback != NULL) { /* 回調函數 */ hdma->XferErrorCallback(hdma); } } } }
39.3.4 DMAMUX初始化流程總結
DMAMUX沒有單獨的初始化流程,要結合第40章和42章的函數一起使用。
39.4 源文件stm32h7xx_hal_dma_ex.c
DMAMUX用到如下四個說明,這里把這四個函數的使用為大家做個說明:
- HAL_DMAEx_ConfigMuxSync
- HAL_DMAEx_ConfigMuxRequestGenerator
- HAL_DMAEx_EnableMuxRequestGenerator
- HAL_DMAEx_DisableMuxRequestGenerator
39.4.1 函數HAL_DMAEx_ConfigMuxSync
函數原型:
HAL_StatusTypeDef HAL_DMAEx_ConfigMuxSync(DMA_HandleTypeDef *hdma, HAL_DMA_MuxSyncConfigTypeDef *pSyncConfig) { uint32_t syncSignalID = 0; uint32_t syncPolarity = 0; /* 檢測參數 */ assert_param(IS_DMA_STREAM_ALL_INSTANCE(hdma->Instance)); assert_param(IS_DMAMUX_SYNC_STATE(pSyncConfig->SyncEnable)); assert_param(IS_DMAMUX_SYNC_EVENT(pSyncConfig->EventEnable)); assert_param(IS_DMAMUX_SYNC_REQUEST_NUMBER(pSyncConfig->RequestNumber)); /* 檢測是否使能了同步觸發 */ if(pSyncConfig->SyncEnable == ENABLE) { assert_param(IS_DMAMUX_SYNC_POLARITY(pSyncConfig->SyncPolarity)); if(IS_D2_DMA_INSTANCE(hdma) != 0U) { assert_param(IS_D2_DMAMUX_SYNC_SIGNAL_ID(pSyncConfig->SyncSignalID)); } else { assert_param(IS_D3_DMAMUX_SYNC_SIGNAL_ID(pSyncConfig->SyncSignalID)); } syncSignalID = pSyncConfig->SyncSignalID; syncPolarity = pSyncConfig->SyncPolarity; } /* 檢測DMA是否處於就緒態 */ if(hdma->State == HAL_DMA_STATE_READY) { /* 上鎖 */ __HAL_LOCK(hdma); /* 應用新的配置前禁止同步和產生同步事件 */ CLEAR_BIT(hdma->DMAmuxChannel->CCR,(DMAMUX_CxCR_SE | DMAMUX_CxCR_EGE)); /* 配置新的參數,同時DMAMUX_CxCR_DMAREQ_ID 位保持不變 */ MODIFY_REG( hdma->DMAmuxChannel->CCR, \ (~DMAMUX_CxCR_DMAREQ_ID) , \ (syncSignalID << POSITION_VAL(DMAMUX_CxCR_SYNC_ID)) | \ ((pSyncConfig->RequestNumber - 1U) << POSITION_VAL(DMAMUX_CxCR_NBREQ)) | \ syncPolarity | (pSyncConfig->SyncEnable << DMAMUX_POSITION_CxCR_SE) | \ (pSyncConfig->EventEnable << DMAMUX_POSITION_CxCR_EGE)); /* 開鎖 */ __HAL_UNLOCK(hdma); return HAL_OK; } else { /* 設置錯誤標志 */ hdma->ErrorCode = HAL_DMA_ERROR_BUSY; /* 返回狀態HAL_ERROR */ return HAL_ERROR; } }
函數描述:
此函數用於配置DMAMUX的同步觸發,可以用來控制DMAMUX的輸入端的DMA外設請求到輸出端的同步控制,其實就是控制何時輸出。
函數參數:
- 第1個參數是DMA_HandleTypeDef類型結構體指針變量,用於配置DMA的初始化參數。
- 第2個參數是HAL_DMA_MuxSyncConfigTypeDef類型結構體變量,參數成員的含義在本章的3.2小節有講解說明。
- 返回值,返回HAL_ERROR表示配置失敗,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示時間溢出。
注意事項:
- 第1個參數的結構體成員介紹在第40章進行了講解。
- 調用此函數前要先調用函數HAL_DMA_Init配置好DMA。
使用舉例:
此函數的舉例可以看此貼:
http://www.armbbs.cn/forum.php?mod=viewthread&tid=88925 。
39.4.2 函數HAL_DMAEx_ConfigMuxRequestGenerator
函數原型:
HAL_StatusTypeDef HAL_DMAEx_ConfigMuxRequestGenerator (DMA_HandleTypeDef *hdma, HAL_DMA_MuxRequestGeneratorConfigTypeDef *pRequestGeneratorConfig) { HAL_StatusTypeDef status = HAL_OK; /* 檢查參數 */ assert_param(IS_DMA_STREAM_ALL_INSTANCE(hdma->Instance)); if(IS_D2_DMA_INSTANCE(hdma) != 0U) { assert_param(IS_D2_DMAMUX_REQUEST_GEN_SIGNAL_ID(pRequestGeneratorConfig->SignalID)); } else { assert_param(IS_D3_DMAMUX_REQUEST_GEN_SIGNAL_ID(pRequestGeneratorConfig->SignalID)); } assert_param(IS_DMAMUX_REQUEST_GEN_POLARITY(pRequestGeneratorConfig->Polarity)); assert_param(IS_DMAMUX_REQUEST_GEN_REQUEST_NUMBER(pRequestGeneratorConfig->RequestNumber)); /* 如果DMA配置中未使用DMAMUX的請求發生器,返回HAL_ERROR */ if(hdma->DMAmuxRequestGen == 0U) { /* 設置參數錯誤 */ hdma->ErrorCode = HAL_DMA_ERROR_PARAM; /* 設置錯誤狀態 */ status = HAL_ERROR; } /* 必須保證請求發生器是關閉的才可以配置 */ else if((hdma->State == HAL_DMA_STATE_READY) && ((hdma->DMAmuxRequestGen->RGCR & DMAMUX_RGxCR_GE) == 0)) { /* 上鎖 */ __HAL_LOCK(hdma); /* 設置新參數 */ hdma->DMAmuxRequestGen->RGCR = pRequestGeneratorConfig->SignalID | \ ((pRequestGeneratorConfig->RequestNumber - 1U) << POSITION_VAL(DMAMUX_RGxCR_NBREQ))| \ pRequestGeneratorConfig->Polarity; /* 解鎖 */ __HAL_UNLOCK(hdma); return HAL_OK; } else { /* 設置錯誤標志 */ hdma->ErrorCode = HAL_DMA_ERROR_BUSY; /* 設置錯誤狀態 */ status = HAL_ERROR; } return status; }
函數描述:
此函數用於配置DMAMUX的發生器。請求觸發器最大的優勢就是可以讓不支持DMA傳輸的外設也可以通過Trigger inputs接口觸發DMA傳輸,比如我們可以將RAM中的數據通過定時器觸發直接輸出到GPIO,就可以產生各種脈沖效果,這樣就比較靈活了。
函數參數:
- 第1個參數是DMA_HandleTypeDef類型結構體指針變量,用於配置DMA的初始化參數。
- 第2個參數是HAL_DMA_MuxRequestGeneratorConfigTypeDef f類型結構體變量,參數成員的含義在本章的3.1小節有講解說明。
- 返回值,返回HAL_ERROR表示配置失敗,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示時間溢出。
注意事項:
- 第1個參數的結構體成員介紹在第40章進行了講解。
- 調用此函數前要先調用函數HAL_DMA_Init配置好DMA。
使用舉例:
HAL_DMA_MuxRequestGeneratorConfigTypeDef dmamux_ReqGenParams ={0} 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請求發生器 */
39.4.3 函數HAL_DMAEx_EnableMuxRequestGenerator
函數原型:
HAL_StatusTypeDef HAL_DMAEx_EnableMuxRequestGenerator (DMA_HandleTypeDef *hdma) { /* 檢測參數 */ assert_param(IS_DMA_STREAM_ALL_INSTANCE(hdma->Instance)); /* 如果DMA配置中使用了DMAMUX的請求發生器,則將其使能並返回HAL_OK */ if((hdma->State != HAL_DMA_STATE_RESET) && (hdma->DMAmuxRequestGen != 0U)) { /* 使能請求發生器 */ hdma->DMAmuxRequestGen->RGCR |= DMAMUX_RGxCR_GE; return HAL_OK; } else { return HAL_ERROR; } }
函數描述:
調用函數HAL_DMAEx_ConfigMuxRequestGenerator配置了請求發生器后,就可以調用此函數使能請求發生器。跟禁止函數HAL_DMAEx_DisableMuxRequestGenerator是一對。
函數參數:
- 第1個參數是DMA_HandleTypeDef類型結構體指針變量。
- 返回值,返回HAL_ERROR表示配置失敗,HAL_OK表示配置成功,HAL_BUSY表示忙(操作中),HAL_TIMEOUT表示時間溢出。
使用舉例:
HAL_DMA_MuxRequestGeneratorConfigTypeDef dmamux_ReqGenParams ={0} 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請求發生器 */
39.4.4 函數HAL_DMAEx_DisableMuxRequestGenerator
函數原型:
HAL_StatusTypeDef HAL_DMAEx_DisableMuxRequestGenerator (DMA_HandleTypeDef *hdma) { /* 檢查參數 */ assert_param(IS_DMA_STREAM_ALL_INSTANCE(hdma->Instance)); /* 如果DMA配置中使用了DMAMUX的請求發生器,則將其禁止並返回HAL_OK */ if((hdma->State != HAL_DMA_STATE_RESET) && (hdma->DMAmuxRequestGen != 0U)) { /* 禁止請求發生器 */ hdma->DMAmuxRequestGen->RGCR &= ~DMAMUX_RGxCR_GE; return HAL_OK; } else { return HAL_ERROR; } }
函數描述:
此函數用於禁止請求發生器,跟使能函數HAL_DMAEx_EnableMuxRequestGenerator是一對,
函數參數:
- 第1個參數是DMA_HandleTypeDef類型結構體指針變量。
使用舉例:
此函數跟前面的HAL_DMAEx_EnableMuxRequestGenerator是一對,使用時直接調用即可。
39.5 總結
本章節就為大家講解這么多,DMXMUX用到的地方比較多,這幾個常用的函數要熟練掌握。