打印

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

[复制链接]
997|3
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 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的各数据流通道映射表,如表所示


评论
877049204 2018-6-1 11:39 回复TA
附件太大啦,不上传了 

相关帖子

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

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

void MYDMA_Config(DMA_Stream_TypeDef *DMA_Streamx,u32 chx,u32 par,u32 mar,u16 ndtr)
{  
  DMA_InitTypeDef  DMA_InitStructure;
  if((u32)DMA_Streamx>(u32)DMA2)//µÃµ½µ±Ç°streamÊÇDMA2»¹ÊÇ DMA1
  {
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE);//DMA2ʱÖÓʹÄÜ
  }else  
  {
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1,ENABLE);//DMA1ʱÖÓʹÄÜ
  }
  DMA_DeInit(DMA_Streamx);
        while (DMA_GetCmdStatus(DMA_Streamx) != DISABLE){}//µÈ´ýDMA¿ÉÅäÖÃ
  /* ÅäÖÃDMA Stream */
  DMA_InitStructure.DMA_Channel = chx;  //ͨµÀÑ¡Ôñ
  DMA_InitStructure.DMA_PeripheralBaseAddr = par;//DMAÍâÉèµØÖ·
  DMA_InitStructure.DMA_Memory0BaseAddr = mar;//DMA ´æ´¢Æ÷0µØÖ·
  DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;//´æ´¢Æ÷µ½ÍâÉèģʽ
  DMA_InitStructure.DMA_BufferSize = ndtr;//Êý¾Ý´«ÊäÁ¿
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //ÍâÉè·ÇÔöÁ¿Äģʽ
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//´æ´¢Æ÷ÔöÁ¿Ä£Ê½
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //ÍâÉèÊý¾Ý³¤¶È8λ
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;  //´æ´¢Æ÷Êý¾Ý³¤¶È:32 λ
         DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;// ÆÕͨģʽ
  DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;//ÖеÈÓÅÏȼ¶
  DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;//FIFOģʽ½ûÖ¹      
  DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;//FIFOãÐÖµ
  DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;  //´æ´¢Æ÷Í»·¢µ¥´Îģʽ
  DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;  //ÍâÉèÍ»·¢µ¥´Îģʽ
  DMA_Init(DMA_Streamx, &DMA_InitStructure);//³õʼ»¯ DMA Stream
}  
//¿ªÆôÒ»´ÎDMA´«Êä
//DMA_Streamx:DMAÊý¾ÝÁ÷,DMA1_Stream0~7/DMA2_Stream0~7  
//ndtr:Êý¾Ý´«ÊäÁ¿  
void MYDMA_Enable(DMA_Stream_TypeDef *DMA_Streamx,u16 ndtr)
{
  DMA_Cmd(DMA_Streamx, DISABLE);                      //??DMA ??  
  while (DMA_GetCmdStatus(DMA_Streamx) != DISABLE){}  //??DMA?????   
  DMA_SetCurrDataCounter(DMA_Streamx,ndtr);          //?????   
  DMA_Cmd(DMA_Streamx, ENABLE);                      //?? DMA ??  
}   


使用特权

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




使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

158

主题

1836

帖子

20

粉丝