DMA
直接存储器存取(DMA)用来提供在外设和存储器之间或者存储器和存储器之间的高速数据传
输。无须CPU干预,数据可以通过DMA快速地移动,这就节省了CPU的资源来做其他操作通道配置过程下面是配置DMA通道x的过程(x代表通道号):
1. 在DMA_CPARx寄存器中设置外设寄存器的地址。发生外设数据传输请求时,这个地址将是数据传输的源或目标。
2. 在DMA_CMARx寄存器中设置数据存储器的地址。发生外设数据传输请求时,传输的数据将从这个地址读出或写入这个地址。
3. 在DMA_CNDTRx寄存器中设置要传输的数据量。在每个数据传输后,这个数值递减。
4. 在DMA_CCRx寄存器的PL[1:0]位中设置通道的优先级。
5. 在DMA_CCRx寄存器中设置数据传输的方向、循环模式、外设和存储器的增量模式、外设和存储器的数据宽度、传输一半产生中断或传输完成产生中断。
6. 设置DMA_CCRx寄存器的ENABLE位,启动该通道
1.串口DMA数据传输!!(内存到外设)
/**
USART1 TX DMA 配置,内存到外设(USART1->DR)
*/
void USART_DMA_init(void)
{
DMA_InitTypeDef DMA_InitStructure;/*开启DMA时钟*/
RCC_AHB1PeriphClockCmd(DEBUG_USART_DMA_CLK, ENABLE);
/* 复位初始化DMA数据流 */
DMA_DeInit(DEBUG_USART_DMA_STREAM);/* 确保DMA数据流复位完成 */
while (DMA_GetCmdStatus(DEBUG_USART_DMA_STREAM) != DISABLE) {
}/*usart1 tx对应dma2,通道4,数据流7*/
DMA_InitStructure.DMA_Channel = DEBUG_USART_DMA_CHANNEL;
/*设置DMA源:串口数据寄存器地址*/
DMA_InitStructure.DMA_PeripheralBaseAddr = DEBUG_USART_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_Priority = DMA_Priority_Medium;
/*禁用FIFO*/
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
/*存储器突发传输 16个节拍*/
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
/*外设突发传输 1个节拍*/
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
/*配置DMA2的数据流7*/
DMA_Init(DEBUG_USART_DMA_STREAM, &DMA_InitStructure);
/*使能DMA*/
DMA_Cmd(DEBUG_USART_DMA_STREAM, ENABLE);
/* 等待DMA数据流有效*/
while(DMA_GetCmdStatus(DEBUG_USART_DMA_STREAM) != ENABLE)
{
}
}
2.存储器到存储器数据传输配置
/**
* DMA传输配置
*/
static void DMA_init(void)
{
DMA_InitTypeDef DMA_InitStructure;
__IO uint32_t Timeout = TIMEOUT_MAX;
/* 使能DMA时钟 */
RCC_AHB1PeriphClockCmd(DMA_STREAM_CLOCK, ENABLE);
/* 复位初始化DMA数据流 */
DMA_DeInit(DMA_STREAM);/* 确保DMA数据流复位完成 */
while (DMA_GetCmdStatus(DMA_STREAM) != DISABLE)
{
}
/* DMA数据流通道选择 */
DMA_InitStructure.DMA_Channel = DMA_CHANNEL; // 1
/* 源数据地址 */
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)aSRC_Const_Buffer; // 2
/* 目标地址 */
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)aDST_Buffer; // 3
/* 存储器到存储器模式 */
DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToMemory; //4
/* 数据数目 */
DMA_InitStructure.DMA_BufferSize = (uint32_t)BUFFER_SIZE; //4
/* 使能自动递增功能 */
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable; //5
/* 使能自动递增功能 */
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //6 存储器
/* 源数据是字大小(32位) */
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word; //7 外设
/* 目标数据也是字大小(32位) */
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word; //8
/* 一次传输模式,存储器到存储器模式不能使用循环传输 */
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //9
/* DMA数据流优先级为高 */
DMA_InitStructure.DMA_Priority = DMA_Priority_High; //10
/* 禁用FIFO模式 */
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; //11
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full; //12
/* 单次模式 */
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; //13
/* 单次模式 */
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; //14
/* 完成DMA数据流参数配置 */
DMA_Init(DMA_STREAM, &DMA_InitStructure);
/* 清除DMA数据流传输完成标志位 */
DMA_ClearFlag(DMA_STREAM,DMA_FLAG_TCIF);
/* 使能DMA数据流,开始DMA数据传输 */
DMA_Cmd(DMA_STREAM, ENABLE);/* 检测DMA数据流是否有效并带有超时检测功能 */
Timeout = TIMEOUT_MAX;
while ((DMA_GetCmdStatus(DMA_STREAM) != ENABLE) && (Timeout-- > 0))
{
}
/* 判断是否超时 */
if (Timeout == 0)
{
/* 超时就让程序运行下面循环:RGB彩色灯闪烁 */
while (1)
{
LED_RED;
Delay(0xFFFFFF);
LED_RGBOFF;
Delay(0xFFFFFF);
}
}
}应用:主函数中
/* 等待DMA传输完成 */
while(DMA_GetFlagStatus(DMA_STREAM,DMA_FLAG_TCIF)==DISABLE)
{
}