MSPM0L2228: MSPM0L2228 LPM EXIT Issue

Part Number: MSPM0L2228

i have developed gas flow meter based on MSPM0L2228 and we have implemented LPM mode. after our task we enter LPM. when ever there is an interrupt we planned to exit LPM. we see that out entry & LPM exit with interrupts are working fine. but after LPM exit main loop is not executing.  i have Uart pull ups, I2C interface enable & disable but still facing the issue, dont have a clue how to solve it .

void LOW_POWER_MODE_ENABLE(void) {
  // print_string((unsigned char *)"\r\nLOW POWER MODE",
  //              strlen("\r\nLOW POWER MODE"), DEBUG_COM);
  LOW_POWER_MODE = true;
  ADC_DISABLE();
  CAP_TOUCH_COUNT = 0;

  DL_UART_disable(BLE_UART_INST);
  DL_UART_disable(NBIOT_UART_INST);
  DL_UART_disable(CONSOLE_UART_INST);
  DL_I2C_disableController(I2C_INST);
  DL_SYSCTL_setPowerPolicyRUN2SLEEP2();
  __WFI();
}

void LOW_POWER_MODE_DISABLE(void) {
  if (LOW_POWER_MODE) {
    DL_SYSCTL_setPowerPolicyRUN0SLEEP0();
    DL_UART_enable(BLE_UART_INST);
    DL_UART_enable(NBIOT_UART_INST);
    DL_UART_enable(CONSOLE_UART_INST);
    DL_I2C_enableController(I2C_INST);

    LOW_POWER_MODE = false;
    print_string((unsigned char *)"\r\nLOW POWER MODE EXIT",
                 strlen("\r\nLOW POWER MODE EXIT"), DEBUG_COM);
  }
}

ti_msp_dl_config.h ti_msp_dl_config.c   

Regards

