提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
目录
前言
DMA数据转运学习
提示:以下是本篇文章正文内容,下面案例可供参考
一、DMA
DMA,全称Direct Memory Access,即直接存储器访问。
DMA传输将数据从一个地址空间复制到另一个地址空间,提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。当CPU初始化这个传输动作,传输动作本身是由DMA控制器来实现和完成的。DMA传输方式无需CPU直接控制传输,也没有中断处理方式那样保留现场和恢复现场过程,通过硬件为RAM和IO设备开辟一条直接传输数据的通道,使得CPU的效率大大提高。
二、使用步骤
1.DMA的初始化配置(DMA.C)
代码如下(实例STM32F103):
#include "stm32f10x.h" // Device header
uint16_t MyDMA_Size; //定义全局变量;用于取值
void MyDMA_Init(uint32_t AddrA, uint32_t AddrB, uint16_t Size) //DMA初始化;参数设置三个;AddrA为外设地址;AddrB为存储器地址;Size为传输几次
{
MyDMA_Size = Size; //赋值;取值
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //开启DMA1的时钟;注意:这里是AHB总线
DMA_InitTypeDef DMA_InitStructure;
DMA_InitStructure.DMA_PeripheralBaseAddr = AddrA; //设置外设地址AddrA
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //设置数据宽度;DMA_PeripheralDataSize_Byte字节宽度
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable; //设置是否自增;DMA_PeripheralInc_Enable:自增;DMA_PeripheralInc_Disable:不自增
DMA_InitStructure.DMA_MemoryBaseAddr = AddrB; //设置存储器地址AddrB
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //设置数据宽度;Size字节宽度
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //设置是否自增;Enable:自增;Disable:不自增
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //设置方向;DMA_DIR_PeripheralSRC:外设站点到存储器站点;DMA_DIR_PeripheralDST:存储器站点到外设站点;
DMA_InitStructure.DMA_BufferSize = Size; //设置传输计数器的次数
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //设置模式(是否自动重装);Normal正常递减到零停止(不重装);DMA_Mode_Circular:循环模式(自动重装)
DMA_InitStructure.DMA_M2M = DMA_M2M_Enable; //设置触发源(M2M:软件到软件);DMA_M2M_Enable:软件触发;DMA_M2M_Disable:硬件触发;
//注意:自动重装和软件出发不能同时使用,会造成死循环
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //设置优先级:DMA_Priority_Medium中等优先级;如果多个DMA可以设置一下以便取值
DMA_Init(DMA1_Channel1, &DMA_InitStructure);
DMA_Cmd(DMA1_Channel1, DISABLE); //使能开启DMA1的通道1
}
2.多次转运函数(DMA.C)
代码如下(示例):
void MyDMA_Transfer(void) //传输DMA;调用这个函数就再次启动一次DMA的转运
{
DMA_Cmd(DMA1_Channel1, DISABLE); //失能关闭DMA1的通道1
DMA_SetCurrDataCounter(DMA1_Channel1, MyDMA_Size); //设置当前数据寄存器的值(用来传输计数器写数据)DMA1_Channel1(DMA1的通道1)MyDMA_Size(获取的值)
DMA_Cmd(DMA1_Channel1, ENABLE); //使能开启DMA1的通道1
while (DMA_GetFlagStatus(DMA1_FLAG_TC1) == RESET); //获取标志位状态;DMA1_FLAG_TC1(通道 1 传输完成标志位)
DMA_ClearFlag(DMA1_FLAG_TC1); //清楚标志位
}
3.主函数调用(main.c)
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "MyDMA.h"
uint8_t DataA[] = {0x01, 0x02, 0x03, 0x04}; //定义数组;赋值
uint8_t DataB[] = {0, 0, 0, 0}; //定义数组;赋值
int main(void)
{
OLED_Init(); //OLED初始化
MyDMA_Init((uint32_t)DataA, (uint32_t)DataB, 4); //调用初始化MDA(A的地址,B的地址,想要传输数据的个数也就是传输几次)
OLED_ShowString(1, 1, "DataA");
OLED_ShowString(3, 1, "DataB");
OLED_ShowHexNum(1, 8, (uint32_t)DataA, 8);
OLED_ShowHexNum(3, 8, (uint32_t)DataB, 8);
while (1)
{
DataA[0] ++; //数据A 自增
DataA[1] ++;
DataA[2] ++;
DataA[3] ++;
OLED_ShowHexNum(2, 1, DataA[0], 2); //显示A地址数据
OLED_ShowHexNum(2, 4, DataA[1], 2);
OLED_ShowHexNum(2, 7, DataA[2], 2);
OLED_ShowHexNum(2, 10, DataA[3], 2);
OLED_ShowHexNum(4, 1, DataB[0], 2); //显示B地址数据
OLED_ShowHexNum(4, 4, DataB[1], 2);
OLED_ShowHexNum(4, 7, DataB[2], 2);
OLED_ShowHexNum(4, 10, DataB[3], 2);
Delay_ms(1000);
MyDMA_Transfer(); //调用自动转运DMA数据函数
OLED_ShowHexNum(2, 1, DataA[0], 2);
OLED_ShowHexNum(2, 4, DataA[1], 2);
OLED_ShowHexNum(2, 7, DataA[2], 2);
OLED_ShowHexNum(2, 10, DataA[3], 2);
OLED_ShowHexNum(4, 1, DataB[0], 2);
OLED_ShowHexNum(4, 4, DataB[1], 2);
OLED_ShowHexNum(4, 7, DataB[2], 2);
OLED_ShowHexNum(4, 10, DataB[3], 2);
Delay_ms(1000);
}
}
总结
自我学习;仅供参考