立即注册 找回密码

微雪课堂

搜索
微雪课堂 STM32 STM32CubeMX系列教程 查看内容

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

2016-5-3 13:48| 发布者: MyMX1213| 查看: 65220| 评论: 16|原作者: MyMX1213

摘要: 上一章讲解了串口的轮询和中断模式,这一章介绍一下通过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。


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


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


 

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



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


生成报告以及代码,编译程序。在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函数前面添加发送的数据。

/* 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 */

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

  /* USER CODE BEGIN WHILE */
  while (1)
  {
  /* USER CODE END WHILE */
 
  /* USER CODE BEGIN 3 */
        HAL_UART_Transmit_DMA(&huart1, (uint8_t *)aTxMessage, sizeof(aTxMessage));
        HAL_Delay(1000);
  }
  /* USER CODE END 3 */

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


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

795

顶一下

刚表态过的朋友 (795 人)

相关阅读

发表评论

最新评论

引用 游客 2020-7-1 10:08
HAL_UART_Transmit_DMA(&huart1, (uint8_t *)aTxMessage, sizeof(aTxMessage));需要改成:
HAL_UART_Transmit_DMA(&huart1, (uint8_t *)aTxMessage, sizeof(aTxMessage)-1);不然发送的最后一个字节为00,windows这边接收后显示字符有问题
引用 游客 2020-5-1 16:08
请问一下,使用DMA方式transmit的时候(HAL_UART_Transmit_DMA),普通的HAL_UART_Transmit还能使用吗?因为printf里面调用的是HAL_UART_Transmit函数
引用 游客 2020-1-5 17:17
2020年1月5日实测,HAL_UART_Transmit_DMA(&huart1, (uint8_t *)aTxMessage, sizeof(aTxMessage));中(uint8_t *)aTxMessage改成
(uint8_t *)&aTxMessage
引用 游客 2019-4-6 16:06
我串口采用的还是接收中断,只要寄存器不是空的就进入中断处理,指导接收完成。
引用 peter58 2018-2-27 12:48
串口必须加中断才行
引用 dark_ness 2018-1-17 21:22
感谢精彩的教程。
请问HAL_UART_Receive_DMA() 怎么用?
有没有例程
引用 1623311678 2017-11-22 21:33
楼楼加油哦
引用 1623311678 2017-11-22 21:32
不错啊哦
引用 游客 2017-10-12 15:48
厉害的工程师
引用 游客 2017-8-10 10:58
你们这些不懂得瞎评论,害我论证半天,这个帖子例程是对的,不开启串口中断确实不可以。
引用 游客 2017-5-21 10:45
我用的STM32F103VET6,串口通讯可以,DMA就不行。串口没反应!
引用 游客 2017-5-12 08:59
: 串口中断不需要开启吧,这个例程有问题
之前版本的库是一定要开启中断才可以的。现在不知道库有没有改过。
引用 游客 2017-5-10 14:40
串口中断不需要开启吧,这个例程有问题
引用 MyMX1213 2016-12-30 09:26
如果触发了中断了,就不要再继续接受数据了,需要重新调用接受函数才行。寄存器操作没有弄过。我这里有个stm32F103通过空闲中断不定长接收的程序。你可以加下我QQ,我发给你参考下。2853908288
引用 游客 2016-12-30 09:24
[quote]决狐疑: 请问下,我用DMA+空闲中断接收如果串口数据接收溢出后,为什么DMA就再也接收不到数据了,显示 ...
引用 决狐疑 2016-12-29 17:22
请问下,我用DMA+空闲中断接收如果串口数据接收溢出后,为什么DMA就再也接收不到数据了,显示了接收的数据长度为0,哪里可以清楚DMA的缓冲区呢(用寄存器操作)

查看全部评论(16)

CubeMX教程

微雪官网|产品资料|手机版|小黑屋|微雪课堂. ( 粤ICP备05067009号 )

GMT+8, 2024-3-29 08:59 , Processed in 0.029066 second(s), 21 queries .

返回顶部