STM32F103单片机开发例程-直接内存访问DMA_M2M功能介绍【wulianjishu666】

嵌入式单片机开发例程合集

链接:https://pan.baidu.com/s/1gasn4fKb4XCf0Xz-ghXgvA?pwd=yzze
提取码:yzze

DMA_M2M模块测试

1、功能描述

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

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

2、主要特性

        (1) 7个独立的可配置的通道(请求)

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

        (3) 在7个请求间的优先权可以通过软件编程设置(共有四级:很高,高,中等和低),假如在相等优先权时由硬件决定(请求0优先于请求1,依此类推)。

        (4) 独立的源和目标传输宽度(字节,半字,全字),模拟打包和拆包的过程。

        (5) 支持循环的缓冲器管理

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

        (7) 存储器和存储器间的传输。

        (8) 外设和存储器,存储器和外设的传输。

     (9)闪存,SRAM,外设的SRAM,APB1和APB2外设均可作为访问的源和目标               (10) 可编程的数据传输数据:最大为65536      

3、硬件电路

4、软件代码

/***********************************************************************

* 文件 : main.c

* 说明 :通过DMA进行数据传输,实现两块内存空间的拷贝,如果两块内存中的数据一致,蜂鸣器会响起,否则不响

************************************************************************/

/* Includes ------------------------------------------------------------------*/

#include "stm32f10x_lib.h"    //包含了所有的头文件 它是唯一一个用户需要包括在自己应用中的文件,起到应用和库之间界面的作用。

#include <stdio.h>

typedef enum {FAILED = 0, PASSED = !FAILED} TestStatus;   //定义一个枚举

#define BufferSize      32     //定义缓存区大小

vu16 CurrDataCounter_Begin = 0; //DMA传输开始时的数据的大小

vu16 CurrDataCounter_End = 0;   //DMA传输结束后数据的大小

TestStatus TransferStatus;     //发送状态 ,用来表示数据传输是否正确完成,如果传输成功为1,否则为0;

//ErrorStatus       HSEStartUpStatus; 

uc32 SRC_Const_Buffer[BufferSize] = {0x01020304,0x05060708,0x090A0B0C,0x0D0E0F10,  //源数据的地址

                                     0x11121314,0x15161718,0x191A1B1C,0x1D1E1F20,

                                     0x21222324,0x25262728,0x292A2B2C,0x2D2E2F30,

                                     0x31323334,0x35363738,0x393A3B3C,0x3D3E3F40,

                                     0x41424344,0x45464748,0x494A4B4C,0x4D4E4F50,

                                     0x51525354,0x55565758,0x595A5B5C,0x5D5E5F60,

                                     0x61626364,0x65666768,0x696A6B6C,0x6D6E6F70,

                                     0x71727374,0x75767778,0x797A7B7C,0x7D7E7F80};

u32 DST_Buffer[BufferSize];         //目的数组:用来保存源地址中的数据

void Delay_Ms(u16 time);

void RCC_Configuration(void);

void GPIO_Configuration(void);

void NVIC_Configuration(void);

void DMA1_Channel6_Configuration(void);

TestStatus Buffercmp(uc32 *pBuffer,u32* pBuffer1,u16 BufferLength);     //比较两内存块中的数据是否相等

/* Private functions ---------------------------------------------------------*/

/*******************************************************************************

* Function Name  : main

* Description    : Main program.

* Input          : None

* Output         : None

* Return         : None

*******************************************************************************/

int main(void)

{

        #ifdef DEBUG

       debug();

        #endif

        u8 i;

       RCC_Configuration();    //使能外设时钟

       GPIO_Configuration();   //初始化GPIO管脚

        GPIO_SetBits(GPIOA, GPIO_Pin_3); //关闭蜂鸣器

        NVIC_Configuration();

        DMA1_Channel6_Configuration(); //DMA通道6的配置

        TransferStatus = Buffercmp(SRC_Const_Buffer, DST_Buffer, BufferSize);

       while (1)

        {

                 if(TransferStatus == 1) //如果两块内存空间的数据一样

                 {

                         for(i=0;i<5;i++)

                         {

                                  GPIO_SetBits(GPIOA, GPIO_Pin_3);

                                  Delay_Ms(1000);

                                  GPIO_ResetBits(GPIOA, GPIO_Pin_3);

                                  Delay_Ms(1000);

                                  GPIO_SetBits(GPIOA, GPIO_Pin_3);

                                  Delay_Ms(1000);       

                         }      

                 }

        }

}

/*******************************************************************************

* Function Name  : Delay_Ms

* Description    : delay 1 ms.

* Input          : time (ms)

* Output         : None

* Return         : None

*******************************************************************************/

void Delay_Ms(u16 time)  //延时函数

{

        u16 i,j;

        for(i=0;i<time;i++)

               for(j=1000;j>0;j--);

}

/*******************************************************************************

* Function Name  : RCC_Configuration

* Description    : Configures the different system clocks.

* Input          : None

* Output         : None

* Return         : None

*******************************************************************************/

void RCC_Configuration(void)