Nandish 

  • Hello Nandish,

    Could you show the code of main loop part? I want to know the main loop part logic you used. And please notice that if you want M0 won't go back to LPM after waking up, we recommend you add below API in your main code

    DL_SYSCTL_disableSleepOnExit();
    Best Regards, 
    Janz Bai
  • int main(void) {

      SYSCFG_DL_init();
      SYSCFG_DL_RTC_A_init();

      NVIC_ClearPendingIRQ(CONSOLE_UART_INST_INT_IRQN);
      NVIC_EnableIRQ(CONSOLE_UART_INST_INT_IRQN);

      NVIC_ClearPendingIRQ(NBIOT_UART_INST_INT_IRQN);
      NVIC_EnableIRQ(NBIOT_UART_INST_INT_IRQN);

      NVIC_ClearPendingIRQ(BLE_UART_INST_INT_IRQN);
      NVIC_EnableIRQ(BLE_UART_INST_INT_IRQN);

      NVIC_ClearPendingIRQ(EXT_IN_GPIOA_INT_IIDX);
      NVIC_EnableIRQ(EXT_IN_GPIOA_INT_IIDX);

      NVIC_ClearPendingIRQ(EXT_IN_GPIOB_INT_IIDX);
      NVIC_EnableIRQ(EXT_IN_GPIOB_INT_IIDX);

      NVIC_ClearPendingIRQ(EXT_IN_GPIOC_INT_IIDX);
      NVIC_EnableIRQ(EXT_IN_GPIOC_INT_IIDX);

      DL_RTC_A_enableClockControl(RTC_A);
      NVIC_EnableIRQ(RTC_A_INT_IRQn);

      NVIC_ClearPendingIRQ(I2C_INST_INT_IRQN);
      NVIC_EnableIRQ(I2C_INST_INT_IRQN);

      NVIC_EnableIRQ(SUPPLY_SOH_ADC_INST_INT_IRQN);
      DL_ADC12_startConversion(SUPPLY_SOH_ADC_INST);

      DL_GPIO_setPins(EXT_OUT_EEPROM_LOAD_SW_PORT,
                      EXT_OUT_EEPROM_LOAD_SW_PIN); // EEPROM_LOAD_SW pin enable

      memset(print_data, '\0', 256);
      sprintf((char *)print_data,
              "\r\n/*****CAPITAL INNOTECH GAS METER*****/\nFIRMWARE VERSION %s "
              "\nBUILD TIME %s",
              DEVICE_FIRMWARE_VERSION, BUILD_TIME);

      print_string((unsigned char *)print_data, strlen((char *)print_data),
                   DEBUG_COM);
      memset(print_data, '\0', 256);
      sprintf((char *)print_data, "\r\n/*****MCU RESTARTED & REASON IS %d*****\n",
              DL_SYSCTL_getResetCause());
      print_string((unsigned char *)print_data, strlen((char *)print_data),
                   DEBUG_COM);
      memset(print_data, '\0', 256);

      RIO_FLASH_TIME_READ();

      LCD_BACKLIGHT_OFF; /**< Turn off LCD backlight initially */

      RIO_FLASH_READ(&TAMPER_DATA, gNextRecordAddress_Tamperflag,
                     sizeof(TAMPER_DATA));
      print_tamper_data(&TAMPER_DATA);

      RIO_FLASH_READ(&RIO_DEFAULT_APP_CONFIG_DATA, gNextRecordAddress_AppConfig,
                     sizeof(RIO_DEFAULT_APP_CONFIG_DATA));
      print_RIO_DEFAULT_APP_CONFIG_DATA(&RIO_DEFAULT_APP_CONFIG_DATA);
      while (1) {  
     print_string((unsigned char *)"\r\nmain loop",
                     strlen("\r\nmain loop"),
                     DEBUG_COM);    delay_cycles(32000000);}
  • Hello Nandish,

    As you shared, you call "WFI()" in the API LOW_POWER_MODE_ENABLE, but I haven't find where you call LOW_POWER_MODE_ENABLE in your main loop. "WFI()“ is used to let MCU enter into low power mode. CPU will stop at the WFI() and wait for interrupt wake up. And when interrupt occurs and after MCU complete the handling of the interrupt, MCU will continue to operate the code below "WFI()". This is the logic of entering and existing LPM. Please add DL_SYSCTL_disableSleepOnExit(); firstly and then check your main loop logic. 

    BR,

    Janz Bai

  • HI 

    uint8_t sl_count = 0;
    int main(void) {

      SYSCFG_DL_init();
      SYSCFG_DL_RTC_A_init();

      NVIC_ClearPendingIRQ(CONSOLE_UART_INST_INT_IRQN);
      NVIC_EnableIRQ(CONSOLE_UART_INST_INT_IRQN);

      NVIC_ClearPendingIRQ(NBIOT_UART_INST_INT_IRQN);
      NVIC_EnableIRQ(NBIOT_UART_INST_INT_IRQN);

      NVIC_ClearPendingIRQ(BLE_UART_INST_INT_IRQN);
      NVIC_EnableIRQ(BLE_UART_INST_INT_IRQN);

      NVIC_ClearPendingIRQ(EXT_IN_GPIOA_INT_IIDX);
      NVIC_EnableIRQ(EXT_IN_GPIOA_INT_IIDX);

      NVIC_ClearPendingIRQ(EXT_IN_GPIOB_INT_IIDX);
      NVIC_EnableIRQ(EXT_IN_GPIOB_INT_IIDX);

      NVIC_ClearPendingIRQ(EXT_IN_GPIOC_INT_IIDX);
      NVIC_EnableIRQ(EXT_IN_GPIOC_INT_IIDX);

      DL_RTC_A_enableClockControl(RTC_A);
      NVIC_EnableIRQ(RTC_A_INT_IRQn);

      NVIC_ClearPendingIRQ(I2C_INST_INT_IRQN);
      NVIC_EnableIRQ(I2C_INST_INT_IRQN);

      NVIC_EnableIRQ(SUPPLY_SOH_ADC_INST_INT_IRQN);
      DL_ADC12_startConversion(SUPPLY_SOH_ADC_INST);

      DL_GPIO_setPins(EXT_OUT_EEPROM_LOAD_SW_PORT,
                      EXT_OUT_EEPROM_LOAD_SW_PIN); // EEPROM_LOAD_SW pin enable

      memset(print_data, '\0', 256);
      sprintf((char *)print_data,
              "\r\n/*****METER*****/\nFIRMWARE VERSION %s "
              "\nBUILD TIME %s",
              DEVICE_FIRMWARE_VERSION, BUILD_TIME);

      print_string((unsigned char *)print_data, strlen((char *)print_data),
                   DEBUG_COM);
      memset(print_data, '\0', 256);
      sprintf((char *)print_data, "\r\n/*****MCU RESTARTED & REASON IS %d*****\n",
              DL_SYSCTL_getResetCause());
      print_string((unsigned char *)print_data, strlen((char *)print_data),
                   DEBUG_COM);
      memset(print_data, '\0', 256);

      DL_SYSCTL_disableSleepOnExit();
      while (1) {
        sl_count++;

        print_string((unsigned char *)"\r\nMain loop", strlen("\r\nMain loop"),
                     DEBUG_COM);

        if (!LOW_POWER_MODE)
          SCREEN_CHANGE(); /**< Handle screen change */

        if (sl_count >= 10) {
          sl_count = 0;
          LOW_POWER_MODE_ENABLE(); /**< Enable low power mode */
        }
        delay_cycles(32000000);
      }
    // this is interrupt where i am exiting the LPM  
    if (pending_interrupt_ext_inb == EXT_IN_TOUCH_2_IIDX) {
        LOW_POWER_MODE_DISABLE();
        print_string((unsigned char *)"\r\n/***INTERRUPT***/",
                     strlen("\r\n/***INTERRUPT***/"), DEBUG_COM);
        DL_GPIO_clearInterruptStatus(GPIOB, EXT_IN_TOUCH_2_PIN);
      }   
    i have added the sleepon_exit but still no main loop only interrupts 
    Regards
    Nandish 
  • Hello Janz,

    i have tried debugging in many ways and i havent seen code executing after WFI in my project. during initial development we faced similar issue and at that time our observation was enabling UARTS was causing the LPM exit issue and later i got instructions to enable pull ups on UART pins and it worked at that time but now we are in final phase of development facing the issue again 

    BR,

    Nandish 

  • Hello Nandish,

    According to your current shared code, CPU will stop at here to wait for interrupt

    Then after interrupt occurs and CPU complete handling, CPU will continue operation in the "while(1) loop". And wait for next interrupt

    So I don't know where you add below code

    You said that interrupt can enter normally and exit normally, just main loop can't operate normally. So have you tried in debug mode, to see where CPU will stop after existing from LPM? I mean you can set a break point at the code line which should operate after waking up from LPM, and in debug mode to see whether it can run this point, if not, where CPU runs to. 

    Did you set any interrupt that has high frequency ? For example, you set a timer interrupt or RTC interrupt, which has a high frequency which will trigger interrupt forever. That will cause CPU don't have time to handle main loop code.

    And I think if you can simply your code step by step and then add function step by step, to do tests, to confirm which will be the possible reason, I think it is also a better way

    BR.

    Janz Bai

  • Hi Janz,

     

    __WFI();    
    print_string((unsigned char *)"\r\nLOW POWER MODE"
                   strlen("\r\nLOW POWER MODE"), DEBUG_COM);  tried to debug the code with breakpoint and seen no breakpoint hit after interrupt. 
    Note: we can publish our product code in public forum. whatever i have given whole code logic how we are running.
    Regards
    Nandish 
  • Hi Janz, 

    after debugging we found that our code is stuck in RUN2SLeep2 function ,   DL_SYSCTL_setMCLKSource(SYSOSC, LFCLK, (booltrue);   and stiuck in clock verification 

      while ((DL_SYSCTL_getClockStatus() & SYSCTL_CLKSTATUS_CURMCLKSEL_MASK) !=
               DL_SYSCTL_CLK_STATUS_MCLK_SOURCE_LFCLK) {
            ;
        }
    its not coming out of here.

    void DL_SYSCTL_switchMCLKfromSYSOSCtoLFCLK(bool disableSYSOSC)
    {
        if (disableSYSOSC == false) {
            // Set SYSOSC back to base frequency if left enabled
            DL_SYSCTL_setSYSOSCFreq(DL_SYSCTL_SYSOSC_FREQ_BASE);
            SYSCTL->SOCLOCK.SYSOSCCFG &= ~SYSCTL_SYSOSCCFG_DISABLE_ENABLE;
        } else {
            SYSCTL->SOCLOCK.SYSOSCCFG |= SYSCTL_SYSOSCCFG_DISABLE_ENABLE;
        }
        SYSCTL->SOCLOCK.MCLKCFG |= SYSCTL_MCLKCFG_USELFCLK_ENABLE;

        // Verify LFCLK -> MCLK
        while ((DL_SYSCTL_getClockStatus() & SYSCTL_CLKSTATUS_CURMCLKSEL_MASK) !=
               DL_SYSCTL_CLK_STATUS_MCLK_SOURCE_LFCLK) {
            ;
        }
    }
    __STATIC_INLINE void DL_SYSCTL_setPowerPolicyRUN2SLEEP2(void)
    {
        DL_SYSCTL_setMCLKSource(SYSOSC, LFCLK, (bool) true);
        SCB->SCR &= ~(SCB_SCR_SLEEPDEEP_Msk);
    Regards
    Nandish