打印
[其他ST产品]

梳理STM32F429之通信传输部分---DMA—直接存储区访问

[复制链接]
309|9
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
DMA简介:

       DMA(Direct Memory Access,直接存储区访问)为实现数据高速在外设寄存器与存储器之间或者存储器与存储器之间传输提供了高效的方法。
DMA1:P->M,M->P

DMA2:P->M,M->P,M->M
二、通道和流:

流:是数据传输的一条链路,每个DMA控制器有8条独立的数据流,每次传输的数据量最大为65535,如果数据的单位为字的话,那一次可以传输256KB。

通道:每个数据流有8个通道选择,每个通道对应不同的DMA请求。

使用特权

评论回复
评论
发GV第几啊 2023-1-31 20:48 回复TA
———————————————— 版权声明:本文为CSDN博主「Sumjess」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/qq_38351824/article/details/101865426 
沙发
发GV第几啊|  楼主 | 2023-1-31 20:48 | 只看该作者
DMA1 请求映射

使用特权

评论回复
板凳
发GV第几啊|  楼主 | 2023-1-31 20:48 | 只看该作者
DMA2 请求映射

使用特权

评论回复
地板
发GV第几啊|  楼主 | 2023-1-31 20:48 | 只看该作者
仲裁器

多个DMA同时请求,怎么办?

1、软件阶段,DMA_SxCR:PL

2、硬件阶段,数据流编号小的优先级大

同一个数据流只能使用一个通道,同一个DMA控制器可以使用多个数据流。

使用特权

评论回复
5
发GV第几啊|  楼主 | 2023-1-31 20:52 | 只看该作者
DMA结构体详解:
typedef struct {
uint32_t DMA_Channel;             通道选择
uint32_t DMA_PeripheralBaseAddr;  外设地址
uint32_t DMA_Memory0BaseAddr;     存储器 0 地址
uint32_t DMA_DIR;                 传输方向
uint32_t DMA_BufferSize;          数据数目
uint32_t DMA_PeripheralInc;       外设递增
uint32_t DMA_MemoryInc;           存储器递增
uint32_t DMA_PeripheralDataSize;  外设数据宽度
uint32_t DMA_MemoryDataSize;      存储器数据宽度
uint32_t DMA_Mode;                模式选择
uint32_t DMA_Priority;            优先级
uint32_t DMA_FIFOMode;            FIFO 模式
uint32_t DMA_FIFOThreshold;       FIFO 阈值
uint32_t DMA_MemoryBurst;         存储器突发传输
uint32_t DMA_PeripheralBurst;     外设突发传输
} DMA_InitTypeDef;

使用特权

评论回复
6
发GV第几啊|  楼主 | 2023-1-31 20:52 | 只看该作者
DMA_Channel: DMA 请求通道选择,可选通道 0 至通道 7,每个外设对应固定的通道,DMA_SxCR :CHSEL[2:0]。

DMA_PeripheralBaseAddr: 外设地址, DMA_SxPAR。

DMA_Memory0BaseAddr:存储器 0 地址,DMA_SxM0AR。

DMA_DIR:传输方向选择,可选外设到存储器、存储器到外设以及存储器到存储器,DMA_SxCR :DIR[1:0] 。

DMA_BufferSize:设定一次传输的数据个数,DMA_SxNDTR 。

DMA_PeripheralInc:外设地址是否递增, DMA_SxCR :PINC 。

DMA_MemoryInc:存储器地址是否递增,DMA_SxCR :MINC。

DMA_PeripheralDataSize: 外设数据宽度,可选字节(8 位)、半字(16 位)和字(32位),DMA_SxCR :PSIZE[1:0]。

DMA_BufferSize:设定一次传输的数据个数,DMA_SxNDTR 。

DMA_MemoryDataSize:存储器数据宽度,可选字节(8 位)、半字(16 位)和字(32位),DMA_SxCR :MSIZE[1:0]。

DMA_Mode : DMA 传 输 模 式 选 择 , 可 选 一 次 传 输 或 者 循 环 传 输 , DMA_SxCR :CIRC 位的值。

DMA_Priority:优先级,非常高、高、中和低,DMA_SxCR :PL[1:0]。

DMA_FIFOMode: FIFO 模式使能,DMA_SxFCR :DMDIS 。

DMA_FIFOThreshold: FIFO 阈值选择,1/4、1/2、 3/4 和满,DMA_SxFCR :FTH[1:0]。

DMA_MemoryBurst:存储器突发模式选择,单次模式、 4 节拍、8 节拍、16 节拍,DMA_SxCR :MBURST[1:0]。

DMA_PeripheralBurst:外设突发模式选择,单次模式、 4 节拍、8 节拍、16 节拍,DMA_SxCR :PBURST[1:0] 。

使用特权

评论回复
7
发GV第几啊|  楼主 | 2023-1-31 20:53 | 只看该作者
编程时需要用到的固件库函数

1-初始化DMA的寄存器到复位状态

DMA_DeInit(DMA_Stream_TypeDef* DMAy_Streamx);

2-DMA初始化函数

void DMA_Init(DMA_Stream_TypeDef* DMAy_Streamx, DMA_InitTypeDef* DMA_InitStruct);

3-DMA使能函数

DMA_Cmd(DMA_Stream_TypeDef* DMAy_Streamx, FunctionalState NewState);

使用特权

评论回复
8
发GV第几啊|  楼主 | 2023-1-31 20:57 | 只看该作者
串口1的接收和发送的DMA的配置
DMA 存储器到串口1模式/

uint8_t SendBuff[SENDBUFF_SIZE];

