datasheet

STM32中USART的DMA 实现

2016-10-04来源: eefocus关键字:STM32  USART  DMA
对于没玩过DMA 的朋友,这里简单说一下DMA,用自己的语言说吧,那就是,从某个位置
传输数据到某个位置,如果不用DMA,那要CPU参与操作,一个字节一个字节地搬,效率高
点的,就一个字一个字地搬.但当你用了DMA 后,那就是只需要设置:A.从哪里开始搬; B,
搬到哪里去;C以字节方式搬还是半字还是字;D:一共搬多少个.之后,启动DMA.CPU内部
就会开始搬数据了,整个搬数据的过程都不需要指令的参与,唯一要做的,就是检测什么时
候搬完.你可以扫描寄存器,也可以用中断.这里,我使用了中断.
具体设置功能看注释就可以明白了.注意一点就是,有一个设置:
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
这个是外设的地址不递增.也就是说,每次搬动,都是从源头,也就是USART1的DR寄存器
搬,但内存地址却是递增的:
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;

这个历程实现了 接受 串口的数据 写到FLASH 之中工作,而DMA的作用在于将 串口收寄存器 USART1->DR 的 数据写到内存之中 比如某个数组之中 u8 USART1_DMA_Buf1[512]; 写满512个字节之后将进入DMA中断(通道5)在这里修改DMA 的内存写入入口
u8 USART1_DMA_Buf2[512]; ,同时标记 下次的入口Free_Buf_No=BUF_NO1; 与 Buf_Ok=TRUE; 证明已有数据准备完成。这时CUP将USART1_DMA_Buf1中的数据写入FLASH .

又抄了一点

这次使用的是双缓冲,也有人
叫乒乓缓冲.因为一般情况下,串口的数据DMA 传输进BUF1 的过程中,是不建议对
BUF1 进行操作的.但由于串口数据是不会等待的直传,所以你总不能等BUF1 满了,
才往FLASH 上写,因为这时候串口数据依旧是源源不断.于是,使用双缓冲就变的理
所当然了.当BUF1 满了的时候,就马上设置DMA的目标为BUF2,并且BUF1的数据
往25F080上灌.当串口DMA写满了BUF2的时候,再设置DMA的目标为BUF1,此时
再操作BUF2写进25F080.如此一直循环,就好像打乒乓球那样吧,所以就叫乒乓缓冲.
用这个方法的速度极限就是,你必须确保两点a.DMA 灌满了BUF1 的时候,会发生中
断,此时切换DMA 的目标缓冲为BUF2,而且切换的过程必须在新的串口数据溢出之
前完成.b.在DMA的BUF1满之前,另外一个有数据的BUF2必须能全部写进25F080,
其中包括了遇到新的扇区边界而要刷除扇区的操作时间!!
可以看出,BUF的增大,并不能够很大程度的提升速度极限.

STM32中USART的DMA 实现 - java - stm32学习日志
 

假设 USART 与 FLASH 的 底层驱动已经写好了。   点击查看。
/************DMA方式传输***************************/

#define SRC_USART1_DR    (&(USART1->DR))        //串口接收寄存器作为源头

//DMA目标缓冲,这里使用双缓冲
u8 USART1_DMA_Buf1[512];
u8 USART1_DMA_Buf2[512];
bool Buf_Ok;    //BUF是否已经可用
BUF_NO Free_Buf_No;        //空闲的BUF号  typedef enum{BUF_NO1=0,BUF_NO2=1}BUF_NO;


DMA_InitTypeDef DMA_InitStructure;

void USART_DMAToBuf1(void)
{
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);                             //开DMA时钟
    DMA_DeInit(DMA1_Channel5);                                                                               //将DMA的通道1寄存器重设为缺省值
    DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)SRC_USART1_DR;                //源头BUF 既是 (&(USART1->DR)) 
    DMA_InitStructure.DMA_MemoryBaseAddr = (u32)USART1_DMA_Buf1;                //目标BUF 既是要写在哪个个数组之中
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;                                      //外设作源头//外设是作为数据传输的目的地还是来源
    DMA_InitStructure.DMA_BufferSize = 512;                                        //DMA缓存的大小  单位在下边设定
    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_PeripheralDataSize_Byte;            //内存字节为单位
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;                                //工作在循环缓存模式
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;                            //4优先级之一的(高优先) VeryHigh/High/Medium/Low
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;                                //非内存到内存
    DMA_Init(DMA1_Channel5, &DMA_InitStructure);                                    //根据DMA_InitStruct中指定的参数初始化DMA的通道1寄存器
    
    DMA_ITConfig(DMA1_Channel5, DMA_IT_TC, ENABLE);                                //DMA5传输完成中断

