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.

[参考译文] MSP430F5438A:使用 VCC 参考时、ADC 手动转换挂起

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

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/1297448/msp430f5438a-adc-manual-conversion-hangs-using-vcc-reference

器件型号:MSP430F5438A

我们的应用程序以单个顺序读取5个输入,在 main ()中手动触发。 我们没有使用中断。

4个输入 存储在3个 ADC 存储段中、1个输入存储在1个 ADC 存储段中。

3个输入使用 共享基准、2个输入使用 VCCS-基准。

配置 如下所示:

    // Enable VREF=2.5V shared reference, disable temperature sensor
    REFCTL0   |= REFMSTR+REFVSEL_2+REFON+REFTCOFF;

    // Configure for sequence of A5-A7, A12 and A 13
    ADC12CTL0   =  ADC12ON+ADC12MSC+ADC12SHT0_2;   // Turn on ADC12, set sampling time
    ADC12CTL1   =  ADC12SHP + ADC12CONSEQ_1;       // Use sampling timer, single sequence

    ADC12MCTL3  =  ADC12INCH_5 + ADC12SREF_1;      // Ref=VREF, channel = A5
    ADC12MCTL4  =  ADC12INCH_5 + ADC12SREF_1;      // Ref=VREF, channel = A5
    ADC12MCTL5  =  ADC12INCH_5 + ADC12SREF_1;      // Ref=VREF, channel = A5

    ADC12MCTL6  =  ADC12INCH_6 + ADC12SREF_1;      // Ref=VREF, channel = A6
    ADC12MCTL7  =  ADC12INCH_6 + ADC12SREF_1;      // Ref=VREF, channel = A6
    ADC12MCTL8  =  ADC12INCH_6 + ADC12SREF_1;      // Ref=VREF, channel = A6

    ADC12MCTL9  =  ADC12INCH_7 + ADC12SREF_1;      // Ref=VREF, channel = A7
    ADC12MCTL10 =  ADC12INCH_7 + ADC12SREF_1;      // Ref=VREF, channel = A7
    ADC12MCTL11 =  ADC12INCH_7 + ADC12SREF_1;      // Ref=VREF, channel = A7

    ADC12MCTL12 =  ADC12INCH_12;                   // Ref=Vcc, channel = A12
    ADC12MCTL13 =  ADC12INCH_12;                   // Ref=Vcc, channel = A12
    ADC12MCTL14 =  ADC12INCH_12;                   // Ref=Vcc, channel = A12

    ADC12MCTL15 =  ADC12INCH_13 + ADC12EOS;        // Ref=Vcc, channel = A13, end seq.

    ADC12CTL0   |= ADC12ENC;                       // Enable conversions

转换和内存读取 如下所示:

        ADC12IFG  = 0x00;                                    // Clear flags
        ADC12CTL0 |= ADC12SC;                                // Start conversion
        while (!(ADC12IFG & 0x4000));                        // Wait for conversion to complete

        Input1  = ADC12MEM3 + ADC12MEM4 + ADC12MEM5;
        Input1  = ANALOG_IBAT / 3;

        Input2 = ADC12MEM6 + ADC12MEM7 + ADC12MEM8;
        Input2 = ANALOG_ILAMP / 3;

        Input3  = ADC12MEM9 + ADC12MEM10 + ADC12MEM11;
        Input3  = ANALOG_VBAT / 3;

        Input4 = ADC12MEM0 + ADC12MEM1 + ADC12MEM2;
        Input4 = ANALOG_LIGHT / 3;

        Input5  = ADC12MEM15;

第一次转换始终成功。  但是、在第二次转换后、应用程序会挂起。 在调试模式中查看寄存器、值不会写入内存、并且在第二次 转换请求后中断标志不会被置位。

我们通过注释掉"ADC12IFG = 0x00"行并将内存段从 ADC12MEM[12-14]重新分配到 ADC12MEM[0-3]来解决这个问题。 换句话说-将使用 VCCS-基准的两个输入分开。

必须注意的是、在制造的1500块板中、只有 20块表现出这种行为。 我们做了广泛的电路跟踪、(几乎)排除了外部因素、尤其是 VCC 系列。

