1.DMA的作用
DMA,全称Direct Memory Access,即直接存储器访问。
DMA提供了外设到存储器(硬件触发)或者存储器到存储器(软件触发)之间的高速数据传输,无需cpu的干预,节省cup的资源。比如我可以使用内部定时器计时控制ADC,再利用DMA传出数据,这一过程不需要cpu的任何指令,便可以得到温度,湿度等的值。
存储器映像(存储器的地址及其作用)
比如,在外设寄存器的ADC->DR中存储着转换完成的数字信号。
在Flash中存储着const只读常量。
运行内存SRAM中存储临时变量
2.DMA的配置与使用
1)DMA请求
关于硬件触发和软件触发就等于DMA请求
STM32F103C8T6 DMA资源:DMA1(7个通道)
EN位决定数据选择器是否工作
硬件触发需要选择特定通道进入,而软件触发不用
2)数据宽度与对齐
作用是指定一次转运要按多大的数据宽度来进行,可以选择字节Byte,半字HalhWord和字Word。字节是8位,半字是16位。
当数据源码宽度小于目标宽度时:高位补0
当数据源码宽度大于目标宽度时:高位舍弃
3)数据传输
若是在两个存储器之间的数据传输,比如SRAM中一个变量到SRAM的另一个变量
此时我们需要打开DAM中源数据地址自增和目标地址自增
当我们使用DMA传输ADC转换值到SRAM的一个数组时
显而易见,此时我们需要关闭DAM中源数据地址自增和打开目标地址自增。
否则ADC->DR即源数据地址改变,就传输错误数据了
4)DMA的转运程序
1.打开RCC中AHB从设备的时钟
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
2.初始化DMA_Init()函数
DMA_InitTypeDef DMA_InitStructure;
DMA_InitStructure.DMA_PeripheralBaseAddr = ;//外设地址
DMA_InitStructure.DMA_PeripheralDataSize = ;//外设数据宽度
DMA_InitStructure.DMA_PeripheralInc = ;//外设地址是否自增
DMA_InitStructure.DMA_MemoryBaseAddr = ;//存储器地址
DMA_InitStructure.DMA_MemoryDataSize = ;存储器数据宽度
DMA_InitStructure.DMA_MemoryInc = ;//存储器地址是否自增
DMA_InitStructure.DMA_DIR = ;//选择传输方向, DST(外设为目标) SRC(外设为源头)
DMA_InitStructure.DMA_BufferSize = ;//传输计数器值
DMA_InitStructure.DMA_Mode = ;//DMA工作模式:循环和常规模式
DMA_InitStructure.DMA_M2M = ;//软件触发(1)还是硬件触发(0)
DMA_InitStructure.DMA_Priority = ;//DMA处理优先级
DMA_Init(DMA1_Channel1, &DMA_InitStructure);
补充:在DMA工作模式下,循环模式即为打开自动重装,但在软件触发条件下,不能打开循环模式,一旦打开,DMA就无法停下来。
通道优先级只对软件触发有用,因为硬件触发有指定通道
3.最后完成通道使能
DMA_Cmd(DMA1_Channel1, ENABLE);
DMA工作需要满足3个条件:计数器>0,有触发信号,DMA使能。
4.软件触发的多次转运
先在DMA初始化中赋予失能,再写下面手动重启软件触发函数
void MyDMA_Transfer(void)
{
DMA_Cmd(DMA1_Channel1, DISABLE);
DMA_SetCurrDataCounter(DMA1_Channel1, MyDMA_Size);//MyDMA_Size一个全局变量,与DMA初始化的传输计数器值一样
DMA_Cmd(DMA1_Channel1, ENABLE);
while (DMA_GetFlagStatus(DMA1_FLAG_TC1) == RESET);//转换完成标志位为1时完成转换
DMA_ClearFlag(DMA1_FLAG_TC1);//清除转换完成标志位
}