STM32中的DMA数据转运——上篇

STM32中的DMA数据转运——下篇(扩展版)-CSDN博客

DMA(Direct Memory Access,直接存储器访问)是STM32中的一个重要功能,允许外设与存储器之间直接传输数据,而不需要通过CPU参与。这不仅减轻了CPU的负担,还提高了数据传输的效率。本文将详细介绍STM32中的各种存储器地址与类型、DMA框图与总线设计、DMA的基本结构及其工作原理,包括一些常见的使用场景。

一、STM32中的存储器类型与地址范围


在STM32的芯片结构中,存储器分为几种类型,每种类型都有其特定的用途和特点。理解这些存储器的地址范围与作用,有助于正确使用DMA进行数据传输。

Flash存储器

类型:非易失性存储器,断电后数据不会丢失。
地址范围:0x08000000 ~ 0x080FFFFF(以STM32F103为例)。
用途:主要用于存储程序代码和一些不可变的数据,如常量。Flash存储器通常是只读的(在正常程序运行时),但可以通过特殊的操作来擦除和重写。DMA可以从Flash中读取数据,常用于从非易失存储器中加载数据到RAM进行处理。
典型应用:程序启动时,将Flash中的数据加载到SRAM中,供程序快速访问。

SRAM

类型:易失性存储器,断电后数据会丢失。
地址范围:0x20000000 ~ 0x2001FFFF(STM32F103具有20KB的SRAM)。
用途:主要用于存储运行时的变量、堆栈、全局变量和临时数据。DMA在大多数情况下都用于在SRAM中进行读写操作,因为SRAM访问速度快,非常适合频繁的读写需求。
典型应用:DMA可以用于从ADC获取采样数据,并将其存储到SRAM中,供后续处理。

外部RAM/ROM(扩展内存)

类型:可以通过FSMC(灵活静态存储控制器)扩展的存储器。
地址范围:0x60000000 ~ 0x6FFFFFFF。
用途:扩展内存通常用于需要大容量数据存储的场景,如图片、音频等数据的存储。外部存储器访问的速度可能比内部SRAM要慢,但它提供了额外的存储空间。
典型应用:DMA可以用于快速地在外部存储器和内存之间传输大块数据,比如视频处理或文件系统应用。

外设寄存器

类型:映射到内存的外设控制寄存器。
地址范围:0x40000000 ~ 0x50000000。
用途:控制和访问STM32的外设,如GPIO、UART、SPI等。DMA通常与这些外设协同工作,自动将外设的数据传输到内存中或从内存传输到外设。
典型应用:例如,使用USART发送数据时,可以通过DMA从SRAM中自动读取数据并传输到USART寄存器,避免CPU占用。

系统存储器

类型:只读存储器。
地址范围:0x1FFFF000 ~ 0x1FFFF7FF。
用途:存储STM32的启动代码,如引导程序。这部分存储器通常不会在正常程序中使用,但在引导过程中可能会用到。
这些存储器类型决定了DMA可以传输数据的源地址和目标地址。通过灵活配置DMA控制器,开发者可以实现高效的数据流动,大幅提高系统的性能。

二、DMA的框图与总线设计

DMA控制器的核心优势在于其独立于CPU进行数据传输的能力。STM32中的DMA通过AHB(Advanced High-performance Bus)和APB(Advanced Peripheral Bus)两种总线来进行存储器和外设之间的数据传输。

AHB总线(Advanced High-performance Bus)

AHB总线是STM32中用于高速传输的主总线,DMA控制器通过AHB总线与内存(如SRAM、Flash)进行交互。AHB总线的特点是它支持多主设备访问,这意味着多个设备(包括DMA、CPU等)可以同时请求总线资源,而不会互相阻塞。总线仲裁机制确保了各个设备能够公平、高效地访问总线。

优点:AHB总线的高带宽使得DMA能够以较高的速度在内存和外设之间传输大块数据,减少传输延迟。
典型应用:例如,在图像处理应用中,DMA可以通过AHB总线快速地将图像数据从外部RAM传输到SRAM,供CPU或其他外设处理。

APB总线(Advanced Peripheral Bus)

APB总线是STM32中连接低速外设的总线,如UART、SPI、I2C等。虽然APB总线的带宽较低,但它的设计更加简单,适合那些不需要高速数据传输的外设。DMA通过APB总线与这些外设进行数据交换,完成数据传输任务。

典型应用:例如,通过SPI与外部存储器通信时,DMA可以通过APB总线自动将接收到的数据写入内存,而无需CPU的干预。

三、DMA的基本结构与工作原理

DMA控制器通常包含多个独立的通道,每个通道都可以配置为处理特定的外设和存储器间的数据传输任务。每个通道有自己独立的寄存器集,用于配置其操作参数。

DMA请求

DMA请求信号是由外设发出的,用于通知DMA控制器开始数据传输。STM32中的许多外设,如ADC、USART、SPI等,都可以生成DMA请求信号。DMA控制器根据外设的请求,启动对应的通道,执行数据传输任务。