STM32中USART的DMA 实现 - java - stm32学习日志
 
     USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE);                               //使能USART1的接收DMA请求
   /*****************************************************************************************************************************************************/
    //初始化BUF标志
    Free_Buf_No=BUF_NO2; //因为 DMA_InitStructure.DMA_MemoryBaseAddr = (u32)USART1_DMA_Buf1;  
    Buf_Ok=FALSE;  //此时没有数据准备完成 当然FALSE
    DMA_Cmd(DMA1_Channel5, ENABLE);                                                //正式允许DMA
    
}

再来看看DMA中断:

//u16 DataCounter;
extern DMA_InitTypeDef DMA_InitStructure;
void DMA1_Channel5_IRQHandler(void)
{
    if(DMA_GetITStatus(DMA1_IT_TC5))  //通道5传输完成中断TC 还有传输 过半中断HT  错误中断TE  全局中断GL
     {
        //DataCounter = DMA_GetCurrDataCounter(DMA1_Channel5);//获取剩余长度,一般都为0,调试用
        DMA_ClearITPendingBit(DMA1_IT_GL5);    //清除全部中断标志
        
        //转换可操作BUF
        if(Free_Buf_No==BUF_NO1)
        {    
            DMA_InitStructure.DMA_MemoryBaseAddr = (u32)USART1_DMA_Buf1;
            DMA_Init(DMA1_Channel5, &DMA_InitStructure);
            Free_Buf_No=BUF_NO2;
        }
        else
        {
            DMA_InitStructure.DMA_MemoryBaseAddr = (u32)USART1_DMA_Buf2;
            DMA_Init(DMA1_Channel5, &DMA_InitStructure);
            Free_Buf_No=BUF_NO1;
        }
        Buf_Ok=TRUE; //有准备好的数据了
    
     }
}

写FLASH的操作
  while(1)
    {
        if(Buf_Ok==TRUE)
        {
            LED1_ON;   //一个标记
            Buf_Ok=FALSE; //操作了准备好的数据
            if((addr%4096)==0)        //跨越一个扇区,则需要先刷除
            {
                SST25SectorErase(addr);    
                sector_count++;
            }
            if(Free_Buf_No==BUF_NO1)
                SST25Write(addr,USART1_DMA_Buf1,512);
            else
                SST25Write(addr,USART1_DMA_Buf2,512);
            addr+=512;
            Timer1=5000; //时间重置
            LED1_OFF;
        }
        
        //检测超时  开了 定时器
        if(Timer1==0) //五秒内没准备好的数据
        {
            //获取长度
            len=512-DMA_GetCurrDataCounter(DMA1_Channel5);
            //写入最后数据
            if(Free_Buf_No==BUF_NO1)
                SST25Write(addr,USART1_DMA_Buf2,len);
            else
                SST25Write(addr,USART1_DMA_Buf1,len);
            addr+=len;
            
            break;
        }
    }

STM32中USART的DMA 实现 - java - stm32学习日志
  
还是很简单的。
有一点比较困扰 就是 FlagStatus标志位  与 ITStatus中断标志位 的区别。 其实就 DMA 来说  DMA_IT值 与 DMA_FLAG值 是一样的
甚至2者值的获取 都是读 DMA ISR register 的值  清除也是设置 DMA_IFCR 寄存器来清除的所以貌似没有区别.........同理这个问题在别的中断也存在但我还不可保证 IT 与FLAG 的值总是相同的这个存在也许是为了兼容但一定有其意义务必不可混用即使有时用错也正确.....

关键字:STM32  USART  DMA

编辑:什么鱼 引用地址:http://www.eeworld.com.cn/mcu/article_2016100430024.html
本网站转载的所有的文章、图片、音频视频文件等资料的版权归版权所有人所有,本站采用的非本站原创文章及图片等内容无法一一联系确认版权者。如果本网所选内容的文章作者及编辑认为其作品不宜公开自由传播,或不应无偿使用,请及时通过电子邮件或电话通知我们,以迅速采取适当措施,避免给双方造成不必要的经济损失。

