Skip to content

DMA

Direct Memory Access直接存储器访问, 主要的功能是数据的搬运, 不占用CPU, 通过硬件为RAM和IO开辟一条通道

DMA1: 有七个通道, 可以实现P->M, M->P, M->M(M是内存, P是外设)

DMA2: 五个通道, 只存在于大容量或者互联型

STM实现

image-20230702193710282

通过总线矩阵访问外设或者SRAM, 不通过CPU

不同的外设都有自己对应的特殊的外设

仲裁器可以控制有多个响应的时候优先处理哪一个

  • 实现过程

image-20231228165050829

image-20230702194001379

image-20230702194013891

每个通道用来管理来自于一个或多个外设对存储器访问的请求。且都有一个仲裁器,用于处理DMA请求间的优先级。

image-20231228165254334

在使用M->M的时候所有的通道都可以使用

在实际使用的时候涉及优先级, 可以使用软件控制DMA_CCRx的PL, 之后还有硬件优先级, DMA1优先级高于DMA2

寄存器

image-20231228165424692

  • DMA_ISR: 中断状态寄存器

image-20231228171040527

  • DMA_IFCR: 中断标志位清除寄存器

image-20231228171120097

  • DMA_CCRx: 通道x配置寄存器

image-20230702195605618

image-20231228170632277

image-20230702200241096

image-20230702200148107

image-20230702200131250

image-20230702200659287

image-20230702195311117

image-20230702200943603

  • DMA_CNDTRx: 传输数量寄存器, 在DMA关闭的时候可以写入

数据传输结束后,寄存器的内容或者变为0;或者当该通道配置为自动重加载模式时,寄存 器的内容将被自动重新加载为之前配置时的数值, 寄存器的数字为0的时候停止传输

image-20230702195918363

  • DMA_CPARx: DMA通道x外设地址寄存器, 数据的来源
  • DMA_CMARx: DMA通道x存储器地址寄存器, 数据的目标

固件库

c
typedef struct
{
  uint32_t DMA_PeripheralBaseAddr; /*!< Specifies the peripheral base address for DMAy Channelx. 外设的地址*/

  uint32_t DMA_MemoryBaseAddr;     /*!< Specifies the memory base address for DMAy Channelx. 目标的地址*/

  uint32_t DMA_DIR;                /*!< Specifies if the peripheral is the source or destination.
                                       This parameter can be a value of @ref DMA_data_transfer_direction传输的方向
                                       实际的参数
#define DMA_DIR_PeripheralDST              ((uint32_t)0x00000010), Periphra作为目的地
#define DMA_DIR_PeripheralSRC              ((uint32_t)0x00000000), Periphra作为初始地址*/

  uint32_t DMA_BufferSize;         /*!< Specifies the buffer size, in data unit, of the specified Channel. 
                                        The data unit is equal to the configuration set in DMA_PeripheralDataSize
                                        or DMA_MemoryDataSize members depending in the transfer direction. 数据处传										输的位数*/

  uint32_t DMA_PeripheralInc;      /*!< Specifies whether the Peripheral address register is incremented or not.
                                        This parameter can be a value of @ref DMA_peripheral_incremented_mode
                                        传输的时候外设地址是否增量*/

  uint32_t DMA_MemoryInc;          /*!< Specifies whether the memory address register is incremented or not.
                                        This parameter can be a value of @ref DMA_memory_incremented_mode 
                                        传输的时候存储器的地址是否增加*/

  uint32_t DMA_PeripheralDataSize; /*!< Specifies the Peripheral data width.
                                        This parameter can be a value of @ref DMA_peripheral_data_size
                                        外设的数据宽度*/

  uint32_t DMA_MemoryDataSize;     /*!< Specifies the Memory data width.
                                        This parameter can be a value of @ref DMA_memory_data_size
                                        目的地的传输的宽度*/

  uint32_t DMA_Mode;               /*!< Specifies the operation mode of the DMAy Channelx.
                                        This parameter can be a value of @ref DMA_circular_normal_mode.
                                        @note: The circular buffer mode cannot be used if the memory-to-memory
                                              data transfer is configured on the selected Channel
                                              传输的时候什么时候结束, 是否为循环操作*/

  uint32_t DMA_Priority;           /*!< Specifies the software priority for the DMAy Channelx.
                                        This parameter can be a value of @ref DMA_priority_level 设置优先级*/

  uint32_t DMA_M2M;                /*!< Specifies if the DMAy Channelx will be used in memory-to-memory transfer.
                                        This parameter can be a value of @ref DMA_memory_to_memory
                                        设置是否为内存之间转移*/
}DMA_InitTypeDef;

数据的宽度不相同的时候, 源比较大, 其他的直接丢弃, 源比较小, 剩余的位置设置为空

实际使用

实现地址之间的传输

