当前位置: 首页 > article >正文

【STM32】DMA数据转运(存储器到外设)

本篇博客重点在于标准库函数的理解与使用,搭建一个框架便于快速开发

目录

前言

外设DMA请求使能

DMA1

DMA2 

常用的外设DMA使能库函数 

配置串口发送的DMA请求

驱动代码

MyDMA.h

MyDMA.c

main.c 


前言

【STM32】DMA数据转运(存储器到存储器)_stm32dma往ccr搬运-CSDN博客

【STM32】ADC模拟数字转换(规则组多通道)+ DMA数据转运(外设到存储器)-CSDN博客

本博客学习DMA将数据从存储器转运到外设的代码,其实就是外设到存储器反过来

外设DMA请求使能

DMA请求同时只能有一个请求有效 !!!

DMA1

DMA2 

注意: DMA2控制器及相关请求仅存在于大容量产品和互联型产品中

常用的外设DMA使能库函数 

void USART_DMACmd(USART_TypeDef* USARTx, uint16_t USART_DMAReq,FunctionalState NewState);
void ADC_DMACmd(ADC_TypeDef* ADCx, FunctionalState NewState);
void DAC_DMACmd(uint32_t DAC_Channel, FunctionalState NewState);
void I2C_DMACmd(I2C_TypeDef* I2Cx, FunctionalState NewState);
void SDIO_DMACmd(FunctionalState NewState);
void SPI_I2S_DMACmd(SPI_TypeDef* SPIx, uint16_t SPI_I2S_DMAReq, FunctionalState NewState);

void TIM_DMAConfig(TIM_TypeDef* TIMx, uint16_t TIM_DMABase, uint16_t TIM_DMABurstLength)
void TIM_DMACmd(TIM_TypeDef* TIMx, uint16_t TIM_DMASource,FunctionalState NewState);

配置串口发送的DMA请求

DMA请求同时只能有一个请求有效 

	DMA_InitTypeDef DMA_InitStructure;
	DMA_InitStructure.DMA_PeripheralBaseAddr = AddrA;
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//USART1->DR寄存器为8位
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设地址指针不自增,固定为&USART1->DR
	DMA_InitStructure.DMA_MemoryBaseAddr = AddrB;
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//存储器地址指针自增
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;//外设为转运的目的地
	DMA_InitStructure.DMA_BufferSize = Size;
	DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;//单次转运
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;//失能,存储器到存储器才使能
	DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
	DMA_Init(DMA1_Channel4, &DMA_InitStructure);//USART1的Tx引脚位于DMA1的通道4

串口利用DMA发送

使用DMA进行发送,可以通过设置USART_CR3寄存器上的DMAT位激活。当TXE位被置为’1’ 时,DMA就从指定的SRAM区传送数据到USART_DR寄存器。为USART的发送分配一个DMA 通道的步骤如下(x表示通道号):

1. 在DMA控制寄存器上将USART_DR寄存器地址配置成DMA传输的目的地址。在每个TXE 事件后,数据将被传送到这个地址。

2. 在DMA控制寄存器上将存储器地址配置成DMA传输的源地址。在每个TXE事件后,将从 此存储器区读出数据并传送到USART_DR寄存器。

3. 在DMA控制寄存器中配置要传输的总的字节数。

4. 在DMA寄存器上配置通道优先级。

5. 根据应用程序的要求,配置在传输完成一半还是全部完成时产生DMA中断。

6. 在DMA寄存器上激活该通道。

当传输完成DMA控制器指定的数据量时,DMA控制器在该DMA通道的中断向量上产生一中断。 在发送模式下,当DMA传输完所有要发送的数据时,DMA控制器设置DMA_ISR寄存器的TCIF 标志;监视USART_SR寄存器的TC标志可以确认USART通信是否结束,这样可以在关闭 USART或进入停机模式之前避免破坏最后一次传输的数据;软件需要先等待TXE=1,再等待 TC=1。

USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);//使能USART1的Tx发送请求

驱动代码

配置串口发送的代码这里不再赘述,如有需要可以阅读下方博客。

【STM32】USART通用同步/异步收发器(串口数据的接收与发送)_stm32 usart同步时钟-CSDN博客

MyDMA.h

#ifndef __MYDMA_H
#define __MYDMA_H
 
void MyDMA_Init(uint32_t AddrA, uint32_t AddrB, uint16_t Size);
void MyDMA_Transfer(void);
 
#endif

MyDMA.c

