5430|2

172

帖子

3

TA的资源

一粒金砂(高级)

楼主
 

TI【LP_MSPM0L1306开发板】测评——DMA使用以及示例学习 [复制链接]

 

DMA使用以及示例学习

DMA(Direct Memory Access)作为嵌入式控制器中标准外设,在源地址和目标地址之间传递数据,过程不需要CPU的干预,这提升了外设模块的数据传输速率。
TI的DMA控制器具有以下特点:
  • 最多可达16个独立的传输通道;
  • 可以配置的DMA通道优先级;
  • 支持8位(byte),16位(short word)、32位(word)和64位(long word)或者混合大小(byte 和 word)传输;
  • 支持最大可达64K任意数据类型的数据块传输;
  • 可配置的DMA传输触发源;
  • 6种灵活的寻址模式;
  • 单次或者块传输模式;
MSPM0L1306共有3个DMA通道,各个通道可以独立配置,多种多样的数据传输模式可以适应不同应用场景的数据传输需要。
通过查看TI的数据手册,DMA功能除了常见的内存与外设间的地址寻址方式,还提供了Fill Mode和Table Mode两种拓展模式,DMA通道分为基本类型和全功能类型两种。
通过查看数据手册,只有全功能类型的DMA通道支持重复传输、提前中断以及拓展模式,基本功能的DMA通道支持基本的数据传输和中断,但是足够满足简单的数据传输要求。

Block传输模式

在Block模式下,数据的传输和常见的DMA传输一样,实现源地址和目标地址之间的数据传输,源地址指针和目标地址指针是否增减、数据的大小和中断都可以配置。
该模式下TI提供的示例程序dma_block_transfer_LP_MSPM0L1306_nortos_ticlang,实现从Flash中的数据到SRAM中的数据传输过程。SysConfig中对DMA的配置如下:
源代码如下,逻辑简单,DMA完成从Flash中传递数据到SRAM中,然后对比数据传输结果是否正确,并置位相关的标志位。
#include "ti_msp_dl_config.h"

#define DMA_TRANSFER_SIZE_WORDS (16)

const uint32_t gSrcData[DMA_TRANSFER_SIZE_WORDS] = {0x00000000, 0x10101010,
    0x20202020, 0x30303030, 0x40404040, 0x50505050, 0x60606060, 0x70707070,
    0x80808080, 0x90909090, 0xA0A0A0A0, 0xB0B0B0B0, 0xC0C0C0C0, 0xD0D0D0D0,
    0xE0E0E0E0, 0xF0F0F0F0};
uint32_t gDstData[DMA_TRANSFER_SIZE_WORDS];

volatile bool gChannel0InterruptTaken = false;
volatile bool gVerifyResult;

int main(void)
{
    /*
     * Initialize the DMA peripheral and set up a transaction according to
     * the parameters defined in ti_msp_dl_config.h
     */
    SYSCFG_DL_init();

    /* Setup interrupts on device */
    DL_SYSCTL_disableSleepOnExit();
    NVIC_EnableIRQ(DMA_INT_IRQn);

    /* Configure DMA source, destination and size */
    DL_DMA_setSrcAddr(DMA, DMA_CH0_CHAN_ID, (uint32_t) &gSrcData[0]);
    DL_DMA_setDestAddr(DMA, DMA_CH0_CHAN_ID, (uint32_t) &gDstData[0]);
    DL_DMA_setTransferSize(
        DMA, DMA_CH0_CHAN_ID, sizeof(gSrcData) / sizeof(uint32_t));
    DL_DMA_enableChannel(DMA, DMA_CH0_CHAN_ID);

    /* Start block transfer */
    gChannel0InterruptTaken = false;
    DL_DMA_startTransfer(DMA, DMA_CH0_CHAN_ID);

    /* Wait for transfer */
    while (gChannel0InterruptTaken == false) {
        __WFE();
    }

    gVerifyResult = true;
    for (int i = 0; i < DMA_TRANSFER_SIZE_WORDS; i++) {
        gVerifyResult &= gSrcData[i] == gDstData[i];
    }

    /* Breakpoint to inspect verification result */
    __BKPT(0);

    while (1) {
        __WFI();
    }
}

