DMA——STM32F407ZGT6

DMA简介

DMA(Direct Memory Access)直接存储器存取

DMA可以提供外设和存储器或者存储器和存储器之间的高速数据传输,无须CPU干预,节省了CPU的资源。

DMA的作用就是解决大量数据转移过度消耗CPU资源的问题,有了DMA得CPU可以更加专注的实用的的操作——计算、控制等。外围设备可以通过DMA控制器直接访问内存,与此同时,CPU可以继续执行程序。DMA传输期间,DMA控制器接管了总线的控制权。在DMA传输结束后,DMA控制器将总线的控制权交给CPU。通过硬件为 RAM 与 I/O 设备开辟一条直接传送数据的通路,能使 CPU 的效率大为提高。(CPU控制DMA开启、关闭)

附:存储器映像

STM32F407的DMA

        STM32的两个 DMA 控制器总共有 16 个数据流(每个控制器 8 个通道),每一个 DMA 控制器都用于管理 一个或多个外设的存储器访问请求。每个数据流总共可以有多达 8 个通道(或称请求)。每个通道都有一个仲裁器,用于处理 DMA 请求间的优先级。

        每个通道都支持软件触发(存储器到存储器)和特定的硬件触发(存储器到外设,触发一次转运一次)

DMA 的数据传输方向方式共有四种:

1.外设到内存

2.内存到外设

3.内存到内存

4.外设到外设(保留模式,基本不用)

DMA控制器提供两个 AHB 主端口:AHB 存储器端口(用于连接存储器)和 AHB 外设端口 (用于连接外设)。但是,要执行存储器到存储器的传输,AHB 外设端口必须也能访问存储器。

但需要注意的是,只有DMA2能够实现内存到内存的传输。

DMA基本结构

DMA请求

如果外设要想通过 DMA 来传输数据,必须先给 DMA 控制器发送 DMA 请求, DMA 控制器根据通道优先级处理该请求。控制器会给外设一个应答信号,当外设 应答后且 DMA 控制器收到应答信号之后,就会启动 DMA 的传输,直到 传输完毕。

数据宽度与对齐

数据转运+DMA

ADC扫描模式+DMA

通道选择

DMA1和DMA2均有8个数据流,每个数据流都与一个 DMA 请求相关联,此 DMA 请求可以从 8 个可能的通道请求中选出。 每个通道都有一个仲裁器,用于处理DMA 请求间的优先级。此选择由 DMA_SxCR 寄存器中的 CHSEL[2:0] 位控制。

下面为DMA1和DMA2的请求映射关系:

仲裁器

仲裁器为两个 AHB 主端口(存储器和外设端口)提供基于请求优先级的 8 个 DMA 数据流请 求管理,并启动外设/存储器访问序列。

优先级管理分为软件和硬件,软件部分由数据流的优先级(DMA_SxCR寄存器种)决定,硬件部分由流的编号决定,机制类似中断硬件编号。

FIFO直接模式和阈值突发模式

1.直接模式(禁止FIFO):不使用FIFO 的阈值级别控制。每完成一次从外设到FIFO 的数据传输后,相应的数据立即就会移出并存储到目标中。

注:存储器到存储器传输时不得使用直接模式

2.FIFO阈值突发模式:在此模式下,每次产生外设请求.数据流都会启动数据源到FIFO的传输。达到FIFO的阈值级别时,FIFO的内容移出并存储到目标中。

  FIFO用于在源数据传输到目标之前临时存储这些数据。每个数据流都有一个独立的(总容量16字节)FIFO,FIFO临时存储数据最多为16字节,FIFO的存储阈值级别可由软件配置为1/4(4字节)、1/2(8字节)、3/4(12字节)或满(16字节)。

DMA传输模式

DMA传输方向使用 DMA_SxCR 寄存器中的 DIR[1:0] 位进行配置,有三种可能的传输方向:存储器到外设、外设到存储器或存储器到存储器。

