STM32 DMAMUX模块的初步学习

前言

        在做项目时我使用的板子是STM32G0x0系列的,做到有关DMA模块就感觉和以前的F1系列使用上不一样,F1的DMA通道是固定的,每个通道都只能设置固定的外设模块,但G0X0系列的DMA就没有该限制,再使用CUBEMX开发时发现任何模块你都可以使用任意DMA通道来传输,而做到这个功能的就是DMAMUX模块。我这里就不解释这个东西的原理了,我看了几遍也没怎么理解这个东西,我只说说这个东西是怎么配合DMA使用的。

正文

/* SPI1_TX Init */
    hdma_spi1_tx.Instance = DMA1_Channel3;
    hdma_spi1_tx.Init.Request = DMA_REQUEST_SPI1_TX; //为SPI1_TX配置DMA通道
    hdma_spi1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
    hdma_spi1_tx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_spi1_tx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_spi1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_spi1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_spi1_tx.Init.Mode = DMA_NORMAL;
    hdma_spi1_tx.Init.Priority = DMA_PRIORITY_LOW;
    if (HAL_DMA_Init(&hdma_spi1_tx) != HAL_OK)
    {
      Error_Handler();
    }

        我的项目是用SPI+DMA的方式通信,上面是用CUBEMX生成的代码,把SPI1的发送接到DMA通道上。其他的参数都是配置DMA模式的,对本文意义不大,主要是探讨DMA通道的搭建。

        进入初始化函数后首先是一堆的参数检查函数,但点开是下图这样的,没什么用,估计是要开启什么选项才会开启参数检查吧。 

        然后是下图DMA2部分的内容,我没有了解,不过全是灰灰的一片,估计没有这个宏定义,可能是其他型号芯片的内容。用VScode这一点就是方便啊,直接帮我忽略掉无用的代码。

        遇到了第一行有用的代码,直接直译就是根据根据前面选的通道几,把这个值相应的设置为几。我选的是DMA1_Channel3,对照着宏的值计算,写的简约点就是ChannelIndex = (3-1)<<2;

#define DMA1_Channel1       ((DMA_Channel_TypeDef *) DMA1_Channel1_BASE) //0x40020008
#define DMA1_Channel2       ((DMA_Channel_TypeDef *) DMA1_Channel2_BASE) //0x4002001C
#define DMA1_Channel3       ((DMA_Channel_TypeDef *) DMA1_Channel3_BASE) //0x40020030
#define DMA1_Channel4       ((DMA_Channel_TypeDef *) DMA1_Channel4_BASE) //0x40020044
#define DMA1_Channel5       ((DMA_Channel_TypeDef *) DMA1_Channel5_BASE) //0x40020058
hdma->ChannelIndex = (((uint32_t)hdma->Instance - (uint32_t)DMA1_Channel1) / ((uint32_t)DMA1_Channel2 - (uint32_t)DMA1_Channel1)) << 2U;

        下面这部分就是设置开始配置的DMA各个参数了,然后写到相应DMA通道的CCR寄存器。 

  /* Clear PL, MSIZE, PSIZE, MINC, PINC, CIRC, DIR and MEM2MEM bits */
  CLEAR_BIT(hdma->Instance->CCR, (DMA_CCR_PL    | DMA_CCR_MSIZE  | DMA_CCR_PSIZE  | \
                                  DMA_CCR_MINC  | DMA_CCR_PINC   | DMA_CCR_CIRC   | \
                                  DMA_CCR_DIR   | DMA_CCR_MEM2MEM));

  /* Set the DMA Channel configuration */
  SET_BIT(hdma->Instance->CCR, (hdma->Init.Direction           |                               \
                                hdma->Init.PeriphInc           | hdma->Init.MemInc           | \
                                hdma->Init.PeriphDataAlignment | hdma->Init.MemDataAlignment | \
                                hdma->Init.Mode                | hdma->Init.Priority));

         看注释了解,这个函数初始化了一些需要用到的参数。