{

        //========================= 使用内部RC晶振 =========================

    /*  

        RCC_HSICmd(ENABLE);//使能内部高速晶振 ;

        RCC_SYSCLKConfig(RCC_SYSCLKSource_HSI);//选择内部高速时钟作为系统时钟SYSCLOCK=8MHZ      

        RCC_HCLKConfig(RCC_SYSCLK_Div1);//选择HCLK时钟源为系统时钟SYYSCLOCK

       RCC_PCLK1Config(RCC_HCLK_Div4);//APB1时钟为2M

       RCC_PCLK2Config(RCC_HCLK_Div4);//APB2时钟为2M

       RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE);//使能APB2外设GPIOB时钟

        */

//======================使用外部RC晶振===================================

       RCC_DeInit();                             //初始化为缺省状态

       RCC_HSEConfig(RCC_HSE_ON);  //高速时钟使能

       while (RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET);  //等待高速时钟使能就绪

    FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);  //Enable Prefetch Buffer

    FLASH_SetLatency(FLASH_Latency_2);                                               // Flash 2 wait state

    RCC_HCLKConfig(RCC_SYSCLK_Div1);                                              // HCLK = SYSCLK

    RCC_PCLK2Config(RCC_HCLK_Div1);                                                          // PCLK2 = HCLK

    RCC_PCLK1Config(RCC_HCLK_Div2);                                                        // PCLK1 = HCLK/2

    RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);   // PLLCLK = 8MHz * 9 = 72 MHz 

    RCC_PLLCmd(ENABLE);                                                                             // Enable PLL

    while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);                // Wait till PLL is ready

    RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);                         // Select PLL as system clock source

    while(RCC_GetSYSCLKSource() != 0x08);                                      // Wait till PLL is used as system clock source

        //===================使能相应的外设时钟==================================

        RCC_APB2PeriphClockCmd(      RCC_APB2Periph_GPIOA, ENABLE);

        RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

}

void NVIC_Configuration(void)

{

        NVIC_InitTypeDef NVIC_InitStructure

        #ifdef  VECT_TAB_RAM 

               NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);

        #else

               NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);  

        #endif

        NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel6_IRQChannel;   //DMA中断通道

        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;

        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;

       NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

       NVIC_Init(&NVIC_InitStructure);

}

/*******************************************************************************

* Function Name  : GPIO_Configuration

* Description    : 初始化GPIO外设

* Input          : None

* Output         : None

* Return         : None

*******************************************************************************/

void GPIO_Configuration(void)

{

        GPIO_InitTypeDef      GPIO_InitStructure;             //声明一个结构体变量

        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;       //选择PA.3

        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;       //管脚频率为50MHZ

        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;        //输出模式为推挽输出

        GPIO_Init(GPIOA,&GPIO_InitStructure);                               //初始化GPIOA寄存器            

}

void DMA1_Channel6_Configuration(void)

{

        DMA_InitTypeDef      DMA_InitStructure;

        DMA_DeInit(DMA1_Channel6);  // 将DMA1_Channel6寄存器重设为初始值 ;

        DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)SRC_Const_Buffer;       //用来定义DMA外设的基地址

    DMA_InitStructure.DMA_MemoryBaseAddr = (u32)DST_Buffer;                              //用来定义DMA内存的基地址

        DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;                                   //传输方向

        DMA_InitStructure.DMA_BufferSize = BufferSize;                                          //传输数据的大小

        DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable;            //DMA外设地址+1

        DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                         //DMA内存地址+1

        DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;//传输的字节宽度

        DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;              //字节宽度

        DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;                                                     //传输模式

        DMA_InitStructure.DMA_Priority = DMA_Priority_High;                                           //优先级

        DMA_InitStructure.DMA_M2M = DMA_M2M_Enable;                                                      //使能内存到内存的传输

        DMA_Init(DMA1_Channel6,&DMA_InitStructure);                                                           //初始化

        DMA_ITConfig(DMA1_Channel6,DMA_IT_TC,ENABLE);                                             //中断配置

        CurrDataCounter_Begin = DMA_GetCurrDataCounter(DMA1_Channel6);

        DMA_Cmd(DMA1_Channel6,ENABLE);                                              //使能DMA

}

/**********************************************************************

* 函数名称:TestStatus Buffercmp(uc32* pBuffer,u32* pBuffer1,u16 BufferLength) //比较数据是否相同

* 函数功能:用来测试两块内存中的数据是否一致

* 入口参数:

                       uc32* pBuffer:                             源数据的地址指针

                       u32* pBuffer:                              目的数据的地址指针

                        u16 BufferLength:                        比较两块内存数据的个数                                     

* 出口参数:如果数据相等返回PASSED(1),OR 返回FAILED(0)

**********************************************************************/

TestStatus Buffercmp(uc32* pBuffer,u32* pBuffer1,u16 BufferLength)      //比较数据是否相同

{

        while(BufferLength--)

        {

                 if(*pBuffer != *pBuffer1)     //只要有一个数据不同,返回FAILED,DMA传输出错;

                 {

                         return FAILED;

                 }

                 pBuffer++;

                 pBuffer1++;

        }

        return        PASSED;

}

  • 21
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值