c
#include "bsp_dma.h"
//原始数据
const uint32_t aSRC_Const_Buffer[BUFFER_SIZE]= {
                                    0x01020304,0x05060708,0x090A0B0C,0x0D0E0F10,
                                    0x11121314,0x15161718,0x191A1B1C,0x1D1E1F20,
                                    0x21222324,0x25262728,0x292A2B2C,0x2D2E2F30,
                                    0x31323334,0x35363738,0x393A3B3C,0x3D3E3F40,
                                    0x41424344,0x45464748,0x494A4B4C,0x4D4E4F50,
                                    0x51525354,0x55565758,0x595A5B5C,0x5D5E5F60,
                                    0x61626364,0x65666768,0x696A6B6C,0x6D6E6F70,
                                    0x71727374,0x75767778,0x797A7B7C,0x7D7E7F80};
//目标
uint32_t aDST_Buffer[BUFFER_SIZE];

void DMA_MtoM_Config(void)
{
	//初始化时钟
	RCC_AHBPeriphClockCmd(MTM_DMA_CLK, ENABLE);
	
	DMA_InitTypeDef DMA_InitStructure;
	DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)aSRC_Const_Buffer;	//源地址
	DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)aDST_Buffer;				//目标地址
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
	DMA_InitStructure.DMA_BufferSize = BUFFER_SIZE;
	
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable;			//递增
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;				//设置为递增
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;	//设置长度
	DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;					//设置不循环
	
	DMA_InitStructure.DMA_Priority = DMA_Priority_High;				//设置优先级
	DMA_InitStructure.DMA_M2M = DMA_M2M_Enable;
	
	DMA_Init(MTM_DMA_CHANNEL, &DMA_InitStructure);
    //清除标志位
	DMA_ClearFlag(DMA1_FLAG_TC6);
	//使能
	DMA_Cmd(MTM_DMA_CHANNEL, ENABLE);
}

uint8_t Buffercmp(const uint32_t* pBuffer, 
                  uint32_t* pBuffer1, uint16_t BufferLength)
{
  /* 数据长度递减 */
  while(BufferLength--)
  {
    /* 判断两个数据源是否对应相等 */
    if(*pBuffer != *pBuffer1)
    {
      /* 对应数据源不相等马上退出函数,并返回0 */
      return 0;
    }
    /* 递增两个数据源的地址指针 */
    pBuffer++;
    pBuffer1++;
  }
  /* 完成判断并且对应数据相对 */
  return 1;  
}
c
	LED_GPIO_Config();
	LED_R(OFF)
	LED_B(OFF)
	LED_G(OFF)
	uint8_t status = 0;
	DMA_MtoM_Config();
	//检测是否完成
	while(DMA_GetFlagStatus(DMA1_FLAG_TC6)==RESET);
	status = Buffercmp(aSRC_Const_Buffer, aDST_Buffer, BUFFER_SIZE);
	if(status == 0)
	{
		LED_R(ON)
	}else
	LED_G(ON)

实现串口的传输

  1. 实现初始化
  2. 串口发出请求
c
LED_GPIO_Config();
LED_R(OFF)
    LED_B(OFF)
    LED_G(OFF)
    LED_B(ON)
    USART_Config();
//初始化数组
for(uint16_t i=0; i<SENDBUFF_SIZE;i++)
{
    SendBuff[i] = 'a';
}

DMA_USART_Config();
//发送信号
USART_DMACmd(DEBUG_USARTx, USART_DMAReq_Tx, ENABLE);


while(1){
    LED_G_TOGGLE
        for(uint16_t i = 0; i< 0xfff;i++)
            for(uint16_t b = 0; b< 0xff;b++);
};
c
void DMA_USART_Config(void)
{
	//初始化时钟
	RCC_AHBPeriphClockCmd(USART_TX_DMA_CLK, ENABLE);
	
	DMA_InitTypeDef DMA_InitStructure;
	DMA_InitStructure.DMA_PeripheralBaseAddr = USART_DR_ADDRESS;		//外设地址
	DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)SendBuff;				//内存地址
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
	DMA_InitStructure.DMA_BufferSize = SENDBUFF_SIZE;
	
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;			//不增
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
	DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte;
	DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
	
	DMA_InitStructure.DMA_Priority = DMA_Priority_High;
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
	
	DMA_Init(USART_TX_DMA_CHANNEL, &DMA_InitStructure);
	DMA_ClearFlag(USART_TX_DMA_FLAG_TCL);
	//使能
	DMA_Cmd(USART_TX_DMA_CHANNEL, ENABLE);
}

F4/F7/H7

image-20231228184523179

image-20231228184257596

image-20231228184702856

image-20231228184946978

image-20231228185241603

image-20231228185321689

image-20231228185548617

寄存器

image-20231228190031861

image-20231228190554873

image-20231228190626449

image-20231228190640701

image-20231228190733400

image-20231228190930429

image-20231228191152517