STM32之DMA

本文详细介绍了直接存储器存取(DMA)的工作原理与特性,包括DMA控制器的架构、数据传输方式及STM32F103系列微控制器中的DMA配置方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

DMA 简介


        直接存储器存取(DMA)用来提供在外设和存储器之间或者存储器和存储器之间的高速数据传
输。无须CPU干预,数据可以通过DMA快速地移动,这就节省了CPU的资源来做其他操作。
两个DMA控制器有12个通道(DMA1有7个通道,DMA2有5个通道),每个通道专门用来管理来自

于一个或多个外设对存储器访问的请求。还有一个仲裁器来协调各个DMA请求的优先权。


       DMA控制器基于一个复杂的总线矩阵架构,结合了功能强大的双AHB主总线架构与独立的FIFO,以优化系统带宽。 两个DMA控制器共有16个数据流(stream),每个数据流可以编程与规定的通道中的一个搭配。


       DMA 主要特性
● 12个独立的可配置的通道(请求):DMA1有7个通道,DMA2有5个通道
● 每个通道都直接连接专用的硬件DMA请求,每个通道都同样支持软件触发。这些功能通过
软件来配置。
● 在同一个DMA模块上,多个请求间的优先权可以通过软件编程设置(共有四级:很高、高、
中等和低),优先权设置相等时由硬件决定(请求0优先于请求1,依此类推) 。
● 独立数据源和目标数据区的传输宽度(字节、半字、全字),模拟打包和拆包的过程。源和目
标地址必须按数据传输宽度对齐。
● 支持循环的缓冲器管理
● 每个通道都有3个事件标志(DMA半传输、DMA传输完成和DMA传输出错),这3个事件标志
逻辑或成为一个单独的中断请求。
● 存储器和存储器间的传输
● 外设和存储器、存储器和外设之间的传输
● 闪存、SRAM、外设的SRAM、APB1、APB2和AHB外设均可作为访问的源和目标。

● 可编程的数据传输数目:最大为65535


DMA工作过程:

1.外设向DMAC发出DMA传送请求;

2.DMAC通过连接到CPU的HOLD信号向CPU提出DMA请求;

3.CPU在完成当前总线操作后,会立即对DMA做出响应

  ①CPU将地址总线、控制总线、数据总线悬空(放弃总线控制权)

  ②CPU将有效的HLDA信号加到DMAC上,以通知DMAC CPU已经放弃了总线控制权

4.CPU将总线悬空,DMAC接管系统总线的控制权,并向外设送出DMA应答信号

5.DMAC送出地址信号和控制信号,实现外设与内存或内存与内存之间的大量数据传输

6.DMAC将数据传送完成后,通过给CPU发HLDA信号,撤销对CPU的DMA请求;CPU接收信号后,一方面使HDLA无效,一方面重新开始控制总线;

 

DMA数据传送


1.外设与存储器之间

 DMAC只是输出地址信号和控制信号(IOR/IRW/MEMR/MEMW),数据传送直接在内存和外设端口之间进行,并不经过DMAC

2.存储器与存储器之间

 先用一个DMA存储器读周期将数据从源地址读出,放到DMA的数据暂存器中,再利用一个DMA存储器写周期将数据写到目的区域



        

 STM32F103 DMA 控制

相关寄存器介绍:

主要说一下DMA_CCRx(DMA通道x配置寄存器x=1…7)
14位:MEM2MEM存储器到存储器模式(手动),定义:0(非存储器到存储器模式),1(启动存储器到存储器模式)
13和12位:PL[1:0]通道优先级(手动),定义:00(低),01(中),10(高),11(最高)
11和10位:MSIZE[1:0]存储器数据宽度(手动)定义:00(8位),01(16位),10(32位),11(保留)
9和8位PSIZE[1:0]外设数据宽度(手动)定义:00(8位),01(16位),10(32位),11(保留)
7位:MINC存储器地址增量模式(手动)定义:0(不执行存储器地址增量操作),1(执行存储器地址增量操作)
6位:PINC外设地址增量模式(手动)定义:0(不执行存储器地址增量操作),1(执行存储器地址增量操作)
5位:CIRC循环模式(手动)定义:0(不执行循环操作),1(执行循环操作)
4位:DIR数据传输方向(手动)定义:0(从外设读),1(从存储器读)
3位:TEIE允许传输错误中断(手动)定义:0(禁止TE中断),1(允许TE中断)
2位:HEIE允许半传输中断(手动)定义:0(禁止TE中断),1(允许TE中断)
1位:TCIE允许传输完成中断(手动)定义:0(禁止TE中断),1(允许TE中断)
0位:EN开启通道(手动)定义:0(不工作),1(开启)

