×
单片机 > 其他资讯 > 详情

STM32开发 -- Git的详细使用

发布时间:2020-07-10 发布时间:
|

在GPS部分有用到DMA,接下来看一下它的使用。


一、DMA简介

直接存储器存取(DMA) 用来提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。无须CPU干预,数据可以通过DMA快速地移动,这就节省了CPU的资源来做其他操作。

两个DMA控制器有12个通道(DMA1有7个通道, DMA2有5个通道),每个通道专门用来管理来自于一个或多个外设对存储器访问的请求。还有一个仲裁器来协调各个DMA请求的优先权。


二、DMA主要特性

● 12个独立的可配置的通道(请求): DMA1有7个通道, DMA2有5个通道

● 每个通道都直接连接专用的硬件DMA请求,每个通道都同样支持软件触发。这些功能通过软件来配置。

● 在同一个DMA模块上,多个请求间的优先权可以通过软件编程设置(共有四级:很高、高、中等和低),优先权设置相等时由硬件决定(请求0优先于请求1,依此类推) 。

● 独立数据源和目标数据区的传输宽度(字节、半字、全字),模拟打包和拆包的过程。源和目标地址必须按数据传输宽度对齐。

● 支持循环的缓冲器管理

● 每个通道都有3个事件标志(DMA半传输、 DMA传输完成和DMA传输出错),这3个事件标志逻辑或成为一个单独的中断请求。

● 存储器和存储器间的传输

● 外设和存储器、存储器和外设之间的传输

● 闪存、 SRAM、外设的SRAM、 APB1、 APB2和AHB外设均可作为访问的源和目标。

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


三、功能框图


四、DMA请求映像

DMA1控制器

从外设(TIMx[x=1、 2、 3、 4]、 ADC1、 SPI1、 SPI/I2S2、 I2Cx[x=1、 2]和USARTx[x=1、 2、 3])产生的7个请求,通过逻辑或输入到DMA1控制器,这意味着同时只能有一个请求有效。外设的DMA请求,可以通过设置相应外设寄存器中的控制位,被独立地开启或关闭。


DMA2控制器

从外设(TIMx[5、 6、 7、 8]、 ADC3、 SPI/I2S3、 UART4、 DAC通道1、 2和SDIO)产生的5个请求,经逻辑或输入到DMA2控制器,这意味着同时只能有一个请求有效。参见下图的DMA2请求映像。外设的DMA请求,可以通过设置相应外设寄存器中的DMA控制位,被独立地开启或关闭。

注意: DMA2控制器及相关请求仅存在于大容量产品和互联型产品中。



五、相关寄存器

DMA中断状态寄存器(DMA_ISR)


如果开启了 DMA_ISR 中这些中断,在达到条件后就会跳到中断服务函数里面去,即使没开启,我们也可以通过查询这些位来获得当前 DMA 传输的状态。这里我们常用的是 TCIFx,即通道 DMA 传输完成与否的标志。注意此寄存器为只读寄存器,所以在这些位被置位之后,只能通过其他的操作来清除。


DMA中断标志清除寄存器(DMA_IFCR)

DMA_IFCR 的各位就是用来清除 DMA_ISR 的对应位的,通过写 1 清除。在 DMA_ISR 被置位后,我们必须通过向该位寄存器对应的位写入 1 来清除。


其他寄存器

自行查看《STM32中文参考手册_V10.pdf》 150页


六、DMA配置

举个栗子:

需要配置USART2 的DMA接收,DMA该怎么配置。

查看上面介绍的得出:

USART2_RX 在DMA1的通道 6,USART2是挂载在 APB1 下面的外设。


然后就可以配置了:


DMA_InitTypeDef DMA_InitStructure;


RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);  //开启DMA1时钟

  USART_DMACmd(USART2, USART_DMAReq_Rx, ENABLE);   //打开串口2 DMA接收使能  开启串口DMA接收

 

DMA_DeInit(DMA1_Channel6);  //恢复缺省值

  DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(USART2->DR); //设置USART2发送数据寄存器

  DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)buf; //设置发送缓冲区首地址

  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //设置外设位目标,内存缓冲区->外设寄存器

  DMA_InitStructure.DMA_BufferSize = BufferSize; //需要发送的字节数

  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址不做增加调整,调整不调整都是DMA自动实现的

  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存缓冲区地址增加调整

  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //外设数据宽度8位,1个字节

  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //内存数据宽度8位,1个字节

  DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; //单次传输模式

  DMA_InitStructure.DMA_Priority = DMA_Priority_High; //优先级设置

  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //关闭内存到内存的DMA模式

  DMA_Init(DMA1_Channel6, &DMA_InitStructure); //写入配置

  DMA_Cmd(DMA1_Channel6, ENABLE); //开启DMA通信,等待接收数据


七、使用

一个比较重要的函数,获取当前剩余数据量大小:


    uint16_t DMA_GetCurrDataCounter(DMA_Channel_TypeDef* DMAy_Channelx)


则:

先配置DMA


    GpsRxDMACfg( GpsTransferBuffer,DEF_GPS_RBUFSIZE );   

    //GpsTransferBuffer为接收buffer,DEF_GPS_RBUFSIZE 为设置的接收buffer大小(512)


根据设置的接收buff大小减去当前剩余数据量,得到当前接收数据大小。


curcount = DEF_GPS_RBUFSIZE - DMA_GetCurrDataCounter( GPS_RxDMA_Ch );

 

『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
输入引脚的过电应力(EOS)保护