任何帮助都 是 感激的。 谢谢你。

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

    > ADC12CTL1 = ADC12SHP + ADC12CONSEQ_1;//使用采样定时器、单序列

    这使用 ADC12MCTL0-2进行转换、但这些寄存器的内容在复位后"未定义"[请参阅用户指南(SLAU208Q)表28-3]。 这可能是您有时只看到症状的原因。 尝试改用如下所示的:

    > ADC12CTL1 = ADC12SHP + ADC12CONSEQ_1 + ADC12CSTARTADD_3;//使用采样计时器、单序列、从 MEM3开始

    ----------------

    根据 UG 第28.2.7.2节、在为下一序列再次设置 ADC12SC 之前、需要明确清零 ADC12SC。 我不是很确定你的改变是如何使它变得更好(也许与 CSTARTADD 有关),但你可能需要这样做。

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

    感谢您的答复。  实际上我错过了 CSTARTADD 指令、但 尝试了 不同的 MCTL 安排、包括按顺序使用前13个 MCTL、但除了将 A13输入与存储器中的其他输入分离之外、似乎什么都不起作用。 我还测试了您建议的解决方案、但没有效果。 尽管如此 、我将执行该指令。

    我们不会将 SC 位复位(在调试过程中、我看到 SC 位会自行复位、但我们仍然应该手动复位)、这是 我在前面的测试中首先尝试的东西之一。 如果我在中断标志之后立即进行复位...

    ADC12CTL0 |= ADC12SC;
    while (!(ADC12IFG & 0x4000));
    ADC12CTL0 &=~ADC12SC;

    ... 锁定仍在发生。 仅当 读取存储器后 SC 位复位时、该功能才起作用。 这特别奇怪、因为在读取存储器之前或之后的放置无关紧要。  实际上、TI 的 "msp430x54xA_adc12_09.c"示例 读取 MCTL 前会重置位。

    我们发现的其他权变措施是连续两次设置 SC 位...

    ADC12CTL0 |= ADC12SC;
    ADC12CTL0 |= ADC12SC;
    while (!(ADC12IFG & 0x4000));

    ...或 在转换之间重置 ENC 位...

    ADC12CTL0 |= ADC12SC + ADC12ENC;
    while (!(ADC12IFG & 0x4000));
    ADC12CTL0 &=~ADC12SC;
    ADC12CTL0 &=~ADC12ENC;

    就权变措施而言、这些措施是没有问题的、但 实施任何这些措施都会表明 MCU 可能 不在规格范围内运行。 有什么想法?

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

    我们能够确认问题出在 MCU 而不是电路板。  我还创建了一个示例程序(基于 TI 自己的"msp430x54xA_ADC12_09.c"示例程序)、该程序与我们发现的问题相同。

    以下程序在未对 正常工作的 MCU 进行修改的情况下运行。 在一个有故障的 MCU 上、第一个 ADC 转换请求将会成功、但第二个请求将导致 程序挂起。 所请求的转换从不会发生、因此 ICR 从不会被触发。

    有3种"权变措施"被注释掉。 取消注释这三种权变措施中的任何一种都会允许程序在有故障的 MCU 上运行、但 我认为 如果 MCU 符合规范(SLAU208Q)、这两种权变措施都不是必需的。

    我不 排除 编程有误或者  安装了 MCU 的电路板有问题的可能性、我欢迎 对 我的发现提出质疑的任何讨论。

    否则、我希望这会对其他可能遇到同样问题的人有所帮助。  

    #include <msp430.h>
    
    volatile unsigned int results[13];
    
    int main(void)
    {
      WDTCTL = WDTPW+WDTHOLD;                   // Stop watchdog timer
    
      // Enable A/D channel inputs
      P6SEL = 0xE0;
      P7SEL = 0x30;
    
      // Enable VREF=2.5V shared reference, disable temperature sensor
      REFCTL0 |= REFMSTR+REFVSEL_2+REFON+REFTCOFF;
    
      ADC12CTL0 = ADC12ON+ADC12MSC+ADC12SHT0_2; // Turn on ADC12, set sampling time
      ADC12CTL1 = ADC12SHP+ADC12CONSEQ_1;       // Use sampling timer, single sequence
      ADC12MCTL0 = ADC12INCH_5+ADC12SREF_1;     // Ref=VREF, channel = A5
      ADC12MCTL1 = ADC12INCH_5+ADC12SREF_1;
      ADC12MCTL2 = ADC12INCH_5+ADC12SREF_1;
      ADC12MCTL3 = ADC12INCH_6+ADC12SREF_1;     // Ref=VREF, channel = A6
      ADC12MCTL4 = ADC12INCH_6+ADC12SREF_1;
      ADC12MCTL5 = ADC12INCH_6+ADC12SREF_1;
      ADC12MCTL6 = ADC12INCH_7+ADC12SREF_1;     // Ref=VREF, channel = A7
      ADC12MCTL7 = ADC12INCH_7+ADC12SREF_1;
      ADC12MCTL8 = ADC12INCH_7+ADC12SREF_1;
      ADC12MCTL9 = ADC12INCH_12;                // Ref=Vcc, channel = A12
      ADC12MCTL10 = ADC12INCH_12;
      ADC12MCTL11 = ADC12INCH_12;
      ADC12MCTL12 = ADC12INCH_13 + ADC12EOS;    // Ref=Vcc, channel = A13
      ADC12IE = 0x08;                           // Enable ADC12IFG.3
      ADC12CTL0 |= ADC12ENC;                    // Enable conversions
    
      while(1)
      {
        ADC12CTL0 |= ADC12SC;                   // Start convn - software trigger
    
        // Workaround 1 - Set conversion bit twice
        /*
        ADC12CTL0 |= ADC12SC;
        */
    
        // Workaround 2 - Reset enable bit between conversions
        /*
        ADC12CTL0 &=~ADC12SC;
        ADC12CTL0 &=~ADC12ENC;
        ADC12CTL0 |= ADC12SC + ADC12ENC;
        */
    
        __bis_SR_register(LPM4_bits + GIE);     // Enter LPM4, Enable interrupts
        __no_operation();                       // For debugger
      }
    }
    
    #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
    #pragma vector=ADC12_VECTOR
    __interrupt void ADC12ISR (void)
    #elif defined(__GNUC__)
    void __attribute__ ((interrupt(ADC12_VECTOR))) ADC12ISR (void)
    #else
    #error Compiler not supported!
    #endif
    {
      switch(__even_in_range(ADC12IV,34))
      {
      case  0: break;                           // Vector  0:  No interrupt
      case  2: break;                           // Vector  2:  ADC overflow
      case  4: break;                           // Vector  4:  ADC timing overflow
      case  6: break;                           // Vector  6:  ADC12IFG0
      case  8: break;                           // Vector  8:  ADC12IFG1
      case 10: break;                           // Vector 10:  ADC12IFG2
      case 12:                                  // Vector 12:  ADC12IFG3
        ADC12CTL0 &=~ADC12SC;                   // For sequence-of-Channels mode, ADC12SC must be cleared by software after each sequence to trigger another sequence
        results[0] = ADC12MEM0;                 // Move results, IFG is cleared
        results[1] = ADC12MEM1;                 // Move results, IFG is cleared
        results[2] = ADC12MEM2;                 // Move results, IFG is cleared
        results[3] = ADC12MEM3;                 // Move results, IFG is cleared
        results[4] = ADC12MEM4;                 // Move results, IFG is cleared
        results[5] = ADC12MEM5;                 // Move results, IFG is cleared
        results[6] = ADC12MEM6;                 // Move results, IFG is cleared
        results[7] = ADC12MEM7;                 // Move results, IFG is cleared
        results[8] = ADC12MEM8;                 // Move results, IFG is cleared
        results[9] = ADC12MEM9;                 // Move results, IFG is cleared
        results[10] = ADC12MEM10;               // Move results, IFG is cleared
        results[11] = ADC12MEM11;               // Move results, IFG is cleared
        results[12] = ADC12MEM12;               // Move results, IFG is cleared
    
        // Workaround 3 - Reset conversion bit after reading memory
        /*
        ADC12CTL0 &=~ADC12SC;
        */
    
        __bic_SR_register_on_exit(LPM4_bits);   // Exit active CPU, SET BREAKPOINT HERE
      case 14: break;                           // Vector 14:  ADC12IFG4
      case 16: break;                           // Vector 16:  ADC12IFG5
      case 18: break;                           // Vector 18:  ADC12IFG6
      case 20: break;                           // Vector 20:  ADC12IFG7
      case 22: break;                           // Vector 22:  ADC12IFG8
      case 24: break;                           // Vector 24:  ADC12IFG9
      case 26: break;                           // Vector 26:  ADC12IFG10
      case 28: break;                           // Vector 28:  ADC12IFG11
      case 30: break;                           // Vector 30:  ADC12IFG12
      case 32: break;                           // Vector 32:  ADC12IFG13
      case 34: break;                           // Vector 34:  ADC12IFG14
      default: break;
      }
    }