This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] CCS/MSP430FR5739:使用 DMA + ADC10时出现问题

Guru**** 2553440 points


请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/593881/ccs-msp430fr5739-issue-using-dma-adc10

器件型号:MSP430FR5739
主题中讨论的其他器件:MSP430WARE

工具/软件:Code Composer Studio

大家好、我将在重复单通道模式下使用 ADC10来转换两个通道。 我使用 ADCIFG 作为 DMA0的触发器、DMA0被配置为从 ADC10MEM0获取8个 ADC 读数、并使用 DMA0SZ=8转移到缓冲器。 我开始一个通道(例如 A0)的转换五次、然后读取另一个通道(例如 A1)。 我发现的问题是、缓冲区包含两个来自之前转换的读数、例如:

T=1、A0_buffer=[490、491、490、491、 489、490、490、491]

T=2、A0_buffer=[490、491、480、481、 482、480、480、481]

T=3、A0_buffer=[480、481、490、491、 489、490、490、491]

T=4、A0_buffer=[490、491、480、481、 481、480、480、481]

T=5、A0_buffer=[480、481、490、491、 489、490、490、491]

T=5、A1_buffer=[490、491、690、691、 689、690、690、691]

T=6、A0_buffer=[690、691、490、491、 489、490、490、491]

此示例假设在 T1、T3、T5和 T6、通道 A0的读数约为490、对于 T2和 T4、通道 A0的读数为~480。 通道 A1应为~690。

以下是我为执行此操作而执行的步骤:

配置 DMA (目标地址)、

2.配置 ADC (通道)、

3.启用 DMA

4.启动 ADC 转换。

5.当 DMA 中断被激活时,禁用 ADC

在执行一些调试后、我发现在第3步中首次运行程序(T1)时、DMA0SZ=8、然后在第4步中、DMA0SZ 保持不变。 在第二个周期(T2) 中、DMA0SZ=8在步骤3中、但是在用 DMAEN 位启用 DMA 并转到下一行后、DMA0SZ 变为6。 这解释了最终缓冲器中两个读数错误的原因。

