STM32F0单片机快速入门八: Coolie DMA

  1. 苦力 DMA

世上本没有路,走的人多了,便成了路。世上本没有 DMA,需要搬运的数据多了,便有了 DMA。

大多数同学应该没有在项目中用过这个东西,因为一般情况下也真不需要这个东西。在早期的单片机中也不存在DMA模块。再加上很多谈 DMA 的文章,一上来就先来一个总线架构图,然后来一大堆让人生畏的词儿:共享总线,仲裁器,指针增量,对齐,中断 ... 好吧,每一个词都能吓跑一批胆小的。

真的需要这么复杂吗?就好比我们学开车一样,能不能先别去尝试弄懂发动机的原理,直接挂档踩油门走起来呢?

DMA是很简单的一个模块,首先他的功能单一,就是把数据从一个地方搬运到另一个地方,再一个它的用法也很简单,我们还是先从一个例子说起:

我们用 Keil 打开下面这个工程:

STM32Cube_FW_F0_V1.11.0\Projects\STM32F030R8-Nucleo\Examples\DMA\DMA_FLASHToRAM\MDK-ARM\Project.uvprojx

 

如图,有一些存储在 Flash 的数据需要搬运到 RAM 区的一个数组。通常我们可以用如下的代码实现:

for(i=0;i<BUFFER_SIZE;i++)

  aDST_Buffer[i] = aSRC_Const_Buffer[i];

上面这个操作是 CPU 亲自完成的,首先把数据装进自己的寄存器,再把寄存器中的数据存放到目的地址。在例中所示这种数据比较少的情况下,这种搬运工作可以说瞬间就完成了。但如果数据量比较大,比如说要往显示屏刷新显示数据,就要占用 CPU 大量的时间了。这时候 CPU 就可以叫来 DMA 来干这件苦差事。DMA 就是芯片中的苦力集中营。

跟苦力需要交代清楚的最基本的事情就是:从哪儿搬到哪儿,货物有多少,搬一次还是有货物源源不断的到来,需要循环不断的搬。

让我们看一下代码,主程序非常简单,调用 DMA_Config(); 进行了一下配置后就自己该干嘛干嘛去了。

2. 代码

像串口工程代码声明了串口类型的 Handle一样,这里声明了一个 DMA 类型的 Handle 来负责 DMA 模块的处理。

DMA_HandleTypeDef     DmaHandle;

需要注意的地方:

__HAL_RCC_DMA1_CLK_ENABLE();

使能模块时钟,使能模块时钟,使能模块时钟!重要的事情要说3遍。在使用任何一个模块之前首先要使能该模块的时钟,这是经常被忘记的一件事儿。这个功能在老型号单片机里是没有的。在不使用某模块时,彻底关断其时钟可以达到最大节省功耗的目的。

初始化参数(DmaHandle.Init.):

Direction  从外设到内存,从内存到内存,还是从内存到外设?

PeriphInc  每传完一个数后外设地址是否自增1

MemInc  每传完一个数后内存地址是否自增1

PeriphDataAlignment  外设地址对齐方式,Byte,Halfword or Word

MemDataAlignment  内存地址对齐方式,Byte,Halfword or Word

Mode  单次,还是循环模式

Priority  优先级

初始化参数(DmaHandle.Instance):

DMA模块中有多个通道,此参数指明使用哪一个通道。

这个代码调用 HAL_DMA_Start_IT 这个函数启动了 DMA 传输,当数据搬运完后会产生一个完成中断,并调用回调函数 TransferComplete。在HAL层驱动中,已经完成了 DMA 中断所要做的基本处理,比如根据中断类型清除相应中断标志等。在回调函数中用户可以什么都不做,也可以根据需要添加代码,比如此例中用点亮 LED 灯的方式来标志传输完成。

3.串口如何使用 DMA 传输

前面的例子是用软件的方式触发 DMA 传输,在应用中经常会用到由某个事件触发的情况。比如通过串口发送,接收中断来触发 DMA 传输。

我们打开下面这个例子:

STM32Cube_FW_F0_V1.11.0\Projects\STM32F030R8-Nucleo\Examples\UART\UART_TwoBoards_ComDMA\MDK-ARM\ Project.uvprojx

在串口初始化的回调函数 HAL_UART_MspInit(UART_HandleTypeDef *huart)中:

a 声明了两个 DMA 类型的 Handle: hdmatx 和 hdmarx

b 初始化这两个 Handle

c 把这两个 Handle 和串口的 UartHandle 连接起来

__HAL_LINKDMA(huart, hdmatx, hdma_tx);

__HAL_LINKDMA(huart, hdmarx, hdma_rx);

 

在串口及其关联 DMA 通道初始化完成后,既可以启动DMA方式的接收和发送。从下图中可以看到接收 HAL_UART_Receive_DMA 的调用过程,发送调用过程类似:

 

 

 

下图是UART中断,和DMA中断的触发调用过程。USART1模块产生错误时仍然进USART1的中断向量,DMA模块传输完成或传输过程中产生错误时进 DMA 中断向量。

如果没有迫切的需要,DMA 模块了解一下就行了。没有必要在细节上过多纠缠,即使现在搞懂了,过两三个月估计也忘了。建议在真正用到大量数据传输时再仔细研究和优化相关代码。

参考资料:

PM0215  STM32F0xxx Cortex-M0 programming manual

UM1785 Description of STM32F0 HAL and low-layer drivers

STM32F030 Datasheet

