MSP430+DMA

2024-06-07 00:08
文章标签 dma msp430

本文主要是介绍MSP430+DMA,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

直接存储器存取(DMADirect Memory Access)方式是用硬件实现存储器与存储器之间或存储器与I\O设备之间直接进行高速数据传送,不需要CPU的干预。这种方式通常用来传送数据块。MSP430f16x系列单片机内部含有DMA模块,而且几乎内部所有外设都可以触发DMA开始存取数据。这里实现了这个模块的程序通用的函数库,方便使用。

  1. 硬件介绍:

    MSP430F15X/16X 系列单片机具有DMA 控制器,从而能够为数据高速传输提供保证。例如,通过DMA控制器可以直接将ADC 转换存贮器的内容传到RAM 单元。

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

    MSP430F16x系列单片机的DMA模块有以下特点:数据传送不需要CPU介入,完全由DMA控制器自行管理。在整个地址空间范围内传输数据,块方式传输可达65536字节;能够提高片内外设数据吞吐能力,实现高速传输,每个字或者字节的传输仅需要2个MCLK;减少系统功耗,即使在片内外设进行数据输入或输出时,CPU也可以处于超低功耗模式而不需唤醒;字节和字数据可以混合传送:DMA传输可以是字节到字节、字到字、字节到字或者字到字节。当字到字节传输时,只有字中较低字节能够传输,当从字节到字传输时,传输到字的低字节,高字节被自动清零;四种传输寻址模式:固定地址到固定地址、固定地址到块地址、块地址到固定地址以及块地址到块地址;触发方式灵活:边沿或者电平触发。单个、块或突发块传输模式:每次触发DMA操作,可以根据需要传输不同规模的数据

    DMA的四种寻址模式如下图所示:

    image

    DMA控制器模块:3个独立的传输通道:通道0、通道1和通道2。每个通道都有源地址寄存器、目的地址寄存器、传送数据长度寄存器和控制寄存器。每个通道的触发请求可以分别允许和禁止;可配置的通道优先权:优先权裁决模块,传输通道的优先级可以调整,对同时有触发请求的通道进行优先级裁决,确定哪个通道的优先级最高。MSP430的DMA控制器可以采用固定优先级,还可以采用循环优先级。程序命令控制模块,每个DMA通道开始传输之前,CPU要编程给定相关的命令和模式控制,以决定DMA通道传输的类型;可配置的传送触发器:触发源选择模块,DMAREQ(软件触发)、Timer_ACCR2输出、Timer_BCCR2输出、I2C 数据接收准备好、I2C 数据发送准备好、USART接收发送数据、DAC12模块DAC12IFG、ADC12模块的ADC12IFGx、DMAxIFG、DMAE0 外部触发源。并且还具有触发源扩充能力。

    DMA有六种传输模式:单字或者单字节传输;块传输;突发块传输;重复单字或者单字节传输;重复块传输;重复突发块传输。前三个,传输完成后DMAEN自动复位;再次传输时需要重新置位DMAEN位以使能DMA通道。后三个为重复模式,一次传输完成后,DMAEN不复位;再次出发时,可以再次启动数据传输。六种传输模式通过DMADTx寄存器设置:

    <span style="color: green;">DMADTx      Transfer Mode               Description
    000         Single transfer             Each transfer requires a trigger. DMAEN isautomatically cleared when DMAxSZ transfers havebeen made.
    001         Block transfer              A complete block is transferred with one trigger.DMAEN is automatically cleared at the end of theblock transfer.
    010, 011    Burst-block transfer        CPU activity is interleaved with a block transfer.DMAEN is automatically cleared at the end of theburst-block transfer.
    100         Repeated single transfer    Each transfer requires a trigger. DMAEN remainsenabled.
    101         Repeated block transfer     A complete block is transferred with one trigger.DMAEN remains enabled.
    110, 111    Repeated burst-block        CPU activity is interleaved with a block transfer.transfer                    DMAEN remains enabled.
    </span>

    单字或者单字节传输:DMA 通道被定义为单字或者单字节传输模式,每个字或者字节的传输都要触发信号触发。设置DMADTx=0 就定义了单字或者单字节传输模式,规定的传输完毕后DMAEN 位自动清除,如果需要再次传输,必须重新置位DMAEN。如果设置DMADTx=4 为重复单字或者单字节传输模式,DMAEN 位一直保持置位,每次触发伴随一次传输。DMAxSZ 寄存器保存传输的单元个数,如果该寄存器为0,则没有传输。传输之前DMAxSZ 寄存器的值写入到一个临时的寄存器中,每次操作之后DMAxSZ 做减操作。当DMAxSZ减为零的时候,它所对应的临时寄存器将原来的值重新置入DMAxSZ,同时相应的DMAIFG标志置位。

    块传输模式:在块传输模式,每次触发可以传输一个数据块。设置DMADTx=1 为块传输模式,每个数据块传输完毕,DMAEN 位自动清除,在触发传输下一个数据块之前,该位要被重新置位。在传输某个数据块期间,其他的传输请求将被忽略。设置DMADTx=5 为重复块传输模式,某个数据块传输完毕,DMAEN 位仍然保持置位,之后,新的触发可以引起又一次数据块传送。DMAxSZ 寄存器保存数据块所包含的单元个数。DMASRCINCR 和DMADSTINCR 反映在数据块传输过程中的目的地址和源地址的变化情况。在块传输或者重复块传输过程中,DMAxSA,DMAxDA,DMAxSZ 寄存器的值写入到对应的临时寄存器中,DMAxSA,DMAxDA寄存器所对应的临时值在块传输过程中增加或者减少,而DMAxSZ 在块传输过程中减计数,始终反映当前数据块还有多少单元没有传输完毕,当DMAxSZ 减为0,它所对应的临时寄存器将原来的值重新置入DMAxSZ,同时相应的DMAIFG被置位。在块传输过程中,CPU 暂停工作,不参与数据的传输。数据块需要2×MCLK×DMAxSZ 个时钟周期。当每个数据块传输完毕,CPU 按照暂停前的状态重新开始执行。

    突发块传输模式:这个和块传输模式类似,只不过每传输4个字或字节,DMA释放内部总线,CPU运行2个MCLK周期;在传输过程中CPU有20%的执行时间,而块传输需要等DMA完全传送完之后,CPU方能运行。

    DMA触发源:每个通道的触发源有DMAxTSELx位进行控制的,这些位必须在DMAEN位为0是进行设置,否则可能出现不可预料的DMA触发。

    <span style="color: green;">DMAxTSELx   Operation
    0000        DMAREQ bit (software trigger)
    0001        TACCR2 CCIFG bit
    0010        TBCCR2 CCIFG bit
    0011        URXIFG0 (UART/SPI mode), USART0 data received (I2C mode)
    0100        UTXIFG0 (UART/SPI mode), USART0 transmit ready (I2C mode)
    0101        DAC12_0CTL DAC12IFG bit
    0110        ADC12 ADC12IFGx bit
    0111        TACCR0 CCIFG bit
    1000        TBCCR0 CCIFG bit
    1001        URXIFG1 bit
    1010        UTXIFG1 bit
    1011        Multiplier ready
    1100        No action
    1101        No action
    1110        DMA0IFG bit triggers DMA channel 1DMA1IFG bit triggers DMA channel 2DMA2IFG bit triggers DMA channel 0
    1111        External trigger DMAE0
    </span>

    另外,单片机的中断程序不影响DMA的传输,当DMA传输过程中,单片机不响应中外部NMI中断(必须DMA的控制位ENNMI位为1时响应NMI中断,否则不予处理)外的所有中断;必须等待DMA数据传送结束之后才运行系统的中断处理程序。

    DMA的中断:数据传送过程中,DMAxSZ寄存器值减为0时,DMA置位DMAIFG,DMA的中断和DAC12模块共享中断向量,使用中断时需要软件判断具体是那个中断。中断响应后DMAIFG不会自动复位,使用时必须软件清零DMAIFG位。

    DMA的寄存器如下:

    <span style="color: green;">Register                            Short Form      Register Type   Address     Initial State
    DMA control 0                       DMACTL0         Read/write      0122h       Reset with POR
    DMA control 1                       DMACTL1         Read/write      0124h       Reset with POR
    DMA channel 0 control               DMA0CTL         Read/write      01E0h       Reset with POR
    DMA channel 0 source address        DMA0SA          Read/write      01E2h       Unchanged
    DMA channel 0 destination address   DMA0DA          Read/write      01E4h       Unchanged
    DMA channel 0 transfer size         DMA0SZ          Read/write      01E6h       Unchanged
    DMA channel 1 control               DMA1CTL         Read/write      01E8h       Reset with POR
    DMA channel 1 source address        DMA1SA          Read/write      01EAh       Unchanged
    DMA channel 1 destination address   DMA1DA          Read/write      01ECh       Unchanged
    DMA channel 1 transfer size         DMA1SZ          Read/write      01EEh       Unchanged
    DMA channel 2 control               DMA2CTL         Read/write      01F0h       Reset with POR
    DMA channel 2 source address        DMA2SA          Read/write      01F2h       Unchanged
    DMA channel 2 destination address   DMA2DA          Read/write      01F4h       Unchanged
    DMA channel 2 transfer size         DMA2SZ          Read/write      01F6h       Unchanged
    </span>

    有关每个寄存器的详细内容参考ti提供的用户指南。

  2. 程序实现:

    DMA的使用主要是DMA寄存器的初始设置,设置完成后,DMA接到触发信号即可自动传输数据。

    设置函数如下:

    <span style="color: blue;">void </span>DMAInit(<span style="color: blue;">char </span>channel,<span style="color: blue;">char </span>trigger,<span style="color: blue;">char </span>transMode,<span style="color: blue;">char </span>srcMode,<span style="color: blue;">char </span>dstMode,<span style="color: blue;">unsigned int </span>src,<span style="color: blue;">unsigned int </span>dst,<span style="color: blue;">unsigned int </span>size)
    {<span style="color: blue;">unsigned int </span>*DMAxCTL,*DMAxSA,*DMAxDA,*DMAxSZ;DMACTL0 = trigger << (channel << 2);DMACTL1 = 0x04;         <span style="color: green;">//DMA收到触发请求时,等待当前指令执行完成后</span><span style="color: blue;">switch </span>(channel)        <span style="color: green;">//选择当前设置哪个DMA通道</span>{<span style="color: blue;">case </span>0: DMAxCTL = (<span style="color: blue;">unsigned int </span>*)&DMA0CTL;DMAxSA = (<span style="color: blue;">unsigned int </span>*)&DMA0SA;DMAxDA = (<span style="color: blue;">unsigned int </span>*)&DMA0DA;DMAxSZ = (<span style="color: blue;">unsigned int </span>*)&DMA0SZ;<span style="color: blue;">break</span>;                                      <span style="color: green;">//指针 = 0通道控制</span><span style="color: blue;">case </span>1: DMAxCTL = (<span style="color: blue;">unsigned int </span>*)&DMA1CTL;DMAxSA = (<span style="color: blue;">unsigned int </span>*)&DMA1SA;DMAxDA = (<span style="color: blue;">unsigned int </span>*)&DMA1DA;DMAxSZ = (<span style="color: blue;">unsigned int </span>*)&DMA1SZ;<span style="color: blue;">break</span>;                                      <span style="color: green;">//指针 = 1通道控制</span><span style="color: blue;">case </span>2: DMAxCTL = (<span style="color: blue;">unsigned int </span>*)&DMA2CTL;DMAxSA = (<span style="color: blue;">unsigned int </span>*)&DMA2SA;DMAxDA = (<span style="color: blue;">unsigned int </span>*)&DMA2DA;DMAxSZ = (<span style="color: blue;">unsigned int </span>*)&DMA2SZ;<span style="color: blue;">break</span>;                                      <span style="color: green;">//指针 = 2通道控制</span>}<span style="color: blue;">switch </span>(transMode)      <span style="color: green;">//设置DMA通道的传输模式</span>{<span style="color: blue;">case </span><span style="color: rgb(163, 21, 21);">'S'</span>: *DMAxCTL = DMADT_0;   <span style="color: blue;">break</span>;          <span style="color: green;">//单次传输</span><span style="color: blue;">case </span><span style="color: rgb(163, 21, 21);">'s'</span>: *DMAxCTL = DMADT_4;   <span style="color: blue;">break</span>;          <span style="color: green;">//重复单次传输</span><span style="color: blue;">case </span><span style="color: rgb(163, 21, 21);">'B'</span>: *DMAxCTL = DMADT_1;   <span style="color: blue;">break</span>;          <span style="color: green;">//块传输</span><span style="color: blue;">case </span><span style="color: rgb(163, 21, 21);">'b'</span>: *DMAxCTL = DMADT_5;   <span style="color: blue;">break</span>;          <span style="color: green;">//重复块传输</span><span style="color: blue;">case </span><span style="color: rgb(163, 21, 21);">'I'</span>: *DMAxCTL = DMADT_2;   <span style="color: blue;">break</span>;          <span style="color: green;">//突发块传输 交错</span><span style="color: blue;">case </span><span style="color: rgb(163, 21, 21);">'i'</span>: *DMAxCTL = DMADT_6;   <span style="color: blue;">break</span>;          <span style="color: green;">//重复突发块传输 交错</span>}*DMAxCTL |= (srcMode & 0x04) << 2;                  <span style="color: green;">//源 字或字节</span>*DMAxCTL |= (srcMode & 0x03) << 8;                  <span style="color: green;">//源 地址改变方式</span>*DMAxCTL |= (dstMode & 0x04) << 3;                  <span style="color: green;">//目的 字或字节</span>*DMAxCTL |= (dstMode & 0x03) << 10;                 <span style="color: green;">//目的 地址改变方式</span>*DMAxSA = src;*DMAxDA = dst;*DMAxSZ = size;*DMAxCTL |= DMAEN;                                  <span style="color: green;">//DMA使能
    </span>}

    函数比较麻烦,函数内容按参数设置每个寄存器。DMACTL0 = trigger << (channel << 2); 这个是设置对应channel通道的的参考源,不大明白的可以看下DMACTL0的寄存器内容;switch (channel)语句则根据通道设置对应指针指向的寄存器;然后对应设置参数即可。

    当设置成非重复模式时,需要重新置位DMAEN,本程序就函数DMAReEnable实现:

    <span style="color: blue;">void </span>DMAReEnable(<span style="color: blue;">char </span>channel)
    {<span style="color: blue;">switch </span>(channel)        <span style="color: green;">//使能对应通道</span>{<span style="color: blue;">case </span>0: DMA0CTL |= DMAEN;   <span style="color: blue;">break</span>;      <span style="color: green;">//0通道</span><span style="color: blue;">case </span>1: DMA1CTL |= DMAEN;   <span style="color: blue;">break</span>;      <span style="color: green;">//1通道</span><span style="color: blue;">case </span>2: DMA2CTL |= DMAEN;   <span style="color: blue;">break</span>;      <span style="color: green;">//2通道</span>}
    }

    这个函数比较简单,只是根据传入参数设置对应通道的DMAEN位。

    当设置为软件触发时,需要软件启动DMA程序如下:

    <span style="color: blue;">void </span>DMAStart(<span style="color: blue;">char </span>channel)
    {<span style="color: blue;">switch </span>(channel)        <span style="color: green;">//使能对应通道</span>{<span style="color: blue;">case </span>0: DMA0CTL |= DMAREQ;  <span style="color: blue;">break</span>;      <span style="color: green;">//0通道</span><span style="color: blue;">case </span>1: DMA1CTL |= DMAREQ;  <span style="color: blue;">break</span>;      <span style="color: green;">//1通道</span><span style="color: blue;">case </span>2: DMA2CTL |= DMAREQ;  <span style="color: blue;">break</span>;      <span style="color: green;">//2通道</span>}
    }

    这个和上个函数类似:仅仅设置一个控制位,函数很简单,不再解释啦。

    程序实现就这么多了,有关详细内容可以下载附件里的程序库,程序的注释很详细。

  3. 使用示例:

    使用这个程序时,步骤和原来的相同:工程中加入DMA.c文件,然后源文件中包含DMA.h头文件即可。

    示例程序主要如下:

    <span style="color: blue;">#include </span><span style="color: rgb(163, 21, 21);"><msp430x16x.h>
    </span><span style="color: blue;">#include </span><span style="color: rgb(163, 21, 21);">"DMA.h"</span><span style="color: blue;">unsigned int </span>a[5] = {8693,5689,2356,23565,5656};
    <span style="color: blue;">unsigned int </span>b[5];
    <span style="color: blue;">void </span>main( <span style="color: blue;">void </span>)
    {<span style="color: green;">// Stop watchdog timer to prevent time out reset</span>WDTCTL = WDTPW + WDTHOLD;ClkInit();<span style="color: green;">//块传输,5个字(16位) a->b</span>DMAInit(0,0x00,<span style="color: rgb(163, 21, 21);">'B'</span>,3,3,(<span style="color: blue;">unsigned int</span>)a,(<span style="color: blue;">unsigned int</span>)b,5);DMAStart(0);<span style="color: green;">//如果需要再次传输 而不改变设置,只需调用DMAReEnable再次启动传输即可 // 如果是重复块传输,则不需要重新使能DMAReEnable 直接启动即可//这里仅仅演示了使用方法,实际应用中,应根据需要选择适当的触发源。//</span>LPM0;
    }

    示例程序完成功能很简单,仅仅把一个数组的值赋给另外一个数组。数组地址即是数组名强制转换为所需类型(无符号16位),传入函数初始化设置。这里为了简便,设置为软件启动。

    运行效果如下:

    image

    单步运行完启动DMA传输后,结果即出来了;说明DMA传输数据的速度是很快的。

