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.

[参考译文] MSP430FR5994:DMA 不随 ADC 触发

Guru**** 2533840 points


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

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/692027/msp430fr5994-dma-not-triggering-with-adc

器件型号:MSP430FR5994

您好!

我一直遇到 DMA 和 ADC 与此 uC 相关的问题。 特别是 DMA 触发器。 我已将 模拟通道的后台采样集成到现有项目中、使用计时器触发 ADC 和 DMA 来移动采样。 我终于开始工作了、但遇到了很多问题、因此我决定尝试一个最小的示例、并找到了类似的问题。 也许我 不理解数据表、但这个相当简单的示例无法触发:

#include 

void ConfigADC( void )


~ADC12CTL0 &=~ADC12ENC;ADC12CTL0 &= ADC12ON;
ADC12CTL0 = ADC12SHT0_2 | ADC12MSC_0;
ADC12CTL1 |=ADC12SHS_0//采样保持源= ADC12SHT0_2 | ADC12MSC_0信号
来源于 ADC12C12CTL1 | ADC12C12C12C12CH_0。
|!ADC12ISSH//采样输入信号未反相
| ADC12DIV_0// ADC12时钟分频器/1
| ADC12SSEL_2// ADC12时钟源= MCLK
| ADC12CONSEQ_0;//通道序列模式
ADC12CTL2 = ADC12RES__12位;
ADC12CTL3 = ADC12CSTARTADD0;
ADC12MCTL0 = ADC12VRSEL_0;ADC12INCH_0;
ADC12IER0 = ADC12C12R0




= ADC12C12R0;ADC12C12C12R0 = ADC12C12IF0 = ADC12R0 = ADC12R0 = ADC12R0 = ADC12C12C12C12R0 = ADC12C12IF0;ADC12R0 = ADC12R0 = ADC12R0 = ADC12C12R0 = ADC12C12R0 = ADC12C12R0 = ADC12C12C12R0 = ADC12C12C12C ~




ADC12CTL0 |= ADC12ENC | ADC12SC;
while (!ADC12IFGR0){}
unsigned int adcResult = ADC12MEM0;
ADC12CTL0 &=~ADC12ENC;
ADC12CTL0 &=~







~ADC12ON;return adcResult;}= ADC12CTL_ ADD0 =无符号 DM0TDA0EN_ADT0;ADD0 = ADD0 = ADD0 = ADD0 = ADD0 = ADDMA0TDA_ADD0 = ADT0 = ADD0;ADT0 = ADD0 = ADD0 = ADD0 = ADD0 = ADD0 = AD


DMADSTINCR_0|
DMASRCINCR_0|
DMADSTBYTE__WORD |
DMASRCBYTE_WORD |
DMALEVEL__EDGE |
DMAIE__ENABLE;
__data16_write_addr ((unsigned short)&DMA0SA、(unsigned long)&TestVar1);
__data16_write_addr (unsigned short)&DMA0DA、(unsigned long)&TestVar2);
DMA0SZ = 1;
DMA0CTL |= DMAEN_ENABLE;
}

