STM32CubeMX系列教程6:直接存储器访问 (DMA)

来自丢石头百科
Admin讨论 | 贡献2019年11月18日 (一) 16:27的版本 (上一章讲解了串口的轮询和中断模式,这一章介绍一下通过DMA模式控制串口传输。)
(差异) ←上一版本 | 最后版本 (差异) | 下一版本→ (差异)


直接存储器访问 (DMA) 用于在外设与存储器之间以及存储器与存储器之间提供高速数据传输。可以在无需任何 CPU 操作的情况下通过 DMA 快速移动数据。这样节省的 CPU 资源可供其它操作使用。说白了DMA就是一个搬运工,将数据从一个地方搬到另一个地方而不需要CPU处理。


        作为一个搬运工,要他正常工作必须要确定几个重要的参数。 1.传输模式:数据从哪里搬到哪里。三种可能的传输方向:存储器到外设、外设到存储器或存储器到存储器。  2.通道选择:就是数据传输的是走那条道路 3.仲裁器:多个DMA传输是优先级高的优先传输。 4.数据长度:每次传输的数据长度,可以一个字节,两个字节(半字),四个字节(字) 5.指针递增:如果使能了递增模式,则下一次传输的地址将是前一次传输的地址递增 1(对于字节)、2(对于半字)或4(对于字)。


        打开STM32CubeMX重新建工程,配置和上一章配置一样。只是这个工程中,在DMA设置栏添加UASART发送TX的DMA。发送选择 DMA2 Stream 7通道,方向从存储器到外设。优先级为低。Mode为Normal,Data Width选择Byte。



134908pdpyz14qqfafz40d.png


其中mode设置可以选择Normal表单次传输,传输一次后终止传输,Circular表示循环传输,传输完成后又重新开始继续传输,不断循环永不停止。此处选择单次传输。



134908eli7y1q787y11pl0.png



Increment Address表示地址指针递增。串口发送数据是将数据不断存进串口的发送数据寄存器(USARTx_TDR)。所以外接的地址是不递增。而内存储器存储的是要发送的数据,所以地址指针要递增才能将所以的数据发送出去。



134908ln7ki0lw0wwpmdp7.png


 


串口数据发送寄存器只能存储8bit,每次发送一个字节,所以数据长度选择Byte。



134909nxjzjo1oy1lkgjhd.png



另外要注意的一点,必须要开启串口中断。DMA2  stream7中断已默认开启。



134909vnr1rd9iati9nl9l.png


生成报告以及代码,编译程序。在usart.c文件中,可以找到刚才的DMA设置。



    /* Peripheral DMA init*/
   
    hdma_usart1_tx.Instance = DMA2_Stream7;
    hdma_usart1_tx.Init.Channel = DMA_CHANNEL_4;
    hdma_usart1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
    hdma_usart1_tx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_usart1_tx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_usart1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_usart1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
    hdma_usart1_tx.Init.Mode = DMA_NORMAL;
    hdma_usart1_tx.Init.Priority = DMA_PRIORITY_LOW;
    hdma_usart1_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
    HAL_DMA_Init(&hdma_usart1_tx);
 
    __HAL_LINKDMA(huart,hdmatx,hdma_usart1_tx);
main函数前面添加发送的数据


<syntaxhighlight lang="python">
/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/
uint8_t aTxMessage[] = "\r\n**** UART-Hyperterminal communication based on DMA ***\r\n    WaveShare Open7XXI-C Board \r\n";
 
/* USER CODE END PV */

</syntaxhighlight>

main()函数的while(1)循环中添加应用程序,通过DMA将数据发送出去


<syntaxhighlight lang="python">
  /* USER CODE BEGIN WHILE */
  while (1)
  {
  /* USER CODE END WHILE */
 
  /* USER CODE BEGIN 3 */
        HAL_UART_Transmit_DMA(&amp;huart1, (uint8_t *)aTxMessage, sizeof(aTxMessage));
        HAL_Delay(1000);
  }
  /* USER CODE END 3 */

</syntaxhighlight>编译程序并下载到开发板。用USB线连接开发板到电脑,在电脑上打开串口调试助手。选择对应的串口号,设置波特率为115200。按下复位按键会接收到如图信息。

134909u99r3k0rmef0mvxq.png


注意:如果不开启串口中断,则程序只能发送一次数据,程序不能判断DMA传输是否完成,USART一直处于busy状态。