📌  相关文章
📜  DMA传输模式(1)

📅  最后修改于: 2023-12-03 14:40:48.328000             🧑  作者: Mango

DMA传输模式

DMA(Direct Memory Access)是一种计算机数据传输模式,这种传输模式涉及到三个组成部分:输入/输出设备、主机内存和DMA控制器。DMA控制器通过一套信号线路将输入/输出设备和内存连接起来,并通过一套独立的地址总线和数据总线对它们进行数据传输。

DMA传输模式可以大大降低CPU的负担,因为在DMA模式中,数据传输的过程中不需要CPU的参与。CPU只需要在起始阶段设置数据传输的起始地址、目标地址和数据长度后,就可以将控制权交给DMA控制器,在数据传输完毕之前,CPU不需要对数据进行任何的处理和干预。

DMA传输模式可以带来以下好处:

  1. 减少CPU负担: 在复杂的数据传输场景中,DMA可以在不占用CPU的情况下完成大量数据的处理和传输。

  2. 提升数据传输速度: 由于DMA不需要CPU的参与,数据传输速度可以得到提升。相比CPU进行的数据传输方式,DMA的数据传输速度可以快2-3倍。

  3. 简化编程难度:由于DMA控制器上手处理数据传输流程,程序员可以将更多的精力投入到业务逻辑上。

DMA传输模式的使用

使用DMA传输模式需要经过以下几步:

  1. 设置DMA控制器:在开始使用DMA模式时,需要设置一些寄存器以及初始化DMA控制器,如 DMA源地址(数据从哪里来)、目标地址(数据要去哪里)、数据长度等参数。

  2. CPU开始DMA传输:一旦DMA控制器初始化完成,CPU就可以将这些信息发送给DMA控制器,DMA控制器开始独立传输数据。

  3. DMA传输执行完毕:DMA控制器将传输的信息回传给CPU,CPU重新获得控制权并继续执行接下来的操作。

示例代码
/*以下示例仅作参考,不可直接使用,具体实现还需要参考对应芯片的文档*/

#define BufferSize             ((uint32_t)0x00000200)

/* DMA传输完成后触发该函数 */
void DMA1_Stream0_IRQHandler(void)
{
  /* 判断传输是否完成 */
  if (DMA_GetITStatus(DMA1_Stream0, DMA_IT_TCIF0))
  {
    /* 清除传输完成中断标志 */
    DMA_ClearITPendingBit(DMA1_Stream0, DMA_IT_TCIF0);
  }
}

/* DMA传输初始化设置 */
void DMA_Init_Config(void)
{
  DMA_InitTypeDef  DMA_InitStructure;

  DMA_DeInit(DMA1_Stream0);

  /* DMA通道设置 */
  DMA_InitStructure.DMA_Channel = DMA_Channel_0;

  /* 源端地址 */
  DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&SPI1->DR; 

  /* 目标端地址 */
  DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)Rx_Buffer;

  /* 传输方向为 从外设到内存 */
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;

  /* 外设数据宽度为 半字 */
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;

  /* 内存数据宽度为 半字 */
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;

  /* DMA传输模式为 循环传输 */
  DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;

  /* 内存地址按字(32位)自增 */
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;

  /* 外设地址按字(32位)禁止自增 */
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

  /* DMA数据操作长度 */
  DMA_InitStructure.DMA_BufferSize = BufferSize;

  /* DMA 优先级为 高 */
  DMA_InitStructure.DMA_Priority = DMA_Priority_High;

  /* 开启 DMA1 通道0 */
  DMA_Cmd(DMA1_Stream0, ENABLE);

  /* DMA 数据传输 */
  DMA_Init(DMA1_Stream0, &DMA_InitStructure);

  /* DMA1通道中断配置 */
  DMA_ITConfig(DMA1_Stream0, DMA_IT_TC, ENABLE);

  /* 开启 DMA1 传输中断 */
  NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream0_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);

  /* 启动SPI1 */
  SPI_Cmd(SPI1, ENABLE);

  while (1)
  {
  }
}