以存储器到外设模式为例,框图如下:

  1. 在此模式下数据流会立即启动传输,从数据源完全填充FIFO。每次发生外设请求,FIFO 的内容都会移出并存储到目标中。当 FIFO 的级别小于或等于预定义的阈值级别时,将使用存储器中的数据完全重载 FIFO。

  2. 如果传输完成或外设请求停止传输或软件关闭通道,传输会立即停止。

  3. 直接模式下,使能了数据流,DMA 便会预装载第一个数据,将其传输到内部 FIFO。一旦外设请 求数据传输,DMA 便会将预装载的值传输到配置的目标。每次传输都会将数据先装载至内部FIFO。

  4. 预装载的数据大小为 DMA_SxCR 寄存器中 PSIZE 位字段的值。

  5. 数据流在经过仲裁后才可以访问源或目标端口

指针递增

外设和存储器指针在每次传输后可以自动向后递增或保持常量。

如果使能了递增模式,则根据在 DMA_SxCR 寄存器 PSIZE 或 MSIZE 位中编程的数据宽度,下一次传输的地址将是前一次传输的地址递增 1(对于字节)、2(对于半字)或 4(对于字)。

单个寄存器访问外设源或目标数据时,禁止递增模式

普通模式与循环模式

普通模式:DMA搬运了设定长度的数据后,CNDTR清0,会产生中断标志,然后DMA就停止工作了,如果再有数据也不接收了。需关断 DMA 使能后再重新配置后才能继续传输。

循环模式: DMA搬运了设定长度的数据后,CNDTR清0,会产生中断标志,如果再有数据,DMA会循环保存到内存中,覆盖前面的数据。在CNDTR=0时DMA会自动装载初始化时的配置,CNDTR重置为初始值。

代码

1.DMA.c

#include "DMA.h"
#include "stm32f4xx.h"


uint8_t data[4] = {0x01,0x02,0x03,0x04};
u16 MyDMA_size;

void dma_usart_init()
{
    DMA_InitTypeDef DMA_InitStructure;    
    
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE);
   
    DMA_InitStructure.DMA_Channel = DMA_Channel_4;  //串口对应的通道4
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART1->DR;      //串口地址
    DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)data;                        //内存地址
    DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;                          //内存到外设    
    DMA_InitStructure.DMA_BufferSize = 4;                                                         //传输数据大小
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;        //外设非增量模式
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                            //内存增量模式
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //外设数据长度1字节
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;                    //内存数据长度1字节
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;                                             //普通模式    
    DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;                                //中等优先级
    DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable;                            //不使用FIFO
    DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull;             //满缓冲
    DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;                    //内存单节拍存储
    DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;    //外设单节拍存储
    
    //DMA_DeInit(DMA2_Stream7);//复位,清除FIFO缓冲区里的数据
    DMA_Init(DMA2_Stream7, &DMA_InitStructure);
    
    DMA_Cmd(DMA2_Stream7, ENABLE);
}


void dma_usart_start()
{
    //1.去使能关闭传输
    DMA_Cmd(DMA2_Stream7, DISABLE);
    
    //2.确保可以正常工作
    while(DMA_GetCmdStatus(DMA2_Stream7) == ENABLE)
        
    //3.开始数据传输
    DMA_SetCurrDataCounter(DMA2_Stream7, MyDMA_size);
        
    //4.使能
    DMA_Cmd(DMA2_Stream7, ENABLE);

    //判断传输是否完成
    if(DMA_GetFlagStatus(DMA2_Stream7, DMA_FLAG_TCIF7) == SET)
    {
        DMA_ClearFlag(DMA2_Stream7, DMA_FLAG_TCIF7);//清空标志位
    }
    
}

2.DMA.h

#ifndef _DMA_H
#define _DMA_H
#include "stm32f4xx.h"
void dma_usart_init(void);
void dma_usart_start(void);
#endif

3.main.c

int main(void)
{

    uint8_t data[8] = {1,2,3,4,5,6,7,8};
    uint8_t databuf[8];
    SysTick_Init();
    
    USART_Init_Config();
    
    dma_usart_init();
    
    USART_DMACmd(USART1,USART_DMAReq_Tx, ENABLE);
    
    while(1)
    {
        dma_usart_start();
        //printf("\r\n");
        Delay_ms(1000);
    }    
}

(这里省略了USART配置的代码)串口部分可参考

串行通信——基于STM32F407ZGT6芯片

串口效果

  • 16
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值