DMA介绍

一 DMA简介

DMA全称Direct Memory Access, 直译为“直接存储器访问”。
DMA的作用是帮助CPU在内存之间搬运数据,搬运的过程中无需CPU的干涉,也不存在中断方式传送数据的那样保留现场和恢复现场的过程,这样的DMA控制器通过硬件来为RAM和IO设备之间开辟一条直接传送数据的通路(从源地址搬运到目的地址),从而使CPU的负担大大减少。

二 DMA有什么用

直接存储器存取用来提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。无须CPU的干预,通过DMA数据可以快速地移动。这就节省了CPU的资源来做其他操作。

三 数据从什么地方送到什么地方?

外设到SRAM,FLASH(I2C/UART等获取数据并送入SRAM,FLASH);
SRAM的两个区域之间;
外设到外设(ADC读取数据后送到TIM1控制其产生不同的PWM占空比);
SRAM到外设(SRAM中预先保存的数据送入DAC产生各种波形);

四 DMA可以传递多少数据?

我理解在STM32中,它的概念被扩展了,也许更多的时候快速是其应用的重点,数据可以从1~65535个。
总之,每个DMA传送由3个操作组成:
1. 从外设数据寄存器或者从DMA_CMARx寄存器指定地址的存储器单元执行加载操作。
2. 存数据到外设数据寄存器或者存数据到DMA_CMARx寄存器指定地址的存储器单元。
3. 执行一次DMA_CNDTRx寄存器的递减操作。该寄存器包含未完成的操作数目。

仲裁器根据通道请求的优先级来启动外设/存储器的访问。
优先级分为两个等级:(可以在DMA传输过半、传输完成和传输错误时产生中断)
1.软件(4个等级:最高、高、中等、低);
2.硬件(有较低编号的通道比拥有较高编号的通道有较高的优先权);

DMA_DeInit(DMA1_Channel6);
//peripheral base address
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)SRC_Const_Buffer;
//memory base address
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)DST_Buffer;
//数据传输方向    Peripheral is source
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
//缓冲区大小 Number of data to be transferred (0 up to 65535).数据传输数目
DMA_InitStructure.DMA_BufferSize = BufferSize;
// the Peripheral address register is incremented
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable;
//the memory address register is incremented
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
//the Peripheral data width
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
//the DMAy Channelx will be used in memory-to-memory transfer
//DMA通道的操作可以在没有外设请求的情况下进行,这种操作就是存储器到存储器模式。
DMA_InitStructure.DMA_M2M = DMA_M2M_Enable;
DMA_Init(DMA1_Channel6, &DMA_InitStructure);

DMA_ITConfig(DMA1_Channel6, DMA_IT_TC, ENABLE);
DMA_Cmd(DMA1_Channel6, ENABLE);

五 外设的DMA请求映像

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

(ADC1,Enable); (这里我启用了ADC中的ADC1模块)。
DMA_DeInit(DMA1_Channel1);
DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&AD_Value;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize = 2; 
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; 
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel1, &DMA_InitStructure);

