Arduino Forum

Products => MKR Boards => MKRNB1500 => Topic started by: JohannaB on Jun 18, 2019, 11:21 am

Title: MKR NB1500 High Power Consumption
Post by: JohannaB on Jun 18, 2019, 11:21 am
I am trying to reduce the power consumption of my MKR NB1500 board. When it is in deep sleep mode it uses 20mA which is way higher than the specs say(microamps). When shutting down the modem the power goes down to 10.6mA, does anyone have an idea about where this energy goes?

I have tried to sleep the board with RTC instead of the premade library "Arduino Deep Sleep" but despite trying everything I could find on these forums it wouldnt wake up after going to sleep, and the current didnt go lower than with the custom library.

Please help and thanks!
Title: Re: MKR NB1500 High Power Consumption
Post by: MartinL on Jun 18, 2019, 12:53 pm
Hi JohannaB,

Here's some example code that uses the RTC to wake the SAMD21 microcontroller every 60 seconds and run an interrupt service routine (RTC_Handler()).

The following code sets up the 32.768kHz external crystal to run in standby (sleep) mode. The generic clock peripheral divides this clock down to 1.024kHz, (32.768kHz/(2^^(4 + 1))) on GCLK4. The RTC's prescaler then divides this down further by 1024 to generate a 1Hz or 1 second tick. The RTC then simply counts from 0 to 59, whereupon it overflows and triggers an interrupt after 1 minute. After setting up the RTC the SAMD21 goes into deep sleep, only to be woken by the interrupt every 60 seconds:

Code: [Select]
// Put SAMD21 into deep sleep and RTC interrupts set to trigger every 60s (PER)
void setup(){
  PORT->Group[PORTA].DIRSET.reg = PORT_PA21;  // Output to D7 to check that the ISR is being called every 60 seconds

// Configure the external crystal----------------------------------------------
  SYSCTRL->XOSC32K.reg = SYSCTRL_XOSC32K_ONDEMAND |       // Enble one demand mode
                         SYSCTRL_XOSC32K_RUNSTDBY |       // Enable run-on-standby mode
                         SYSCTRL_XOSC32K_EN32K |          // Enable the crystal oscillator IO pads
                         SYSCTRL_XOSC32K_XTALEN |         // Enable the crystal oscillator
                         SYSCTRL_XOSC32K_STARTUP(6) |     // Set the crystal start-up time
                         SYSCTRL_XOSC32K_ENABLE;          // Enable the oscillator

// Configure clock source and clock generators (gclk.h)------------------------  
  GCLK->GENDIV.reg =  GCLK_GENDIV_ID(4) |   // Select GLCK4
                      GCLK_GENDIV_DIV(4);   // Select clock divisor to divide by 32 (2 ^ (4 + 1)) to generate 1.024kHz
  while (GCLK->STATUS.bit.SYNCBUSY);        // Wait for synchronization
 
  GCLK->GENCTRL.reg = GCLK_GENCTRL_ID(4) |        // Select GCLK4
                      GCLK_GENCTRL_SRC_XOSC32K |  // Select generic clock source as the external 32.768kHz crystal                    
                      GCLK_GENCTRL_IDC |          // Improve duty cycle for odd div factors
                      //GCLK_GENCTRL_RUNSTDBY |     // Enable run standby mode                
                      GCLK_GENCTRL_DIVSEL |       // Set GLCK divisor as 2 to the power of (divisor) value
                      GCLK_GENCTRL_GENEN;         // Enable GCLK4
  while (GCLK->STATUS.bit.SYNCBUSY);              // Wait for synchronization
    
  GCLK->CLKCTRL.reg = GCLK_CLKCTRL_GEN_GCLK4 |  // Select GCLK4
                      GCLK_CLKCTRL_ID_RTC |     // Connect to the RTC
                      GCLK_CLKCTRL_CLKEN;       // Enable GCLK4
  while (GCLK->STATUS.bit.SYNCBUSY);            // Wait for synchronization

// RTC configuration (rtc.h)--------------------------------------------------                                            
  RTC->MODE1.CTRL.bit.ENABLE = 0;                       // Disable the RTC
  while (RTC->MODE1.STATUS.bit.SYNCBUSY);               // Wait for synchronization

  RTC->MODE1.CTRL.bit.SWRST = 1;                       // Software reset the RTC
  while (RTC->MODE1.STATUS.bit.SYNCBUSY);              // Wait for synchronization
 
  RTC->MODE1.CTRL.reg |= RTC_MODE1_CTRL_PRESCALER_DIV1024 |     // Set prescaler to 1024
                         RTC_MODE1_CTRL_MODE_COUNT16;           // Set RTC to mode 1, 16-bit timer                        
 
  RTC->MODE1.PER.reg = RTC_MODE1_PER_PER(59);                   // Interrupt time 60s: 1Hz/(59 + 1)
  while (RTC->MODE1.STATUS.bit.SYNCBUSY);                       // Wait for synchronization

// Configure RTC interrupts ------------------------------------------
  RTC->MODE1.INTENSET.reg = RTC_MODE1_INTENSET_OVF;             // Enable RTC overflow interrupts

  NVIC_SetPriority(RTC_IRQn, 0);    // Set the Nested Vector Interrupt Controller (NVIC) priority for RTC
  NVIC_EnableIRQ(RTC_IRQn);         // Connect RTC to Nested Vector Interrupt Controller (NVIC)

// Enable Deep Sleep Mode--------------------------------------------------------------
  SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;// | SCB_SCR_SLEEPONEXIT_Msk;  // Put the SAMD21 in deep sleep upon executing the __WFI() function
  NVMCTRL->CTRLB.reg |= NVMCTRL_CTRLB_SLEEPPRM_DISABLED;        // Disable auto power reduction during sleep - SAMD21 Errata 1.14.2

// Enable RTC--------------------------------------------------------------
  RTC->MODE1.CTRL.bit.ENABLE = 1;                       // Enable the RTC
  while (RTC->MODE1.STATUS.bit.SYNCBUSY);               // Wait for synchronization
}

void loop()
{
  // Due to a hardware bug on the SAMD21, the SysTick interrupts become active before the flash has powered up from sleep, causing a hard fault
  // To prevent this the SysTick interrupts are disabled before entering sleep mode
  SysTick->CTRL &= ~SysTick_CTRL_TICKINT_Msk;           // Disable SysTick interrupts
  __DSB();                                              // Complete outstanding memory operations - not required for SAMD21 ARM Cortex M0+
  __WFI();                                              // Put the SAMD21 into deep sleep, Zzzzzzzz...
  SysTick->CTRL |= SysTick_CTRL_TICKINT_Msk;            // Enable SysTick interrupts
}

void RTC_Handler(void)
{
  //if (RTC->MODE1.INTFLAG.bit.OVF && RTC->MODE1.INTENSET.bit.OVF) {  // Check if an overflow caused the interrupt
     PORT->Group[PORTA].OUTTGL.reg = PORT_PA21;                       // Toggle digital pin D7
     RTC->MODE1.INTFLAG.bit.OVF = 1;                                  // Reset the overflow interrupt flag
  //}
}
Title: Re: MKR NB1500 High Power Consumption
Post by: JohannaB on Jul 12, 2019, 11:19 am
Hi!

Thank you for the input and all the code. Thats awesome.

Now the CPU goes to sleep on just above 1mA, which is better than before, so next issue is the modem.. Have you had any luck with setting power saving mode and eDRX-parameters on it?

Thanks again!