4. 关于DMA问题

2019-05-09  本文已影响0人  郑行_aover

1. 问题:

2. 实现思路:

3. 配置时候注意:

    USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);//开启空闲中断
    DMA_InitStructure.DMA_BufferSize = DMA_Rec_Len;  //DMA通道的DMA缓存的大小

4. 乒乓缓存(DMA常常搭配乒乓缓存进行)

优势:


附:DMA部分示意代码

串口之DMA初始化步骤:(在代码中对比着看,加深理解)     
RXEN = 1:移位寄存器中的内容已经转移到RDR     
RXNEIE =1:产生中断  
串口使用DMA进行发送,可以通过设置USART_CR3寄存器上的DMAT位激活。只要TXE位被置起,就从配置成使用DMA外设的SRAM区装载数据到USART_DR寄存器。为 USART的发送分配一个DMA通道的步骤如下(x表示通道号):  
1.  在DMA控制寄存器上将USART_DR寄存器地址配置成DMA传输的目的地址。在每个TXE事件后,数据将被传送到这个地址。  
2.  在DMA控制寄存器上将存储器地址配置成DMA传输的源地址。在每个TXE事件后,数据将从此存储器区传送到USART_DR寄存器。  
3.  在DMA控制寄存器中配置要传输的总的字节数。  
4.  在DMA寄存器上配置通道优先级。  
5.  根据应用程序的要求配置在传输完成一半还是全部完成时产生DMA中断。  
6.  在DMA寄存器上激活该通道。  
7.  当DMA控制器中指定的数据量传输完成时,DMA控制器在该DMA通道的中断向量上产生一中断。在中断服务程序里,软件应将USART_CR3寄存器的DMA位清零。  \

注意:  如果DMA被用于发送,不要使能TXEIE位。

串口使用DMA进行接收,可以通过设置USART_CR3寄存器的DMAR位激活。只要接收到一个字节,数据就从USART_DR寄存器放到配置成使用DMA的SRAM区(参考DMA技术说明)。为USART的接收分配一个DMA通道步骤如下(x表示通道号):  
1.  通过DMA控制寄存器把USART_DR寄存器地址配置成传输的源地址。在每个RXNE事件后此地址上的数据将传输到存储器。  
2.  通过DMA控制寄存器把存储器地址配置成传输的目的地址。在每个RXNE事件后,数据将从USART_DR传输到此存储器区。  
3.  在DMA控制寄存器中配置要传输的总的字节数。  
4.  在DMA寄存器上配置通道优先级。  
5.  根据应用程序的要求配置在传输完成一半还是全部完成时产生DMA中断。  
6.  在DMA控制寄存器上激活该通道。通用同步异步收发器(USART)   
7.  当DMA控制器中指定的传输数据量接收完成时,DMA控制器在该DMA通道的中断矢量上产生一中断。在中断程序里, USART_CR3寄存器的DMAR位应该被软件清零。  
注意:  如果DMA被用来接收,不要使能RXNEIE位。 

四.程序设计     这里摘取了部分代码讲解,完整代码及工程见附件下载哦。

DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;   //外设作源头 
DMA_InitStructure.DMA_BufferSize = dma_len;        //BUF大小  
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址寄存器不变
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;  //内存地址寄存器递增  这两项的配置还是很好理解的,比如在这里我们是要将内存里边的东西发到USART1中去,每次发送8位,那么外设地址当然不能改变,而每一次发送内容都是不一样的,而且数组在内存中的存放就是递增的,所以内存地址寄存器要递增。   

下边是设置数据宽度:

DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //数据宽度为8位 
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; 
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //正常缓存模式(非连续传输)   一些基本定义:  
#define dma_len 100  //定义串口DMA传输数据长度
//(如果串口一次接收数据没有达到dma_len个byte,则不会发生DMA中断)   
extern u8 USART1_DMA_Buf1[dma_len]; 
//BUF1 extern u8 USART1_DMA_Buf2[dma_len]; 
//BUF2 typedef enum {BUF_NO1=0,BUF_NO2=1}BUF_NO; 
extern BUF_NO Free_Buf_Now; 
extern bool Buf_Ok;   

乒乓思想在这里体现:  
void DMA1_Channel5_IRQHandler(void) 
{  
        if(DMA_GetITStatus(DMA1_IT_TC5))   
        {      
                //DataCounter = DMA_GetCurrDataCounter(DMA1_Channel5);  //获取剩余长度,一般都为0,调试用                         
                DMA_ClearITPendingBit(DMA1_IT_GL5); //清除全部中断标志                 
               //转换可操作BUF   
                if(Free_Buf_Now==BUF_NO1) //如果BUF1空闲,将DMA接收数据赋值给BUF1   
                {     
                      DMA_InitStructure.DMA_MemoryBaseAddr = (u32)USART1_DMA_Buf1;    
                      DMA_Init(DMA1_Channel5, &DMA_InitStructure);    
                      Free_Buf_Now=BUF_NO2;   
                }else  //如果BUF2空闲,将DMA接收数据赋值给BUF2   
                {    
                        DMA_InitStructure.DMA_MemoryBaseAddr = (u32)USART1_DMA_Buf2;    
                        DMA_Init(DMA1_Channel5, &DMA_InitStructure);    
                        Free_Buf_Now=BUF_NO1;   
                }   
                Buf_Ok=TRUE;   
          } 
}  

 这是主函数: 
void main() 
{  
        Delay_Init(72); //系统延时函数初始化  
        LED_Init();     //初始化与LED连接的硬件接口  
        KEY_Init();     //初始化与按键连接的硬件接口  
        USART_Config( USART1,115200);  
        // USART_Config( USART2,115200); //com2与led1,led2 接口复用  
        USART_Config( USART3,115200);  //com3
        DMA_UARTToMemConfig();//串口DMA配置   
        NVIC_Config();  //      
        while (1)   
        {   
            //////////////////////////////////////////////////////////////////////////////////////        
            if(Buf_Ok==TRUE)//BUF可用  (在dma中断中置位)   
            {    
                    Buf_Ok=FALSE;      
                    x1=0;    
                    x2=0;    
                    if(Free_Buf_Now==BUF_NO1)//如果BUF1空闲    
                    {     
                          while(x1<dma_len)     
                          {      
                                USART_PutChar(USART1,USART1_DMA_Buf1[x1++]);       //用串口1将BUF1中数据发送出去     
                          }     
                    } else //如果BUF2空闲    
                    {     
                            while(x2<dma_len)     
                            {      
                                    USART_PutChar(USART1,USART1_DMA_Buf2[x2++]);       //用串口1将BUF2中数据发送出去     
                            }    
                     }    
          }
上一篇 下一篇

猜你喜欢

热点阅读