DMA_Cmd(DMA1_Channel1, ENABLE);

ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_InitStructure.ADC_ScanConvMode = ENABLE;
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfChannel = 2;
ADC_Init(ADC1, &ADC_InitStructure);
//内部温度传感器  添加这一句
ADC_TempSensorVrefintCmd(ENABLE);
//################ Channel 10(电位器)
ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_13Cycles5);
//###### 内部温度传感器  Channel 16 ###################
ADC_RegularChannelConfig(ADC1, ADC_Channel_16, 2, ADC_SampleTime_55Cycles5);
//使能ADC1的DMA请求映像
ADC_DMACmd(ADC1, ENABLE);
ADC_Cmd(ADC1, ENABLE);
//使用之前一定要校准
ADC_ResetCalibration(ADC1);
while (ADC_GetResetCalibrationStatus(ADC1));
ADC_StartCalibration(ADC1);
while (ADC_GetCalibrationStatus(ADC1));
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
<think>嗯,用户让我介绍一下STM32F103C8T6的DMA,首先我得确认自己对这个芯片和DMA的了解程度。STM32F103C8T6是STMicroelectronics的Cortex-M3微控制器,属于中端性能的MCU,常用于嵌入式系统。DMA,直接存储器访问,应该是用来不经过CPU直接传输数据的外设,对吧? 接下来,我需要回忆一下这个具体型号的DMA结构。STM32F103系列通常有两个DMA控制器,DMA1和DMA2,但可能C8T6只有DMA1,因为资源可能被裁剪。DMA1有7个通道,每个通道可以分配给不同的外设,比如ADC、SPI、I2C、USART等。用户可能需要知道这些通道的分配情况,以及如何配置它们。 然后,DMA的主要作用是减少CPU负担,提高传输效率。比如在传输大量数据时,比如从ADC采集数据到内存,或者通过USART发送数据,使用DMA可以让CPU去做其他任务,而不是等待数据传输完成。这可能对实时性要求高的应用很重要。 需要解释DMA的工作模式,比如内存到外设、外设到内存、内存到内存,以及循环模式、正常模式等。还有中断机制,传输完成、半传输、错误中断等,这些对用户编写中断服务程序可能有帮助。 另外,STM32F103C8T6的具体外设支持哪些DMA请求?例如,USART1的TX和RX可能使用DMA1的某个通道,而ADC1可能有自己的通道。需要查证具体的数据手册或参考手册,确保准确性。 用户可能的实际应用场景是什么?比如使用DMA进行高速数据采集、通信传输或者PWM控制。这时候可能需要举例说明,比如用DMA控制PWM产生特定波形,或者用DMA实现SPI通信的连续传输。 可能需要注意的配置步骤包括:初始化DMA通道,设置源地址和目的地址,数据长度,传输方向,数据宽度,是否启用循环模式,优先级,中断使能等。用户可能想知道如何用库函数或寄存器配置这些参数,但问题可能只需要概述,不需要详细代码。 还要考虑常见的错误或问题,比如内存对齐问题,DMA传输完成标志未清除导致的中断问题,或者外设和DMA之间的协调,比如ADC的扫描模式需要DMA支持等。 用户可能需要了解DMA的优势,比如提升系统性能,减少功耗(CPU可以进入低功耗模式),以及使用时的注意事项,比如资源冲突,通道分配等。 总结一下,我应该先介绍DMA的基本概念,然后针对STM32F103C8T6的具体DMA结构,通道分配,配置方法,应用场景和优势,最后可能给出简单的示例或注意事项。确保语言通俗易懂,结构清晰,覆盖用户可能关心的各个方面。</think>STM32F103C8T6 是一款基于 ARM Cortex-M3 内核的中端微控制器,广泛应用于嵌入式开发。其 **DMA(Direct Memory Access,直接存储器访问)** 功能是提升系统效率的重要模块,能够在无需 CPU 介入的情况下,直接在内存与外设之间传输数据。以下是其 DMA 的核心介绍: --- ### **1. DMA 的核心作用** - **降低 CPU 负担**:数据传输由 DMA 控制器独立完成,CPU 可执行其他任务或进入低功耗模式。 - **高速传输**:支持批量数据传输,适用于高速外设(如 ADC、UART、SPI 等)。 - **实时性保障**:避免因 CPU 处理中断导致的延迟,适合实时数据流(如音频、传感器采集)。 --- ### **2. STM32F103C8T6 的 DMA 资源** - **DMA 控制器数量**:1 个(DMA1),共 **7 个通道**。 - **支持的外设**: - ADC、SPI、I2C、USART、定时器(TIMx)等。 - 具体通道分配需参考数据手册(如 USART1_TX 使用 DMA1 通道4,ADC1 使用通道1)。 --- ### **3. 关键工作模式** - **传输方向**: - 外设 → 内存(如 ADC 采集数据到数组) - 内存 → 外设(如通过 USART 发送数据) - 内存 → 内存(高速数据拷贝) - **传输模式**: - **单次模式**:传输指定次数后停止。 - **循环模式**:数据缓冲区循环更新(如连续采集)。 - **数据宽度**:支持 8/16/32 位,需与外设及内存对齐一致。 - **中断触发**:支持传输完成、半传输、错误中断。 --- ### **4. 典型应用场景** - **ADC 多通道扫描**:DMA 自动存储 ADC 转换结果,避免 CPU 轮询。 - **串口通信**:大批量数据发送/接收(如 GPS 模块数据解析)。 - **SPI/I2C 传输**:与外部存储器(如 Flash、EEPROM)高效通信。 - **PWM 波形控制**:通过 DMA 更新定时器的 PWM 占空比,生成复杂波形。 --- ### **5. 配置步骤(基于标准库/HAL 库)** 1. **初始化 DMA 通道**:选择通道、设置优先级。 2. **配置传输参数**:源地址、目标地址、数据长度、传输方向。 3. **设置数据宽度与模式**:单次/循环模式,是否使能自动递增地址。 4. **绑定外设请求**:关联外设(如 USART1 的发送请求)。 5. **使能中断(可选)**:处理传输完成事件。 6. **启动传输**:通过库函数或寄存器触发 DMA。 --- ### **6. 注意事项** - **内存对齐**:确保外设与内存的数据宽度对齐,避免传输错误。 - **缓冲区竞争**:循环模式下需防止数据未处理完被覆盖(可用“双缓冲区”策略)。 - **中断冲突**:多个 DMA 通道共用时,需合理分配优先级。 - **电源管理**:DMA 传输期间,避免 CPU 进入深度睡眠模式。 --- ### **示例代码片段(HAL 库)** ```c // 配置 USART1 使用 DMA 发送数据 uint8_t tx_data[] = "Hello, DMA!"; HAL_UART_Transmit_DMA(&huart1, tx_data, sizeof(tx_data) - 1); // DMA 传输完成回调函数(需用户实现) void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) { if (huart == &huart1) { // 发送完成后的处理逻辑 } } ``` --- 通过合理利用 DMASTM32F103C8T6 的系统性能可显著优化,尤其适合高实时性、低功耗或大数据量传输的场景。实际开发中需结合具体外设需求,参考官方文档进行配置。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

啊唯0o

如果能够帮助到您,不介意的话,

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值