C语言学习:STM32F407 DMA串口收发

[复制链接]
 楼主| 877049204 发表于 2018-6-1 11:16 | 显示全部楼层 |阅读模式
本帖最后由 877049204 于 2018-6-1 11:38 编辑

参考:  ALIENTEK探索者 STM32F407开发板教程
开发过程中遇到一个问题:
关于STM32F407 任务执行时间的问题
https://bbs.21ic.com/icview-2515290-1-1.html?fromuser=877049204
(出处: 21ic电子技术论坛)
ADC采样周期50us,想通过串口实时发送出去
为了减少串口发送ADC数据占用的时间,想试试DMA的方法。
DMA,全称为:Direct Memory Access,即直接存储器访问。DMA传输方式无需CPU直接控制传输,也没有中断处理方式那样保留现场和恢复现场的过程,通过硬件为 RAM与I/O 设备开辟一条直接传送数据的通路,能使 CPU的效率大为提高。
STM32F4 最多有 2 个 DMA 控制器(DMA1 和 DMA2) ,共 16 个数据流(每个控制器 8 个 ),每一个 DMA 控制器都用于管理一个或多个外设的存储器访问请求。每个数据流总共可以有多达 8个通道(或称请求)。每个数据流通道都有一个仲裁器,用于处理DMA请求间的优先级。
DMA 控制器执行直接存储器传输:因为采用 AHB 主总线,它可以控制 AHB 总线矩阵来启动AHB事务。它可以执行下列事务:
1,外设到存储器的传输
3, 存储器到外设的传输
3,存储器到存储器的传输
  这里特别注意一下,存储器到存储器需要外设接口可以访问存储器,而仅DMA2的外设接口可以访问存储器,所以仅DMA2控制器支持存储器到存储器的传输,DMA1不支持。
DMA2的各数据流通道映射表,如表所示


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×

评论

附件太大啦,不上传了  发表于 2018-6-1 11:39
 楼主| 877049204 发表于 2018-6-1 11:25 | 显示全部楼层
本帖最后由 877049204 于 2018-6-1 11:29 编辑
  1. <div>上表就列出了 DMA2 所有可能的选择情况,来总共 64 种组合,比如本章我们要实现串口 1的 DMA 发送,即 USART1_TX,就必须选择 DMA2 的数据流 7,通道 4,来进行 DMA 传输。这里注意一下,有的外设(比如 USART1_RX)可能有多个通道可以选择,大家随意选择一个就可以了。
  2. </div>
