关于DMA的笔记详见https://blog.csdn.net/Mr_rustylake/article/details/130140952?spm=1001.2014.3001.5501
实验要求:按下key0按键,实现内部RAM中内存到内存的传输。
首先介绍相关的函数和结构体。
函数:
1、__HAL_RCC_DMAx_CLK_ENABLE():启动相应DMAx的时钟信号;
2、HAL_Init():利用初始化结构体对DMA进行初始化,参数为相应的初始化结构体;
3、HAL_DMA_Start():开始DMA传输,参数为DMA初始化结构体,数据源数组和目标数组以及初始化函数相关,写0即不需要;
注意:在传输的时候,我们先要失能我们的DMA,传入数据长度之后,再使能DMA。
结构体:
DMA_HandleTypeDef g_dma_handler.Instance:选择我们相应的DMAx和它的通道Channelx;
DMA_HandleTypeDef g_dma_handler.Init.Direction:传输方向,有内存到内存,内存到外设,外设到外设,外设到内存;
DMA_HandleTypeDef g_dma_handler.Init.MemoryDataAlignment:数据接收长度;
DMA_HandleTypeDef g_dma_handler.Init.MemInc:是否需要进行接受数据的指针增量;
DMA_HandleTypeDef g_dma_handler.Init.PeriphDataAlignment:数据传输长度;
DMA_HandleTypeDef g_dma_handler.Init.PeriphInc:是否需要进行传输数据的指针增量;
DMA_HandleTypeDef g_dma_handler.Init.Priority:DMA的软件设置优先级;
DMA_HandleTypeDef g_dma_handler.Init.Mode:选择普通模式或者循环模式。普通模式只传输一次,再传输的话是不会被记在目标数组中的;循环模式在数组满了的时候再传输则会把数据放在第一个这样循环传输,可以用于输出持续的波形。
---------------------------------------------------------------------------------
接下来编写我们的实验代码。
先编写我们的函数文件代码dma.c:
#include "./SYSTEM/sys/sys.h"
#Include "./BSPDMA/dma.h"
DMA_HandleTypeDef g_dma_handler;
uint8_t src_buf[10] = {0x0A, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09};
uint8_t dst_buf[10] = {0};
void dma_init(void){
__HAL_RCC_DMA1_CLK_ENABLE();
g_dma_handler.Instance = DMA1_Channel1;
g_dma_handler.Init.Direction = DMA_MEMORY_TO_MEMORY; //数据传输方向
g_dma_handler.Init.MemoryDataAlignment = DMA_MDATAALIGN_BYTE; //数据传输宽度
g_dma_handler.Init.MemInc = DMA_MINC_ENABLE; // 数据传输增量,当传输完一个数据后,要移动到下一个数据
g_dma_handler.Init.Mode = DMA_NORMAL; //不支持循环模式
g_dma_handler.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
g_dma_handler.Init.PeriphInc = DMA_PINC_ENABLE; // 数据接受增量,当接受完一个数据后,要移动到下一个数据
g_dma_handler.Init.Priority = DMA_PRIORITY_HIGH;
HAL_DMA_Init(&g_dma_handler);
HAL_DMA_Start(&g_dma_handler, (uint32_t)src_buf, (uint32_t)dst_buf, 0);
}
void dma_enable_transmit(uint16_t cndtr){ //参数为传输内容长度
__HAL_DMA_DISABLE(&g_dma_handler);
g_dma_handler.Instance->CNDTR = cndtr; //(DMA1_Channel1->CNDTR = cndtr;)也可以
__HAL_DMA_ENABLE(&g_dma_handler);
}
再编写函数头文件dma.h:
#ifndef __DMA_H
#define __DMA_H
DMA_HandleTypeDef g_dma_handler;
extern uint8_t src_buf[10];
extern uint8_t dst_buf[10];
void dma_init(void);
void dma_enable_transmit(uint16_t cndtr);
#endif
编写主函数代码main.c:
#include "./SYSTEM/sys/sys.h"
#include "./BSP/LED/led.h"
#include "./SYSTEM/DELAY/delay.h"
#include "./BSP/DMA/dma.h"
#include "./BSP/KEY/key.h"
#include "./BSP/BEEP/beep.h"
#include "string.h"
#include "./BSP/USART/usart.h"
int main(void){
HAL_Iniy();
sys_stm32_clock_init(RCC_PLL_MUL9);
delay_init(72);
led_init();
beep_init();
key_init();
usart_init(115200);
LED0(0);
while(1){
key = key_scan(0);
if(key == KEY0_PRES){
memset(dst_buf, 10, 0);
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("传输完成\n");
break;
}
}
}
LED0_TOGGLE();
delay_ms(200);
}
}