STM32 HAL DMA中断配置

本文详细介绍了在STM32G030芯片上使用STM32HAL库进行I2C通信时,如何配置DMA并启用中断,包括MXCUBE配置、DMA初始化、I2C初始化和中断通信过程的详细步骤。
摘要由CSDN通过智能技术生成

前言

使用HAL库方式DMA中断时,在网上找了好多资料都没有怎么介绍。所以就自己研究了一下,并做个记录。我的芯片型号是STM32G030。下面我以I2C传数据为例介绍下HAL库是如何使用DMA中断的。

MXCUBE配置

我使用的是I2C2,简单配置下参数,加上DMA通道。
在这里插入图片描述
在这里插入图片描述
DMA貌似默认开启了中断,蓝色的勾勾是我自己勾上的,没有用到I2C的中断不勾也可以。
在这里插入图片描述

DMA初始化

打开工程后主函数里有个MX_DMA_Init();它的内部就是开启DMA的RCC和NVIC,这里就不放图了。

I2C初始化

打开这个文件的第一眼,看到最上端的全局变量hdma_i2c2_rx和hdma_i2c2_tx,实际上DMA的初始化我更感觉是放在这里的。

I2C_HandleTypeDef hi2c2;
DMA_HandleTypeDef hdma_i2c2_rx;
DMA_HandleTypeDef hdma_i2c2_tx;

I2C的初始化我直接略过,和只用I2C通讯配置没区别。拉到最下边的函数HAL_I2C_MspInit

	/* I2C2 DMA Init */
    /* I2C2_RX Init */
    hdma_i2c2_rx.Instance = DMA1_Channel1;
    hdma_i2c2_rx.Init.Request = DMA_REQUEST_I2C2_RX;
    hdma_i2c2_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
    hdma_i2c2_rx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_i2c2_rx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_i2c2_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_i2c2_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_i2c2_rx.Init.Mode = DMA_NORMAL;
    hdma_i2c2_rx.Init.Priority = DMA_PRIORITY_LOW;
    if (HAL_DMA_Init(&hdma_i2c2_rx) != HAL_OK)
    {
      Error_Handler();
    }

    __HAL_LINKDMA(i2cHandle,hdmarx,hdma_i2c2_rx);
        /* I2C2_TX Init */
    hdma_i2c2_tx.Instance = DMA1_Channel2;
    hdma_i2c2_tx.Init.Request = DMA_REQUEST_I2C2_TX;
    hdma_i2c2_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
    hdma_i2c2_tx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_i2c2_tx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_i2c2_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_i2c2_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_i2c2_tx.Init.Mode = DMA_NORMAL;
    hdma_i2c2_tx.Init.Priority = DMA_PRIORITY_LOW;
    if (HAL_DMA_Init(&hdma_i2c2_tx) != HAL_OK)
    {
      Error_Handler();
    }

    __HAL_LINKDMA(i2cHandle,hdmatx,hdma_i2c2_tx);

这里实际上跟I2C+DMA通信也没什么区别。

I2C+DMA+中断通信过程

在我看了他的驱动函数后,我发现只要是后缀带有DMA的函数,都自动有DMA中断的处理过程。有这几个函数:

  • HAL_I2C_Mem_Write_DMA
  • HAL_I2C_Master_Receive_DMA
  • HAL_I2C_Master_Seq_Receive_DMA
  • HAL_I2C_Master_Seq_Transmit_DMA
  • HAL_I2C_Master_Transmit_DMA
  • HAL_I2C_Mem_Read_DMA
  • HAL_I2C_Mem_Write_DMA
  • HAL_I2C_Slave_Receive_DMA

我随便点开一个HAL_I2C_Mem_Write_DMA,这几个都是差不多,只是用途不一样,带Mem的方便与EEPROM类似的通讯,他需要发从机的设备地址和内存地址,就可以用这个。
在该函数内我只列出我觉得重要的代码,

  1. hi2c->XferISR用于绑定中断处理函数

    hi2c->XferISR     = I2C_Master_ISR_DMA;
    
  2. 这里dma绑定了相关的传输处理函数,传输完成和传输错误,然后开启DMA的中断使能,当传输完成后就会进入I2C_DMAMasterTransmitCplt。

    if (hi2c->hdmatx != NULL)
    {
      /* Set the I2C DMA transfer complete callback */
      hi2c->hdmatx->XferCpltCallback = I2C_DMAMasterTransmitCplt;
    
      /* Set the DMA error callback */
      hi2c->hdmatx->XferErrorCallback = I2C_DMAError;
    
      /* Set the unused DMA callbacks to NULL */
      hi2c->hdmatx->XferHalfCpltCallback = NULL;
      hi2c->hdmatx->XferAbortCallback = NULL;
    
      /* Enable the DMA channel */
      dmaxferstatus = HAL_DMA_Start_IT(hi2c->hdmatx, (uint32_t)pData, (uint32_t)&hi2c->Instance->TXDR, hi2c->XferSize);
    }
    
  3. 该函数最后开启DMA搬运。

    /* Enable DMA Request */
      hi2c->Instance->CR1 |= I2C_CR1_TXDMAEN;
    