void DMA_IRQHandler(void)
{
    /* Example interrupt code -- just used to break the WFI in this example */
    switch (DL_DMA_getPendingInterrupt(DMA)) {
        case DL_DMA_EVENT_IIDX_DMACH0:
            gChannel0InterruptTaken = true;
            break;
        default:
            break;
    }
}

 

在CCS中打卡调试窗口,gSrcData中的数据在程序运行前填入了初始值,gDstData初始化为全为0的数组。
程序完成DMA操作后,gSrcData中的数据传输到gDstData中。

Fill模式

Fill模式,源地址改为了一个用户指定的数据内容(手册中描述为“pattern”),在该模式下,目标地址中的内容会被修改为用用指定的数据内容,可以用于内存的特定初始化操作。
该模式下TI提供的示例程序dma_fill_data_LP_MSPM0L1306_nortos_ticlang,实现以某个固定数值对目标区内的内存进行初始化操作。SysConfig中对DMA的配置如下:
工程的源码如下,DMA在中断中检测是否完成数据传输,并对其进行校验
#include "ti_msp_dl_config.h"

#define DMA_FILL_SIZE_WORDS (16)

const uint32_t gFillPattern = 0xF711BEEF;
uint32_t gDstData[DMA_FILL_SIZE_WORDS];

volatile bool gChannel0InterruptTaken = false;
volatile bool gVerifyResult           = false;

int main(void)
{
    /*
     * Initialize the DMA peripheral and set up a transaction according to
     * the parameters defined in ti_msp_dl_config.h
     */
    SYSCFG_DL_init();

    /* Setup interrupts on device */
    DL_SYSCTL_disableSleepOnExit();
    NVIC_EnableIRQ(DMA_INT_IRQn);

    /* Configure DMA source, destination and size */
    DL_DMA_setSrcAddr(DMA, DMA_CH0_CHAN_ID, gFillPattern);
    DL_DMA_setDestAddr(DMA, DMA_CH0_CHAN_ID, (uint32_t) &gDstData[0]);
    DL_DMA_setTransferSize(
        DMA, DMA_CH0_CHAN_ID, sizeof(gDstData) / sizeof(uint32_t));
    DL_DMA_enableChannel(DMA, DMA_CH0_CHAN_ID);

    /* Start fill data */
    gChannel0InterruptTaken = false;
    DL_DMA_startTransfer(DMA, DMA_CH0_CHAN_ID);

    /* Wait for transfer */
    while (gChannel0InterruptTaken == false) {
        __WFE();
    }

    gVerifyResult = true;
    for (int i = 0; i < DMA_FILL_SIZE_WORDS; i++) {
        gVerifyResult &= (gDstData[i] == gFillPattern);
    }

    /* Breakpoint to inspect verification result */
    __BKPT(0);

    while (1) {
        __WFI();
    }
}

void DMA_IRQHandler(void)
{
    /* Example interrupt code -- just used to break the WFI in this example */
    switch (DL_DMA_getPendingInterrupt(DMA)) {
        case DL_DMA_EVENT_IIDX_DMACH0:
            gChannel0InterruptTaken = true;
            break;
        default:
            break;
    }
}

 

在CCS中打卡调试窗口,gFillPattern作为常量初始化为0xF711BEEF(),gDstData初始化为全为0的数组。
程序完成DMA操作后,gSrcData中的数据被初始化为gFillPattern的值。

Table模式

在Table模式中,DMA控制器从源地址读取两个数据(第一个数据为写入数据的地址,第二个数据位写入数据的内容),向目标地址写入一个数据。该特点在根据数据表初始化指定数据时,对数据表进行解析时不需要占用CPU的资源,从而节省CPU的资源。
TI提供的dma_table_transfer_LP_MSPM0L1306_nortos_ticlang中,初始化了目标地址和数据组成的表格数组作为源数据,目标地址指向变量再该模式下根据表格中的数据进行初始化。
工程的源码如下,DMA在中断中检测是否完成数据传输,并对其进行校验
#include "ti_msp_dl_config.h"

