📅  最后修改于: 2023-12-03 14:40:48.328000             🧑  作者: Mango
DMA(Direct Memory Access)是一种计算机数据传输模式,这种传输模式涉及到三个组成部分:输入/输出设备、主机内存和DMA控制器。DMA控制器通过一套信号线路将输入/输出设备和内存连接起来,并通过一套独立的地址总线和数据总线对它们进行数据传输。
DMA传输模式可以大大降低CPU的负担,因为在DMA模式中,数据传输的过程中不需要CPU的参与。CPU只需要在起始阶段设置数据传输的起始地址、目标地址和数据长度后,就可以将控制权交给DMA控制器,在数据传输完毕之前,CPU不需要对数据进行任何的处理和干预。
DMA传输模式可以带来以下好处:
减少CPU负担: 在复杂的数据传输场景中,DMA可以在不占用CPU的情况下完成大量数据的处理和传输。
提升数据传输速度: 由于DMA不需要CPU的参与,数据传输速度可以得到提升。相比CPU进行的数据传输方式,DMA的数据传输速度可以快2-3倍。
简化编程难度:由于DMA控制器上手处理数据传输流程,程序员可以将更多的精力投入到业务逻辑上。
使用DMA传输模式需要经过以下几步:
设置DMA控制器:在开始使用DMA模式时,需要设置一些寄存器以及初始化DMA控制器,如 DMA源地址(数据从哪里来)、目标地址(数据要去哪里)、数据长度等参数。
CPU开始DMA传输:一旦DMA控制器初始化完成,CPU就可以将这些信息发送给DMA控制器,DMA控制器开始独立传输数据。
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)
{
}
}