欢迎光临散文网 会员登陆 & 注册

MSP430F1单片机的学习1——认识和使用DMA

2020-06-24 09:07 作者:江湖夜雨飘零客  | 我要投稿

MSP430F1单片机的学习1——认识和使用DMA

使用编译工具:IAR For MSP430 6.4

使用单片机:MSP430F1611

单片机的DAM是个啥?

说起DAM,玩单片机的人应该大多都听说过,但也有一些初学者不太了解,这到底是个啥,有人说用DAM的速度快,有人说用DMA不占用CPU内存,但是有没有比较好理解的解释呢?哎嘿,那绝对是当然的了,请看我的表演,其实DMA可以看做是一家专门的搬运公司,没错,DMA就是MCU中的一家搬运公司,它可以帮你把货物从货源地A搬运到目的地B地址,只要你告诉他什么时候开始搬,要怎样搬,你就不用管了,他就会给你搬过去,而且速度贼快。

 

在MSP430F1611中,搬运公司共有3个司机,分别是DMA0、DMA1、DMA2,

DMA总寄存器,DMACTL0、DMACTL1是公司的统一控制器,分别控制着三个司机的工作方式

DMACTL0         :选择DAM的工作模式,选择触发源,运输的条件
DMACTL1         : 传输条件、中断,需要运输时,司机响应的情况

DMA0寄存器,主要给DMA0分配具体工作

DMA0SA          :设置DAM的货源,必须为16位地址,(u16)                                       DMA0DA          :设置DAM的目的地,必须为16位地址,(u16)*
DMA0SZ          :设置送货的数量,字节为单位
DMA0CTL         :设置运输方式,、启动,停止、中断、等控制

DMA1寄存器,主要给DMA1分配具体工作

DMA1SA          :设置DAM的货源,必须为16位地址,(u16)                                       DMA1DA          :设置DAM的目的地,必须为16位地址,(u16)*
DMA1SZ          :设置送货的数量,字节为单位
DMA1CTL         :设置运输方式、启动,停止、中断、等控制

DMA2寄存器,主要给DMA2分配具体工作

DMA2SA          :设置DAM的原始货源地,必须为16位地址,(u16)*                                    DMA2DA          :设置DAM的原始目的地,必须为16位地址,(u16)*
DMA2SZ          :设置送货的数量,字节为单位
DMA2CTL         :设置运输方式、启动,停止、中断、等控制

重点要控制的是,

  • DMACTL0 ——选择触发源,

  • DMAxCTL(以DMA0位代表DMA0CTL)——设置运输方式、启动,停止、中断、等控制

  • DMAxSA(DMA0SA)——原始货源地,可以设置单片机内的所有地址,包括UART的发送BUF,Flash,ROM等,

  • DMAxDA(DMA0DA )——原始货源地,可以设置单片机内的所有地址,包括UART的发送BUF,Flash,ROM等,

  • DMAxSZ (DMAxSZ )——货物总量,所要传输的数据大小,以字节为单位,

  • DMACTL1
           


具体程序测试,使用DMA0进行测试,DMA1、DMA2的用法一样,不赘述。

测试内容:

  • 在DMACTL1、DMA0SA、DMA0DA、DMA0SZ、DMA0CTL寄存器不变的情况下,改变DMACTL0的值,从而改变触发传输的方式

  • DMACTL0、DMA0SA、DMA0DA、DMA0SZ、DMA0CTL不变的情况下,改变DMACTL1

  • DMACTL1、DMACTL0、DMA0SA、DMA0SZ、DMA0CTL不变的情况下,改变DMA0DA

在DMACTL1、DMA0SA、DMA0DA、DMA0SZ、DMA0CTL寄存器不变的情况下,改变DMACTL0的值,从而改变触发传输的方式;DMACTL0中低四位控制DMA0的触发方式,总共有2^4=16种,如下图所示,

测试开始:DMACTL0 = DMA0TSEL_0,DMA_REQ触发模式,DMA0CTL寄存器的DMAREQ位 置位 了,就触发1次传输,该位软件设置触发,DMA0CTL |= DMAREQ;该位自动清零;

测试改变DMACTL0的值

打开Memory,在左上角的Go to中输入我们要观察的地址,

