寒假学习之stm32(15)----DMA(direct memory access)
2017-02-10 17:09
197 查看
DMA的基础科普
老规矩,最先进行的是基础知识的科普DMA(百度百科):
http://baike.baidu.com/subview/32471/5048463.htm
DMA 传输将数据从一个地址空间复制到另外一个地址空间。当CPU 初始化这个传输动作,传输动作本身是由 DMA 控制器来实行和完成。典型的例子就是移动一个外部内存的区块到芯片内部更快的内存区。像是这样的操作并没有让处理器工作拖延,反而可以被重新排程去处理其他的工作。DMA 传输对于高效能 嵌入式系统算法和网络是很重要的。
在实现DMA传输时,是由DMA控制器直接掌管总线,因此,存在着一个总线控制权转移问题。即DMA传输前,CPU要把总线控制权交给DMA控制器,而在结束DMA传输后,DMA控制器应立即把总线控制权再交回给CPU。一个完整的DMA传输过程必须经过DMA请求、DMA响应、DMA传输、DMA结束4个步骤。
1. DMA请求 CPU对DMA控制器初始化,并向I/O接口发出操作命令,I/O接口提出DMA请求。
2. DMA响应 DMA控制器对DMA请求判别优先级及屏蔽,向总线裁决逻辑提出总线请求。当CPU执行完当前总线周期即可释放总线控制权。此时,总线裁决逻辑输出总线应答,表示DMA已经响应,通过DMA控制器通知I/O接口开始DMA传输。
3. DMA传输 DMA控制器获得总线控制权后,CPU即刻挂起或只执行内部操作,由DMA控制器输出读写命令,直接控制RAM与I/O接口进行DMA传输。 在DMA控制器的控制下,在存储器和外部设备之间直接进行数据传送,在传送过程中不需要中央处理器的参与。开始时需提供要传送的数据的起始位置和数据长度。
4. DMA结束 当完成规定的成批数据传送后,DMA控制器即释放总线控制权,并向I/O接口发出结束信号。当I/O接口收到结束信号后,一方面停 止I/O设备的工作,另一方面向CPU提出中断请求,使CPU从不介入的状态解脱,并执行一段检查本次DMA传输操作正确性的代码。最后,带着本次操作结果及状态继续执行原来的程序。
由此可见,DMA传输方式无需CPU直接控制传输,也没有中断处理方式那样保留现场和恢复现场的过程,通过硬件为RAM与I/O设备开辟一条直接传送数据的通路,使CPU的效率大为提高。
stm32的DMA特性
聊完了总的性质,接下来该谈谈DMA在stm32上的特性了stm32下的 DMA主要特性
1. 12个独立的可配置的通道(请求): DMA1有7个通道, DMA2有5个通道
每个通道对应的具体外设如中文参考手册所给出的图所示:
DMA1:
DMA2:
每个通道都直接连接专用的硬件DMA请求,每个通道都同样支持软件触发。这些功能通过
软件来配置。
在同一个DMA模块上,多个请求间的优先权可以通过软件编程设置(共有四级:很高、高、
中等和低),优先权设置相等时由硬件决定(请求0优先于请求1,依此类推) 。
独立数据源和目标数据区的传输宽度(字节、半字、全字),模拟打包和拆包的过程。源和目
标地址必须按数据传输宽度对齐。
支持循环的缓冲器管理
每个通道都有3个事件标志(DMA半传输、 DMA传输完成和DMA传输出错),这3个事件标志逻辑或成为一个单独的中断请求。
存储器和存储器间的传输
外设和存储器、存储器和外设之间的传输
闪存、 SRAM、外设的SRAM、 APB1、 APB2和AHB外设均可作为访问的源和目标。
可编程的数据传输数目:最大为65535
祭出DMA的程序框图,先看看总体印象:
库函数的配置过程:
1.CPU对IO的初始化指令:void USART_DMACmd(USART_TypeDef* USARTx, uint16_t USART_DMAReq,FunctionalState NewState); void ADC_DMACmd(ADC_TypeDef* ADCx, FunctionalState NewState); void DAC_DMACmd(uint32_t DAC_Channel, FunctionalState NewState); void I2C_DMACmd(I2C_TypeDef* I2Cx, FunctionalState NewState); void SDIO_DMACmd(FunctionalState NewState); void SPI_I2S_DMACmd(SPI_TypeDef* SPIx, uint16_t SPI_I2S_DMAReq,FunctionalState NewState); void TIM_DMAConfig(TIM_TypeDef* TIMx, uint16_t TIM_DMABase,uint16_t TIM_DMABurstLength) void TIM_DMACmd(TIM_TypeDef* TIMx, uint16_t TIM_DMASource,FunctionalState NewState);
CPU对DMA的初始化指令以及 2.DMA响应的过程:
时钟的初始化:
由图片可以看出,stm32的dma是在AHB总线上的,所以在时钟初始化的时候:
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
DMA初始化:
DMA_DeInit(DMA_CHx); //将DMA的通道x寄存器重设为缺省值 DMA_Init(DMA_CHx,&DMA_InitStruct); 其中,DMA_InitStruct的结构体成员如下: 1. DMA_PeripheralBaseAddr:外设的基地址(寄存器的地址) 2. DMA_MemoryBaseAddr: 内存的基地址(可以是代码中定义的数组的地址) 3. DMA_BufferSize : 传送数据的数量,其有效参数需要自己设置(0~65535) 4. DMA_DIR :DMA的数据传输方向,其有效参数为:DMA_DIR_PeripheralDST(外设作为数据发送的目的地)或者DMA_DIR_PeripheralSRC(外设作为数据发送的源头) 5. DMA_PeripheralInc:外设的自增模式(每次传输一个数据之后,指针自动+1),有效的参数为:DMA_PeripheralInc_Enable,DMA_PeripheralInc_Disable 6. DMA_MemoryInc:内存的自增模式,有效参数同5类似 7. DMA_PeripheralDataSize:外设的每个数据的大小,其有效参数为:DMA_MemoryDataSize_Byte, DMA_MemoryDataSize_HalfWord, DMA_MemoryDataSize_Word 8. DMA_MemoryDataSize,内存的每个数据大小,其概念类似于7 9. DMA_Mode:DMA的数据传输模式,DMA_Mode_Circular(循环传递),DMA_Mode_Normal(只传递一次) 10. DMA_Priority:DMA的数据传递优先级别,其有效参数为:DMA_Priority_VeryHigh(非常高),DMA_Priority_High(高),DMA_Priority_Medium(中),DMA_Priority_Low(低)
使能DMA(在每次数据传输结束以后,数据传输数量都会被清零,所以,每次传输数据,都必须使能一次DMA)
void MYDMA_Enable(DMA_Channel_TypeDef*DMA_CHx) { DMA_Cmd(DMA_CHx, DISABLE ); //关闭USART1 TX DMA1 所指示的通道 DMA_SetCurrDataCounter(DMA_CHx,DMA1_MEM_LEN);//DMA通道的DMA缓存的大小 DMA_Cmd(DMA_CHx, ENABLE); //使能USART1 TX DMA1 所指示的通道 }
3.DMA传输,4.DMA传输结束
while(1) { if(DMA_GetFlagStatus(DMA1_FLAG_TC4)!=RESET) //判断通道4传输完成 { DMA_ClearFlag(DMA1_FLAG_TC4);//清除通道4传输完成标志 break; } pro=DMA_GetCurrDataCounter(DMA1_Channel4);//得到当前还剩余多少个数据 pro=1-pro/SEND_BUF_SIZE;//得到百分比 pro*=100; //扩大100倍,得到真正的数据 }
总体的过程:
DMA_InitTypeDef DM
b924
A_InitStructure;
u16 DMA1_MEM_LEN;//保存DMA每次数据传送的长度
//DMA1的各通道配置
//这里的传输形式是固定的,这点要根据不同的情况来修改
//从存储器->外设模式/8位数据宽度/存储器增量模式
//DMA_CHx:DMA通道CHx
//cpar:外设地址
//cmar:存储器地址
//cndtr:数据传输量
void MYDMA_Config(DMA_Channel_TypeDef* DMA_CHx,u32 cpar,u32 cmar,u16 cndtr)
{
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //使能DMA传输
DMA_DeInit(DMA_CHx); //将DMA的通道1寄存器重设为缺省值
DMA1_MEM_LEN=cndtr;
DMA_InitStructure.DMA_PeripheralBaseAddr = cpar; //DMA外设基地址
DMA_InitStructure.DMA_MemoryBaseAddr = cmar; //DMA内存基地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; //数据传输方向,从内存读取发送到外设
DMA_InitStructure.DMA_BufferSize = cndtr; //DMA通道的DMA缓存的大小
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_Byte; //数据宽度为8位
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //工作在正常模式
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //DMA通道 x拥有中优先级
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //DMA通道x没有设置为内存到内存传输
DMA_Init(DMA_CHx, &DMA_InitStructure); //根据DMA_InitStruct中指定的参数初始化DMA的通道
//USART1_Tx_DMA_Channel所标识的寄存器
}
//开启一次DMA传输
void MYDMA_Enable(DMA_Channel_TypeDef*DMA_CHx) { DMA_Cmd(DMA_CHx, DISABLE ); //关闭USART1 TX DMA1 所指示的通道 DMA_SetCurrDataCounter(DMA_CHx,DMA1_MEM_LEN);//DMA通道的DMA缓存的大小 DMA_Cmd(DMA_CHx, ENABLE); //使能USART1 TX DMA1 所指示的通道 }
相关文章推荐
- 寒假学习之stm32(15)----DMA(direct memory access)
- DMA(Direct Memory Access直接存储器访问)总结
- 【STM32 .Net MF开发板学习-15】红外遥控智能小车 推荐
- STM32 ADC单通道与多通道_DMA学习笔记 百度搜索
- 寒假学习之STM32(2)----时钟
- 寒假学习之STM32(1)----GPIO
- STM32学习笔记之ADC--DMA方式
- 寒假学习之STM32(6)---- 外部中断
- STM32学习笔记之DMA使用
- STM32学习日志--使用DMA功能自动更新PWM的输出
- 寒假学习之stm32(4)----中断优先级
- 【STM32 .Net MF开发板学习-15】红外遥控智能小车
- STM32 使用DMA处理ADC 学习笔记!!
- DMA(direct memory access)控制方式
- 学习Stm32--DMA
- 【STM32 .Net MF开发板学习-15】红外遥控智能小车
- linuxMTD子系统之一DMA(Direct Memory Access)
- stm32学习笔记——DMA
- STM32入门学习之DMA(STM32F030F4P6基于CooCox IDE)
- 寒假学习之STM32(5)----串口实验