基于HAL库的STM32以DMA方式实现的连续发送

文章目录

    • 〇、什么是DMA?
      • 1. 概念
      • 2. **DMA**的数据传输四要素
      • 3. DMA控制器特点
      • 4. 数据传输方式
      • 5. HAL库DMA发送函数
    • 一、STM32CubeMX创建项目
    • 二、Keil编译代码
    • 三、实际效果
    • 四、总结
    • 五、参考文章

〇、什么是DMA?

1. 概念

直接存储器访问(DMA): 用于在外设与存储器之间以及存储器与存储器之间进行高速数据传输。DMA传输过程的初始化和启动由CPU完成,传输过程由DMA控制器来执行,无需CPU参与,从而节省CPU资源,提高利用率。

2. DMA的数据传输四要素

  • 传输源:DMA数据传输的来源

  • 传输目标:DMA数据传输的目的

  • 传输数量:DMA传输数据的数量

  • 触发信号:启动一次DMA数据传输的动作

3. DMA控制器特点

  • STM32F411微控制器具备两个DMA控制器:DMA1和DMA2,每个控制器有8个数据流,每个数据流可以映射到8个通道(或请求);

  • 每一个DMA控制器用于管理一个或多个外设的存储器访问请求,并通过总线仲裁器来协调各个DMA请求的优先级;

  • 数据流(stream)是用于连接传输源和传输目标的数据通路,每个数据流可以配置为不同的传输源和传输目标,这些传输源和传输目标称为通道(Channel) ;

  • 具备16字节的FIFO。使能FIFO功能后,源数据先送入FIFO,达到FIFO的触发阈值后,再传送到目标地址。

4. 数据传输方式

普通模式:传输结束后(即要传输数据的数量达到零),将不再产生DMA操作。若开始新的DMA传输,需在关闭DMA通道情况下,重新启动DMA传输。

循环模式:可用于处理环形缓冲区和连续数据流(例如ADC扫描模式)。当激活循环模式后,每轮传输结束时,要传输的数据数量将自动用设置的初始值进行加载,并继续响应DMA请求。

5. HAL库DMA发送函数

① 函数主体:

HAL_StatusTypeDef HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{
     
  uint32_t *tmp;
  
  /* Check that a Tx process is not already ongoing */
  if(huart->gState == HAL_UART_STATE_READY)
  {
     
    if((pData == NULL ) || (Size == 0U))
    {
     
      return HAL_ERROR;
    }
 
    /* Process Locked */
    __HAL_LOCK(huart);
 
    huart->pTxBuffPtr = pData;
    huart->TxXferSize = Size;
    huart->TxXferCount = Size;
 
    huart->ErrorCode = HAL_UART_ERROR_NONE;
    huart->gState = HAL_UART_STATE_BUSY_TX;
 
    /* Set the UART DMA transfer complete callback */
    huart->hdmatx->XferCpltCallback = UART_DMATransmitCplt;
 
    /* Set the UART DMA Half transfer complete callback */
    huart->hdmatx->XferHalfCpltCallback = UART_DMATxHalfCplt;
 
    /* Set the DMA error callback */
    huart->hdmatx->XferErrorCallback = UART_DMAError;
 
    /* Set the DMA abort callback */
    huart->hdmatx->XferAbortCallback = NULL;
 
    /* Enable the UART transmit DMA Stream */
    tmp = (uint32_t*)&pData;
    HAL_DMA_Start_IT(huart->hdmatx, *(uint32_t*)tmp, (uint32_t)&huart->Instance->DR, Size);
    
    /* Clear the TC flag in the SR register by writing 0 to it */
    __HAL_UART_CLEAR_FLAG(huart, UART_FLAG_TC);
    
    /* Process Unlocked */
    __HAL_UNLOCK(huart);
    
    /* Enable the DMA transfer for transmit request by setting the DMAT bit
       in the UART CR3 register */
    SET_BIT(huart->Instance->CR3, USART_CR3_DMAT);
    
    return HAL_OK;
  }
  else
  {
     
    return HAL_BUSY;
  }
}

② 功能描述: 在DMA方式下发送一定数量的数据
③ 入口参数:

  • huart:串口句柄地址
  • pData:待发送数据的首地址
  • Size:待发送数据的个数

④ 返回值:

  • HAL状态值:HAL_OK表示发送成功
  • HAL_ERROR表示参数错误
  • HAL_BUSY标志串口被占用

⑤ 注意事项:

  • 该函数将启动DMA方式的串口数据发送

  • 完成指定数量的数据发送后,可以触发DMA中断,在中断中将调用发送中断回调函数HAL_UART_TxCpltCallback进行后续处理

  • 该函数由用户调用

一、STM32CubeMX创建项目

  • New一个Project

  • 激活串口一

  • 设置异步通信并使能中断
    基于HAL库的STM32以DMA方式实现的连续发送_第1张图片

  • DMA设置
    基于HAL库的STM32以DMA方式实现的连续发送_第2张图片
    基于HAL库的STM32以DMA方式实现的连续发送_第3张图片

  • 创建代码

二、Keil编译代码

在main.c中添加代码:

  /* USER CODE BEGIN Init */
  uint8_t Senbuff[] = "HELLO WORLD!!!";  //定义数据发送数组
  /* USER CODE END Init */

在while循环中添加代码:

  while (1)
  {
     
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
		HAL_UART_Transmit_DMA(&huart1, (uint8_t *)Senbuff, sizeof(Senbuff)-1);  //串口发送Senbuff数组
	  HAL_Delay(1000);
  }
  /* USER CODE END 3 */
}

如果不开启中断,程序只能发送一次数据,程序无法判断DMA传输是否完成。

三、实际效果

基于HAL库的STM32以DMA方式实现的连续发送_第4张图片

四、总结

使用DMA的好处就是它不需要CPU的干预而直接服务外设,这样CPU就可以去处理别的事务,从而提高系统的效率,对于慢速设备,如UART,其作用只是降低CPU的使用率,但对于高速设备,如硬盘,它不只是降低CPU的使用率,而且能大大提高硬件设备的吞吐量。

五、参考文章

平行叶子: HAL库完成STM32F103以DMA方式实现的连续发送
blogernice: CPU体系架构–DMA

你可能感兴趣的:(嵌入式系统,stm32,单片机,arm)