继续运行,可以看到 0x0220——0x025f 共0x40个字节被重新赋值,而0x0280——0x02bf 的0x40个字节的值还是没变,比较乱;

继续运行,盯着这个值,运行当前一句代码,

如下,DAM0把0x0220中的货物(值)运送到了目的地0x0280中,

以后每次触发REQ,发现DMA0都会去以原始货源地地址为基准的下一个地址,然后把那里的值运送到以原始目的地为基准的下一地址,最终把所有货物 DMA0SZ = 0x040;运输完成

DMA完成传输,之后再触发REQ,后面地址的值也不会变,DAM0已经干完活,去休息了。

测试代码:

#include <msp430.h>
__no_init u8 SDEventBuf[0x10] @0x0220;
//u8 SDEventBuf[0x10] ={0};
int main(void)
{
  WDTCTL = WDTPW + WDTHOLD;                 // 关闭看门狗
  for(u16 temp=0;temp<0x40;temp++)          //给数组赋值
  {
     *(SDEventBuf+temp) = temp;
  }
  DMACTL0 = DMA0TSEL_0;                     // 选择DMA0触发方式   ,REQ
  DMACTL1 = 0;                              //触发时的响应,中断等,无
  DMA0SA = (u16)SDEventBuf;                 // DMA0货源地,16bit
  DMA0DA = 0x0280;                          // DMA0目的地,16bit
  DMA0SZ = 0x040;                           // 货物总量,字节
  // 字节to字节,每次触发运输一个字节,货源地地址自加,目的地地址自加,启动DMA0
  DMA0CTL = DMASBDB + DMADT_4 + DMASRCINCR_3 + DMADSTINCR_3 + DMAEN;

  for (;;)                                  
  {
    DMA0CTL |= DMAREQ;                      // 手动触发,DMA0REQ
  }
}

改变DMACTL0,DMACTL0 = DMA0TSEL_0,触发方式为Timer_A(TACCR2.IFG), TACCTL2的CCIFG位 置位 了,就触发1次传输,如果设置了Timer_A定时器的CCR2,并使能了标志位,那么每次定时时间到,就触发1次传输;本次测试使用软件设置该位,TACCTL2 |= CCIFG;标志位自动清零;这就是DMA和定时器Timer的结合使用

直接来到这一步,触发之前,可以看到 0x0220——0x025f 共0x40个字节被重新赋值,而0x0280——0x02bf 的0x40个字节的值还是没变,比较乱;

运行当前一句代码,如下,同样的,DAM0把0x0220中的货物(值)运送到了目的地0x0280中,

跟上面是一样的,除了触发方式不一样了,其他都一样,

测试代码:

#include <msp430.h>
#include "typeredefine.h"
__no_init u8 SDEventBuf[0x10] @0x0220;
//u8 SDEventBuf[0x10] ={0};
int main(void)
{
  WDTCTL = WDTPW + WDTHOLD;                 // 关闭看门狗
  for(u16 temp=0;temp<0x40;temp++)          //给数组赋值
  {
     *(SDEventBuf+temp) = temp;
  }
  DMACTL0 = DMA0TSEL_1;                     // 选择DMA0触发方式   ,REQ
  DMACTL1 = 0;                              //触发时的响应,中断等,无
  DMA0SA = (u16)SDEventBuf;                 // DMA0货源地,16bit
  DMA0DA = 0x0280;                          // DMA0目的地,16bit
  DMA0SZ = 0x040;                           // 货物总量,字节
  // 字节to字节,每次触发运输一个字节,货源地地址自加,目的地地址自加,启动DMA0
  DMA0CTL = DMASBDB + DMADT_4 + DMASRCINCR_3 + DMADSTINCR_3 + DMAEN;

  for (;;)
  {
    TACCTL2 |= CCIFG;                       // 手动触发,TACCTL2 |= CCIFG
  }
}

总结, DMACTL0控制着DMA0——DMA2的触发方式,每个DMA通道有16种触发方式,以DMA为例(其他的为相应的DMAxTSEL_x)进行简单描述:

