MSP430系列单片机的DMA使用全面认识

DMA的解释

DMA(Direct Memory Access,直接存储器访问)。 DMA 传输将数据从一个地址空间复制到另外一个地址空间。当CPU 初始化这个传输动作,传输动作本身是由 DMA 控制器来实行和完成。典型的例子就是移动一个外部内存的区块到芯片内部更快的内存区。像是这样的操作并没有让处理器工作拖延,反而可以被重新排程去处理其他的工作。DMA 传输对于高效能 嵌入式系统算法和网络是很重要的。

  • MSP430系列单片机中的DMA

MSP430系列单片机扩展的DMA具有来之所有外设的触发器不需要CPU的干预即可提供先进的可配置的数据传输能力,从而加速了基于MCU的信号处理进程,DMA传输的触发来源对CPU 来说是完全透明的,DMA控制器可在内存与外部及外部硬件之间进行精确的传输控制。DMA 消除了数据传输延迟时间以及各种开销,从而可以解放16位RISC CPU,以便其将更多的时间用于处理数据,而非执行正在处理的任务。

  • MSP430 DMA控制器的特性

MSP430系列单片机的DMA模块大多有以下特点:

  • 无需CPU介入,完全由DMA控制器自行管理。
  • 在整个地址空间范围内有效,块方式传输可达65536字节;
  • 每次传输仅需要2个MCLK;
  • 可在CPU进入超低功耗模式时运行;
  • 字节和字混合传输;
  • 四种传输寻址模式:固定地址到固定地址、固定地址到块地址、块地址到固定地址以及块地址到块地址;
  • 触发方式灵活:边沿或者电平触发。
  • 多种触发源可配置。
  • 多通道优先级可配置。

DMA的应用

最常见的场景,当你想吃饭时,你需要中止你的工作,走出去,到某家店,点餐,等餐,用餐,再回到你的工作地点继续你的工作。如果工作比较多的时候呢?你就没有时间外出,那你一般就是点个外卖,然后继续你的工作,等外卖员把餐送到了,再用餐,用餐后再继续你的工作。现在把这个场景全部类比到单片机的工作中来,吃饭是一个支线任务,但无法直接开始,需要等待,点餐是一个机器周期可以完成的简单操作,你的工作是CPU的主线任务。对于CPU而言,如果主线任务比较繁重,而支线任务又不得不做,那做了支线任务就必然要占用做主线的时间,这个结果就可能导致主线任务完成得不好,所以在这个时候我们就需要一个外卖员,他就是DMA!

  • 明确你得需求

好多人是按章节学习,到了DMA这一章就到处询问怎么使用DMA,要程序要代码,但是我在上面也举过例子了,你只有在CPU主线特别忙得时候才需要用到DMA,又或者是某种低功耗需求而IO处理有特别多得时候。没有这种需求你完全没必要去搞清楚DMA是怎么用的,你只要知道有这么个东西就行了,将来有需求了再回来研究。因为这里面还是有很多坑的,如果你急这在项目里上马DMA,那不可预料的BUG真的是会耽误你很多时间。所以根据你的需求,谨慎选择是否继续读下去。

  • 一个能用起来的官方例程

注释已翻译成中文了

#include <msp430.h>
#include <stdint.h>

int main(void)
{
  WDTCTL = WDTPW+WDTHOLD;                   // 关闭看门狗
  P1DIR |= 0x01;                            // P1.0 设为输出
  __data20_write_long((uintptr_t) &DMA0SA,(uintptr_t) 0x1C00);
                                            // 设置源地址
  __data20_write_long((uintptr_t) &DMA0DA,(uintptr_t) 0x1C20);
                                            // 设置目标地址
  DMA0SZ = 16;                              // 设置传输快尺寸
  DMA0CTL = DMADT_5+DMASRCINCR_3+DMADSTINCR_3; 
  		// 通道0:重复块传输、源地址和目标地址自动增计数,默认为软件触发
  DMA0CTL |= DMAEN;                         // 使能DMA通道0

  while(1)
  {
    P1OUT |= 0x01;                          // 置位P1.0
    DMA0CTL |= DMAREQ;                      // 触发块传输
    P1OUT &= ~0x01;                         // 复位P1.0
  }
}

一些说明

  • 官方历程由来:点我下载msp430ware,具体请自行搜索。
  • 关于程序执行过程,手册说DMA块传输需要2×MCLK×DMAxSZ(记tD)的时间,所以在执行了触发语句DMA0CTL |= DMAREQ; 后CPU将处于挂起状态,即在本例中,在执行*P1OUT &= ~ 0x01;*之前,系统会待机tD ,一定要引起注意。
  • 在老版的CCS中用MSP430wave导入的例程中,代码长这样:
#include <msp430.h>

int main(void)
{
  WDTCTL = WDTPW+WDTHOLD;                   // 关闭看门狗
  P1DIR |= 0x01;                            // P1.0 设为输出
  __data16_write_long((unsigned short) &DMA0SA,(unsigned long) 0x1C00);
                                            // 设置源地址
  __data20_write_long((unsigned short) &DMA0DA,(unsigned long) 0x1C20);
                                            // 设置目标地址
  DMA0SZ = 16;                              // 设置传输快尺寸
  DMA0CTL = DMADT_5+DMASRCINCR_3+DMADSTINCR_3; 
  		// 通道0:重复块传输、源地址和目标地址自动增计数,默认为软件触发
  DMA0CTL |= DMAEN;                         // 使能DMA通道0

  while(1)
  {
    P1OUT |= 0x01;                          // 置位P1.0
    DMA0CTL |= DMAREQ;                      // 触发块传输
    P1OUT &= ~0x01;                         // 复位P1.0
  }
}

你在编译的时候会发现在设置地址的地方有警告 #770-D conversion from pointer to smaller integer 你可以自行比较一下新旧连个例程就应该知道问题在哪了1

待续


  1. 之所以提到这个,是因为在我写总结的时候才下载了最新的CCS9.10,而之前我的工程都是用的CCS6.10,而我的工程电脑也不联网,就不知道有新版本。这个警告起初困惑了我很久,因为我确实习惯消除掉程序里的所有警告,而为了解决这个问题我还真是测试了很久才get到20位地址空间这个点,算是个不大不小的坑。通过这个例子,我建议大家还是时不时关注下工具软件的更新,兴许一些老问题就迎刃而解了。 ↩︎

  • 4
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值