美文网首页
stm32---DMA基础

stm32---DMA基础

作者: 飞向深空 | 来源:发表于2019-08-10 11:39 被阅读0次

    DMA,意思为直接存储器访问。
    DMA 可 用于实现外设与存储器之间或者存储器与存储器之间数据高效传输。
    因为 DMA 传输数据移动过程无需 CPU 直接操作,这样节省的 CPU 资 源就可供其它操作使用。
    从硬件层面来理解,DMA 就好像是 RAM 与 I/O 设备间数 据传输的通路,外设与存储器之间或者存储器与存储器之间可以直接在这条通路 上进行数据传输。
    这里说的外设一般指外设的数据寄存器,比如 ADC、SPI、I2C、 DCMI 等外设的数据寄存器,存储器一般是指片内 SRAM、外部存储器、片内 Flash 等。


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


    DMA1通道对应外设请求
    DMA2通道对应外设请求

    DMA就像一个中转站一样,里面有源地址和目标地址,多通道并用可以配置优先级,
    只要开启DMA就可以直接实现源地址里的内容传送给目标地址,不需要CPU来管理,它就像个通道一样,开启就传输。


    dma.c

    #include "dma.h"
    
    
    /*******************************************************************************
    * 函 数 名         : DMAx_Init
    * 函数功能         : DMA初始化函数
    * 输    入         : 
                         DMAy_Channelx:DMA通道选择,@ref DMA_channel DMA_Channel_0~DMA_Channel_7
                         par:外设地址
                         mar:存储器地址
                         buff_size:数据传输量
    * 输    出         : 无
    *******************************************************************************/ 
    void DMAx_Init(DMA_Channel_TypeDef* DMA1_Channelx,u32 par,u32 mar,u16 buff_size)
    {
        DMA_InitTypeDef DMA_InitStructure;
        
        //1*开启相应时钟
        RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
        
        //2*DMA结构体配置
        DMA_InitStructure.DMA_PeripheralBaseAddr = par;  //外设目标地址
        DMA_InitStructure.DMA_MemoryBaseAddr = mar;   //存储器源地址
        DMA_InitStructure.DMA_DIR =DMA_DIR_PeripheralDST ;  //方向是DMA存储器到外设寄存器。方向还有外设到存储器,存储器到存储器
        DMA_InitStructure.DMA_BufferSize = buff_size; //传输的字节数目
        DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设寄存器地址自递增,外设通常是一个不需要递增
        DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryInc_Enable;  //传输数据多字节时需要地址自增,实现开启就全部传输完
        DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //DMA传输模式,单次传输
        DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;  //优先级配置,用于多通道时
        DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;  //存储器到存储器时打开
        DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //存储器数据长度为1Byte,8位
        DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //外设接收数据长度为必须要存储器发送数据长度一样
        DMA_Init(DMA1_Channelx,&DMA_InitStructure);
        
    }
    
    /*******************************************************************************
    * 函 数 名         : DMAx_Enable
    * 函数功能         : 开启一次DMA传输
    * 输    入         : DMAy_Channelx:DMA通道选择,@ref DMA_channel DMA_Channel_0~DMA_Channel_7
                         buff_size:数据传输量,传输时再赋值一遍防止出错
    * 输    出         : 无
    *******************************************************************************/ 
    //3*开启DMA
    void DMAx_ENABLE(DMA_Channel_TypeDef* DMA1_Channelx,u16 buff_size)
    {
    
        DMA_Cmd(DMA1_Channelx,DISABLE);   //先关闭DMA使能来赋
        DMA_SetCurrDataCounter(DMA1_Channelx,buff_size);
        DMA_Cmd(DMA1_Channelx,ENABLE);
    }
    

    dma.h

    #ifndef _dma_H
    #define _dma_H
    
    #include "system.h"
    
    
    void DMAx_Init(DMA_Channel_TypeDef* DMA1_Channelx,u32 par,u32 mar,u16 buff_size);
    
    void DMAx_ENABLE(DMA_Channel_TypeDef* DMA1_Channelx,u16 buff_size); 
    
    
    #endif
    
    

    main.c

    #include "systick.h"
    #include "led.h"
    #include "system.h"
    #include "key.h"
    #include "usart.h"
    #include "dma.h"
    
    #define data_size 5000
    u8 data[data_size];
    
    //数组赋值专用函数
    void Data_zhuang(u8 *p)
    {
        u16 i;
        for(i=0;i<data_size;i++)
        {
            *p = '5';
            p++;
    
        }
    }
    
    
    int main()
    {
        u8 i=0;
        u8 key;
        
        SysTick_Init(72);  //系统时钟初始
        LED_INIT(); 
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); 
        USART1_Init(9600);
        KEY_INIT();
        
        Data_zhuang(data); //给数组赋值
        DMAx_Init(DMA1_Channel4,(u32)&USART1->DR,(u32)data,data_size); //DMA初始化,(u32)&USART1->DR是串口1的数据寄存器,(u32)data是我们在内存中造的数组
        
        while(1)
        { 
            key = KEY_Scan(0);
            if(key==KEY_UP)
            {
                USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE); //是哪个外设就开启哪个的DMA功能
                DMAx_ENABLE(DMA1_Channel4,data_size);  //使能DMA
                
                while(1)
                {
                    if(DMA_GetFlagStatus(DMA1_FLAG_TC4)==1) //判断DMA1的通道4是否传输完成
                    {
                        DMA_ClearFlag(DMA1_FLAG_TC4);  //清除传输完成标志
                        break;
                    }
                    led2=!led2;
                    delay_ms(300);
                }   
            }
        
            i++;
            if(i%20==0) //200ms变换一次
            {
                led1=!led1;
            }
        
        }
    }
    

    相关文章

      网友评论

          本文标题:stm32---DMA基础

          本文链接:https://www.haomeiwen.com/subject/xxaljctx.html