#pragma vector = DMA_vector
__interrupt void DMA_ISR (void)
{
static int int_count = 0;
switch (__even_in_range (DMAIV、0x10)){
case DMAIV_DMA0IFG:static int IN_COUNT = 0;switch (





void




= DTPW+
);void =(DTPW)=(void =);void DTPW+)=(= void =中断(=);(DTPW) //这会中断 DMA 触发

器 ConfigDMA();

Convert();
Convert();
Convert();
Convert();Convert();
__no_operation();
}

我发现、在设置 DMA 之前执行 ADC 转换会中断它、这意味着它永远不会使用 ADC12IFGR0触发。 即使我再次重新配置 DMA 和 ADC (之前清除每个寄存器)。 当我在_no_operation()处使用断点运行上述示例时,我看到 int_count == 0,这意味着从未发生中断,而且 DMA IFG 也未设置,这意味着 DMA 从未触发。 ADC 的工作只是罚款、因为我在结束时到达了__no_operation()(如果没有提升 ADC 标志、则 UC 会一直停留在 while 循环中)。

在对 ConfigDMA()按预期工作之前调用 Convert()的行进行注释时, 在执行结束时 int_count =4。

代码是否有问题?

提前感谢、

费德里科

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

    您好 Federico、

    感谢您的发帖。

    Convert()函数中,您有代码 unsigned int adcResult = ADC12MEM0;该代码访问 ADC12MEM0内存位置。 这将复位 ADC12IFGR0标志。

    我建议尝试以下几项更改:

    1_data16_write_addr  ((unsigned short)&DMA0SA、(unsigned long)&TestVar1);源地址应为 ADC 存储器位置 ADC12MEM0。

    unsigned int adcResult = ADC12MEM0;adcResult 应等于 TestVar2、这是 DMA 的目标地址。

    3.在进行 ADC 转换之前配置 DMA。

    谢谢、

    是的

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    如果我将 ConfigDMA 的最后一行(DMAEN 设置)替换为:

    > DMA0CTL |= DMALEVEL__LEVEL;//电平敏感一会儿
    >DMA0CTL |= DMAEN_ENABLE;
    >DMA0CTL &=~DMALEVEL__LEVEL;//好的,那一刻就结束了。

    即、在前面设置 LEVEL=1、恰好在后面设置=0、我得到一个立即的 DMA 传输/ISR -即使 LEVEL (IFG)是0 -然后程序的其余部分正常运行、使用 LEVEL=0 (EDGE)。 (INT_COUNT=1+4)

    从外部看、第一个 ADC IFG 似乎发送了 DMA 请求、而 DMA 单元锁存了"它的高电平"指示器。 但是、由于 ADC DMA 请求未启用、DMA 单元未注意到 IFG 电平再次变为低电平。 由于(其他)边沿在电平变为低电平前不能发生[ref sec 11.2.3]、因此 DMA (如所述)卡滞。 但是、设置 LEVEL=1与 DMA 的存储状态匹配、所以它在第一次传输后运行、然后停止、因为它会观察到电平不再是高电平[参考图11-3]。 此时、它已解除卡滞。

    如果发生这种情况、我想设计人员不打算这样做。 除了上面的(相当笨拙)之外、我也看不到明显的权变措施。 该变通办法的成本是一个无关的 DMA 传输、这可能是可以容忍的、也可能不容忍。 如果 DMA 单元中没有卡滞状态、至少不会造成任何损害。

    [免责声明:SLAU367O 第11.2.3.2节确实显示"为了正常运行、仅当选择外部触发 DMAE0作为触发器时才可使用电平敏感型触发器。"、因此严格地说、我的实验不在规格范围内。 不过、在上下文中、它看起来很有趣。]
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    Yiding、您好、感谢您花时间  回答问题。

    恐怕我 已经尝试 过您的建议。 实际上  、这就是我开始尝试使用计时器时、ADC 和 DMA 在没有 CPU 干预的情况下定期采样的时间。问题是、你在 "3. 在进行 ADC 转换之前配置 DMA。" 不是解决方案、因为我需要不时停止后台采样、并使用 DE ADC 在其他通道上执行一些手动转换。 在这些转换之后、当我重新配置 DMA 以恢复后台采样时、它将不再工作。

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

    Bruce、您好、感谢您的回答。

    这是一个有趣的结果。 我怀疑是这种情况、但无法确定测试方法。 我找到了类似的权变措施:

    DMACTL0 |= DMAEN_ENABLE;
    DMACTL0 = 0;
    DMACTL0 = DMA0TSEL_ADC12IFG; 

    这也不符合规范、因为触发器设置不应在启用 DMA 的情况下修改、因为它可以(也确实)生成随机触发器。 因此、此变通办法的成本与您的解决方案相同、是伪 DMA 传输。 我的解释是、这种伪传输会使触发电路复位、实际上会变得卡滞。

    是否有办法将此问题提交给德州仪器(TI)支持? 也许他们可以验证这是否是 DMA 控制器的问题、并 将其包含在 uC 的勘误表中。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    我仍然想知道的事情(我可能/可能不会很快回到这个问题):

    1) 1)为什么 DMA 锁存(或至少看起来是)从非触发通道进入任何状态? 如果(看起来)这是发生的情况、这就是所有情况的根本原因。 也许有一个很好的理由、但我不能想到其中一个。
    2) 2)这是否发生在其他 DMA "客户端"上? 我当然编写了一些程序(包括 FR5系列)、这些程序使用 SPI 并在 DMA 和 PIO 之间翻转。 这种情况很常见、例如在使用 SD 卡时。

    我与 TI 员工没有特殊的"输入"。 不过、我想他们会观看这个论坛。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好 Federico、

    我知道 Bruce 现在在这里提到的行为、我将深入研究它以了解更多详细信息。

    但我认为您的情况与 Bruce 所描述的行为不同。

    首先、正如您说过的、您希望立即使用 DMA、而不是手动进行 ADC 转换、为此、我相信您将需要两个不同的 ADC 转换函数。 请让我解释一下原因:

    如果我们使用 DMA、在第1个 ADC 转换完成后、ADCIFG 将被置位、并且立即触发 DMA 并访问 ADCMEM、ADCIFG 将被清除。 因此、您无法轮询 ADCIFG 以启动下一个 ADC 转换、因为 ADCIFG 已被 DMA 清除。 如果您只检查 ADCIFG、则第2次转换将永远不会开始。

    以下是我为 DMA ADC 转换修改的代码:

    unsigned int Convert( void ){
    
    isADCDone = false;
    ADC12IFGR0 = 0;
    ADC12CTL0 |= ADC12ON;
    ADC12CTL0 &=~ADC12ENC;
    ADC12CTL0 |= ADC12ENC | ADC12SC;
    
    _disable_interrupt ();
    while (isADCDone == false)
    {
    _bis_SR_register (LPM0_bits | GIE);
    }
    
    unsigned int adcResult = TestVar2;
    ADC12CTL0 &=~ADC12ENC;
    ADC12CTL0 &=~ADC12ON;
    返回 adcResult;
    }
    
    void ConfigDMA()
    {
    DMA0CTL &=~DMAEN__ENABLE;
    DMACTL0 = DMA0TSEL__ADC12IFG;
    DMA0CTL = DMADT_4 |
    DMADSTINCR_0 |
    DMASRCINCR_0 |
    DMADSTBYTE__WORD |
    DMASRCBYTE_WORD |
    DMALEVEL__EDGE |
    DMAIE_ENABLE;
    __data16_write_addr ((unsigned short)&DMA0SA、(unsigned long)&ADC12MEM0);
    __data16_write_addr ((unsigned short)&DMA0DA、(unsigned long)&TestVar2);
    DMA0SZ = 1;
    DMA0CTL |= DMAEN_ENABLE;
    }
    
    #pragma vector = DMA_vector
    __interrupt void DMA_ISR (void)
    {
    静态 int int_count = 0;
    switch (__even_in_range (DMAIV、0x10)){
    案例 DMAIV_DMA0IFG:
    INT_COUNT++;
    isADCDone = true;
    LPM0_EXIT;
    中断;
    }
    } 

    其次,如果只想进行手动 ADC 转换,则在 unsigned int Convert( void ) 函数中可以保持不变,但您需要禁用 DMA 并在  ADC ISR 中更改 isADCDone 标志,因为您的不使用 DMA。

    如果这有道理、请告诉我。

    谢谢、

    是的

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

    我知道您现在在这里提到的行为、我将对其进行详细介绍。

    谢谢、
    是的