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.

MSP430F5658: ADC12 report wrong values exit LPM0/3/4

Part Number: MSP430F5658
Other Parts Discussed in Thread: MSP430F5659

I'm doing multichannel continuous sampling of 60Hz signal on 8 channels,
when i power up the system everything is ok and results are exactly as expected.

when i turn off the mains power the code goes into LPM when power is Up again the device exits LPM but the first few samples from ADC are in correct

- at the beginning i were doing some Pre-LPM setting (turning off some module and i/o to save power) before calling LPM and doing some Post-LPM reinitialization after exit from LPM

- to debug the issue I canceled all the Pre-LPM and Post-LPM but the issue still the same

appreciate if you can help

while(1)
{


WDT_A_resetTimer(WDT_A_BASE);

if (PwrupDwnFromCmpr == 0x0) /// this flag indicat power down sensed by comparator
{

                                                                                                                      ///////////// below code is to ENTER LPM
WDT_A_hold(WDT_A_BASE); //turn off Watchdog during initialization

/*                                   /////////////// all Pre-LPM is commented
Healthy_OFF();
TURN_OFFLEDS_456789();
TRIP_OFF_PHASE_A();
Pick_OFF();
Analog_Disable(); ///turn off analog supply

ADC12_A_disableConversions(ADC12_A_BASE, 1);
ADC12_A_disable(ADC12_A_BASE);
Timer_A_stop(TIMER_A0_BASE);
Timer_A_stop(TIMER_A1_BASE);
USCI_A_UART_disable(USCI_A1_BASE);

GPIO_setOutputLowOnPin(GPIO_PORT_P9,GPIO_PIN0); /// LCD RST
UCB1CTL1 |= UCSWRST;                                                                                                                                // disable I2C
GPIO_setAsOutputPin(GPIO_PORT_P8,GPIO_PIN_ALL8);///GPIO_setAsOutputPin(GPIO_PORT_P8,GPIO_PIN2);
GPIO_setOutputLowOnPin(GPIO_PORT_P8,GPIO_PIN_ALL8);// GPIO_PIN2+GPIO_PIN3+GPIO_PIN5+GPIO_PIN6);// init all as Zero output

GPIO_setOutputLowOnPin(CTRL_LCD_ENABLE_PORT,CTRL_LCD_ENABLE_PIN); /// turn off lcd power


GPIO_setOutputLowOnPin(GPIO_PORT_P3,GPIO_PIN0);// Txen pin to 0 to save pwr
GPIO_setOutputLowOnPin(GPIO_PORT_P1,GPIO_PIN7);// Rxen pin to 0 to save pwr


GPIO_setAsOutputPin(GPIO_PORT_P2,GPIO_PIN0+GPIO_PIN1); /// Dinput 1 , 2 as output 0
GPIO_setOutputLowOnPin(GPIO_PORT_P2,GPIO_PIN0+GPIO_PIN1+GPIO_PIN4); /// Dinput 1 , 2 & oscilator as output 0


GPIO_setAsOutputPin(GPIO_PORT_P1,GPIO_PIN_ALL8);
GPIO_setOutputLowOnPin(GPIO_PORT_P1,GPIO_PIN_ALL8);
GPIO_setAsOutputPin(GPIO_PORT_P6,GPIO_PIN_ALL8);
GPIO_setOutputLowOnPin(GPIO_PORT_P6,GPIO_PIN_ALL8);

__no_operation();


// save to flash


HWREG8(PMM_BASE + OFS_PMMCTL0_H) = 0xA5; /// unlock PMM password
HWREG8(PMM_BASE + OFS_PMMCTL0_L) |= 0x10;//// disabl PMM regulator
UCS_turnOffXT2();                                                                                           /// if timer is not stopped and timer is drivern from XT2 dependent clock i.e SMCLK/MCLK xt2 will not stop

*/ //Comp_B_disable(COMP_B_BASE);

if(PwrupDwnFromCmpr == 0)
{
__bis_SR_register(LPM3_bits | GIE); /// with disabled regulator it's LPM3.5
}
                                                                                                        ///////////// below code is to exit LPM
/*                                                                 ////////////////////  all Post-LPM commented for debug

WDT_A_hold(WDT_A_BASE); //turn off Watchdog during initialization



GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P7, GPIO_PIN2+GPIO_PIN3);// P7.2 & P7.3 are Xtl2 and
Clk_Init();

GPIO_Init_();
Analog_Enable(); /// turn on analog supply

#ifdef LCD_ON
{
initI2C();
}
#endif
InitPhStruct(HALF_CHANNELS);///////////we need to init the structure for PhaseTripStruct[4] and tripConfig
 TimerTa0_Init(); //no need to reinit timer just start it in the A2D_Init()
// __delay_cycles(300000);                                                                                       ///  delay teseted at different delays  BUT it approved to be is useless 
A2D_Init(); /// this function start the timer


Timer_A1_10ms_Init();
/////////////////////////////// UART RE INIT
serial_Interlock = UNLOCKED;
UartTx_Buf_index = 0;
UartTx_Buf_State = EMPTY;
Init_Urat0();

/////////////////////////////// LCD RE INIT
//GPIO_setOutputHighOnPin(CTRL_LCD_ENABLE_PORT,CTRL_LCD_ENABLE_PIN); /// turn ON lcd power
//GPIO_setOutputHighOnPin(GPIO_PORT_P8, GPIO_PIN2+GPIO_PIN3+GPIO_PIN5+GPIO_PIN6);// init all as Zero output
initialized = 0; /// LCD is not initialized
lcd_handle = 0;
writeByteLock = 0;
ST7032_init_state = ST7032_RESET;
ST7032_disp_state = ST7032_DISPLAY;
ST7032_sub_state = ST7032_SUB_IDLE;
WDT_A_start(WDT_A_BASE);
//A2D_Init(); /// this function start the timer
*/
}



normal code to continue 

  • It's a little hard to tell what you're doing since there are only about 3 lines of (executable) code here.

    In case it needs to be said: Waking from LPM3.5 doesn't happen at the line after the LPM, but at the reset vector (top of main()). [Ref User Guide (SLAU208Q) Sec 1.4.2]. TI Example msp430f665x_LPM35_RTC.c illustrates this:

    https://dev.ti.com/tirex/explore/node?node=AIz.eYhqJHW1HBKPAb1eKQ__IOGqZri__LATEST

    As for the ADC, my first guess is that you're using the internal REF, but you aren't waiting for it to start up -- 75us probably covers a few samples with CONSEQ=3. TI Example msp430f665x_adc_02.c illustrates (though I would probably use __delay_cycles() rather than a for-loop):

    https://dev.ti.com/tirex/explore/node?node=ABT0Wn622Mi0KVB49IrTjQ__IOGqZri__LATEST

    Can you show your ADC initialization?

  • Hello Mohammed,

    When posting code in the forum, please utilize the Insert ->  </> Code function to properly format it for readability on the forum. I've already edited your post to reflect this change. 

    I also agree with Bruce here that most likely you are not waiting for your reference to settle before sampling after coming up from LPM. If you are using LPM3.5, you are performing a while device reset essentially when coming back up. Try a higher level LPM that leaves your reference on and faster wakeup if you need quicker response. This will consume more power than being in a lower state, but you will have to compensate the timing in the lower state. 

  • @Jace h

    Thanks a lot for your reply and for editing the post
    - i'm using external REF
    - as you can see from the main post i added a huge delay before starting the ADC but it doesn't help
    - I comment all the code before and after entering the LPM, that is to remove all doubt about modules start up issues
    - i assure that the code works very fine every time i apply power as long as it is coming up from reset.

    void A2D_Init(){
    
         /* disable all ADC interrupts
          * clear all ADC interrupt flags
          * select conversion clock source (MODclk = 5Mhz)
          * set conversion clk dividers (ADC12DIVx= 00 >> DIVx =1)
          * predive (ADC12PDIV = 0 >> predive =1 )
          * set ADC resolution to 12 bits
          * ADC12MEM0 WILL hold first conversion result
          */
    
    S_index = 0;
    start_fft = false;
         //  init ADC  for timer as SC signal, Clock source is MODclk = 5Mhz, divider is 1
         ADC12_A_init(ADC12_A_BASE,
                      ADC12_A_SAMPLEHOLDSOURCE_1,
    #ifdef ADC_CLK_is_MODOSC_5Mhz
             ADC12_A_CLOCKSOURCE_ADC12OSC,
             ADC12_A_CLOCKDIVIDER_1
    #else           
                      ADC12_A_CLOCKSOURCE_SMCLK,
                      ADC12_A_CLOCKDIVIDER_5
    #endif                    
             );
    
    
         /* TURN ON ADC ADC12ON=1
          *
          */
    
         ADC12_A_enable(ADC12_A_BASE);
    
    
         /*
          * Base address of ADC12_A Module
          * For memory buffers 0-7 sample/hold for 8 clock cycles
          * For memory buffers 8-15 sample/hold for 8 clock cycles (default)
          * Enable Multiple Sampling
          */
         ADC12_A_setupSamplingTimer(ADC12_A_BASE,
             ADC12_A_CYCLEHOLD_8_CYCLES,
             ADC12_A_CYCLEHOLD_8_CYCLES,
             ADC12_A_MULTIPLESAMPLESENABLE);
    
    	 /*ADC12_A_setupSamplingTimer(ADC12_A_BASE,
    								ADC12_A_CYCLEHOLD_16_CYCLES,
    								ADC12_A_CYCLEHOLD_16_CYCLES,
    	          ADC12_A_MULTIPLESAMPLESENABLE);*/
    
    
         //Configure Memory Buffer
         /*
          * Base address of the ADC12_A Module
          * Configure memory buffer 0
          * Map input A0 to memory buffer 0
          * Vref+ = VeREF+ (ext)     Internal 2.5v for test on LunchPad
          * Vref- = AVss
          * Memory buffer 0 is not the end of a sequence
          */
         ADC12_A_configureMemoryParam param = {0};
         param.memoryBufferControlIndex = ADC12_A_MEMORY_0;
         param.inputSourceSelect = ADC12_A_INPUT_A0;
    
    //#ifdef Xtrnl_Ref
    #if defined (__MSP430F5659__)
         param.positiveRefVoltageSourceSelect = ADC12_A_VREFPOS_EXT;
    #else
         param.positiveRefVoltageSourceSelect = ADC12_A_VREFPOS_INT;                            //
    #endif
    
         param.negativeRefVoltageSourceSelect = ADC12_A_VREFNEG_AVSS;
    #ifdef channel0
         param.endOfSequence = ADC12_A_ENDOFSEQUENCE;  // END SEQUENCE
    #else
         param.endOfSequence = ADC12_A_NOTENDOFSEQUENCE;
    #endif
    
         ADC12_A_configureMemory(ADC12_A_BASE ,&param);
    
    
    
          //param = {0};
         param.memoryBufferControlIndex = ADC12_A_MEMORY_1;
         param.inputSourceSelect = ADC12_A_INPUT_A1;
    
    #if defined (__MSP430F5659__)
         param.positiveRefVoltageSourceSelect = ADC12_A_VREFPOS_EXT;
    #else
         param.positiveRefVoltageSourceSelect = ADC12_A_VREFPOS_INT;                            //
    #endif
    
         param.negativeRefVoltageSourceSelect = ADC12_A_VREFNEG_AVSS;
    #ifdef channel1
         param.endOfSequence = ADC12_A_ENDOFSEQUENCE;  // END SEQUENCE
    #else
         param.endOfSequence = ADC12_A_NOTENDOFSEQUENCE;
    #endif
         ADC12_A_configureMemory(ADC12_A_BASE ,&param);
    
    
          //param = {0};
         param.memoryBufferControlIndex = ADC12_A_MEMORY_2;
         param.inputSourceSelect = ADC12_A_INPUT_A2;
    
    #if defined (__MSP430F5659__)
         param.positiveRefVoltageSourceSelect = ADC12_A_VREFPOS_EXT;
    #else
         param.positiveRefVoltageSourceSelect = ADC12_A_VREFPOS_INT;                            //
    #endif
    
         param.negativeRefVoltageSourceSelect = ADC12_A_VREFNEG_AVSS;
    #ifdef channel2
         param.endOfSequence = ADC12_A_ENDOFSEQUENCE;  // END SEQUENCE
    #else
         param.endOfSequence = ADC12_A_NOTENDOFSEQUENCE;
    #endif
         ADC12_A_configureMemory(ADC12_A_BASE ,&param);
    
          //param = {0};
         param.memoryBufferControlIndex = ADC12_A_MEMORY_3;
         param.inputSourceSelect = ADC12_A_INPUT_A3;
    
    #if defined (__MSP430F5659__)
         param.positiveRefVoltageSourceSelect = ADC12_A_VREFPOS_EXT;
    #else
         param.positiveRefVoltageSourceSelect = ADC12_A_VREFPOS_INT;                            //
    #endif
    
         param.negativeRefVoltageSourceSelect = ADC12_A_VREFNEG_AVSS;
    #ifdef channel3
         param.endOfSequence = ADC12_A_ENDOFSEQUENCE;  // END SEQUENCE
    #else
         param.endOfSequence = ADC12_A_NOTENDOFSEQUENCE;
    #endif
         ADC12_A_configureMemory(ADC12_A_BASE ,&param);
    
    
          //param = {0};
         param.memoryBufferControlIndex = ADC12_A_MEMORY_4;
         param.inputSourceSelect = ADC12_A_INPUT_A4;
    
    #if defined (__MSP430F5659__)
         param.positiveRefVoltageSourceSelect = ADC12_A_VREFPOS_EXT;
    #else
         param.positiveRefVoltageSourceSelect = ADC12_A_VREFPOS_INT;                            //
    #endif
    
         param.negativeRefVoltageSourceSelect = ADC12_A_VREFNEG_AVSS;
    #ifdef channel4
         param.endOfSequence = ADC12_A_ENDOFSEQUENCE;  // END SEQUENCE
    #else
         param.endOfSequence = ADC12_A_NOTENDOFSEQUENCE;
    #endif
         ADC12_A_configureMemory(ADC12_A_BASE ,&param);
    
    
          //param = {0};
         param.memoryBufferControlIndex = ADC12_A_MEMORY_5;
         param.inputSourceSelect = ADC12_A_INPUT_A5;
    
    #if defined (__MSP430F5659__)
         param.positiveRefVoltageSourceSelect = ADC12_A_VREFPOS_EXT;
    #else
         param.positiveRefVoltageSourceSelect = ADC12_A_VREFPOS_INT;                            //
    #endif
    
         param.negativeRefVoltageSourceSelect = ADC12_A_VREFNEG_AVSS;
    #ifdef channel5
         param.endOfSequence = ADC12_A_ENDOFSEQUENCE;  // END SEQUENCE
    #else
         param.endOfSequence = ADC12_A_NOTENDOFSEQUENCE;
    #endif
         ADC12_A_configureMemory(ADC12_A_BASE ,&param);
    
    
          //param = {0};
         param.memoryBufferControlIndex = ADC12_A_MEMORY_6;
         param.inputSourceSelect = ADC12_A_INPUT_A6;
    
    #if defined (__MSP430F5659__)
         param.positiveRefVoltageSourceSelect = ADC12_A_VREFPOS_EXT;
    #else
         param.positiveRefVoltageSourceSelect = ADC12_A_VREFPOS_INT;                            //
    #endif
    
         param.negativeRefVoltageSourceSelect = ADC12_A_VREFNEG_AVSS;
    #ifdef channel6
         param.endOfSequence = ADC12_A_ENDOFSEQUENCE;  // END SEQUENCE
    #else
         param.endOfSequence = ADC12_A_NOTENDOFSEQUENCE;
    #endif
         ADC12_A_configureMemory(ADC12_A_BASE ,&param);
    
    
    
          //param = {0};
         param.memoryBufferControlIndex = ADC12_A_MEMORY_7;
         param.inputSourceSelect = ADC12_A_INPUT_A7;
    
    #if defined (__MSP430F5659__)
         param.positiveRefVoltageSourceSelect = ADC12_A_VREFPOS_EXT;
    #else
         param.positiveRefVoltageSourceSelect = ADC12_A_VREFPOS_INT;                            //
    #endif
    
         param.negativeRefVoltageSourceSelect = ADC12_A_VREFNEG_AVSS;
    #ifdef channel7
         param.endOfSequence = ADC12_A_ENDOFSEQUENCE;  // END SEQUENCE
    #else
         param.endOfSequence = ADC12_A_NOTENDOFSEQUENCE;
    #endif
         ADC12_A_configureMemory(ADC12_A_BASE ,&param);
    
    
    
         ADC12_A_clearInterrupt(ADC12_A_BASE,
             ADC12IFG1);
         ADC12_A_enableInterrupt(ADC12_A_BASE,
             ADC12IE1);
         //Enable memory buffer 7 interrupt
             ADC12_A_clearInterrupt(ADC12_A_BASE,
                 ADC12IFG7);
             ADC12_A_enableInterrupt(ADC12_A_BASE,
                 ADC12IE7);
    
             //Enable/Start first sampling and conversion cycle
             /*
              * Base address of ADC12_A Module
              * Start the conversion into memory buffer 0
              * Use the repeated sequence of CHANNELS
              */
             ADC12_A_startConversion(ADC12_A_BASE,
                 ADC12_A_MEMORY_0,
                 ADC12_A_REPEATED_SEQOFCHANNELS);
            /* HWREG8(ADC12_A_BASE + OFS_ADC12CTL0_L) |= ADC12SC;
             HWREG8(ADC12_A_BASE + OFS_ADC12CTL0_L) &=~ADC12ENC;
             HWREG8(ADC12_A_BASE + OFS_ADC12CTL0_L) |= ADC12ENC;*/
    
             ///  START TA0 IN UPMODE AS THE START CONVERSION SOURCE
             Timer_A_startCounter(TIMER_A0_BASE,TIMER_A_UP_MODE);  // START THE TIME IN THE UP MODE
             //Timer_A_stop (TIMER_A0_BASE);
     }


  • > #if defined (__MSP430F5659__)

    Are you using the F5659 or the F5658? I'm pretty sure this isn't defined if your project is configured for the F5658.

    Also, are you clocking the ADC using ADC12OSC or SMCLK? (I.e. is ADC_CLK_is_MODOSC_5Mhz defined?) ADC12OSC will run in LPM3, but SMCLK doesn't.

    Unsolicited: These two settings conflict:

     >                 ADC12_A_SAMPLEHOLDSOURCE_1,

      >      ADC12_A_MULTIPLESAMPLESENABLE);

    With CONSEQ=3 and MSC=1, once the first conversion starts, the ADC runs continuously  and the timer trigger is irrelevant. This may or may not relate to your symptom.

  • Thanks for the reply

    - I'm using F5659 it's defined in the linker file (IAR), i also tested it using a breakpoint and it's defined and working as expected.
    - ADC12OSC is used NOT SMCLK ( ADC_CLK_is_MODOSC_5Mhz is defined)

    - I'm using Repeat-Sequence-of-Channels Mode ( when triggered it samples 8 channels and stores the data in each channel ADC MEM then wait for the next 
       trigger to repeat again). I'm doing DFT so must have samples at specific rate.
       I tested it by toggling pin inside the ADC interrupt and it works very fine.

    -I believe this MODE is NOT described well in Ti datasheet (SLAU208Q–June 2008–Revised March 2018 page 742 ) I spent a couple of days to make it work.

    The trick is that you have to clear ADC12ENC before the end of each sequence and SET it again after last channel of the sequence.

    It's described  in the datasheet from the ASIC implementation point of view (SLAU208Q–June 2008–Revised March 2018 page 742 ) NOT the user point of view which make the confusion.

    in my code i enable interrupts for channel 1 (could be 2,3,4,5) and 7. In ch1 Interrupt I just disable ADC12ENC (I do it early during the sequence sampling and conversion so the MCU state machine can capture it and process before end of sequence),

    In ch7 interrupt i
    process the 8 channels data and Enable ADC12ENC so the MCU ADC state machine will wait for next trigger


    Just to highlight it


    the code work very fine for every condition, Only when power goes down and enters LPM and power returns and exit from LPM i have like 2-3 cycles ((32-48)*8 samples ) of wrong data from ADC 

    Also for testing purpose I only enter LPM with power down and Exit  LPM with power up without touching any I/O, clk or module configuration.

  • OK, your ENC manipulations in the ISR weren't obvious from what you had presented. It seems that you've effectively implemented CONSEQ=1 using CONSEQ=3. Is there a reason you didn't just use CONSEQ=1?

    What clock are you using for TA0? Does it run in LPM3? I'm wondering if what you're seeing is stale samples taken while your sensor system was powered down.

    Also, what "wrong" values do you get (vs "right" values)? Do those tell you anything?

  • - I used CONSEQ = 3 coz this repeated sequence and i understood CONSEQ =1 is not repeated 
    - TA0 Clk is SMCLK, but i tried also ACLk (derived for xtl1 32768Khz) and i face the same problem
    - it's not stale samples as I can track the ADC interrupt is triggered and the sample buffur is accessed and filled.

    - regarding the clock question, i tried all LPM0, LPM3 and LPM4 
      Just entering LPM and exit from LPM without any pre processing or post processing also i make sure dedicated CLK is running during LPM 

    P.S

    I'm using XTl2 running at 24Mhz as the source for MCLK and SMCLK with div_0 so both MCLK and SMCLK are 24Mhz 
    ADC is running at the MODOSC rate = 5Mhz

  • Where I'm starting from in all this is that running the ADC while in LPM is a very standard practice, so I'm trying to guess what you're doing differently.

    Once you go into LPM, how does the wakeup happen?

    CONSEQ=1 is non-repeated, which is what you (typically) want for a timer trigger -- each new trigger runs a full (MSC=1) sequence. What you've described puts the ADC into repeating mode but then prevents it from repeating. (With CONSEQ=1 you have to toggle ENC (=0 then =1) for each batch, but you're already doing that.) I haven't tried the method you're using, though I don't see why it would malfunction.

    [Edit: I forgot to ask: Where does your external reference come from?]

  • Dear All,

    Many thanks for all your replies, I found the issue. 
    I have a 3D array to collect samples and one of the array's index was not reset after LPM Exit.
    Once i reset that index things goes well.  Thanks a lot

    Dear Bruce, 
    I'll revisit the issue of CONSEQ again based on your advice

    Thanks a lot

**Attention** This is a public forum