上一篇:STM32 的GPIO使用
下一篇:SST25VF080B SPI接口FLASH STM32驱动

关注eeworld公众号 快捷获取更多信息
关注eeworld公众号
快捷获取更多信息
关注eeworld服务号 享受更多官方福利
关注eeworld服务号
享受更多官方福利

推荐阅读

STM32堆栈设置

1.堆和栈大小 定义大小在startup_stm32f2xx.sStack_Size      EQU     0x00000400                AREA    STACK, NOINIT, READWRITE, ALIGN=3Stack_Mem      
发表于 2019-04-16
STM32堆栈设置

STM32堆和栈(Heap & Stack)的资料理解

源起:在移植cjson的过程中,解析json包的时候发现动态内存分配不足而导致解析失败,为解决这一问题,而深入了解stm32的堆和栈。stm32的存储器结构。Flash,SRAM寄存器和输入输出端口被组织在同一个4GB的线性地址空间内。可访问的存储器空间被分成8个主要块,每个块为512MB。FLASH存储下载的程序。SRAM是存储运行程序中的数据。而SRAM一般分这几个部分:静态存储区:内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。它主要存放静态数据、全局数据和常量。栈区:在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率
发表于 2019-04-16
STM32堆和栈(Heap & Stack)的资料理解

STM32定义堆栈地址到ram区顶部

本设置针对stm32f103rbt6的设置,该芯片RAM大小为20kB,故RAM区地址范围为0x20000000—0x20005000,芯片信息如下图所示;第一步:设置.sct文件;;*************************************************************; *** Scatter-Loading Description Filegenerated by uVision ***; *************************************************************LR_IROM1 0x08000000 0x00020000  
发表于 2019-04-16
STM32定义堆栈地址到ram区顶部

STM32之程序如何防止堆栈溢出

近日为某个项目写了个草稿程序,即非正式程序,后来发现老是进入hardfaulthandler,原来是堆栈溢出,后仔细查看发现函数调用纵深太深,最多的时候可保持7个函数在堆栈中调用。因此有心得如下:一、函数调用不要纵深太深,即以下模式:main(){   fun1();}fun1(){  fun2();}fun2(){   fun3();}fun3(){  fun4();}fun4(){  fun5();}fun5(){  fun6();}fun6(){   fun7();}这样子main函数要调用fun1函数完成某个功能,则要一直调到
发表于 2019-04-16

stm32之堆栈

stm32中的堆栈设置keil编译完成时存储情况当编译成功时,会出现: BUILD://Program Size: Code=340 RO-data=252 RW-data=0 ZI-data=1632Code:程序代码部分RO-data: 程序定义的常量const tempRW-data:已初始化的全局变量ZI-data:未初始化的全局变量片中的:flash=Code+RO-data+RW-dataRAM=RW-data+ZI-data通过上面的BUILD可以看出,这个程序已经用了1600多的RAM,为什么会出用到这么多的RAM呢?在startup_stm32f10x_md.s文件中存在:St
发表于 2019-04-16

说说STM32的堆栈与内存

1.概念这里所说的堆栈,是针对单片机所说的“堆”与“栈”,指的是内存中一片特殊用途的区域。而不是数据结构中的堆栈(虽然其实规则一样)。这里所说的内存,是指RAM,RAM包括SRAM,DRAM等。而不是什么手机内存卡之类。这里所说的flash,指的是用作为ROM的存储器,保存代码与常量数据。而不是动画制作。。。栈的生长方向:指的是入栈方向,从高地址向低地址生长叫做向下生长,或逆向生长;反过来就叫向上生长,或正向生长。STM32的栈是向下生长。2.内存中的堆栈安排确切地说,是keil mdk根据STM32的特性,对stm32的RAM甚至flash进行部署。编译工程后,在生成的.map文件里可以看到具体的安排。双击工程界面的工程根目录
发表于 2019-04-16
说说STM32的堆栈与内存

小广播

何立民专栏

单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号 电信业务审批[2006]字第258号函 京公海网安备110108001534 Copyright © 2005-2019 EEWORLD.com.cn, Inc. All rights reserved