#include "stm32f10x.h"                  // Device header
#include "MyDMA.h"

uint16_t MyDMA_Size;
 
void MyDMA_Init(uint32_t AddrA, uint32_t AddrB, uint16_t Size)
{
	MyDMA_Size = Size;
	
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
	
	DMA_InitTypeDef DMA_InitStructure;
	DMA_InitStructure.DMA_PeripheralBaseAddr = AddrA;
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//USART1->DR寄存器为8位
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设地址指针不自增,固定为&USART1->DR
	DMA_InitStructure.DMA_MemoryBaseAddr = AddrB;
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//存储器地址指针自增
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;//外设为转运的目的地
	DMA_InitStructure.DMA_BufferSize = Size;
	DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;//单次转运
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;//失能,存储器到存储器才使能
	DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
	DMA_Init(DMA1_Channel4, &DMA_InitStructure);//USART1的Tx引脚位于DMA1的通道4
	
	DMA_Cmd(DMA1_Channel4, DISABLE);//先不开始转运
}
 
void MyDMA_Transfer(void)
{
	USART_DMACmd(USART1, USART_DMAReq_Tx, DISABLE);
	DMA_Cmd(DMA1_Channel4, DISABLE);
	DMA_SetCurrDataCounter(DMA1_Channel4, MyDMA_Size);//设置数据转运的大小
	DMA_Cmd(DMA1_Channel4, ENABLE);
	
	USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);//使能USART1的Tx发送请求
	while (DMA_GetFlagStatus(DMA1_FLAG_TC4) == RESET);
	DMA_ClearFlag(DMA1_FLAG_TC4);
}

main.c 

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "MyDMA.h"
#include "Serial.h"
#include "Key.h"

uint8_t Buff_Send[200] = {0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D};
uint16_t Conuter, Percent;
uint8_t KeyNum;
int main(void)
{
	Serial_Init();
	Key_Init();
	MyDMA_Init((uint32_t)&USART1->DR, (uint32_t)Buff_Send, 200);
	
	while (1)
	{
		KeyNum = Key_GetNum();
		if(KeyNum)
		{
			printf("\r\nData:\r\n");
			MyDMA_Transfer();
			Conuter = DMA_GetCurrDataCounter(DMA1_Channel4);
			Percent = 100 - (float)Conuter * 100 / 200;
			printf("\r\nSend%d%%", Percent);//显示传输百分比
			if(Percent == 100)
			{
				printf("\r\n*************Send Finish!******************\r\n");
			}

		}
		

	}
}

http://www.kler.cn/news/304600.html

相关文章:

  • VS Code 配置 Rust-Analyzer 报错
  • VUE下拉选择分页,远程搜索
  • 软件测试工程师面试整理-测试方法
  • ZCC40036 过压保护芯片
  • 用SpringBoot进行阿里云大模型接口调用同步方法和异步方法
  • C# 中的多线程同步:原子变量、原子操作、内存顺序和可见性
  • uni-app 聊天界面滚动到消息底部
  • Java后端程序员简单操作Linux系统命令
  • 深度学习——数据预处理,张量降维
  • Qt 边框border - qss样式
  • C++类与对象深度解析(一):从抽象到实践的全面入门指南
  • Linux相关:在阿里云下载centos系统镜像
  • Leetcode Hot 100刷题记录 -Day16(旋转图像)
  • 15.2 定义一个prometheus数据存储使用的pv
  • A Single Generic Prompt forSegmenting Camouflaged Objects
  • java: 程序包org.junit.jupiter.api不存在
  • 数据分析-前期数据处理
  • MacOS Sonoma(14.x) 大写模式或中文输入法下的英文模式,光标下方永远会出现的CapsLock箭头Icon的去除办法
  • Prompt提示词技巧
  • OA项目值用户登入首页展示
  • ArrayList、LinkedList和Vector的区别
  • Python 的分支结构
  • 如何选择适合企业的高效财税自动化软件
  • 桌面应用框架:tauri是后起之秀,赶上electron路还很长。
  • Mysql | 知识 | 理解是怎么加锁的
  • ansible企业实战
  • 高级java每日一道面试题-2024年9月09日-数据库篇-事务提交后数据仍然没有持久化,可能的原因是什么?
  • 海外服务器:开启全球业务的关键钥匙
  • 神经网络的公式推导与代码实现(论文复现)
  • OFDM系统PAPR算法的MATLAB仿真,对比SLM,PTS以及CAF,对比不同傅里叶变换长度