STM32F030 Reference Manual

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
第1章ARM及Cortex-M3处理器概述 1.1ARM处理器系列 1.1.1命名规则 1.1.2ARM处理器系列 1.2ARMCortex-M3处理器 1.2.1处理器组件 1.2.2Cortex-M3的层次和实现选项 1.2.3处理器内核 1.2.4嵌套向量中断控制器(NVIC) 1.2.5总线矩阵 1.2.6集成调试 1.2.7可选组件 1.2.8Cortex-M3处理器应用 1.3ARMCortex-M3指令集 1.4ARMCortex-M3的优势 第2章STM32系列微控制器 2.1STM32系列微控制器简介 2.1.1STM32微控制器的主要优点 2.1.2STM32微控制器的应用 2.2STM32F101xx系列微控制器 2.2.1特点 2.2.2总体结构 2.3STM32F103xx系列微控制器 2.3.1特点 2.3.2总体结构 第3章STM32系列微控制器存储器与外设 3.1存储器和总线的结构 3.1.1系统结构 3.1.2存储器结构 3.1.3存储器映射 3.1.4启动配置 3.2电源控制 3.2.1电源供应 3.2.2电源供应管理 3.2.3低功耗模式 3.2.4电源控制寄存器 3.3复位和时钟控制 3.3.1复位 3.3.2时钟 3.3.3RCC寄存器描述 3.4通用I/O和复用I/O(GPIO和AFIO) 3.4.1GPIO功能描述 3.4.2GPIO寄存器描述 3.4.3复用功能I/O和调试配置(AFIO) 3.4.4AFIO寄存器描述 3.5中断和事件 3.5.1嵌套向量中断控制器(NVIC) 3.5.2外部中断/事件控制器(EXTI) 3.5.3EXTI寄存器 3.6DMA控制器 3.6.1简介 3.6.2主要特性 3.6.3功能描述 3.6.4DMA寄存器 3.7实时时钟(RTC) 3.7.1简介 3.7.2主要特性 3.7.3功能描述 3.7.4RTC寄存器描述 3.8备份寄存器(BKP) 3.8.1简介 3.8.2主要特性 3.8.3干扰检测 3.8.4RTC校验 3.8.5BKP寄存器描述 3.9独立的看门狗 3.9.1简介 3.9.2IWDG寄存器描述 3.10窗口看门狗(WWDG) 3.10.1简介 3.10.2主要特性 3.10.3功能描述 3.10.4如何编程看门狗的超时时间 3.10.5调试模式 3.10.6寄存器描述 3.11高级控制定时器 3.11.1简介 3.11.2主要特性 3.11.3框图 3.11.4功能描述 3.11.5TIMI寄存器描述 3.12通用定时器(TIMx) 3.12.1简介 3.12.2主要特性 3.12.3框图 3.12.4功能描述 3.12.5TIMx寄存器描述 3.13控制器局域网(bxCAN) 3.13.1简介 3.13.2主要特性 3.13.3总体描述 3.13.4运行模式 3.13.5功能描述 3.13.6中断 3.13.7寄存器访问保护 3.13.8CAN寄存器描述 3.14内部集成电路(I2C)接口 3.14.1简介 3.14.2主要特性 3.14.3总体描述 3.14.4功能描述 3.14.5中断请求 3.14.6I2C调试模式 3.14.7I2C寄存器描述 3.15串行外设接FI(SPI) 3.15.1简介 3.15.2主要特性 3.15.3功能描述 3.15.4SPI寄存器描述 3.16通用同步异步收发机(USART) 3.16.1简介 3.16.2主要特性 3.16.3总体描述 3.16.4中断请求 3.16.5USART寄存器描述 3.17USB全速设备接口 3.17.1概述 3.17.2主要特性 3.17.3结构框图 3.17.4功能描述 3.17.5编程中需要考虑的问题 3.17.6USB寄存器描述 3.18模/数转换器(ADC) 3.18.1概述 3.18.2主要特性 3.18.3引脚描述 3.18.4功能描述 3.18.5校准 3.18.6数据对齐 3.18.7基于通道的可编程的采样时间 3.18.8外部触发转换 3.18.9DMA请求 3.18.10双ADC模式 3.18.11温度传感器 3.18.12中断 3.18.13ADC寄存器描述 3.19调试支持(DBG) 3.19.1概述 3.19.2相关的ARM文档 3.19.3SWJ调试端口(串行线和JTAG) 3.19.4引脚分布和调试端口引脚 3.19.5STM32F10xJTAGTAP连接 3.19.6ID编码和锁定机制 3.19.7JTAG调试端口 3.19.8SW调试端口 第4章STM32固件库 4.1STM32固件库的定义规则 4.1.1固件库命名规则 4.1.2代码标准 4.2STM32库的层次结构 4.2.1固件包描述 4.2.2固件库文件描述 4.3STM32库的使用 第5章STM32系列微控制器开发工具与应用 5.1KeilMDK介绍 5.1.1开发过程及集成开发环境简介 5.1.2工程管理 5.1.3编写源程序 5.1.4编译程序 5.1.5调试程序 5.2IAREWARM介绍 5.2.1EWARM集成开发环境及配套仿真器 5.2.2在EWARM中生成一个新项目 5.2.3编译和链接应用程序 5.2.4用J-LINK调试应用程序 5.3STM32-SK仿真评估板 5.3.1评估板规格说明 5.3.2测试程序 5.3.3关于仿真评估板的几个问题 5.4STM32-DK开发板 5.4.1开发板规格说明 5.4.2开发板实例程序 5.4.3关于STARM的常见问题 5.5mx-Pro量产编程器使用简介 5.5.1编程文件管理 5.5.2芯片烧写 5.6应用实例:基于STM32的数据采集器 5.6.1硬件设计 5.6.2软件设计 参考文献

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值