硬件触发:例如,当ADC完成一次采样时,它会自动产生一个DMA请求信号,触发DMA将采样数据写入到SRAM中。
软件触发:有时,开发者可以通过软件手动触发DMA进行数据传输,特别是在需要快速传输大量数据时。

数据转运

数据转运是DMA的核心功能。DMA控制器根据配置的源地址和目标地址,将数据从一个存储区域复制到另一个存储区域。这个过程中,DMA支持不同的数据宽度传输,如字节、半字(16位)、全字(32位),以适应不同的外设和存储器需求。

典型应用:例如,从SRAM传输一组传感器数据到USART寄存器,用于串口通信。


地址自增与定向传输

DMA支持多种地址模式,常见的有地址自增模式和定向传输模式。地址自增模式:每次数据传输完成后,源地址或目标地址可以自动递增,适合连续数据块的传输。定向传输模式:地址保持不变,适合从固定外设寄存器读取或写入数据的场景。


四、DMA的参数控制

硬件触发

外设如ADC、USART可以通过硬件事件产生DMA请求。比如,当ADC完成一次采样时,它会自动触发DMA,将数据传输到存储器。

开关控制

DMA通道可以通过软件配置进行启动和关闭。当DMA传输完成后,软件可以关闭该通道,避免资源浪费。开发者可以通过寄存器或直接通过编程接口控制DMA的开关状态。

传输计数器

DMA控制器的每个通道都有一个传输计数器,用于指示还需要传输的数据项数量。这个计数器在每次数据传输后会自动递减,直到所有数据传输完毕。当计数器达到0时,DMA将自动停止。

DMA请求与响应机制

DMA传输依赖于外设的请求信号。外设在需要传输数据时,向DMA发出请求,DMA控制器在接受到请求后将执行数据传输任务。完成后,DMA会向外设发送响应信号,通知传输成功。这种机制确保了数据传输的同步性与可靠性。

小结

STM32中的DMA控制器是高效数据传输的核心工具,能够显著提升系统性能。理解DMA的框图、存储器类型、总线架构和基本结构,可以帮助开发者更好地应用DMA,实现外设和存储器间的高效数据传输。下一篇文章将深入探讨DMA的具体配置方法及常见应用场景。

以下是一个基本的 STM32F4 DMA 数据传输的代码示例: ``` #include "stm32f4xx.h" #define BUFFER_SIZE 1024 uint32_t src_buffer[BUFFER_SIZE]; uint32_t dst_buffer[BUFFER_SIZE]; void init_DMA(void) { DMA_InitTypeDef dma_init; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE); DMA_StructInit(&dma_init); dma_init.DMA_Channel = DMA_Channel_0; dma_init.DMA_PeripheralBaseAddr = (uint32_t)src_buffer; dma_init.DMA_Memory0BaseAddr = (uint32_t)dst_buffer; dma_init.DMA_DIR = DMA_DIR_PeripheralToMemory; dma_init.DMA_BufferSize = BUFFER_SIZE; dma_init.DMA_PeripheralInc = DMA_PeripheralInc_Enable; dma_init.DMA_MemoryInc = DMA_MemoryInc_Enable; dma_init.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word; dma_init.DMA_MemoryDataSize = DMA_MemoryDataSize_Word; dma_init.DMA_Mode = DMA_Mode_Normal; dma_init.DMA_Priority = DMA_Priority_High; dma_init.DMA_FIFOMode = DMA_FIFOMode_Enable; dma_init.DMA_FIFOThreshold = DMA_FIFOThreshold_Full; dma_init.DMA_MemoryBurst = DMA_MemoryBurst_Single; dma_init.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; DMA_Init(DMA2_Stream0, &dma_init); } int main(void) { init_DMA(); // 启动 DMA 传输 DMA_Cmd(DMA2_Stream0, ENABLE); while (1) { // 循环等待 DMA 传输完成 while (DMA_GetFlagStatus(DMA2_Stream0, DMA_FLAG_TCIF0) == RESET) {} DMA_ClearFlag(DMA2_Stream0, DMA_FLAG_TCIF0); // 处理数据 for (int i = 0; i < BUFFER_SIZE; i++) { // ... } // 重新启动 DMA 传输 DMA_Cmd(DMA2_Stream0, ENABLE); } } ``` 在这个代码,我们首先定义了两个缓冲区 `src_buffer` 和 `dst_buffer`,它们的大小均为 `BUFFER_SIZE`。然后我们在 `init_DMA()` 函数初始化了 DMA 控制器,并将 `src_buffer` 的地址作为外设地址,`dst_buffer` 的地址作为内存地址,设置了数据传输方向为外设到内存,以及传输数据的大小和增量等参数。 在 `main()` 函数,我们启动了 DMA 的传输,并在一个无限循环等待 DMA 的传输完成。一旦传输完成,我们处理数据,并再次启动 DMA 的传输。在这个无限循环DMA 将会不断地传输数据,直到程序结束。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值