STM32_DMA 标准初始化设置解释

本文详细介绍了STM32中的DMA(直接内存访问)模块及其配置方法。DMA作为STM32中的一个重要组成部分,能够实现外设与内存之间的高效数据传输,减轻CPU负担。文章通过实例展示了如何设置DMA通道、配置传输方向及数据大小等关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

DMA 全称是:Direct Memory Access;根据 ST 公司提供的相关信息,DMA是STM32中一个独立于 Cortex-M3 内核的模块,有点类似于 ADC、PWM、TIMER 等模块;主要功能是起通信“桥梁”的作用,可以将所有外设映射的寄存器“连接”起来,这样就可以高速访问各寄存器,其传输不受 CPU 的支配,传输还是双向的;例如,从“表面”上看,它可以将 flash 中的数据与储存器中变量建立通讯,还可以将某一个外设的寄存器或缓冲器与另一个外设的寄存器或缓冲器建立双向通讯,有点像把外设硬件之间用“导线”连接在一起了。其间的通讯不占 CPU 资源,访问速度快,对于实时性强的应用将是一个很好的选择。下面代码是一个标准 DMA 设置,当然实际应用中可根据实际情况进行裁减:

//开启时钟,否则初始化无效。

RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

 

DMA_DeInit(DMA_Channel1);

上面这句是给 DMA 配置通道,根据 ST 提供的资料,STM3210Fx 中 DMA 包含 7 个通道(CH1~CH7),也就是说可以为外设或 memory 提供 7 座“桥梁”;

 

DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;

DMA_PeripheralBaseAddr 是 DMA_InitStructure 结构体中一个数据成员,给 DMA 一个起始地址,好比是一个 buffer 起始地址,ADC1_DR_Address 是我定义的一个地址变量;

 

DMA_InitStructure.DMA_MemoryBaseAddr = (u32)ADC_ConvertedValue;

上面这句很显然是 DMA 要连接在 Memory 中变量的地址,ADC_ConvertedValue 是我自己在memory 中定义的一个变量地址;

 

DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;

上面的这句是设置 DMA 的传输方向,就如前面所说的,DMA 可以双向传输,也可以单向传输,这里设置的是单向传输,如果需要双向传输:把 DMA_DIR_PeripheralSRC 改成DMA_DIR_PeripheralDST 即可。

 

DMA_InitStructure.DMA_BufferSize = 2;

上面的这句是设置 DMA 在传输时缓冲区的长度,前面有定义过了 buffer 的起始地址:ADC1_DR_Address ,为了安全性和可靠性,一般需要给 buffer 定义一个储存片区,这个参数的单位有三种类型:Byte、HalfWord、word,我设置的 2 个half-word(见下面的设置);32位的 MCU 中 1 个 half-word 占 16 bits。

 

DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

上面的这句是设置 DMA 的外设递增模式,如果 DMA 选用的通道(CHx)有多个外设连接,需要使用外设递增模式:DMA_PeripheralInc_Enable;我的例子里 DMA 只与 ADC1 建立了联系,所以选用 DMA_PeripheralInc_Disable。

 

DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;

上面的这句是设置DMA的内存递增模式,DMA 访问多个内存参数时,需要使用DMA_MemoryInc_Enable,当DMA只访问一个内存参数时可设置成 :DMA_MemoryInc_Disable。

 

DMA_InitStructure.DMA_PeripheralDataSize =

DMA_PeripheralDataSize_HalfWord;

上面的这句是设置 DMA 在访问时每次操作的数据长度。有三种数据长度类型,前面已经讲过了,这里不在叙述。

 

DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;

与上面雷同。在此不再说明。

 

DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;

上面的这句是设置 DMA 的传输模式:连续不断的循环模式,若只想访问一次后就不要访问了(或按指令操作来反问,也就是想要它访问的时候就访问,不要它访问的时候就停止),可以设置成通用模式:DMA_Mode_Normal。

 