#define DMA_TABLE_ENTRIES (4)

volatile bool gChannel0InterruptTaken;

volatile uint32_t gDstData1;
volatile uint32_t gDstData2;
volatile uint32_t gDstData3;
volatile uint32_t gDstData4;

__attribute__((aligned(8)))
const uint32_t gTableData[DMA_TABLE_ENTRIES * 2] = {(uint32_t) &gDstData1,
    0x10101010, (uint32_t) &gDstData2, 0x20202020, (uint32_t) &gDstData3,
    0x30303030, (uint32_t) &gDstData4, 0x40404040};

volatile bool gVerifyResult;

int main(void)
{
    bool compare = true;
    /*
     * Initialize the DMA peripheral and set up a transaction according to
     * the parameters defined in ti_msp_dl_config.h
     */
    SYSCFG_DL_init();

    /* Configure DMA source, destination and size */
    DL_DMA_setSrcAddr(DMA, DMA_CH0_CHAN_ID, (uint32_t) &gTableData[0]);
    DL_DMA_setDestAddr(DMA, DMA_CH0_CHAN_ID, (uint32_t) &gTableData[0]);
    DL_DMA_setTransferSize(DMA, DMA_CH0_CHAN_ID, DMA_TABLE_ENTRIES);
    DL_DMA_enableChannel(DMA, DMA_CH0_CHAN_ID);

    /* Setup interrupts on device */
    DL_SYSCTL_disableSleepOnExit();
    NVIC_EnableIRQ(DMA_INT_IRQn);

    gChannel0InterruptTaken = false;

    /* Start fill data */
    DL_DMA_startTransfer(DMA, DMA_CH0_CHAN_ID);

    while (false == gChannel0InterruptTaken) {
        __WFE();
    }

    compare &= (gTableData[1] == gDstData1);
    compare &= (gTableData[3] == gDstData2);
    compare &= (gTableData[5] == gDstData3);
    compare &= (gTableData[7] == gDstData4);

    gVerifyResult = compare;

    /* Breakpoint to inspect verification result */
    __BKPT(0);

    while (1) {
        __WFI();
    }
}

void DMA_IRQHandler(void)
{
    /* Example interrupt code -- just used to break the WFI in this example */
    switch (DL_DMA_getPendingInterrupt(DMA)) {
        case DL_DMA_EVENT_IIDX_DMACH0:
            gChannel0InterruptTaken = true;
            break;
        default:
            break;
    }
}

 

在CCS中打卡调试窗口,gTableData数组为指定的目标地址和数据的组合,gDstDatan(n=1,2,3,4)为DMA数据传输的目标变量。
再数据传输完成后,可以看到数据被成功初始化为表格中指定的数据。

总结

TI的DMA控制器支持基本寻址和扩展寻址方式,给用户设计应用程序提供了更多的灵活性。TI提供的DMA功能示例演示了在某个寻址地址模式下的数据传输示例,基于这些例子,在使用别的外设时作为参考,实现数据的高效传递。
此帖出自MSPM0 MCU论坛

最新回复

学习一下,感谢楼主的分享!小白,先收藏起来,学习!  详情 回复 发表于 2023-12-4 01:38
点赞 关注
 
 

回复
举报

755

帖子

5

TA的资源

纯净的硅(高级)

沙发
 

感谢楼主提供的技术分享,先收藏学习再发表个人意见,顶起来

此帖出自MSPM0 MCU论坛
 
 
 

回复

27

帖子

0

TA的资源

一粒金砂(中级)

板凳
 

学习一下,感谢楼主的分享!小白,先收藏起来,学习!


此帖出自MSPM0 MCU论坛
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/9 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表