22.STM32的DMA

1.DMA简介

学习过操作系统都知道,DMA就是直接存储器访问。就是当CPU给予DMA指命,DMA就会将数据从一个地址复制到另外一个地址空间。为什么需要呢,因为CPU是一个很重要的资源,在等待取数据和等待数据发送完成,是极其不划算的,所以CPU直接给DMA指命,DMA就去干数据移动。为CPU减少了很多工作量。
STM32F最多有2个DMA寄存器,2个DMA寄存器总共有16个数据流(每个控制器8个)。每个DMA控制器都用于管理一个或者多个外设的存储器访问请求,而每个数据流总共有多达8个通道,有一个仲裁器,用于处理DMA请求间的优先级。
2个DMA寄存器>每个DMA寄存器16个数据流>每个数据流最多可多达8个通道
有一个仲裁器

2.DMA特性

1.每个DMA控制器都用于管理一个或者多个外设的存储器访问请求,而每个数据流总共有多达8个通道
2.每个数据流都有单独的四级32位先进先出的存储缓冲区,可以用于FIFO模式或之间模式
FIFO模式:可以通道软件将阈值分别选为FIFO大小的1/4,1/2,3/4
直接模式:每个DMA请求会立即启动对存储器的转输,当在直接模式下将DMA的请求配置以存储器到外设模式转输数据时,DMA仅会将一个数据从存储器预加到内部FIFO,从而确保一旦外设触发DMA请求时立即转输数据
通过硬件可以将每个数据流配置为
支持外设到存储器,存储器到外设,存储器到存储器的常规通道
支持在存储器双缓冲的双缓冲区通道
3.8个数据流中每一个都哟偶一个两节到专用的DMA通道
4.DMA数据流请求之前的优先级可以用软件编程(非常高,高,中,低),在软件优先级相同的情况下,可以通过硬件决定优先级(请求优先级0高于优先级1)
5.每个数据流也支持通过软件触发存储器到存储器的转输
6.可供数据流选择的通道请求多达8个,可以通过软件配置。
7.要转输的数目可以由DMA控制器或外设管理
6.对于数据位宽不对的地方,有一个数据缓存器
7.5个事件标志位

3.DMA框图

请添加图片描述
很明显,有8个数据流(REQ_STREAM0-REQ_STREAM8)
每个数据;流对应最多8个通道,
通道的选择
请添加图片描述
DMA的通道与数据流
请添加图片描述
DMA的数据流
8个DMA控制器数据能够提供源和目标之间的单向转输。
可配置
外设到存储器,存储器到外设,存储器到存储器
双缓冲,使用存储器的两个存储器指针的双缓冲转输
要转输的数据量可以编程
DMA事务
请添加图片描述
请添加图片描述
DMA仲裁器
请添加图片描述
DMA指针递增
就是转输数据指针一直加一
请添加图片描述

DMA循环模式
转输数据完后,重新回到开头继续转输
请添加图片描述
可编程数据宽度
请添加图片描述
单次或多次转输
可以一个字节一个字节转输,也可以一次多个字节
请添加图片描述
双缓冲模式
就是两个地址转入数据到一个地址,一个在传数据中,可以准备另一个缓冲的准备。
请添加图片描述
DMA中断
开启对应的中断需要对应的使能位
请添加图片描述

4.数据流配置

1.将DMA_SxCR中的EN位置0,就是禁止转输数据了,我要开始配置了的意思。
2.外设基地址
3.存储器基地址
4.数据数,一次转输数据大小
5.选择DMA通道
6.
7.配置数据流优先级
8.配置FIFO
9.数据转输方向,中断等
10DMA_SxCR中的EN位置1,开始转输
请添加图片描述请添加图片描述

5.DMA的HAL库函数

1.DMA初始化函数
HAL_StatusTypeDef HAL_DMA_Init(DMA_HandleTypeDef *hdma);
Instance设置了数据流与DMA选择,
Init配置数据流方向,
外设增量,存储器增量(每次转输时候是否地址移动)
外设长度,存储器长度(一次转输的内容长度)
模式
优先级
FIFO模式
存储器与外设突发模式
请添加图片描述
请添加图片描述
2.开启DMA通道
开启的时候是否开启中断
请添加图片描述
请添加图片描述
第一个正在转输时候中断
第二个等待中断
第三个中断通用处理函数
还有一个回调函数,但是在结构体里面
3.双缓冲DMA通道
请添加图片描述
4.DMA通道连接
就是说相关结构体中专门有一个变量,可以用于指向DMA结构体变量,用于将两方软件连接
请添加图片描述
4.DMA外设相关函数
请添加图片描述
5.DMA配置相关步骤
请添加图片描述

6.DMA的程序