/* Initialize parameters for DMAMUX channel :
     DMAmuxChannel, DMAmuxChannelStatus and DMAmuxChannelStatusMask
  */
  DMA_CalcDMAMUXChannelBaseAndMask(hdma);

 进入后发现这个函数主要是更新了几个参数。第一个DMAmuxChannel,这个参数貌似就是说DMAMUX也有五个通道,分别依次连接了DMA的五个通道。参照着宏定义来看,唯一的变量就是ChannelIndex,这个是不是我们之前算的 (3-1)<<2 啊,这里又给右移回去了,所以DMAmuxChannel =  0x04 * x (x = 0 to 4),x就是DMA通道1~5.

channel_number 的值就是0~4,对应DMA通道1~5。

DMAmuxChannelStatus 这个变量我不是很理解,通道状态等于DMAMUX1_ChannelStatus,这是个固定值,就是0x40020880这个地址的值,也就是下面第三张图的寄存器。

DMAmuxChannelStatusMask 最后这个就不用解释了。

#define DMAMUX1            ((DMAMUX_Channel_TypeDef *) DMAMUX1_BASE) //0x40020800
#define DMAMUX1_Channel0   ((DMAMUX_Channel_TypeDef *) DMAMUX1_Channel0_BASE)//DMAMUX1+0
#define DMAMUX1_Channel1   ((DMAMUX_Channel_TypeDef *) DMAMUX1_Channel1_BASE)//DMAMUX1+4
#define DMAMUX1_Channel2   ((DMAMUX_Channel_TypeDef *) DMAMUX1_Channel2_BASE)//DMAMUX1+8
#define DMAMUX1_Channel3   ((DMAMUX_Channel_TypeDef *) DMAMUX1_Channel3_BASE)//DMAMUX1+C
#define DMAMUX1_Channel4   ((DMAMUX_Channel_TypeDef *) DMAMUX1_Channel4_BASE)//DMAMUX1+10
/* Associate a DMA Channel to a DMAMUX channel */
  hdma->DMAmuxChannel = (DMAMUX_Channel_TypeDef *)(uint32_t)((uint32_t)DMAMUX1_Channel0 + ((hdma->ChannelIndex >> 2U) * ((uint32_t)DMAMUX1_Channel1 - (uint32_t)DMAMUX1_Channel0)));

  /* Prepare channel_number used for DMAmuxChannelStatusMask computation */
  channel_number = (((uint32_t)hdma->Instance & 0xFFU) - 8U) / 20U;
#endif

  /* Initialize the field DMAmuxChannelStatus to DMAMUX1_ChannelStatus base */
  hdma->DMAmuxChannelStatus = DMAMUX1_ChannelStatus;

  /* Initialize the field DMAmuxChannelStatusMask with the corresponding index of the DMAMUX channel selected for the current ChannelIndex */
  hdma->DMAmuxChannelStatusMask = 1UL << (channel_number & 0x1FU);

        下面这个就是最重要的部分了,将DMAMUX的通道的一头连接到外设上。这里我们就搞完了DMAMUX通道的两头了,一头连接外设,一头连接DMA。

Request 的值一开始配置的时候设置好的,为SPI的TX请求。这部分的宏太多只截取了一部分。

CCR就是下面官方图的CXCR,这个X就是每个DMAMUX通道都有这个寄存器的意思。

/* Set peripheral request  to DMAMUX channel */
  hdma->DMAmuxChannel->CCR = (hdma->Init.Request & DMAMUX_CxCR_DMAREQ_ID);

总结

        至此就结束了我对DMAMUX的理解,总之就是这部分被归到了DMA部分,属于是从原来的DMA--外设,到现在的DMA--DMAMUX--外设。最后DMA初始化还有一部分,如果当你将DMA请求设置为下面几个宏,就会还有一部分设置。这部分我没用过不是很了解,看文档感觉像是为了一些没有DMA功能的东西准备的。

#define DMA_REQUEST_GENERATOR0       LL_DMAMUX_REQ_GENERATOR0
#define DMA_REQUEST_GENERATOR1       LL_DMAMUX_REQ_GENERATOR1
#define DMA_REQUEST_GENERATOR2       LL_DMAMUX_REQ_GENERATOR2
#define DMA_REQUEST_GENERATOR3       LL_DMAMUX_REQ_GENERATOR3

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值