DMA_InitStructure.DMA_Priority = DMA_Priority_High;

上面的这句是设置 DMA 的优先级别:可以分为 4 级:VeryHigh,High,Medium,Low.

 

DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;

上面的这句是设置 DMA 的 2 个 memory 中的变量互相访问的

 

DMA_Init(DMA_Channel1,&DMA_InitStructure);

前面那些都是对 DMA 结构体成员的设置,在次再统一对 DMA 整个模块做一次初始化,使得 DMA 各成员与上面的参数一致。

 

DMA_Cmd(DMA_Channel1,ENABLE);

使能启动。

 

要使 DMA 与外设建立有效连接,这不是 DMA 自身的事情,是各个外设的事情,每个外设都有 一个 xxx_DMACmd(XXXx,Enable )函数,如果使 DMA 与 ADC 建立有效联系,就使用ADC_DMACmd(ADC1,Enable); (这里我启用了 ADC 中的 ADC1 模块)。

### STM32CubeMX 中配置 DMA 实现 GPIO 翻转 在 STM32 微控制器中,通过 DMA 控制器可以高效地完成数据传输任务而无需 CPU 干预。为了实现 GPIO 的翻转功能,可以通过设置内存到外设的数据传输来控制 GPIO 输出状态的变化。 以下是具体配置方法以及示例代码: #### 配置步骤说明 1. **初始化时钟源** 使用外部高速晶振 (HSE) 作为系统的时钟源,并通过锁相环 (PLL) 倍频至目标频率(如 84 MHz),从而提高系统性能[^4]。 2. **启用 DMA 功能** 在 CubeMX 工具中,选择 `DMA` 模块并为其分配通道资源。例如,在本案例中可以选择 `DMA1_Channel1` 或其他可用的 DMA 通道[^3]。 3. **配置 GPIO 引脚** 设置目标端口上的某个引脚为通用推挽输出模式 (`GPIO_Output`),以便能够对其进行高低电平切换操作。 4. **定义存储区与映射关系** 创建两个缓冲数组分别代表高/低两种不同的输出值;然后将这些数值依次写入对应寄存器地址以改变指定针的状态。 5. **启动 DMA 转移过程** 编程完成后调用 HAL 库函数开启一次性的或者连续循环式的 DMA 数据搬运动作,这样就可以自动交替更新该 IO 口的逻辑电位了。 #### 示例代码展示 下面提供了一段基于 HAL API 的 C 语言程序片段用于演示上述原理的实际应用情况: ```c #include "main.h" #define BUFFER_SIZE 2U // Buffer size, two values for toggling. uint32_t aMemoryBuffer[BUFFER_SIZE]; // Memory buffer containing the data to be transferred. volatile uint32_t uhToggleIndex = 0; // Index used during transfer complete callback function call. /* Private function prototypes -----------------------------------------------*/ static void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_DMA_Init(void); int main(void) { /* Reset of all peripherals, Initializes the Flash interface and Systick */ HAL_Init(); /* Configure the system clock */ SystemClock_Config(); /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_DMA_Init(); /* Fill memory buffer with toggle states */ aMemoryBuffer[0] = GPIO_PIN_SET; aMemoryBuffer[1] = GPIO_PIN_RESET; /* Start DMA Transfer from memory to peripheral register */ HAL_DMA_Start_IT(&hdma_memtomem_dma1_channel1,(uint32_t)aMemoryBuffer, (uint32_t)&GPIOB->ODR,BUFFER_SIZE); while (1){ __asm volatile ("nop"); // Infinite loop here waiting interrupts handling transfers. } } /** * @brief This function handles DMA interrupt request. */ void HAL_DMA_IRQHandler(DMA_HandleTypeDef *hdma) { HAL_DMA_IRQHandler(hdma); } ``` 此代码展示了如何利用直接内存访问技术驱动微处理器中的输入 / 输出接口执行周期性反转行为的过程[^1]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值