1.DMA概念介绍
DMA,全称Direct Memory Access,即直接存储器访问。
DMA传输 将数据从一个地址空间复制到另一个地址空间。
注意:DMA传输无需CPU直接控制传输
2.DMA框图
3.DMA处理过程
外设的 8 个请求独立连接到每个通道,由 DMA_SxCR 控制数据流选择哪一个通道,每个
数据流有 8 个通道可供选择,每次只能选择其中一个通道进行 DMA 传输。
5 DMA优先级
第一阶段(软件阶段):每个通道的优先级可在DMA_CCRx寄存器中设置,有四个等级:最高、高、中和低优先级。
第二阶段(硬件阶段):如果两个请求有相同软件优先级,较低编号的通道比较高编号的通道有较高的优先级。
6.寄存器
7.DMA句柄结构体
typedef struct __DMA_HandleTypeDef
{
void Instance; / 寄存器基地址 /
DMA_InitTypeDef Init; / DAM 通信参数 */
uint32_t StreamBaseAddress
uint32_t StreamIndex
…
}DMA_HandleTypeDef;
typedef struct
{
uint32_t Channel; /* 传输通道,例如:DMA_CHANEL_4 /
uint32_t Direction; / 传输方向,例如存储器到外设 DMA_MEMORY_TO_PERIPH /
uint32_t PeriphInc; / 外设(非)增量模式,非增量模式 DMA_PINC_DISABLE /
uint32_t MemInc; / 存储器(非)增量模式,增量模式 DMA_MINC_ENABLE /
uint32_t PeriphDataAlignment; / 外设数据大小:8/16/32 位 /
uint32_t MemDataAlignment; / 存储器数据大小:8/16/32 位 /
uint32_t Mode; / 模式:外设流控模式/循环模式/普通模式 /
uint32_t Priority; / DMA 优先级:低/中/高/非常高 */
}DMA_InitTypeDef;
8 8.2以DMA方式传输串口数据配置步骤
代码:
8.1 dma.c
//DMA数据传输(内存到内存的传输)实现步骤:
//1.全局变量与宏定义
//1.1源与目标缓冲区定义//2.函数定义
//初始化DMA配置
//2.1DMA时钟使能
//2.3初始化DMA句柄及DMA配置
//2.4关联源和目标地址//3 传输控制
//3.1传输失能
//3.2设置传输数据的长度
//3.3传输使能//4.函数调用、执行
//4.1硬件初始化,HAL_Init()调用
//4.2 DMA配置初始化化函数调用调用
//4.3 等待DMA传输完成
//4.4 while(1)中执行代码//DMA数据传输(内存到内存的传输)实现步骤:
//2.2DMA句柄创建
DMA_HandleTypeDef g_dma_handler;
//1.全局变量与宏定义
//1.1源与目标缓冲区定义
uint8_t src_buf[10] = {0x0a, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09};
uint8_t dest_buf[10] = {0};//2.函数定义
//初始化DMA配置
void dma_init(void)
{//2.1DMA1时钟使能__HAL_RCC_DMA1_CLK_ENABLE();//2.3初始化DMA句柄及DMA配置g_dma_handler.Instance = DMA1_Channel1;g_dma_handler.Init.Direction = DMA_MEMORY_TO_MEMORY;/* 与目标地址相关 */g_dma_handler.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;g_dma_handler.Init.MemInc = DMA_MINC_ENABLE;/* 与源地址相关 */g_dma_handler.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;g_dma_handler.Init.PeriphInc = DMA_PINC_ENABLE;g_dma_handler.Init.Priority = DMA_PRIORITY_HIGH;g_dma_handler.Init.Mode = DMA_NORMAL; /* 内存到内存是不支持循环模式 */HAL_DMA_Init(&g_dma_handler);//2.4关联源和目标地址,启动DMA传输的函数HAL_DMA_Start(&g_dma_handler, (uint32_t)src_buf, (uint32_t)dest_buf, 0);}//3 传输控制函数
void dma_enable_transmit(uint16_t cndtr)
{//3.1传输失能__HAL_DMA_DISABLE(&g_dma_handler);//3.2设置传输数据的长度g_dma_handler.Instance->DMA_CNDTR = cndtr; // 设置传输数据长度//3.3传输使能__HAL_DMA_ENABLE(&g_dma_handler);}
8.2 main.c
int main()
{uint8_t key = 0;//3.1硬件初始化,HAL_Init()调用HAL_Init(); /* 初始化HAL库 */sys_stm32_clock_init(336, 8, 2, 7); /* 设置时钟,168Mhz */delay_init(168); /* 延时初始化 */usart_init(115200);led_init(); /* 初始化LED */key_init(); /* 初始化按键 */LED0(0); /* 先点亮LED0 *///3.2 DMA配置初始化化函数调用调用dma_init();while(1){key = key_scan(0); /* 得到键值 */if (key == KEY0_PRES){memset(dest_buf, 0, 10);dma_enable_transmit(10);while(1){if (__HAL_DMA_GET_FLAG(&g_dma_handler, DMA_FLAG_TC1)){__HAL_DMA_CLEAR_FLAG(&g_dma_handler, DMA_FLAG_TC1);printf("传输完成 \r\n");break;}}}LED0_TOGGLE();delay_ms(200); }}