查看: 1306|回复: 0
收起左侧

第十三章:CH32V103应用教程——DMA(存储器到存储器)

[复制链接]

  离线 

  • TA的每日心情
    慵懒
    2021-7-23 17:16
  • 签到天数: 17 天

    [LV.4]

    发表于 2021-4-23 11:04:53 | 显示全部楼层 |阅读模式

    有人预言,RISC-V或将是继Intel和Arm之后的第三大主流处理器体系。欢迎访问全球首家只专注于RISC-V单片机行业应用的中文网站

    您需要 登录 才可以下载或查看,没有帐号?立即注册

    x
    本帖最后由 草帽王子 于 2021-9-10 16:55 编辑

    本章教程讲解DMA存储器到存储器模式。存储器到存储器模式可以实现数据在两个内存的快速拷贝。程序中,首先定义一个静态的源数据,存放在内部 FLASH,然后使用DMA传输把源数据拷贝到目标地址上(内部SRAM),最后对比源数据和目标地址的数据,判断传输是否准确。


    1、DMA简介及相关函数介绍

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

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

    关于DMA具体信息,可参考CH32V103应用手册。DMA标准库函数具体内容如下:
    1. void DMA_DeInit(DMA_Channel_TypeDef* DMAy_Channelx);
    2. void DMA_Init(DMA_Channel_TypeDef* DMAy_Channelx, DMA_InitTypeDef* DMA_InitStruct);
    3. void DMA_StructInit(DMA_InitTypeDef* DMA_InitStruct);
    4. void DMA_Cmd(DMA_Channel_TypeDef* DMAy_Channelx, FunctionalState NewState);
    5. void DMA_ITConfig(DMA_Channel_TypeDef* DMAy_Channelx, uint32_t DMA_IT, FunctionalState NewState);
    6. void DMA_SetCurrDataCounter(DMA_Channel_TypeDef* DMAy_Channelx, uint16_t DataNumber);
    7. uint16_t DMA_GetCurrDataCounter(DMA_Channel_TypeDef* DMAy_Channelx);
    8. FlagStatus DMA_GetFlagStatus(uint32_t DMAy_FLAG);
    9. void DMA_ClearFlag(uint32_t DMAy_FLAG);
    10. ITStatus DMA_GetITStatus(uint32_t DMAy_IT);
    11. void DMA_ClearITPendingBit(uint32_t DMAy_IT);
    复制代码

    1.1、void DMA_DeInit(DMA_Channel_TypeDef* DMAy_Channelx)
    功  能:将DMAy Channelx寄存器初始化为其默认重置值。
    输  入:DMAy_Channelx:这里y可以是1或2来选择DMA,x可以是1到7对于DMA1,1到5对于DMA2选择DMA频道。

    1.2、void DMA_Init(DMA_Channel_TypeDef* DMAy_Channelx, DMA_InitTypeDef* DMA_InitStruct)

    功  能:根据DMA_InitStruct中指定的参数初始化DMAy Channelx。
    输  入:DMAy_Channelx:这里y可以是1或2来选择DMA,x可以是1到7对于DMA1,1到5对于DMA2选择DMA通道。DMA_InitStruct:指向包含指定DMA频道的配置信息的DMA_InitTypeDef结构的指针。

    1.3、void DMA_StructInit(DMA_InitTypeDef* DMA_InitStruct)
    功  能:用默认值填充每个DMA_InitStruct成员。
    输  入:DMA_InitStruct:指向要初始化的DMA_InitTypeDef结构的指针,对于DMA1,它是1到7,对于DMA2是1到5。

    1.4、void DMA_Cmd(DMA_Channel_TypeDef* DMAy_Channelx, FunctionalState NewState)
    功  能:启用或禁用指定的DMAy Channelx。
    输  入:DMAy_Channelx:其中y可以是1或2来选择DMA,x可以是1到7(对于DMA1)和1到5(对于DMA2)来选择DMA通道。NewState:DMAy Channelx的新状态(启用或禁用)。

    1.5、void DMA_ITConfig(DMA_Channel_TypeDef* DMAy_Channelx, uint32_t DMA_IT, FunctionalState NewState)

    功  能:启用或禁用指定的DMAy Channelx中断。
    输  入:DMAy_Channelx:其中y可以是1或2来选择DMA,x可以是1到7(对于DMA1)和1到5(对于DMA2)来选择DMA通道。NewState:DMAy Channelx的新状态(启用或禁用)。

    1.6、void DMA_SetCurrDataCounter(DMA_Channel_TypeDef* DMAy_Channelx, uint16_t DataNumber)
    功  能:设置当前DMAy Channelx传输中的数据单元数。
    输  入:DMAy_Channelx:其中y可以是1或2来选择DMA,x可以是1到7(对于DMA1)和1到5(对于DMA2)来选择DMA通道。DataNumber:当前DMAy Channelx传输中的数据单元数。

    1.7、uint16_t DMA_GetCurrDataCounter(DMA_Channel_TypeDef* DMAy_Channelx)
    功  能:返回当前DMAy Channelx传输中剩余的数据单元数。
    输  入:DMAy_Channelx:其中y可以是1或2来选择DMA,x可以是1到7(对于DMA1)和1到5(对于DMA2)来选择DMA通道。

    1.8、FlagStatus DMA_GetFlagStatus(uint32_t DMAy_FLAG)
    功  能:检查是否设置了指定的DMAy Channelx标志。
    输  入:DMAy_FLAG:指定要检查的标志。

    1.9、void DMA_ClearFlag(uint32_t DMAy_FLAG)
    功  能:清除DMAy Channelx的挂起标志。
    输  入:DMAy_FLAG:指定要检查的标志。

    1.10、ITStatus DMA_GetITStatus(uint32_t DMAy_IT)
    功  能:检查指定的DMAy Channelx中断是否发生。
    输  入:DMAy_IT:指定要检查的DMAy中断源。

    1.11、void DMA_ClearITPendingBit(uint32_t DMAy_IT)
    功  能:清除DMAy Channelx的中断挂起位。
    输  入:DMAy_IT:指定要清除的DMAy中断源。

    以上函数在程序编写时直接调用即可。


    2、硬件设计

    本章教程所用资源均为CH32V103开发板内部资源,无需进行其他硬件连接,只需进行程序配置即可。


    3、软件设计

    DMA存储器到存储器模式程序如下:

    dma.h文件
    1. #ifndef __DMA_H
    2. #define __DMA_H

    3. #include "ch32v10x_conf.h"

    4. /* Global define */
    5. #define Buf_Size 32       //定义要发送的数据大小

    6. /* Global Variable */
    7. u32 SRC_BUF[Buf_Size];    //定义SRC_BUF数组作为DMA传输数据源
    8. u32 DST_BUF[Buf_Size];    //定义DMA传输目标存储器,存储在内部SRAM中

    9. void DMA1_CH3_Init(void); //DMA传输参数初始化配置
    10. u8 BufCmp( u32* buf1,u32* buf2,u16 buflength); //源数据与目标地址数据对比

    11. #endif
    复制代码
    dma.h文件主要包含相关定义及函数声明。

    dma.c文件
    1. #include "dma.h"

    2. //定义SRC_BUF数组作为DMA传输数据源,并将数据存储在内部FLASH中
    3. u32 SRC_BUF[Buf_Size]=
    4.                       {      0x01020304,0x05060708,0x090A0B0C,0x0D0E0F10,
    5.                              0x11121314,0x15161718,0x191A1B1C,0x1D1E1F20,
    6.                              0x21222324,0x25262728,0x292A2B2C,0x2D2E2F30,
    7.                              0x31323334,0x35363738,0x393A3B3C,0x3D3E3F40,
    8.                              0x41424344,0x45464748,0x494A4B4C,0x4D4E4F50,
    9.                              0x51525354,0x55565758,0x595A5B5C,0x5D5E5F60,
    10.                              0x61626364,0x65666768,0x696A6B6C,0x6D6E6F70,
    11.                              0x71727374,0x75767778,0x797A7B7C,0x7D7E7F80
    12.                       };
    13. //定义DST_BUF数组作为DMA传输目标存储器,并将数据存储在内部SRAM中
    14. u32 DST_BUF[Buf_Size]={0};

    15. /*******************************************************************************
    16. * Function Name  : DMA1_CH3_Init
    17. * Description    : Initializes Channel3 of DMA1 collection.
    18. * Input          : None
    19. * Return         : None
    20. *******************************************************************************/
    21. //DMA1通道3传输参数配置
    22. void DMA1_CH3_Init(void)
    23. {
    24.   DMA_InitTypeDef DMA_InitStructure;
    25.   RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);            //使能DMA1时钟

    26.   DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(SRC_BUF);    //设置源数据地址
    27.   DMA_InitStructure.DMA_MemoryBaseAddr = (u32)DST_BUF;          //设置目标地址
    28.   DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;            //设置传输方向:外设到存储器(此处外设为内部FLASH)
    29.   DMA_InitStructure.DMA_BufferSize = Buf_Size*4;                //设置传输大小
    30.   DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable;         //指定外设地址寄存器递增。
    31.   DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                 //指定内存地址寄存器递增。
    32.   DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //设置外设数据单位
    33.   DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte;     //设置存储器数据单位
    34.   DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;                 //设置对应DMA工作模式为正常模式
    35.   DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;       //DMA1通道3优先级高
    36.   DMA_InitStructure.DMA_M2M = DMA_M2M_Enable;                   //使能DMA存储器到存储器的传输方式
    37.   DMA_Init(DMA1_Channel3, &DMA_InitStructure);                  //根据DMA_InitStruct中指定的参数初始化DMA1通道3
    38.   DMA_ClearFlag(DMA1_FLAG_TC3);   //清除DMA1通道3传输完成挂起标志

    39.   DMA_Cmd(DMA1_Channel3, ENABLE); //使能DMA1通道3
    40. }

    41. /*******************************************************************************
    42. * Function Name  : BufCmp
    43. * Description    : Compare the  buf
    44. * Input          : buf1:pointer of buf1
    45. *                  buf2:pointer of buf1
    46. *                  buflength: length of buf
    47. * Return         : 1:Two arrays are identical
    48. *                  0:Two arrays are inconsistent
    49. *******************************************************************************/
    50. //源数据与目标地址数据对比
    51. u8 BufCmp( u32* buf1,u32* buf2,u16 buflength)
    52. {
    53.   while(buflength--)
    54.     {
    55.       if(*buf1 != *buf2)  //判断两个数据源是否对应相等
    56.         {
    57.           return 0;       //对应数据源不相等马上退出函数,并返回 0
    58.         }
    59.         /* 递增两个数据源的地址指针 */
    60.         buf1++;
    61.         buf2++;
    62.     }
    63.     return 1;             //完成判断并且对应数据相对 ,返回1
    64. }
    复制代码
    dma.c文件主要包括DMA1通道3传输参数初始化配置以及数据比较两个函数,DMA1_CH3_Init函数主要进行DMA1时钟使能、DMA1通道3参数配置、DMA1通道3传输完成挂起标志清除以及DMA1通道3使能。BufCmp函数主要进行数据对比,并根据对比结果返回相应值。

    main.c函数
    1. /*******************************************************************************
    2. * Function Name  : main
    3. * Description    : Main program.
    4. * Input          : None
    5. * Return         : None
    6. *******************************************************************************/
    7. int main(void)
    8. {
    9.     u8 i=0;
    10.     u8 Flag=0;

    11.     Delay_Init();
    12.     USART_Printf_Init(115200);
    13.     DMA1_CH3_Init();

    14.     printf("SystemClk:%d\r\n",SystemCoreClock);
    15.     printf("DMA MEM2MEM TEST\r\n");

    16.     while(DMA_GetFlagStatus(DMA1_FLAG_TC3)==RESET) //等待DMA1通道3传输完成
    17.     {
    18.     }
    19.     Flag=BufCmp(SRC_BUF,DST_BUF,Buf_Size);         //源数据与传输后数据比较结果
    20.     if(Flag==0)                                    //判断源数据与传输后数据比较结果
    21.     {
    22.       printf("DMA Transfer Fail\r\n");
    23.     }
    24.     else
    25.     {
    26.       printf("DMA Transfer Success\r\n");
    27.     }

    28.     printf("SRC_BUF:\r\n");
    29.     for(i=0;i<Buf_Size;i++)
    30.     {
    31.         printf("0x%08x\r\n",SRC_BUF[i]);
    32.     }

    33.     printf("DST_BUF:\r\n");
    34.     for(i=0;i<Buf_Size;i++)
    35.     {
    36.         printf("0x%08x\r\n",DST_BUF[i]);
    37.     }
    38.     while(1)
    39.     {
    40.     }
    41. }
    复制代码
    main.c文件主要进行相关函数初始化以及DMA传输状态及结果显示。


    4、下载验证

    将编译好的程序下载到开发板并复位,串口打印情况具体如下:

    CH32V CH573单片机芯片-第十三章:CH32V103应用教程——DMA(存储器到存储器)risc-v单片机中文社区(1)

    DMA.rar附件下载
    CH32V CH573单片机芯片-第十三章:CH32V103应用教程——DMA(存储器到存储器)risc-v单片机中文社区(2) 12、DMA.rar (468.91 KB, 下载次数: 12)
    链接:https://pan.baidu.com/s/1PxLY0W9XNqf0mACGGToYXg
    提取码:5n3f
    复制这段内容后打开百度网盘手机App,操作更方便哦






    上一篇:第十二章:CH32V103应用教程——RTC
    下一篇:第十四章:CH32V103应用教程——硬件I2C读写EEPROM
    RISCV作者优文
    全球首家只专注于RISC-V单片机行业应用的中文网站
    回复

    使用道具 举报

    高级模式
    B Color Image Link Quote Code Smilies

    本版积分规则

    关闭

    RISC-V单片机中文网上一条 /2 下一条



    版权及免责声明|RISC-V单片机中文网 |网站地图

    GMT+8, 2024-4-24 17:36 , Processed in 0.733209 second(s), 48 queries .

    快速回复 返回顶部 返回列表