通过DMA,将内存中一个数组连续发送至串口,而且显示当前转输百分比

#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"

#include "lcd.h"

#include "usart.h"
DMA_HandleTypeDef DMAhandle_2;
float pro=0;                    //进度
#define SEND_BUF_SIZE 7800	//发送数据长度,最好等于sizeof(TEXT_TO_SEND)+2的整数倍.

u8 SendBuff[SEND_BUF_SIZE]; //发送数据缓冲区
const u8 TEXT_TO_SEND[]={"ALIENTEK Apollo STM32F4 DMA 串口实验"}; 
void MY_DMAInit(void)  //DMA2数据流7通道4
{
	__HAL_RCC_DMA2_CLK_ENABLE();
	__HAL_LINKDMA(&UART1_Handler,hdmatx,DMAhandle_2);   //第一个参数外设的句柄,第二个赋值的地方,第三个DMA句柄
	
	
	
	DMAhandle_2.Instance=DMA2_Stream7;
	DMAhandle_2.Init.Channel =DMA_CHANNEL_4;
	DMAhandle_2.Init.Direction=DMA_MEMORY_TO_PERIPH;
	
	DMAhandle_2.Init.FIFOMode= DMA_FIFOMODE_DISABLE;        //不使用FIFO
	DMAhandle_2.Init.FIFOThreshold=DMA_FIFO_THRESHOLD_FULL;
	
	DMAhandle_2.Init.MemBurst=DMA_MBURST_SINGLE;          //存储器单次转输
	DMAhandle_2.Init.PeriphBurst=DMA_PBURST_SINGLE;				//外设单次转输
	
	DMAhandle_2.Init.MemDataAlignment= DMA_MDATAALIGN_BYTE;     			//存储器数据宽度
	DMAhandle_2.Init.PeriphDataAlignment=DMA_PDATAALIGN_BYTE;   //外设数据宽度
	
	DMAhandle_2.Init.MemInc=DMA_MINC_ENABLE;           //存储器递增
	DMAhandle_2.Init.PeriphInc=DMA_PINC_DISABLE;   //外设不递增
	
	DMAhandle_2.Init.Mode=DMA_NORMAL;            //正常模式

	DMAhandle_2.Init.Priority=	DMA_PRIORITY_MEDIUM;
	
	HAL_DMA_DeInit(&DMAhandle_2);   //初始化为普通配置
	HAL_DMA_Init(&DMAhandle_2);
}
void MYDMA_USART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{
    HAL_DMA_Start(huart->hdmatx, (u32)pData, (uint32_t)&huart->Instance->DR, Size);//开启DMA传输
    
    huart->Instance->CR3 |= USART_CR3_DMAT;//使能串口DMA发送
}	

int main(void)
{
	
	u16 i;
	u8 t=0;
	u8 j,mask=0;
	float pro=0;                    //进度
    Stm32_Clock_Init(360,25,2,8);   //设置时钟,180Mhz
    delay_init(180);                //初始化延时函数
    uart_init(115200);              //初始化USART
    LED_Init();                     //初始化LED 
	
    LCD_Init();                     //LCD初始化
		printf("转输1");
		MY_DMAInit();
	printf("转输2");
	j=sizeof(TEXT_TO_SEND);	   
	for(i=0;i<SEND_BUF_SIZE;i++)//填充ASCII字符集数据
{
		if(t>=j)//加入换行符
		{
			if(mask)
			{
				SendBuff[i]=0x0a;
				t=0;
			}
			else 
			{
				SendBuff[i]=0x0d;
				mask++;
			}	
		}
		else//复制TEXT_TO_SEND语句
		{
			mask=0;
			SendBuff[i]=TEXT_TO_SEND[t];
			t++;
		}   	   
 }   
		i=0;
 printf("转输3");
	while(1)
	{
		printf("转输开始");
		MYDMA_USART_Transmit(&UART1_Handler,(u8*)SendBuff,SEND_BUF_SIZE); //启动传输
		while(1)
		{
				pro=__HAL_DMA_GET_COUNTER(&DMAhandle_2);//得到当前还剩余多少个数据
				pro=1-pro/SEND_BUF_SIZE;    //得到百分比	 
				pro*=100;
				printf("%f",pro);	
				if(__HAL_DMA_GET_FLAG(&DMAhandle_2,DMA_FLAG_TCIF3_7))//等待DMA2_Steam7传输完成
        {
          __HAL_DMA_CLEAR_FLAG(&DMAhandle_2,DMA_FLAG_TCIF3_7);//清除DMA2_Steam7传输完成标志
          HAL_UART_DMAStop(&UART1_Handler);      //传输完成以后关闭串口DMA
					break; 
        }
    
		 }
		printf("转输完成");
		 delay_ms(10000);
	}
	
}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值