[其他ST产品] 梳理STM32F429之通信传输部分---DMA—直接存储区访问

[复制链接]
474|9
 楼主| 发GV第几啊 发表于 2023-1-31 20:48 | 显示全部楼层 |阅读模式
DMA简介:

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

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

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

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

评论

———————————————— 版权声明:本文为CSDN博主「Sumjess」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/qq_38351824/article/details/101865426  发表于 2023-1-31 20:48
 楼主| 发GV第几啊 发表于 2023-1-31 20:48 | 显示全部楼层
DMA1 请求映射 watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM4MzUxODI0,size_16,color_FFFFFF,t_70.jpg

 楼主| 发GV第几啊 发表于 2023-1-31 20:48 | 显示全部楼层
DMA2 请求映射 watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM4MzUxODI0,size_16,color_FFFFFF,t_70.jpg

 楼主| 发GV第几啊 发表于 2023-1-31 20:48 | 显示全部楼层
仲裁器

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

1、软件阶段,DMA_SxCR:PL

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

同一个数据流只能使用一个通道,同一个DMA控制器可以使用多个数据流。
 楼主| 发GV第几啊 发表于 2023-1-31 20:52 | 显示全部楼层
DMA结构体详解:
  1. typedef struct {
  2. uint32_t DMA_Channel;             通道选择
  3. uint32_t DMA_PeripheralBaseAddr;  外设地址
  4. uint32_t DMA_Memory0BaseAddr;     存储器 0 地址
  5. uint32_t DMA_DIR;                 传输方向
  6. uint32_t DMA_BufferSize;          数据数目
  7. uint32_t DMA_PeripheralInc;       外设递增
  8. uint32_t DMA_MemoryInc;           存储器递增
  9. uint32_t DMA_PeripheralDataSize;  外设数据宽度
  10. uint32_t DMA_MemoryDataSize;      存储器数据宽度
  11. uint32_t DMA_Mode;                模式选择
  12. uint32_t DMA_Priority;            优先级
  13. uint32_t DMA_FIFOMode;            FIFO 模式
  14. uint32_t DMA_FIFOThreshold;       FIFO 阈值
  15. uint32_t DMA_MemoryBurst;         存储器突发传输
  16. uint32_t DMA_PeripheralBurst;     外设突发传输
  17. } DMA_InitTypeDef;
 楼主| 发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] 。
 楼主| 发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);
 楼主| 发GV第几啊 发表于 2023-1-31 20:57 | 显示全部楼层
串口1的接收和发送的DMA的配置
  1. DMA 存储器到串口1模式/

  2. uint8_t SendBuff[SENDBUFF_SIZE];

  3. void USART1_TX_DMA_Config(void)
  4. {
  5.         DMA_InitTypeDef DMA_InitStructure;

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

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

  13.   /*usart1 tx对应dma2,通道4,数据流7*/       
  14.   DMA_InitStructure.DMA_Channel = USART1_DMA_CHANNEL;  
  15.   /*设置DMA源:串口数据寄存器地址*/
  16.   DMA_InitStructure.DMA_PeripheralBaseAddr = USART1_DR_BASE;         
  17.   /*内存地址(要传输的变量的指针)*/
  18.   DMA_InitStructure.DMA_Memory0BaseAddr = (u32)SendBuff;
  19.   /*方向:从内存到外设*/               
  20.   DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;       
  21.   /*传输大小DMA_BufferSize=SENDBUFF_SIZE*/       
  22.   DMA_InitStructure.DMA_BufferSize = SENDBUFF_SIZE;
  23.   /*外设地址不增*/            
  24.   DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  25.   /*内存地址自增*/
  26.   DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;       
  27.   /*外设数据单位*/       
  28.   DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
  29.   /*内存数据单位 8bit*/
  30.   DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;       
  31.   /*DMA模式:不断循环*/
  32.   //DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
  33.         DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;       
  34.   /*优先级:中*/       
  35.   DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
  36.        
  37.   /*禁用FIFO*/
  38.   DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;        
  39.   DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;   
  40.   /*存储器突发传输 单次传输*/
  41.   DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;   
  42.   /*外设突发传输 单次传输*/
  43.   DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
  44.        
  45.   /*配置DMA2的数据流7*/                  
  46.   DMA_Init(USART1_TX_DMA_STREAM, &DMA_InitStructure);
  47.   
  48.   /*使能DMA*/
  49.   DMA_Cmd(USART1_TX_DMA_STREAM, ENABLE);
  50.   
  51.   /* 等待DMA数据流有效*/
  52.   while(DMA_GetCmdStatus(USART1_TX_DMA_STREAM) != ENABLE);
  53. }

  54. uint8_t RevBuff[REVBUFF_SIZE];

  55. void USART1_RX_DMA_Config(void)
  56. {
  57.         DMA_InitTypeDef DMA_InitStructure;

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

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

  65.   /*usart1 tx对应dma2,通道4,数据流2*/       
  66.   DMA_InitStructure.DMA_Channel = USART1_DMA_CHANNEL;  
  67.   /*设置DMA源:串口数据寄存器地址*/
  68.   DMA_InitStructure.DMA_PeripheralBaseAddr = USART1_DR_BASE;         
  69.   /*内存地址(要传输的变量的指针)*/
  70.   DMA_InitStructure.DMA_Memory0BaseAddr = (u32)RevBuff;
  71.   /*方向:从外设到内存*/               
  72.   DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;       
  73.   /*传输大小DMA_BufferSize=REVBUFF_SIZE*/       
  74.   DMA_InitStructure.DMA_BufferSize = REVBUFF_SIZE;
  75.   /*外设地址不增*/            
  76.   DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  77.   /*内存地址自增*/
  78.   DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;       
  79.   /*外设数据单位*/       
  80.   DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
  81.   /*内存数据单位 8bit*/
  82.   DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;       
  83.   /*DMA模式:不断循环*/
  84.   //DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
  85.         DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;       
  86.   /*优先级:中*/       
  87.   DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
  88.        
  89.   /*禁用FIFO*/
  90.   DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;        
  91.   DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;   
  92.   /*存储器突发传输 单次传输*/
  93.   DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;   
  94.   /*外设突发传输 单次传输*/
  95.   DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
  96.        
  97.   /*配置DMA2的数据流2*/                  
  98.   DMA_Init(USART1_RX_DMA_STREAM, &DMA_InitStructure);
  99.   
  100.   /*使能DMA*/
  101.   DMA_Cmd(USART1_RX_DMA_STREAM, ENABLE);
  102.   
  103.   /* 等待DMA数据流有效*/
  104.   while(DMA_GetCmdStatus(USART1_RX_DMA_STREAM) != ENABLE);
  105. }
 楼主| 发GV第几啊 发表于 2023-1-31 20:57 | 显示全部楼层
  1. #ifndef __BSP_DMA_H
  2. #define        __BSP_DMA_H

  3. #include "stm32f4xx.h"
  4. #include "bsp_led.h"
  5. #include "bsp_systick.h"

  6. #define as 0

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

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

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

  19. void USART1_TX_DMA_Config(void);
  20. void USART1_RX_DMA_Config(void);
  21. #endif
您需要登录后才可以回帖 登录 | 注册

本版积分规则

20

主题

323

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部