上表就列出了 DMA2 所有可能的选择情况,来总共 64 种组合,比如本章我们要实现串口 1的 DMA 发送,即 USART1_TX,就必须选择 DMA2 的数据流 7,通道 4,来进行 DMA 传输。这里注意一下,有的外设(比如 USART1_RX)可能有多个通道可以选择,大家随意选择一个就可以了。
具体步骤见附件:STM32F4开发指南——库函数版本
这里主要介绍函数具体怎么使用

  1. #include "dma.h"
  2. //DMAx µÄ¸öͨµÀÅäÖÃ
  3. //´«ÊäÐÎʽ¹Ì¶¨
  4. //´æ´¢Æ÷->ÍâÉèģʽ/8λÊý¾Ý¿í¶È/´æ´¢Æ÷ÔöÁ¿Ä£Ê½
  5. //DMA_Streamx:DMAÊý¾ÝÁ÷,DMA1_Stream0~7/DMA2_Stream0~7
  6. //chx:DMAͨµÀÑ¡Ôñ, [url=home.php?mod=space&uid=144993]@ref[/url] DMA_channel DMA_Channel_0~DMA_Channel_7  
  7. //par:ÍâÉèµØÖ·  mar:´æ´¢Æ÷µØÖ·  ndtr:Êý¾Ý´«ÊäÁ¿   

  8. void MYDMA_Config(DMA_Stream_TypeDef *DMA_Streamx,u32 chx,u32 par,u32 mar,u16 ndtr)
  9. {  
  10.   DMA_InitTypeDef  DMA_InitStructure;
  11.   if((u32)DMA_Streamx>(u32)DMA2)//µÃµ½µ±Ç°streamÊÇDMA2»¹ÊÇ DMA1
  12.   {
  13.     RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE);//DMA2ʱÖÓʹÄÜ
  14.   }else  
  15.   {
  16.     RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1,ENABLE);//DMA1ʱÖÓʹÄÜ
  17.   }
  18.   DMA_DeInit(DMA_Streamx);
  19.         while (DMA_GetCmdStatus(DMA_Streamx) != DISABLE){}//µÈ´ýDMA¿ÉÅäÖÃ
  20.   /* ÅäÖÃDMA Stream */
  21.   DMA_InitStructure.DMA_Channel = chx;  //ͨµÀÑ¡Ôñ
  22.   DMA_InitStructure.DMA_PeripheralBaseAddr = par;//DMAÍâÉèµØÖ·
  23.   DMA_InitStructure.DMA_Memory0BaseAddr = mar;//DMA ´æ´¢Æ÷0µØÖ·
  24.   DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;//´æ´¢Æ÷µ½ÍâÉèģʽ
  25.   DMA_InitStructure.DMA_BufferSize = ndtr;//Êý¾Ý´«ÊäÁ¿
  26.   DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //ÍâÉè·ÇÔöÁ¿Äģʽ
  27.   DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//´æ´¢Æ÷ÔöÁ¿Ä£Ê½
  28.   DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //ÍâÉèÊý¾Ý³¤¶È8λ
  29.   DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;  //´æ´¢Æ÷Êý¾Ý³¤¶È:32 λ
  30.          DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;// ÆÕͨģʽ
  31.   DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;//ÖеÈÓÅÏȼ¶
  32.   DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;//FIFOģʽ½ûÖ¹      
  33.   DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;//FIFOãÐÖµ
  34.   DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;  //´æ´¢Æ÷Í»·¢µ¥´Îģʽ
  35.   DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;  //ÍâÉèÍ»·¢µ¥´Îģʽ
  36.   DMA_Init(DMA_Streamx, &DMA_InitStructure);//³õʼ»¯ DMA Stream
  37. }  
  38. //¿ªÆôÒ»´ÎDMA´«Êä
  39. //DMA_Streamx:DMAÊý¾ÝÁ÷,DMA1_Stream0~7/DMA2_Stream0~7  
  40. //ndtr:Êý¾Ý´«ÊäÁ¿  
  41. void MYDMA_Enable(DMA_Stream_TypeDef *DMA_Streamx,u16 ndtr)
  42. {
  43.   DMA_Cmd(DMA_Streamx, DISABLE);                      //??DMA ??  
  44.   while (DMA_GetCmdStatus(DMA_Streamx) != DISABLE){}  //??DMA?????   
  45.   DMA_SetCurrDataCounter(DMA_Streamx,ndtr);          //?????   
  46.   DMA_Cmd(DMA_Streamx, ENABLE);                      //?? DMA ??  
  47. }   


 楼主| 877049204 发表于 2018-6-1 11:34 | 显示全部楼层
这个函数主要是第4个参数(u32)CH,这个是存储器的地址,后面的参数5是需要发送的字节数,在函数里面可以选择是发送字节还是字,以及存储器地址是否移位。
这里的CH不能是变量,我在这里使用的数组,取的是数组的地址。
  1. MYDMA_Config(DMA2_Stream7,DMA_Channel_4,(u32)&USART1->DR,(u32)CH,5);
  1. char CH[10]={'\0'};
为了发送完自动换行,数组第5位:
  1. CH[4] = 0X0A;
搞清楚了就很简单,做个笔记记一下。




您需要登录后才可以回帖 登录 | 注册

本版积分规则

158

主题

1836

帖子

20

粉丝
快速回复 在线客服 返回列表 返回顶部