这篇关于MSP430+DMA的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1037623

相关文章

STM32 ADC+DMA导致写FLASH失败

最近用STM32G070系列的ADC+DMA采样时,遇到了一些小坑记录一下; 一、ADC+DMA采样时进入死循环; 解决方法:ADC-dma死循环问题_stm32 adc dma死机-CSDN博客 将ADC的DMA中断调整为最高,且增大ADCHAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_buffer, ADC_Buffer_Size); 的ADC_Bu

学习硬件测试05:NTC(ADC)+正弦波(DAC)+DMA(ADC+DAC)(P73、P76、P78)

文章以下内容全部为硬件相关知识,鲜有软件知识,并且记的是自己需要的部分,大家可能看不明白。 一、NTC(ADC) 1.1实验现象 本实验用 NTC 采集温度,数码管实时显示温度数据(整数),左下角 USB 小串口每隔 1S 打印温度信息。 1.2硬件电路 NTC 电阻是一个模拟温度传感器,随着温度的升高,电阻值逐渐减小。电路简单介绍如下: 电源滤波电容在 25℃ 室温下 NTC 电

物联网——DMA+AD多通道

DMA简介 存储器映像 某些数据在运行时不会发生变化,则设置为常量,存在Flash存储器中,节省运行内存的空间 DMA结构图 DMA访问权限高于cpu 结构要素 软件触发源:存储器到存储器传输完成后,计数器清零 硬件触发源:ADC、定时器、串口 重写计数器时,需关闭DMA DMA请求 数据宽度与对齐 目标宽度小于传输带宽:高位补零,反之,舍弃高位 数据转运与D