是否有关于此问题的提示?

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您好!

    感谢您提供您所看到行为的详细摘要。 考虑到这一点、如果您可以共享您的代码、那将非常有帮助。 由于 t1处缓冲区的结果似乎正常、t2处的结果似乎错误、我怀疑 ADC 或 DMA 的初始设置可能已正确配置(例如 main()中的代码)、但不适用于下一次迭代 (ISR 和/或 while ()循环中的代码)。 共享您的代码将帮助我们了解更多详细信息、例如单次与块传输、由硬件或软件设置的 ADC10IFG0标志等

    对于第二个周期、您提到当您到达步骤4时、DMA0SZ 变为6。 对于此步骤、ADC 转换开始。 如果 DMA0SZ 在 ADC 启动前变为6、则表示已经发生了两次传输。 因此、我怀疑 ADC 可能仍在运行、并且已经在触发 DMA。

    让我还指出、该器件的多个 ADC 和 DMA 勘误表可能会影响或导致此行为。 同时、我建议查看'SP430FR57xx_ADC10_15.c'代码示例。 您可能已经这样做了、但这是一个很好的参考、我想提一下。

    此致、

    James

    MSP 客户应用
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    大家好、James、感谢您的回答。 我将把重复此问题的代码减少到最少、同时我将为您提供一些详细信息。 这是代码的一部分:

    void adc_start_conversion ()
    {
    while (ADC10CTL1 & ADC10BUSY);
    __bis_SR_register (GIE);
    ADC10CTL1 |= ADC10CONSEQ_2;
    ADC10CTL0 |= ADC10ENC + ADC10SC;
    }
    
    ...
    
    if (var == TEMP){
    dma_set_dest (adc_vars.temp_buy_samples);//步骤1
    ADC_SET_CHANNEL (ADC10INCH_2);//步骤2
    }否则{
    dma_set_dest (adc_vars.batt 缓冲区样本);//步骤1
    ADC_SET_CHANNEL (ADC10INCH_0);//步骤2
    }
    DMA_ENABLE ();// DMA0CTL |= DMAEN + DMAIE、步骤3
    ADC_START_conversion ();//步骤4
    
    ……
    
    

    我设置了两个断点、一个在 dma_enable()上、另一个在 adc_start_conversion ()上。 以下是周期1 (T1)和周期2 (T2)中每个断点处的寄存器状态:

    周期1:(工作)

    断点1 (在 DMA_ENABLE 之前):
    ADC10CTL0 0x0290 ADC10控制0 [存储器映射]
    ADC10CTL1 0x0200 ADC10控制1 [存储器映射]
    ADC10CTL2 0x0010 ADC10控制2 [存储器映射]
    ADC10LO 0x0000 ADC10窗口比较器高阈值[存储器映射]
    ADC10HI 0x03FF ADC10窗口比较器高阈值[存储器映射]
    ADC10MCTL0 0x0012 ADC10存储器控制0 [存储器映射]
    ADC10MEM0 0x01FE ADC10转换存储器0 [存储器映射]
    ADC10IE 0x0000 ADC10中断使能[存储器映射]
    ADC10IFG 0x0000 ADC10中断标志[存储器映射]
    ADC10IV 0x0000 ADC10中断向量字[存储器映射]
    DMACTL0 0x001A DMA 模块控制0 [存储器映射]
    DMACTL1 0x0000 DMA 模块控制1 [存储器映射]
    DMACTL2 0x0000 DMA 模块控制2 [存储器映射]
    DMACTL3 0x0000 DMA 模块控制3 [存储器映射]
    DMACTL4 0x0000 DMA 模块控制4 [存储器映射]
    DMAIV 0x0000 DMA 中断向量字[存储器映射]
    DMA0CTL 0x0C24 DMA 通道0控制[存储器映射]
    DMA0SA 0x00000712 DMA 通道0源地址[存储器映射]
    DMA0DA 0x00001D74 DMA 通道0目标地址[存储器映射]
    DMA0SZ 0x0008 DMA 通道0传送大小[存储器映射]
    DMA1CTL 0x0000 DMA 通道1控制[存储器映射]
    DMA1SA 0x00008384 DMA 通道1源地址[存储器映射]
    DMA1DA 0x0002846F DMA 通道1目标地址[存储器映射]
    DMA1SZ 0xBE96 DMA 通道1传输大小[存储器映射]
    DMA2CTL 0x0000 DMA 通道2控制[存储器映射]
    DMA2SA 0x00018828 DMA 通道2源地址[存储器映射]
    DMA2DA 0x00003180 DMA 通道2目标地址[存储器映射]
    DMA2SZ 0x521F DMA 通道2传输大小[存储器映射]
    ----
    断点2 (在 DMA_ENABLE 之后):
    ADC10CTL0 0x0290 ADC10控制0 [存储器映射]
    ADC10CTL1 0x0200 ADC10控制1 [存储器映射]
    ADC10CTL2 0x0010 ADC10控制2 [存储器映射]
    ADC10LO 0x0000 ADC10窗口比较器高阈值[存储器映射]
    ADC10HI 0x03FF ADC10窗口比较器高阈值[存储器映射]
    ADC10MCTL0 0x0012 ADC10存储器控制0 [存储器映射]
    ADC10MEM0 0x01FE ADC10转换存储器0 [存储器映射]
    ADC10IE 0x0000 ADC10中断使能[存储器映射]
    ADC10IFG 0x0000 ADC10中断标志[存储器映射]
    ADC10IV 0x0000 ADC10中断向量字[存储器映射]
    DMACTL0 0x001A DMA 模块控制0 [存储器映射]
    DMACTL1 0x0000 DMA 模块控制1 [存储器映射]
    DMACTL2 0x0000 DMA 模块控制2 [存储器映射]
    DMACTL3 0x0000 DMA 模块控制3 [存储器映射]
    DMACTL4 0x0000 DMA 模块控制4 [存储器映射]
    DMAIV 0x0000 DMA 中断向量字[存储器映射]
    DMA0CTL 0x0C34 DMA 通道0控制[存储器映射]
    DMA0SA 0x00000712 DMA 通道0源地址[存储器映射]
    DMA0DA 0x00001D74 DMA 通道0目标地址[存储器映射]
    DMA0SZ 0x0008 DMA 通道0传送大小[存储器映射]
    DMA1CTL 0x0000 DMA 通道1控制[存储器映射]
    DMA1SA 0x00008384 DMA 通道1源地址[存储器映射]
    DMA1DA 0x0002846F DMA 通道1目标地址[存储器映射]
    DMA1SZ 0xBE96 DMA 通道1传输大小[存储器映射]
    DMA2CTL 0x0000 DMA 通道2控制[存储器映射]
    DMA2SA 0x00018828 DMA 通道2源地址[存储器映射]
    DMA2DA 0x00003180 DMA 通道2目标地址[存储器映射]
    DMA2SZ 0x521F DMA 通道2传输大小[存储器映射]

    周期2:(不起作用)

    断点1 (在 DMA_ENABLE 之前):
    ADC10CTL0 0x0290 ADC10控制0 [存储器映射]
    ADC10CTL1 0x0200 ADC10控制1 [存储器映射]
    ADC10CTL2 0x0010 ADC10控制2 [存储器映射]
    ADC10LO 0x0000 ADC10窗口比较器高阈值[存储器映射]
    ADC10HI 0x03FF ADC10窗口比较器高阈值[存储器映射]
    ADC10MCTL0 0x0012 ADC10存储器控制0 [存储器映射]
    ADC10MEM0 0x01F9 ADC10转换存储器0 [存储器映射]
    ADC10IE 0x0000 ADC10中断使能[存储器映射]
    ADC10IFG 0x0000 ADC10中断标志[存储器映射]
    ADC10IV 0x0000 ADC10中断向量字[存储器映射]
    DMACTL0 0x001A DMA 模块控制0 [存储器映射]
    DMACTL1 0x0000 DMA 模块控制1 [存储器映射]
    DMACTL2 0x0000 DMA 模块控制2 [存储器映射]
    DMACTL3 0x0000 DMA 模块控制3 [存储器映射]
    DMACTL4 0x0000 DMA 模块控制4 [存储器映射]
    DMAIV 0x0000 DMA 中断向量字[存储器映射]
    DMA0CTL 0x0C24 DMA 通道0控制[存储器映射]
    DMA0SA 0x00000712 DMA 通道0源地址[存储器映射]
    DMA0DA 0x00001D74 DMA 通道0目标地址[存储器映射]
    DMA0SZ 0x0008 DMA 通道0传送大小[存储器映射]
    DMA1CTL 0x0000 DMA 通道1控制[存储器映射]
    DMA1SA 0x00008384 DMA 通道1源地址[存储器映射]
    DMA1DA 0x0002846F DMA 通道1目标地址[存储器映射]
    DMA1SZ 0xBE96 DMA 通道1传输大小[存储器映射]
    DMA2CTL 0x0000 DMA 通道2控制[存储器映射]
    DMA2SA 0x00018828 DMA 通道2源地址[存储器映射]
    DMA2DA 0x00003180 DMA 通道2目标地址[存储器映射]
    DMA2SZ 0x521F DMA 通道2传输大小[存储器映射]
    ----
    断点2 (在 DMA_ENABLE 之后):
    ADC10CTL0 0x0290 ADC10控制0 [存储器映射]
    ADC10CTL1 0x0200 ADC10控制1 [存储器映射]
    ADC10CTL2 0x0010 ADC10控制2 [存储器映射]
    ADC10LO 0x0000 ADC10窗口比较器高阈值[存储器映射]
    ADC10HI 0x03FF ADC10窗口比较器高阈值[存储器映射]
    ADC10MCTL0 0x0012 ADC10存储器控制0 [存储器映射]
    ADC10MEM0 0x01F9 ADC10转换存储器0 [存储器映射]
    ADC10IE 0x0000 ADC10中断使能[存储器映射]
    ADC10IFG 0x0012 ADC10中断标志[存储器映射]
    ADC10IV 0x0000 ADC10中断向量字[存储器映射]
    DMACTL0 0x001A DMA 模块控制0 [存储器映射]
    DMACTL1 0x0000 DMA 模块控制1 [存储器映射]
    DMACTL2 0x0000 DMA 模块控制2 [存储器映射]
    DMACTL3 0x0000 DMA 模块控制3 [存储器映射]
    DMACTL4 0x0000 DMA 模块控制4 [存储器映射]
    DMAIV 0x0000 DMA 中断向量字[存储器映射]
    DMA0CTL 0x0C34 DMA 通道0控制[存储器映射]
    DMA0SA 0x00000712 DMA 通道0源地址[存储器映射]
    DMA0DA 0x00001D74 DMA 通道0目标地址[存储器映射]
    DMA0SZ 0x0006 DMA 通道0传送大小[存储器映射]
    DMA1CTL 0x0000 DMA 通道1控制[存储器映射]
    DMA1SA 0x00008384 DMA 通道1源地址[存储器映射]
    DMA1DA 0x0002846F DMA 通道1目标地址[存储器映射]
    DMA1SZ 0xBE96 DMA 通道1传输大小[存储器映射]
    DMA2CTL 0x0000 DMA 通道2控制[存储器映射]
    DMA2SA 0x00018828 DMA 通道2源地址[存储器映射]
    DMA2DA 0x00003180 DMA 通道2目标地址[存储器映射]
    DMA2SZ 0x521F DMA 通道2传输大小[存储器映射]

    两个周期中的第一个断点没有差异、但是在第二个周期中的第二个断点、DMA0SZ 在启用 DMA 后变为6。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好!

    感谢您分享一些附加信息和代码。 将所有内容与我们的代码示例进行比较后、似乎有相当多的代码缺失、无法正确设置 DMA 和 ADC 以便协同工作。 接下来、我强烈建议查看我们的'SP430FR57xx_ADC10_10.c'代码示例(请参阅下面的 MSP430Ware 中的内容)、并将此代码用作项目的基准。 这将有助于您更快地解决问题。

    更具体地说、这个代码示例正确地配置 ADC10IFG 来触发 DMA0并将 ADC10配置为通道序列、而不是单通道单次转换。 这些只是我在您的代码中看不到的几件事。 此外、当您在代码中启动 ADC 样本时、ADC10CTL1 |= ADC10CONSEQ_2只需执行一次。

    MSP430FR57xx_ADC10_10.c

    /*-版权所有-、BSD_EX
    *版权所有(c) 2012、德州仪器(TI)公司
    *保留所有权利。
    *
    *
    只要
    符合以下条件*、允许以源代码和二进制形式重新分发和使用:
    *
    *源代码的重新分发必须保留上述版权
    声明*、此条件列表和以下免责声明。
    *
    ***二进制形式的再发行必须在
    
    *随发行提供的文档和/或其他材料中复制上述版权声明、本条件列表和以下免责声明。
    *
    ***未经
    
    事先书面许可、不得使用德州仪器公司的名称或*其贡献者的名称认可或推广从本软件衍生的产品*。
    *
    *本软件由版权所有者和贡献者"按原样"提供
    *、
    
    不承担任何明示或暗示的保证、包括但不限于*适销性和特定用途适用性的暗示保证*。 在任何情况下、版权所有者或
    *贡献者都不对任何直接、间接、偶然、特殊、
    *模范、 或相应的损害(包括但不限于
    *采购替代产品或服务;丧失使用、数据或利润;
    *或业务中断)、但出于任何责任理论
    、*无论是在合同中、严格责任还是由于
    使用本软件而以任何方式产生的侵权行为(包括疏忽或*其他)
    、*即使已获悉可能会发生此类损坏。
    *
    ***
    *
    * MSP430代码示例免责声明
    *
    * MSP430代码示例是自包含的低级程序
    ,通常*以
    高度*简明的方式演示单个外设功能或器件功能。 为此、代码可能依赖于器件的加电默认
    值*寄存器值和时钟配置等设置、
    并且在组合多个示例中的代码时必须*小心以避免潜在的副作用
    *。 另请参阅 www.ti.com/grace 了解 GUI、并参阅 www.ti.com/msp430ware
    *了解外设配置的 API 函数库方法。
    *
    *--/版权--*
    //*********
    // MSP430FR57xx 演示- ADC10、DMA 采样 A2-0、8位分辨率、单序列、DCO
    //
    说明:以 AVcc 为基准将 A2/A1/A0作为单序列采样。
    //软件设置 ADC10SC 来触发采样序列。 在主循环 MSP430中
    、//在 LPM0中等待节能、直到 ADC10转换完成、DMA_ISR 将
    //强制退出任何 LPMx。 ADC10内部振荡器乘以采样周期
    //(16x)和转换(13x)。 DMA 传输 conv 结果 ADC_Result 变量。
    //
    // MSP430FR5739
    // --------
    // /|\| XIN|-
    // || |
    // -|RST XOUT|-
    // | |
    // --|P1.2/A2 |
    // --|P1.1/A1 |
    // --|P1.0/A0 |
    //
    F. Chen
    // Texas Instruments Inc.
    // 2012年11月
    //使用 IAR 嵌入式工作平台构建版本:5.51.1 & Code Composer Studio v5.2.1
    //*********
    #include 
    
    unsigned char adc_result[3]; // 8位 ADC 转换结果数组
    
    int main (void)
    {
    WDTCTL = WDTPW + WDTHOLD; //停止 WDT
    //配置 ADC 引脚
    P1SEL0 |= BIT0 + BIT1 + BIT2;
    P1SEL1 |= BIT0 + BIT1 + BIT2;
    //配置 ADC10
    ADC10CTL0 = ADC10SHT_2 + ADC10MSC + ADC10ON;// 16ADCclks、ADC10CLKs
    、ADC10CTL0 = ADC10SHT_ADC101;ADC10CMCC = ADC101 //采样定时器,s/w 三态,单序列
    ADC10CTL2 &=~ADC10RES; // 8位分辨率
    ADC10MCTL0 = ADC10INCH_2; // A0、A1、A2 (EOS)、AVCC 基准
    
    //配置 DMA0 (ADC10IFG 触发器)
    DMACTL0 = DMA0TSEL__ADC10IFG; // ADC10IFG 触发
    器__data16_write_addr ((无符号短整型)&DMA0SA、(无符号长整型)&ADC10MEM0);
    //源单地址
    __data16_write_addr ((无符号短整型)&DMA0DA,(无符号长整型)&ADC_Result [0]);
    //目标数组地址
    DMA0SZ = 0x03; // 3次转换
    DMA0CTL = DMADD_4 + DMADSTINCR_3 + DMASRCBYTE + DMADSTBYTE + DMAEN + DMAIE;
    // rpt、inc dest、字节访问、
    //启用转换序列后的 int
    while (1)
    {
    
    while (ADC10CTL1 & BUSY); //等待 ADC10内核处于活动状态
    ADC10CTL0 |= ADC10ENC + ADC10SC; //采样和转换开始
    _bis_SR_register (CPUOFF + GIE); // LPM0、ADC10_ISR 将强制退出
    _DELAY_CYCLES (25000); //序列转换之间的延迟
    __no_operation(); //断点;检查 ADC_Result
    }
    #if
    
    Defined (__TI_Compiler_version__)|| Defined (__IAR_systems_ICC__)
    #pragma vector=DMA_vector
    __interrupt void DMA0_ISR (void)
    #Elif Defined (__GNU__)
    void Compiler_attribute__(interrupt (interrupt (DMA_vector)#DR0_ISR
    
    (void)#defineer_error!#DMA0!
    #endif
    {
    switch (__even_in_range (DMAIV、16))
    {
    情况0:中断; //无中断
    案例2:
    //转换序列完成
    _BIC_SR_REGISTER_ON_EXIT (CPUOFF); //退出 LPM
    中断; // DMA0IFG
    案例4:中断; // DMA1IFG
    案例6:中断; // DMA2IFG
    案例8:中断; //保留
    案例10:中断; //保留
    案例12:中断; //保留
    案例14:中断; //保留
    案例16:中断; //保留
    默认值:中断;
    }
    } 

    希望这对您有所帮助。

    此致、

    James

    MSP 客户应用

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    大家好、James、我将更详细地回顾这个示例。 另一方面、我使用 ADC10CTL1 |= ADC10CONSEQ_2;因为当我在 DMA 中断内停止 ADC 时、我也会清除这些位、这是根据数据表建议(SLAU272C、16.2.7.6)立即停止的。

    我尝试在转换之间保持 CONSEQX 位配置、但这允许在 DMA 中断发生后进行额外的转换。 我将此更改为尝试解决问题、行为相同。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    [引用 user="Gustavevelascoh"] James、您好、我将更详细地查看该示例。

    我建议将 DMA 和 ADC 部分分开。 首先、仔细检查并了解 ADC 配置和实现。 然后、仔细检查并了解 DMA 的配置方式。  这将对您非常有帮助。

    [引用 USER="Gustavevelascoh"]另一方面、我使用 ADC10CTL1 |= ADC10CONSEQ_2;因为当我在 DMA 中断内停止 ADC 时、我也会清除这些位、遵循数据表建议(SLAU272C、16.2.7.6)立即停止。[/QUERQ]

    遗憾的是、该代码未共享、因此很难确切知道正在执行的操作。 查看用户指南中的第16.2.7.6节、我确实看到了停止 ADC 的建议。 但是、DMA 传输应该由 ADC10IFG0中断标志触发。 该中断标志表示结果现在已准备好传输。 我不建议在 DMA 传输的中间停止 ADC、因为结果可能仍在改变或保留在之前的采样中。 理想情况下、DMA 传输发生在完全捕获结果后。

    [引用 user="Gustavevelascoh"]I 尝试在转换之间保持 CONSEQX 位配置、但这允许在 DMA 中断发生后进行额外的转换。 我将此更改为尝试解决问题、行为相同。

    对于 CONSEQX 位、这些位用于配置。 正如您在上面的示例代码中看到的、ADC10ENC 和 ADC10SC 位是唯一需要在 ADC 采样和转换开始时复位的位。

    此致、

    James

    MSP 客户应用

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    此外、查看周期2、ADC10IFG 中断标志等于0x0012。 根据用户指南中的第16.3.12节、这意味着 ADC10OVIFG 和 ADC10INIFG 标志被置位。

    当 ADC10MEM0寄存器在最后一个转换结果被读取前被写入时、ADC10OVIFG 被置位。

    此致、

    James

    MSP 客户应用