//库函数版
u8 SendBuff[SENDBUFF_SIZE];
void USART_DMA_init()
{
	  u16 i; 
	  DMA_InitTypeDef DMA_InitStructure;
    
	  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
    
    DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&USART1->DR;// 设置外设基地址   
    DMA_InitStructure.DMA_MemoryBaseAddr = (u32)SendBuff;//设置内存基地址
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; //设置方向:从内存到外设
    DMA_InitStructure.DMA_BufferSize = SENDBUFF_SIZE;// 一次传输数据量的大小
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设增量
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//内存增量
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//外设数据长度
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //内存数据长度
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal ;//是否循环采集
    DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //优先级设置
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;//是否是内存到内存
       
    DMA_Init(DMA1_Channel4, &DMA_InitStructure); //初始化相关通道(此处选用uart1)     
    DMA_Cmd (DMA1_Channel4,ENABLE);         //使能通道


    for(i=0;i<SENDBUFF_SIZE;i++)
    {
         SendBuff[i] = 'A';
    }      
}
//寄存器版
void DMA_RESET(DMA_Channel_TypeDef *DMA_chx)//设置为缺省值
{
	//
	DMA_chx->CCR=0;
	DMA_chx->CMAR=0;
	DMA_chx->CPAR=0;
	DMA_chx->CNDTR=0;
	//判断通道清除标志位
	if(DMA_chx==DMA1_Channel1)
	{
		DMA1->IFCR=(uint32_t)0x0F;
	}
	else if(DMA_chx==DMA1_Channel2)
	{
		DMA1->IFCR=(uint32_t)0x0F<<4;
	}
	else if(DMA_chx==DMA1_Channel3)
	{
		DMA1->IFCR=(uint32_t)0x0F<<8;
	}
	else if(DMA_chx==DMA1_Channel4)
	{
		DMA1->IFCR=(uint32_t)0x0F<<12;
	}
	else if(DMA_chx==DMA1_Channel5)
	{
		DMA1->IFCR=(uint32_t)0x0F<<16;
	}
	else if(DMA_chx==DMA1_Channel6)
	{
		DMA1->IFCR=(uint32_t)0x0F<<20;
	}
	else if(DMA_chx==DMA1_Channel7)
	{
		DMA1->IFCR=(uint32_t)0x0F<<24;
	}
	else if(DMA_chx==DMA2_Channel1)
	{
		DMA1->IFCR=(uint32_t)0x0F;
	}
	else if(DMA_chx==DMA2_Channel2)
	{
		DMA1->IFCR=(uint32_t)0x0F<<4;
	}
	else if(DMA_chx==DMA2_Channel3)
	{
		DMA1->IFCR=(uint32_t)0x0F<<8;
	}
	else if(DMA_chx==DMA2_Channel4)
	{
		DMA1->IFCR=(uint32_t)0x0F<<12;
	}
	else if(DMA_chx==DMA2_Channel5)
	{
		DMA1->IFCR=(uint32_t)0x0F<<16;
	}
}
void DMA_config(DMA_Channel_TypeDef *DMA_chx,uint32_t par,uint32_t mar,uint16_t lenght,uint32_t ccr)
{
	DMA_chx->CMAR = mar;//内存地址
	DMA_chx->CPAR = par;//外设地址
	DMA_chx->CNDTR= lenght;//数据长度
	DMA_chx->CCR  = ccr;//控制寄存器相关值设置
}
void DMA_ENABLE(DMA_Channel_TypeDef *DMA_chx)//使能
{
	DMA_chx->CCR|=(uint32_t)~0x01;
	DMA_chx->CCR|=(uint32_t)0x01;
}

主要用于内存与外设之间的数据搬运工作,若用于内存与内存之间,DMA存储器到存储器模式不限定通道。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值