STM32F103调试DMA+PWM 实现占空比逐渐增加的软启效果

实现效果:DMA+PWM 实现PWM输出时,从低电平到输出占空比逐渐增加再到保持高电平的效果,达到控制 MOS 功率开关软启的效果。 1.配置时钟 2.TIM 的 PWM 功能配置 选择、配置 TIM 注意:选择 TIM 支持 DMA 控制输出 PWM 功能的通道,有的TIM通道支持PWM 但不支持PWM注意选择。 PWM参数设置 Counter Period :

DMA引起数组越界

今遇到了内存越界问题,很隐蔽   EXTERN  __IO uint16_t RegularConvData_Tab[2*3]; 定义的DMA搬运工的buffer大小为6   实际上当时红线标注,改为了12,导致后续的变量被赋值 只要此值小于定义的buffer的大小就可以了   这个越界是非常不注意的问题,编译器不报错

OpenGL DMA接口

Opengl的DMA版本接口主要作用是解决以前访问opengl对象, 必须先将对象绑定到当前状态机下才能访问的问题,这会导致驱动层需要去频繁的进行对象的引用查找。  比如以前非DMA版本的接口操作顶点数据  glGenBuffers(1, &vbo);glBindBuffer(GL_ARRAY_BUFFER, vbo);glBufferData(GL_ARRAY_BUFFER, sizeof

FPGA PCIE驱动,windriver驱动 wdf驱动 windows linux PCIE DMA驱动 支持win10 server2016

一:相关介绍         本人一直从事fpga pcie dma驱动开发,可以开发windwos Linux 原生驱动 wdf 或者基于第三方库的windriver。支持win10 win server。提供稳定的驱动库,或者源码,开发者可以不关心底层驱动直接使用封装的库。 二:PCIE 驱动开发的稳定性和高效性: 本驱动库均已经进行了实际交付使用,通过了严格的jun

XILINX平台下LINUX DMA驱动调研

专栏目录 高质量文章导航-持续更新中-CSDN博客 基础概念 VA:virtual address称为虚拟地址, PA:physical address称为物理地址。 CPU通过地址来访问内存中的单元,如果CPU没有MMU,或者有MMU但没有启动,那么CPU内核在取指令或者访问内存时发出的地址(此时必须是物理地址,假如是虚拟地址,那么当前的动作无效)将直接传到CPU芯片的外部地址引脚上,

【STM32 Blue Pill编程】-ADC数据采样(轮询、中断和DMA模式)

ADC数据采样(轮询、中断和DMA模式) 文章目录 ADC数据采样(轮询、中断和DMA模式)1、硬件准备及接线2、ADC轮询模式2.1 轮询模式配置2.2 代码实现 3、ADC中断模式3.1 中断模式配置3.2 代码实现 4、ADC的DMA模式4.1 DMA模式配置4.2 代码实现 在本文中,我们将介绍如何使用 ADC 并使用 STM32CubeIDE 和 HAL 库读取模拟输

STM32-HAL库串口DMA空闲中断的正确使用方式及SBUS信号解析

概述 STM32微控制器广泛用于嵌入式系统,其HAL(Hardware Abstraction Layer)库简化了硬件访问,提高了开发效率。在STM32中,使用DMA(Direct Memory Access)进行串口通信可以显著提高数据传输效率,减少CPU负载。本文将介绍如何在STM32中正确使用串口DMA空闲中断,并解析SBUS信号。 串口DMA空闲中断 在STM32中,串口DMA传输