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.

MSP430FR2111: Can the microcontroller detect ADC interrupts while in LPM3?

Part Number: MSP430FR2111

I am trying to wake up my device and service an ADC threshold interrupt (ADC result is greater than a preset threshold) while in low power mode LPM3. My code services the interrupt with no problem if the device is in active mode, but not if the LPM3 bits are set in the SR. I expected to be able to use the ADC and its interrupts in LPM3. Am I mistaken or are there other settings needed to get this to work?

  • Of course all interrupts work in the low power modes.

  • Yes, this works fine, but you need to make sure you aren't relying on SMCLK.

    This includes the ADC clock (ADCSSEL) -- MODCLK is a good choice here -- and if you're using a timer trigger, the timer should run from ACLK.

    What does your configuration look like?

  • Thanks for your reply.

    I've worked on this some more and found that my problem statement is incomplete. There is a dependency on when the event that causes the interrupt occurs:

    1. If the event occurs before the code that configures ADC channel is executed, the interrupt is detected in LPM3.

    2. If the event occurs after the code that configures ADC channel is executed, the interrupt is NOT detected in LPM3.

    If interrupts are enabled in active mode, the ADC interrupt is detected in either test scenario. Scenario 2 is the real world situation where the system must work. Currently the ADC is configured like this --

    void initADC(void)
    {
    static const int fireThresholdFlu8_9 = 10;
    static const int fireThresholdFlu12 = 20;

    // Configure ADC10 channel 4
    ADCCTL0 &= ~ADCENC;                                // Disable ADC
    ADCCTL0 |= ADCSHT_2 | ADCON;                // ADCON, S&H=16 ADC clks
    ADCCTL1 = ADCSHP;                                    // ADCCLK = MODOSC; sample from sampling timer
    ADCCTL2 = ADCRES_1; // 10-bit conversion results
    ADCIE = ADCHIIE; // Enable ADC above upper threshold interrupt
    // Assume FLU 8/9 for now.
    ADCHI = fireThresholdFlu8_9;
    ADCMCTL0 = ADCINCH_4 | ADCSREF_0; // A4 ADC external input select
    // Reference: V(R+)= 3V V(R-) = GND
    return;

    }

    in an initialization routine that runs once before the base level loop begins, and ADC sampling is started and interrupts are enabled in the base level loop.

    while(1)
    {
    ADCCTL0 |= ADCENC | ADCSC; // Sampling and conversion start

    __bis_SR_register(GIE + LPM3_bits);
    __no_operation();

    ...

    Let me know if my configuration gives you any insights into what I'm seeing.

  • I originally interpreted "interrupt not detected" to mean "ISR not called". Now I suspect you meant "ISR is called but main doesn't wake up". [This can be distinguished by setting a breakpoint in the ISR.]

    For the latter, try inserting this on the line just before you set ADCSC:

    > __disable_interrupt();  // Avoid race

    A wakeup (LPM3_EXIT or __bic_SR_register_on_exit()) will only wake up main if main is in LPM at that moment; if main is active, the wakeup is lost. There is a race where the ADC completes and triggers an interrupt before main gets to LPM.

    MODOSC is pretty fast, so with MCLK=1MHz the timing (3 MCLKs) is actually very tight; if a stray (e.g.) timer interrupt hits at just the right time, the window gets very large. [This artifact is unfortunately ignored by many of the TI examples, but they kind of work-by-accident.] By disabling (GIE=0) just before starting the ADC, then atomically enabling (GIE=1) And going into LPM afterward, you close the window.

  • Another way to do it ss to configure the ADC for continuous conversion rather than explicitly trigger each conversion in software. I would have thought this mode would always be used with the window comparator.

    Oh, adding a NOP after fiddling with SR is pretty much a waste since compilers insert these for you. And assemblers issue warnings if they don't see them.

  • To clarify, I do mean that the ISR is not called when I say that the interrupt is not detected.

  • Maybe I should point out here that, the way this is coded, if the level on A4 is below your threshold at the moment you check, the interrupt won't fire, and you won't get another chance. This has to do with LPM, not with LPM3 specifically. Does your test case take this into account?

    [Edit: This is where David's suggestion of CONSEQ=3 2 comes in.]

  • Well, there are two ways to go with repeated single channel. If MSC=0 then you need some trigger for each conversion. A timer perhaps. If MSC=1 then after one conversion completes the next one begins.

    The choice of which to use depends on the signal and your requirements.

    On the other hand, I was just looking at the documentation for the ADC12 on another part (slau367) and it has a section showing that the ADC will only remain active in LPM3 or LMP4 under certain conditions. No such note for this part that I see. But something to think about. As in test with LPM0 to see if that works.

  • With the ADC set for repeated single channel and MSC=1, the ISR gets called while in LPM3. Thanks for your help.

**Attention** This is a public forum