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

Parents
  • Hi David,

    I'm taking over this case from Heidi.

    Can you please read out the GPIO registers using nrfjprog to see the state of the GPIOs. Something like this:

    $ nrfjprog --family nrf91 --memrd 0x50842500 --n 0x28
    0x50842500: 00000000 00000000 00000000 00000000   |................|
    0x50842510: 00000000 00000000 00000000 00000000   |................|
    0x50842520: 00000000 00000000                     |........|

    $ nrfjprog --family nrf91 --memrd 0x50842700 --n 128
    0x50842700: 00000002 00000002 00000002 00000002   |................|
    0x50842710: 00000002 00000002 00000002 00000002   |................|
    0x50842720: 00000002 00000002 00000002 00000002   |................|
    0x50842730: 00000002 00000002 00000002 00000002   |................|
    0x50842740: 00000002 00000002 00000002 00000002   |................|
    0x50842750: 00000002 00000002 00000002 00000002   |................|
    0x50842760: 00000002 00000002 00000002 00000002   |................|
    0x50842770: 00000002 00000002 00000002 00000002   |................|

    Also please post the board schematic. Then I can try to guide you on what state the GPIOs should be in when in idle.

    Are you able to post the complete project?

     

             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.

     Based on this statement it sounds to me that the HF clock and all other peripherals that requires the HF clock to run are successfully shut down when you get to 490 uA. Since the HF clock consumes about 4-500 uA (which will add up to 900uA). This leads me to think that the remaining current is not due to any of the peripherals. I'm thinking that maybe there is a thread still running/polling something? Are you able to measure the power profile and see if you get any regular current spikes suggesting regular wake ups (in the 10-20 ms range)?

    Thanks,
    Stian

  • Thanks for your response.

    This morning I changed the code which waits for the semaphore which is given every second which there is nothing to do.

    Previously I had tried using k_cpu_atomic_idle(key) from an example I saw on the forum.

    Now I just use k_sem_take(&sec_wakeup_sem, K_FOREVER) again. 

    I had a session with our hardware guy in LasVegas after updating the code and he reports a very good current consumption of 31ua which spikes very second as expected. He will check the current with a more precise current meter at work.

    Now I used the direct uart disable and enable examples also found on the forum but after disabling uart0, enabling uart0 does not restore my printouts for debug information. I called printk() with CONFIG_PRINTK=y in one version and then calling z_impl_k_str_out() directly with CONFIG_PRINTK=n with the same results - no printout after reenabling uart0.

    void ami_uart_boot_DeInit(void)
    {
    #if defined(CONFIG_UART_INTERRUPT_DRIVEN)
      //---------------------------------------------------------------------------
      // 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);
    #endif
      //---------------------------------------------------------------------------
      // 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
    
    bool ami_uart_boot_ReInit(void)
    {
    #if defined(CONFIG_UART_INTERRUPT_DRIVEN)
      //---------------------------------------------------------------------------
      // RXD change back to an input
      //---------------------------------------------------------------------------
      ami_board_ConfigPin(AMI_BOARD_OUT_BOOT_RXD,GPIO_INPUT);
      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
    

    The debug serial channel stops working but the rest of the code seems to still work so there is no hard fault exception.

    Again the debug channel works until I can the Deint() function and then ReInit() when I need to send another string.

    What could be my problem?

    Thanks

  • I also tried adding  NRF_UARTE0_NS->PSEL.TXD      = PIN_NUM_UART0_TXD; in ReInit() but still none of my debug information is sent after the Deint() function.

  • I added NRF_UARTE0_NS->PSEL.TXD = PIN_NUM_UART0_TXD; in ReInit() before enabling the uart and now I can reenable the uart and send debug information.

      NRF_UARTE0_NS->PSEL.TXD      = PIN_NUM_UART0_TXD;
      NRF_UARTE0_NS->PSEL.RXD      = PIN_NUM_UART0_RXD; 
      NRF_UARTE0_NS->ENABLE        = 8;
      NRF_UARTE0_NS->TASKS_STARTRX = 1;
      NRF_UARTE0_NS->TASKS_STARTTX = 1;
    

    I hope to have an inetegration session soon to recheck the current.

    Thanks David

  • We verified that now we are getting a little over 29ua in our sleep state which is very good.

Reply Children
No Data
Related