void USART1_TX_DMA_Config(void)
{
        DMA_InitTypeDef DMA_InitStructure;

  /*开启DMA时钟*/
  RCC_AHB1PeriphClockCmd(USART1_DMA_CLK, ENABLE);
  
  /* 复位初始化DMA数据流 */
  DMA_DeInit(USART1_TX_DMA_STREAM);

  /* 确保DMA数据流复位完成 */
  while (DMA_GetCmdStatus(USART1_TX_DMA_STREAM) != DISABLE)  { }

  /*usart1 tx对应dma2,通道4,数据流7*/       
  DMA_InitStructure.DMA_Channel = USART1_DMA_CHANNEL;  
  /*设置DMA源:串口数据寄存器地址*/
  DMA_InitStructure.DMA_PeripheralBaseAddr = USART1_DR_BASE;         
  /*内存地址(要传输的变量的指针)*/
  DMA_InitStructure.DMA_Memory0BaseAddr = (u32)SendBuff;
  /*方向:从内存到外设*/               
  DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;       
  /*传输大小DMA_BufferSize=SENDBUFF_SIZE*/       
  DMA_InitStructure.DMA_BufferSize = SENDBUFF_SIZE;
  /*外设地址不增*/            
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  /*内存地址自增*/
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;       
  /*外设数据单位*/       
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
  /*内存数据单位 8bit*/
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;       
  /*DMA模式:不断循环*/
  //DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
        DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;       
  /*优先级:中*/       
  DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
       
  /*禁用FIFO*/
  DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;        
  DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;   
  /*存储器突发传输 单次传输*/
  DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;   
  /*外设突发传输 单次传输*/
  DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
       
  /*配置DMA2的数据流7*/                  
  DMA_Init(USART1_TX_DMA_STREAM, &DMA_InitStructure);
  
  /*使能DMA*/
  DMA_Cmd(USART1_TX_DMA_STREAM, ENABLE);
  
  /* 等待DMA数据流有效*/
  while(DMA_GetCmdStatus(USART1_TX_DMA_STREAM) != ENABLE);
}

uint8_t RevBuff[REVBUFF_SIZE];

void USART1_RX_DMA_Config(void)
{
        DMA_InitTypeDef DMA_InitStructure;

  /*开启DMA时钟*/
  RCC_AHB1PeriphClockCmd(USART1_DMA_CLK, ENABLE);
  
  /* 复位初始化DMA数据流 */
  DMA_DeInit(USART1_RX_DMA_STREAM);

  /* 确保DMA数据流复位完成 */
  while (DMA_GetCmdStatus(USART1_RX_DMA_STREAM) != DISABLE)  { }

  /*usart1 tx对应dma2,通道4,数据流2*/       
  DMA_InitStructure.DMA_Channel = USART1_DMA_CHANNEL;  
  /*设置DMA源:串口数据寄存器地址*/
  DMA_InitStructure.DMA_PeripheralBaseAddr = USART1_DR_BASE;         
  /*内存地址(要传输的变量的指针)*/
  DMA_InitStructure.DMA_Memory0BaseAddr = (u32)RevBuff;
  /*方向:从外设到内存*/               
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;       
  /*传输大小DMA_BufferSize=REVBUFF_SIZE*/       
  DMA_InitStructure.DMA_BufferSize = REVBUFF_SIZE;
  /*外设地址不增*/            
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  /*内存地址自增*/
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;       
  /*外设数据单位*/       
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
  /*内存数据单位 8bit*/
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;       
  /*DMA模式:不断循环*/
  //DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
        DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;       
  /*优先级:中*/       
  DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
       
  /*禁用FIFO*/
  DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;        
  DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;   
  /*存储器突发传输 单次传输*/
  DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;   
  /*外设突发传输 单次传输*/
  DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
       
  /*配置DMA2的数据流2*/                  
  DMA_Init(USART1_RX_DMA_STREAM, &DMA_InitStructure);
  
  /*使能DMA*/
  DMA_Cmd(USART1_RX_DMA_STREAM, ENABLE);
  
  /* 等待DMA数据流有效*/
  while(DMA_GetCmdStatus(USART1_RX_DMA_STREAM) != ENABLE);
}

使用特权

评论回复
9
发GV第几啊|  楼主 | 2023-1-31 20:57 | 只看该作者
#ifndef __BSP_DMA_H
#define        __BSP_DMA_H

#include "stm32f4xx.h"
#include "bsp_led.h"
#include "bsp_systick.h"

#define as 0

/*存储器到外设串口1TX*/
#define USART1_DR_BASE               (uint32_t)&(USART1->DR)                //数据发送到 USART_DR 寄存器,该寄存器相对 USART 偏移地址为0x04
#define SENDBUFF_SIZE                5000                                //发送的数据量  小于65535

#define USART1_DMA_CLK               RCC_AHB1Periph_DMA2       
#define USART1_DMA_CHANNEL           DMA_Channel_4       //通道4
#define USART1_TX_DMA_STREAM            DMA2_Stream7        //数据流 7
/*存储器到外设串口1RX*/
#define USART1_DR_BASE               (uint32_t)&(USART1->DR)                //数据发送到 USART_DR 寄存器,该寄存器相对 USART 偏移地址为0x04
#define REVBUFF_SIZE                5                                //发送的数据量  小于65535

#define USART1_DMA_CLK               RCC_AHB1Periph_DMA2       
#define USART1_DMA_CHANNEL           DMA_Channel_4       //通道4
#define USART1_RX_DMA_STREAM         DMA2_Stream2        //数据流 2

void USART1_TX_DMA_Config(void);
void USART1_RX_DMA_Config(void);
#endif

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

20

主题

276

帖子

0

粉丝