最后是通讯过程的DMA中断了,当触发了DMA的中断类型就会进入该函数,就只有三种传输完成一半、传输完成以及传输错误。

void DMA1_Channel1_IRQHandler(void)
{
  /* USER CODE BEGIN DMA1_Channel1_IRQn 0 */

  /* USER CODE END DMA1_Channel1_IRQn 0 */
  HAL_DMA_IRQHandler(&hdma_i2c2_rx);
  /* USER CODE BEGIN DMA1_Channel1_IRQn 1 */

  /* USER CODE END DMA1_Channel1_IRQn 1 */
}

进入到HAL_DMA_IRQHandler,假设触发了传输完成,就会执行相应关闭DMA中断、清空DMA中断标志位最后调用传输完成的回调函数。

	...
	if ((hdma->Instance->CCR & DMA_CCR_CIRC) == 0U)
      {
        /* Disable the transfer complete and error interrupt */
        __HAL_DMA_DISABLE_IT(hdma, DMA_IT_TE | DMA_IT_TC);

        /* Change the DMA state */
        hdma->State = HAL_DMA_STATE_READY;
      }
      /* Clear the transfer complete flag */
      __HAL_DMA_CLEAR_FLAG(hdma, (DMA_FLAG_TC1 << (hdma->ChannelIndex & 0x1CU)));

      /* Process Unlocked */
      __HAL_UNLOCK(hdma);

      if (hdma->XferCpltCallback != NULL)
      {
        /* Transfer complete callback */
        hdma->XferCpltCallback(hdma);
      }
    }
    ...

这个hdma->XferCpltCallback()函数指针在我们在开始时就赋值了

 /* Set the I2C DMA transfer complete callback */
  hi2c->hdmatx->XferCpltCallback = I2C_DMAMasterTransmitCplt;

进入到该函数发现关闭了I2C的DMA请求

/* Disable DMA Request */
  hi2c->Instance->CR1 &= ~I2C_CR1_TXDMAEN;

但是函数内我并没有找到用户可以自定义的回调函数,可供我们自己使用。我自己在里边加入了些代码,实测发现是可以进去的。

总结

最后总结HAL库方式的DMA中断默认就是开启状态,只是没有给用户开启自定义回调函数使用,也不知道是没必要还是我没找到。

  • 28
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
STM32F 系列的空闲中断 DMA HAL 是什么? STM32F 系列是意法半导体公司(STMicroelectronics)推出的一系列32位的嵌入式微控制器。空闲中断是其中一种中断类型,当 CPU 空闲时会触发该中断DMA(Direct Memory Access)是一种数据传输方式,允许数据在外设和内存之间直接传输,减少 CPU 的负担。HAL(Hardware Abstraction Layer)是一个软件,提供了对硬件设备的抽象接口,简化了开发过程。 空闲中断 DMA HAL 是一种实现空闲中断DMA 功能的软件。它结合了空闲中断DMA,提供了一种高效的数据传输方式。当 CPU 空闲时,可以通过空闲中断来触发 DMA 数据传输操作,从而实现高速、低延迟的数据传输。使用这个,开发人员可以简化数据传输的编程过程,提高系统性能和效率。 使用 STM32F 系列的空闲中断 DMA HAL ,开发人员可以通过简单的函数调用来配置和使用空闲中断DMA 功能。首先,需要初始化空闲中断DMA 模块,并设置相应的中断处理函数。然后,可以配置和启动 DMA 传输,指定数据源和目的地的地址以及数据长度。在配置完毕后,当 CPU 空闲时,会触发空闲中断并启动 DMA 传输。最后,可以在中断处理函数中进行数据处理或其他操作。 总结而言,STM32F 系列的空闲中断 DMA HAL 是一种方便、高效的数据传输解决方案。它结合了空闲中断DMA 功能,提供了简化的编程接口,使开发人员能够更轻松地使用这些功能,并提高系统的性能和效率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值