完整教程下载地址: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用到的地方比较多,这几个常用的函数要熟练掌握。