Close

Example: Power of Feather M0 Adalogger

A project log for MetaShunt: High Dynamic Range Current Measurement

A low-cost and accurate tool for analyzing the power consumption of ultra-low power and IoT devices with rapidly changing current usage

jake-wachlinJake Wachlin 11/15/2023 at 01:370 Comments

As an example to show MetaShunt's capability, I created an Arduino sketch for the Adafruit Feather M0 Adalogger which would toggle the onboard LED and use various low power modes. This microcontroller development board was then connected to MetaShunt:

Adalogger GND <----> VSNS

Adalogger USB <----> 5V

The code running on the Adalogger is the following:

#include "LowPower.h"
#include <RTCCounter.h>

#define LED_PIN     13

#define CONFIG_PINS     true
#define DISABLE_TC_TCC  true
#define DISABLE_CLOCKS  true
#define DISABLE_ADC     true

void setup() {
  pinMode(LED_PIN, OUTPUT);
  digitalWrite(LED_PIN, LOW);

  #ifdef CONFIG_PINS
  pinMode(0, OUTPUT);
  pinMode(1, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(7, OUTPUT);
  pinMode(8, OUTPUT);
  pinMode(9, OUTPUT);
  pinMode(10, OUTPUT);
  pinMode(11, OUTPUT);
  pinMode(12, OUTPUT);
  pinMode(A0, OUTPUT);
  pinMode(A1, OUTPUT);
  pinMode(A2, OUTPUT);
  pinMode(A3, OUTPUT);
  pinMode(A4, OUTPUT);
  pinMode(A5, OUTPUT);

  digitalWrite(0, LOW);
  digitalWrite(1, LOW);
  digitalWrite(4, LOW);
  digitalWrite(5, LOW);
  digitalWrite(6, LOW);
  digitalWrite(7, LOW);
  digitalWrite(8, LOW);
  digitalWrite(9, LOW);
  digitalWrite(10, LOW);
  digitalWrite(11, LOW);
  digitalWrite(12, LOW);
  digitalWrite(A0, LOW);
  digitalWrite(A1, LOW);
  digitalWrite(A2, LOW);
  digitalWrite(A3, LOW);
  digitalWrite(A4, LOW);
  digitalWrite(A5, LOW);
  #endif

  #ifdef DISABLE_TC_TCC
  TC3->COUNT16.CTRLA.bit.ENABLE = 0;
  TC4->COUNT16.CTRLA.bit.ENABLE = 0;
  TC5->COUNT16.CTRLA.bit.ENABLE = 0;

  TCC0->CTRLA.bit.ENABLE = 0;
  TCC1->CTRLA.bit.ENABLE = 0;
  TCC2->CTRLA.bit.ENABLE = 0;
  #endif

  #ifdef DISABLE_CLOCKS
  SYSCTRL->DFLLCTRL.bit.RUNSTDBY = 0;
  SYSCTRL->VREG.bit.RUNSTDBY = 0;
  #endif

  #ifdef DISABLE_ADC
  ADC->CTRLA.bit.SWRST = 1;
  #endif

  rtcCounter.begin();

}

void loop() {

  // Busy wait
  delay(2000);

  int i;

  for(i=0; i<10; i++)
  {
    delay(250);
    digitalWrite(LED_PIN, HIGH);
    delay(250);
    digitalWrite(LED_PIN, LOW);
  }

  // Another type of sleep
  rtcCounter.setPeriodicAlarm(2);
  SysTick->CTRL &= ~SysTick_CTRL_TICKINT_Msk;  // Disable SysTick interrupts
  LowPower.idle(IDLE_2); 
  SysTick->CTRL |= SysTick_CTRL_TICKINT_Msk;   // Enable SysTick interrupts  
  if (rtcCounter.getFlag()) {
    rtcCounter.clearFlag();
  }

  delay(500);

  // Then standby
  rtcCounter.setPeriodicAlarm(5);
  LowPower.standby(); 
  if (rtcCounter.getFlag()) {
    rtcCounter.clearFlag();
  }

  delay(1000);

  for(i=0; i<2; i++)
  {
    delay(500);
    digitalWrite(LED_PIN, HIGH);
    delay(500);
    digitalWrite(LED_PIN, LOW);
  }

}

This code toggles LEDs and uses active mode (in delays), idle, and standby power modes. 

Using the Python interface script that will be released soon, data was recorded for 20 seconds. The output data was provided at 4kHz (the onboard measurement is much faster, but USB bandwidth limits the output data rate to this level). The overall data cycle is shown below.

Let's look specifically at sections of the code and see how they match to the current profile shown here. The first section involves a 2 second busy wait followed by toggling the LED pin 10 times with a 0.5s period.

// Busy wait
  delay(2000);

  int i;

  for(i=0; i<10; i++)
  {
    delay(250);
    digitalWrite(LED_PIN, HIGH);
    delay(250);
    digitalWrite(LED_PIN, LOW);
  }

 The plot below shows the measurements during this portion of the program. During the busy wait, the current is ~11.6mA, and it increases to about 12.2mA when the LED is turned on.

In the next section, the Idle 2 sleep mode is used. This sleep mode is set for about 2 seconds. Then a 500ms busy wait occurs.

// Another type of sleep  
rtcCounter.setPeriodicAlarm(2);
SysTick->CTRL &= ~SysTick_CTRL_TICKINT_Msk;  // Disable SysTick interrupts
LowPower.idle(IDLE_2);   
SysTick->CTRL |= SysTick_CTRL_TICKINT_Msk;   // Enable SysTick interrupts    
if (rtcCounter.getFlag()) {    
    rtcCounter.clearFlag();  
}

delay(500);

The measurement profile for this portion of the code is shown here. The current in Idle mode drops down to below 4mA, and back up for 500ms during the busy wait.

In the final portion of the code, the system enters standby for 5 seconds, followed by 1 second busy wait, and toggling the LED twice at 1Hz.

// Then standby
  rtcCounter.setPeriodicAlarm(5);
  LowPower.standby(); 
  if (rtcCounter.getFlag()) {
    rtcCounter.clearFlag();
  }

  delay(1000);

  for(i=0; i<2; i++)
  {
    delay(500);
    digitalWrite(LED_PIN, HIGH);
    delay(500);
    digitalWrite(LED_PIN, LOW);
  }

 The profile for this section is shown in the next image. When in standby, the current drops very low for about 5 seconds. The busy wait and pin toggling are also visible.

The standby mode current can be focused on as well. In the lowest power mode, the current is about 160uA - not very low but not bad for a development board not specifically designed for low power!


This example doesn't show all of the capabilities of MetaShunt. In particular, the ratio between the peak and minimum current is only about 75:1. A simple current shunt could measure this with reasonable accuracy, This tool is designed to handle variation across much wider scales, up to approximately 10,000,000:1. Future examples will show systems with significantly larger variation between peak and minimum current, as well as examples of the use of this tool in optimizing a low power system.

Discussions