DMA +串口通信

DMA,全称为: Direct Memory Access,即直接存储器访问, DMA 传输将数据从一个地址空间复制到另外一个地址空间。 当 CPU 初始化这个传输动作,传输动作本身是由DMA 控制器 来实行和完成。典型的例子就是移动一个外部内存的区块到芯片内部更快的
内存区。像是这样的操作并没有让处理器工作拖延,反而可以被重新排程去处理其他的工作。 DMA 传输对于高效能嵌入式系统算法和网络是很重要的。 DMA 传输方式无需 CPU 直接控制传输,也没有中断处理方式那样保留现场和恢复现场的过程,通过硬件为 RAM 与 I/O 设备开辟一条直接传送数据的通路, 能使 CPU 的效率大为提高。

STM32 的 DMA 有以下一些特性:
●每个通道都直接连接专用的硬件 DMA 请求,每个通道都同样支持软件触发。这些功能通过软件来配置。
●在七个请求间的优先权可以通过软件编程设置(共有四级:很高、高、中等和低),假如在相等优先权时由硬件决定(请求 0 优先于请求 1,依此类推) 。
●独立的源和目标数据区的传输宽度(字节、半字、全字),模拟打包和拆包的过程。源和目标地址必须按数据传输宽度对齐。
●支持循环的缓冲器管理
●每个通道都有 3 个事件标志(DMA 半传输, DMA 传输完成和 DMA 传输出错),这 3 个事件标志逻辑或成为一个单独的中断请求。
●存储器和存储器间的传输
●外设和存储器,存储器和外设的传输
●闪存、 SRAM、外设的 SRAM、 APB1 APB2 和 AHB 外设均可作为访问的源和目标。
●可编程的数据传输数目:最大为 65536

本实验是基于战舰开发板 单片机为STM32F103ZET6.
该单片机有两个DAM控制器 ,DMA1和DMA2,本次实验是基于DMA1实验。

DMA初始化步骤:
1、 使能DMA时钟
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
2、
初始化DMA通道参数。DMA通道的选择需要根据自己的需要 ,查询数据手册DMA请求映像,选择所需要初始化的DMA通道。
DMA1请求映像。如下图:
DMA +串口通信_第1张图片
利用ST官方库初始化DMA通道:
void DMA_Init(DMA_Channel_TypeDef* DMAy_Channelx,DMA_InitTypeDef* DMA_InitStruct)
其中,DMA_InitTypeDef结构体定义如下:
typedef struct
{
uint32_t DMA_PeripheralBaseAddr;
uint32_t DMA_MemoryBaseAddr;
uint32_t DMA_DIR;
uint32_t DMA_BufferSize;
uint32_t DMA_PeripheralInc;
uint32_t DMA_MemoryInc;
uint32_t DMA_PeripheralDataSize;
uint32_t DMA_MemoryDataSize;
uint32_t DMA_Mode;
uint32_t DMA_Priority;
uint32_t DMA_M2M;
}DMA_InitTypeDef;
第一个参数 是用来设置DMA传输的外设地址(比如要进行串口传输,那么外设地址应该为USART->DR ,表示方法为 &USART->DR,如果是AD转换的话,那么外设的地址就是ADC->DR,表示方法为&ADC->DR)。
第二个参数 为内存地址,也就是我们存放DMA传输数据的内存地址。
第三个参数是设置数据传输的方向,决定是从外设读取数据到内存还是送数据第四个参数是设置一次传输数据量的大小
第五个参数是设置传输数据的时候外设地址是不变还是递增。如果设置为递增,那么下一次传输的时候地址加 1,这里因为我们是一直往固定外设地址&USART1->DR发送数据,所以地址不递增。
第六个参数是设置传输数据时 候内存地址 是否递增。 这个参数和DMA_PeripheralInc 意思接近,只不过针对的是内存。 这里我们的场景是将内存中连续存储单元的数据发送到串口,毫无疑问内存地址是需要递增的,所以值为 DMA_MemoryInc_Enable。
第七个参数是用来设置外设的数据长度是为字节传输( 8bits),半字 传 输 (16bits) 还 是 字 传 输 (32bits) , 这 里 我 们 是 8 位 字 节 传 输 , 所 以 值 设 置 为DMA_PeripheralDataSize_Byte。 u8—–Byte(字节) u16 —-halfword (半字) u32——word(字)。
第八个参数是用来设置内存的数据长度,和第七个参数意思接近,这
里我们同样设置为字节传输 DMA_MemoryDataSize_Byte。
第九个参数用来设置DMA是否循环采集。如果只采集一次,设置为 DMA_Mode_Normal,如果是循环采集则设置为DMA_Mode_Circular(循环模式通常用于ADC连续转换)
第十个参数用来设置DMA通道的优先级。
第十一个参数设置是否是存储器到存储器模式传输。
接下来为初始化DMA+串口的代码:
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)PerBase_Addr; // 外设地址
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)MemBase_Addr; //内存地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; //数据传输方向为内存到外设
DMA_InitStructure.DMA_BufferSize = Send_Num; //DMA通道缓存的大小
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址不变
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址自增
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //可以设置成循环模式,正常模式下数据传输完成后停止传输
DMA_InitStructure.DMA_Priority = DMA_Priority_High; //通道优先级配置 在多通道DMA传输的时候 这个参数的配置是有意义的
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //禁止内存到内存的传输
DMA_Init(DMA_CHx, &DMA_InitStructure);
使能串口DMA发送:USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);
使能DMA通道,启动传输:
DMA_Cmd(DMA_CHx, ENABLE);

主函数测试代码:
int main(void)
{
NVIC_Config();
SysTick_init();
LED_Config();
USART_Config(115200);
printf(“uart is read!!\r\n”);
DMA_Config(DMA1_Channel4,(u32)&USART1->DR,(u32)tx_buf,txbuf_size);
USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE); //串口向DMA发出请求
LED_Config();
LED_On();
while(1);
}

你可能感兴趣的:(stm32,DMA,STM32,USART)