【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");
}
}
}
}