This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Big current draw when sleeping, nRF9160 custom board with I2C EEPROM & SI7050, SPI ExternalFlash & LSM6DSL, uart0,uart1 using SES v1.6.1

Basically, I  implement code using uart0,uart1,ADC,I2C for EPROM and temperature chip, SPI for the external flash and lsm6dsl chip.

I use a Zephyr timer to keep a one second time base waking up the program for a main loop check if there is anything to be done and then going back to sleep.

Periodically, the temperature, accelerometer & ADC are all read and the results stored in the EEPROM.

Between samples all of those module should be inactive.

I tried using the pm_device_state_set() function on the high level devices (EEPROM , SI7050,  ExternalFlash & LSM6DSL) but saw the code was not implemented.

pm_device_state_set(si7050_dev,device_power_state,NULL, NULL);

I then tried using the pm_device_state_set() function on the lower level I2C and SPI which did not return errors.

void ami_board_SwPMState(unsigned char which,uint32_t device_power_state)
{
#if defined(CONFIG_BOARD_NRF9160AXION_NRF9160NS)
#ifdef CONFIG_DEVICE_POWER_MANAGEMENT
  const struct device *dev;
  switch (which){
    case AMI_BOARD_DEV_SPI3:
      dev = spi_3_dev;
      break;
    case AMI_BOARD_DEV_I2C2:
      dev = i2c_2_dev;
      break;
    default:
      return;
  } // switch
  if (dev!=NULL){
    int err = pm_device_state_set(dev,device_power_state,NULL, NULL);
    //-------------------------------------------------------------------------
    // No error
    //-------------------------------------------------------------------------
    if (!err) {

Uart0 is used for printk and my debug information and also for incoming bytes in a direct serial connection for initial unit configuration, if needed after power up.

Uart1 is used for nRf52 BLE chip communications when needed. In battery operated mode the BLE chip is not powered.

I understand from the forum (many post are old and do not have used defines) that there is code to disable and enable the uarts dynamically in code.

It seems this does not work when asynch mode is used but only with the interrupt mode since a loop in the uart shutdown code hangs in asynch mode.

Below is my code for uart0. It seems to work but I do not know what conf file definitions I should use for both uaart0 & uart1.

//-----------------------------------------------------------------------------
// uart_CB
//  Description
//    Callback for async UART communication
//  Parameters
//    gps_data
//  Returns
//-----------------------------------------------------------------------------
static void uart_cb(const struct device *x,void *user_data)
{
  uart_irq_update(x);
  int data_length = 0;

  if (uart_irq_rx_ready(x)) {
    data_length = uart_fifo_read(x, uart_buf, sizeof(uart_buf));
    //-------------------------------------------------------------------------
    // Make sure that there is no overflow
    //-------------------------------------------------------------------------
...
}

bool ami_uart_boot_Init(void)
{
  //---------------------------------------------------------------------------
  // Bind UART
  //---------------------------------------------------------------------------
  uart_dev = device_get_binding("UART_0");
  if (uart_dev == NULL) {
    d_printf(LINE_INFO,kDbg_Info|kDbg_General,"Failed to get UART device\n");
    return false;
  }
  //---------------------------------------------------------------------------
  // Set Interrupt callback
  //---------------------------------------------------------------------------
  uart_irq_callback_set(uart_dev, uart_cb);
  //---------------------------------------------------------------------------
  // Enable RX interrupt enbale
  //---------------------------------------------------------------------------
  uart_irq_rx_enable(uart_dev);
  //---------------------------------------------------------------------------
  // Nothing to send
  //---------------------------------------------------------------------------
  atomic_set(&msg_to_send_direct_connect,0);
  //---------------------------------------------------------------------------
  // Set Boot driver is active
  //---------------------------------------------------------------------------
  bBootDriverActive = TRUE;
  return TRUE;
} // ami_uart_boot_Init

//-----------------------------------------------------------------------------
// ami_uart_boot_ReInit
//  Description
//   Change RXD back to an input and reenable uart
//  Parameters
//  Returns
//   TRUE = OK
//-----------------------------------------------------------------------------
bool ami_uart_boot_ReInit(void)
{
  NRF_UARTE0_NS->ENABLE = 8;
  NRF_UARTE0_NS->TASKS_STARTRX = 1;
  NRF_UARTE0_NS->TASKS_STARTTX = 1;
  //---------------------------------------------------------------------------
  // Set Boot driver is active
  //---------------------------------------------------------------------------
  bBootDriverActive = TRUE;
  return TRUE;
} //ami_uart_boot_ReInit

//-----------------------------------------------------------------------------
// ami_uart_boot_DeInit
//  Description
//
//  Parameters
//  Returns
//-----------------------------------------------------------------------------
void ami_uart_boot_DeInit(void)
{
  //---------------------------------------------------------------------------
  // Turn off debug information in printk
  //---------------------------------------------------------------------------
  gDisablePrintk = true;
  //---------------------------------------------------------------------------
  // Low power
  //  When putting the system in low power and the peripheral is not needed, 
  // lowest possible power consumption is achieved by stopping, and then disabling the peripheral.
  // The STOPTX and STOPRX tasks may not be always needed (the peripheral might already be stopped), 
  // but if STOPTX and/or STOPRX is sent, software shall wait until the TXSTOPPED and/or RXTO event is received in response,
  // before disabling the peripheral through the ENABLE register.
  //---------------------------------------------------------------------------
  NRF_UARTE0_NS->TASKS_STOPRX=1;
  while(NRF_UARTE0_NS->EVENTS_RXTO == 0);
  NRF_UARTE0_NS->EVENTS_RXTO = 0;

  NRF_UARTE0_NS->TASKS_STOPTX = 1;
  while(NRF_UARTE0_NS->EVENTS_TXSTOPPED == 0);
  NRF_UARTE0_NS->EVENTS_TXSTOPPED = 0;

  NRF_UARTE0_NS->ENABLE = 0;
  NRF_UARTE0_NS->PSEL.TXD = 0xFFFFFFFF;
  //---------------------------------------------------------------------------
  // Set BOOT Txd P0.1
  //---------------------------------------------------------------------------
  NRF_P0_NS->OUTSET = (1 << 1);
  //---------------------------------------------------------------------------
  // Set BOOT Rxd P0.0
  //---------------------------------------------------------------------------
  NRF_P0_NS->OUTSET = (1 << 0);
  //---------------------------------------------------------------------------
  // RXD is now an input change to an output high!
  //---------------------------------------------------------------------------
// ?!?  ami_board_ConfigPin( AMI_BOARD_OUT_BOOT_RXD,GPIO_OUTPUT_HIGH);
  //---------------------------------------------------------------------------
  // Set Boot driver is NOT active
  //---------------------------------------------------------------------------
  bBootDriverActive   = FALSE;
  //---------------------------------------------------------------------------
  // Cancel staying awake because of Debug & Direct connect
  //---------------------------------------------------------------------------
  ami_main_CancelStayAwake(AQUA_MAIN_AWAKE_BOOT_DIRECT | AQUA_MAIN_AWAKE_DEBUG);
} // ami_uart_boot_DeInit

This morning I performed some current tests with our hardware guy (Meeting).

ADC:

  I left the ADC in the overlay file  "okay" but did not reference it in my code and the current was about 900ua.

  I called adc_channel_setup() and adc_read_async() every 3 minutes and the current was about 1000ua.

  I set the ADC in the overlay file "disabled" and the current was also 900ua.

  The base line current was when one uart was not stopped so may be the ADC is not being disabled automatically.

Uart0 & Uart1:

  At startup I just disabled uart1 as above.


         When after using uart0, when sleeping I did not call the uart0 disable code, I got the 900ua baseline current.

         When after using uart0, when sleep I performed  the uart0 code above, I got a 480ua to 490ua draw.

         Again I use a timer that wakes the program up once a second and if nothing is needed to be done goes back to sleep.

      
Evidently something is still on.

Thanks David

  • Yesterday in another integration session, I added code that would just shutdown the nRF9160 I think in order to see how much current the custom was drawing otherwise and to see what pins' state should be adjusted to reduce current when sleeping.

    The current went from 480ua..490ua to about 100ua. I can guess that something in the nRF9160 is still running that gives the 380ua different when the regulator is not shut off.

    //-----------------------------------------------------------------------------
    // ami_main_Sleep
    //  Description
    //   Called to put the board to sleep till RTC one second wakeup
    //  Parameters
    //  Returns
    //-----------------------------------------------------------------------------
    void ami_main_Sleep(void)
    {
      //-------------------------------------------------------------------------
      // Switch pins to sleep
      //-------------------------------------------------------------------------
      ami_board_AwakeSleepSwPins(true);
      //-------------------------------------------------------------------------
      // IRQ Lock to prevent race situation
      //-------------------------------------------------------------------------
      unsigned int key = irq_lock();
      //-------------------------------------------------------------------------
      // Wait for semaphore from ISR; if acquired, do related work, then
      //  go to next loop iteration (the semaphore might have been given again);
      //  else, make the CPU idle.
      //-------------------------------------------------------------------------
      if (k_sem_take(&sec_wakeup_sem, K_NO_WAIT) == 0) {
        //-----------------------------------------------------------------------
        // Ulock IRQ
        //-----------------------------------------------------------------------
        irq_unlock(key);
        //-----------------------------------------------------------------------
        // continue do processing 
        //-----------------------------------------------------------------------
      }else{
            //-------------------------------------------------------------------
            //
            //-------------------------------------------------------------------
     //       pm_low_power_devices();
            //-------------------------------------------------------------------
            // put CPU to sleep to save power 
            //-------------------------------------------------------------------
            k_cpu_atomic_idle(key);
      //      ?!?
            //-------------------------------------------------------------------
            // 
            //-------------------------------------------------------------------
     //       pm_resume_devices();
      }
    
    //#define AMI_EXTRA_LOW_POWER
    #ifdef AMI_EXTRA_LOW_POWER
      while (true){
        struct pm_state_info info;
        k_cpu_idle();
        info.state = PM_STATE_SOFT_OFF;
        pm_power_state_set(info);
      } // while                  
    #endif                
      //-------------------------------------------------------------------------
      // Switch pins to awake state
      //-------------------------------------------------------------------------
      ami_board_AwakeSleepSwPins(false);
    } // ami_main_Sleep
    

    The modem is off as I call lte_lc_deinit(); beforehand.

    I hope this helps...

    Any thoughts on what is still running. I did not exactly understand what defines are needed in interrupt mode for the uarts. I need to set a timer to each uart?

    Thanks David

  • This morning after disabling the SPI bus, I set the pins to output High and when I switch to PM_STATE_SOFT_OFF the current drops from 100ua to 60ua. So when I do not switch PM_STATE_SOFT_OFF I still get more than 400ua, so something is still active in the module. What could be going on?

    Do I need also to configure pins that are not connected? and if so what should they be confugured?

    Thanks David.

  • Hi! I'm looking into this. I'll have an update for you shortly.

Related