DMA0TSEL_0      软件设置DMA0CTL |= DMAREQ;触发,                               DMA0TSEL_1   定时器Timer_A的CCR2标志位 置位,即TACCTL2 &CCIFG==CCIFG触发 DMA0TSEL_2   定时器Timer_B的CCR2标志位 置位,即TACCTL2 &CCIFG==CCIFG;触发     DMA0TSEL_3    UART0/I2C的接收标志位 置位,UART/SPI模式: IFG1 &URXIFG0 == URXIFG0; 触发 。I2C模式,未测试
DMA0TSEL_4    UART0/I2C的发送标志位 置位,  UART/SPI模式 IFG1 &UTXIFG0 == UTXIFG0; 触发;但是需要注意的是,IFG1的UTXIFG0位需要在U0CTL的 SWRST要置零后才能触发,即U0CTL &= ~SWRST; 做个标记,当设置U0CTL &= ~SWRST之后触发了一次中断。后面有时间测试一下UART功能。I2C模式,未测试
DMA0TSEL_5  DAC12的中断标志位 置位,即DAC12_0CTL &DAC12IFG== DAC12IFG;触发  
DMA0TSEL_6 ,标记,测试失败
DMA0TSEL_7   定时器Timer_A的CCR0标志位 置位,即TACCTL0 &CCIFG==CCIFG触发     
DMA0TSEL_8   定时器Timer_B的CCR0标志位 置位,即TACCTL0 &CCIFG==CCIFG;触发     
DMA0TSEL_9   UART1的接收标志位 置位,即 IFG2 &URXIFG1 == URXIFG0; 触发     DMA0TSEL_10   UART1的发送标志位 置位,即 IFG2 &URXIFG1 == URXIFG0; 触发;但是需要注意的是,IFG2的UTXIFG2位需要在U1CTL的 SWRST要置零后才能触发,即U1CTL &= ~SWRST; 做个标记,当设置U1CTL &= ~SWRST之后触发了一次中断。后面有时间测试一下UART功能。    
DMA0TSEL_11       
DMA0TSEL_14  DMA其他中断标志位置位触发,其中DAM2→DMA0,DMA0→ DMA1, DMA1 → DMA2,即,DMA2CTL &DMAIFG ==  DMAIFG; 触发DMA0传输,以此类推。    
DMA0TSEL_15   暂未找到如何测试


DMACTL0、DMA0SA、DMA0DA、DMA0SZ、DMA0CTL不变的情况下,改变DMACTL1, DAMCTL1寄存器的各个位的控制如下                                                             

  • 14-12位,控制每次传输的方式,DMADT_0——DMADT_7共8种模式;

  • 11-10位,控制目的地地址的变化方式,共DMADSTINCR_0——DMADSTINCR_3四种,其实是三种;

  • 9-8位,控制货源地地址的变化方式,共DMASRCINCR_0——DMASRCINCR_3四种,其实是三种;

  • 7-6位,控制货源地→目的地的地址分配方式,共四种,DMASWDW:字→字, DMASBDW:字节→字,DMASWDB :字→字节,DMASBDB:字节→字节;上面的测试使用的都是:字节→字节;

  • 第5位,控制传输触发是上升沿触发,还是高电平触发,DMALEVEL=0为上升沿触发;

  • 第4位,DMAEN控制启动DMA的开关,DMAEN=1,开;

  • 第3位,DMAIFG,中断触发标志位,当开启中断后,传输的总货量完成(DMA0SZ=0)之后,触发中断,DMAIFG =1;

  • 第2位,DMAIE,DMA中断开关,DMAIE=1,开启DMA中断;

  • 第1位,DMAABORT,DMA停止传输开关,当DMAABORT=1,传完当前的一次传输后,停止传输;

  • 第0位,DMAREQ,软件触发DAM传输,当触发方式为DMA0TSEL_0——DMAREQ触发时,DMAREQ = 1,触发传输,并且自动清零。

为了方便测试,DMACTL0 = DMA0TSEL_0;使用软件触发方式进行测试。

先改变传输方式:

DMA0CTL = DMASBDB + DMAIE + DMASRCINCR_3 + DMADSTINCR_3 + DMAEN;

不变,

改变:DMA0CTL |=DMADT_0;从DMADT_0——DMADT_78种模式


程序测试:未完待续。。。

飞花两岸照船红

百里榆堤半日风

卧看满天云不动

不知云与我俱东

                        ——————2020年6月24日09:02:15

MSP430F1单片机的学习1——认识和使用DMA的评论 (共 条)

分享到微博请遵守国家法律