Close
0%
0%

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

Public Chat
Similar projects worth following
Starting from
$99.00
jacobwachlin has 6 orders / 0reviews
Ships from United States of America
MetaShunt is an electronic instrument designed for high-bandwidth, very high dynamic range measurements of the instantaneous current and power and accumulated energy use of low-power and IoT devices between 50 nanoamps and 500 milliamps

MetaShunt leverages a simple idea - by quickly and accurately measuring the voltage across a current shunt resistor and engaging additional shunt stages when needed, MetaShunt ensures that it can provide accurate current measurement across a range of approximately 10,000,000:1 (from 50nA to 500 mA) without providing significant voltage burden. This range of current is specifically targeted for use with ultra-low power and IoT systems. By measuring current rapidly over time, the total energy use during a given portion of your code can be determined. MetaShunt acts as a virtual ground for your system, so that you can use your battery. Or, MetaShunt can provide 3.3V or 5V to the system under test if desired.


Q: Why do you need this tool?

  • You are developing low power electronic projects, and need to know how much power you are using during short wake-up cycles
  • You develop IoT systems, and the power consumption changes drastically during data transmission and you want to measure it
  • You are testing components to validate them against the datasheet, and the current is lower than your multi-meter can measure reliably

Q: Isn't this basically a JouleScope or Otii Arc?

Yes, it is designed for very similar use, but does have significant differences. MetaShunt is designed more for DIY hobbyists than those products are, and that can be seen in price, capabilities, and openness. MetaShunt has an open USB serial interface protocol and example Python interfacing scripts so that users can build their own testing scripts with it. There are no subscriptions or features behind paywalls. In addition, all of the resistors in the feedback and sensing path come with open solder jumpers so that the user can measure the resistance with their multi-meter and provide it to the system for calibration. This allows for accurate measurements without needing expensive high-precision resistors.


Q: Can I buy one?

Yes! It is available in Tindie here!

  • Nanosleeper - Sub 100nA Deep Sleep Dev Board

    Jake Wachlin01/28/2024 at 18:24 0 comments

    I used MetaShunt to test my new ultra-low power development board, called Nanosleeper. The goal with Nanosleeper was to achieve <100nA deep sleep current with the ability to wake up at a selected time. It was built in the Adafruit Feather form factor, but does not 100% match the Feather specification. It has support for controlling external power and I2C pullups for external devices so that very, VERY low power systems can be prototyped.

    Debugging and testing a product like Nanosleeper is difficult without a tool like MetaShunt. The power used when on is over 8,000X times higher than when in deep sleep, so measuring current with a simple shunt is not likely to work. However, MetaShunt has no issues with this.

    Pictures of an assembled Nanosleeper and it connected to MetaShunt are shown below. Nanosleeper is powered by the 3.3V supply from MetaShunt into the BAT input of Nanosleeper. Because Nanosleeper uses an extremely low power linear voltage regulator (1.8V logic level), this gives the same current results as it would if powered by a 3V coin cell battery.

    The firmware used during this test is shown below. The two onboard LEDs are turned on for 5 seconds, then turned off. A 2 second busy wait then occurs. Next, the RTC is set up using I2C, and set to wake the system after 15 seconds. The wakeup pins are then configured and shutdown sleep mode is entered.

      // Toggle LED to indicate awake
      HAL_GPIO_WritePin(D12_GPIO_Port, D12_Pin, GPIO_PIN_SET);
      HAL_GPIO_WritePin(D13_GPIO_Port, D13_Pin, GPIO_PIN_SET);
      HAL_Delay(5000);
      HAL_GPIO_WritePin(D12_GPIO_Port, D12_Pin, GPIO_PIN_RESET);
      HAL_GPIO_WritePin(D13_GPIO_Port, D13_Pin, GPIO_PIN_RESET);
      HAL_Delay(2000);
    
      // Set up RTC, checking if it's already been set up
      bool is_initial_setup = true;
      uint32_t current_time_utc = 1705968815;
      bool rv_3028_setup_ok = init_rv_3028_c7(hi2c1, current_time_utc, is_initial_setup);
    
    
      // Go to shutdown mode, with pin wakeup.
      HAL_PWR_DisableWakeUpPin(PWR_WAKEUP_PIN1);
    
    
      /* Enable wakeup pin WKUP1 */
      HAL_PWREx_EnableGPIOPullDown(PWR_GPIO_C, PWR_GPIO_BIT_14);
      HAL_PWREx_EnableGPIOPullDown(PWR_GPIO_C, PWR_GPIO_BIT_15);
      HAL_PWREx_EnableGPIOPullUp(PWR_GPIO_A, PWR_GPIO_BIT_0);
      HAL_PWREx_EnablePullUpPullDownConfig();
      HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN1_LOW);
      HAL_PWREx_DisableInternalWakeUpLine();
    
      /* enter shutdown */
      __HAL_RCC_PWR_CLK_ENABLE();
      __HAL_PWR_CLEAR_FLAG(PWR_FLAG_WUF1);
      HAL_PWREx_EnterSHUTDOWNMode();

    Each of those sections of the firmware are very clear in the power profile below. The system starts up (the current spike off the chart is due to plugging in Nanosleeper to power) and with both LEDs on the current is steady at about  800uA. With the LEDs off, the current drops to about 600uA. There is a current spike to about 1.15mA during the I2C communication with the RTC, and then the system goes into deep sleep. After 15 seconds, the system starts up again and turns on the LEDs.

    The deep sleep current is shown in higher detail below, and is steady just under 95nA.


    This example shows MetaShunt's performance for an ultra-low power design, with ~8,000X variation in power consumption during operation.

  • Example: ESP32 WiFi and Low Power Modes

    Jake Wachlin11/29/2023 at 01:33 0 comments

    The ESP32 is a commonly used wifi and Bluetooth enabled microcontroller which nicely demonstrates the usefulness of MetaShunt as a measurement and debugging tool. When connected to WiFi and operating at full speed, the ESP32 can consume a lot of power (some sources report up to 240mA maximum). However, it also has low power modes that can get the current consumption down to about 5uA, a level 48,000 times lower than its maximum! MetaShunt is the perfect tool for analyzing the power of such a system. A multimeter is incapable of keeping up with the rapid changes in power consumption, and multiple ranges would likely be needed. A simple current shunt monitored by an oscilloscope would suffer from resolution issues - a shunt sized for 240mA will not be useful at 5uA, and a shunt sized for 5uA will not work at 240mA (the system would brown out). MetaShunt can easily measure current across these ranges without browning out the system.


    This test was completed with an ESP32 Huzzah development board from Adafruit, since it is what I had on-hand. This is not the ideal board to test low-power consumption with, because it has a UART to USB adapter component and a battery charger on board, neither of which can be put into low power mode. Nonetheless, the microcontroller portion of it can be controlled to enter and exit low power modes, as well as connect to WiFi, and I will demonstrate monitoring this system using MetaShunt.

    The board was connected to MetaShunt by the 5V and VSNS pins, just like in the prior log. Note that the measurements will therefore also include quiescent current from the voltage regulator.

    The following Arduino sketch was used in this test. Various active busy waits, waits while connected to WiFi, online data queries, and low power modes are demonstrated. Care is taken before entering deep sleep to turn on the RTC for wakeup later and to set all GPIO into the best power saving mode (this is really important for getting the last few uA out of a low power system).

    #include <WiFi.h>
    #include "time.h"
    #include "driver/rtc_io.h"
    #include "driver/gpio.h"
    #include "esp_wifi.h"
    #include "driver/adc.h"
    
    //#define USE_SERIAL      1
    
    RTC_DATA_ATTR int bootCount = 0;
    
    const char* ssid       = "MYSSID";
    const char* password   = "MYPASSWORD";
    
    const char* ntpServer = "pool.ntp.org";
    const long  gmtOffset_sec = 3600;
    const int   daylightOffset_sec = 3600;
    
    
    void printLocalTime()
    {
      struct tm timeinfo;
      if(!getLocalTime(&timeinfo)){
        Serial.println("Failed to obtain time");
        return;
      }
      Serial.println(&timeinfo, "%A, %B %d %Y %H:%M:%S");
    }
    
    void setup() {
      #ifdef USE_SERIAL
      Serial.begin(115200);
      #endif
      
      pinMode(13,OUTPUT);
      delay(500);
      
      digitalWrite(13,HIGH);
      
      delay(2500);
    
      digitalWrite(13,LOW);
    
      //connect to WiFi
      #ifdef USE_SERIAL
      Serial.printf("Connecting to %s ", ssid);
      #endif
      WiFi.begin(ssid, password);
      while (WiFi.status() != WL_CONNECTED) {
          delay(15);
          #ifdef USE_SERIAL
          Serial.print(".");
          #endif
      }
      #ifdef USE_SERIAL
      Serial.println(" CONNECTED");
      #endif
      
      //init and get the time
      configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
      delay(200);
      int i;
      for(i = 0; i < 10; i++)
      {
        digitalWrite(13,!digitalRead(13));
        delay(100);
      }
      digitalWrite(13,LOW);
      
      #ifdef USE_SERIAL
      printLocalTime();
      #endif
    
      //disconnect WiFi as it's no longer needed
      WiFi.disconnect(true);
      WiFi.mode(WIFI_OFF);
    
      esp_sleep_enable_timer_wakeup(3000000); // 3 sec
      esp_light_sleep_start();
      // we'll wake from light sleep here
    
      //Set things up for lower power
      // ESP32 docs say to isolate pin 12 in deep sleep to save power
      rtc_gpio_isolate(GPIO_NUM_12);  
    
      // Isolate other pins
      rtc_gpio_isolate(GPIO_NUM_39);
      rtc_gpio_isolate(GPIO_NUM_36);
      rtc_gpio_isolate(GPIO_NUM_35);
      rtc_gpio_isolate(GPIO_NUM_34);
      rtc_gpio_isolate(GPIO_NUM_32);
      rtc_gpio_isolate(GPIO_NUM_33);
      rtc_gpio_isolate(GPIO_NUM_27);
      rtc_gpio_isolate(GPIO_NUM_26);
      rtc_gpio_isolate(GPIO_NUM_25);
      rtc_gpio_isolate(GPIO_NUM_23);
      rtc_gpio_isolate(GPIO_NUM_22);
     rtc_gpio_isolate(GPIO_NUM_21);
    ...
    Read more »

  • Example: Power of Feather M0 Adalogger

    Jake Wachlin11/15/2023 at 01:37 0 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...

    Read more »

View all 3 project logs

Enjoy this project?

Share

Discussions

Stephan Walter wrote 02/03/2024 at 17:42 point

I'm certainly looking forward to Metashunt being available on Tindie. I wonder how this compares to Nordic's Power Profiler Kit II which is another hobbyist-friendly (<$100) current measurement tool.

What's nice about the PPK2 is that it can supply an arbitrary voltage to the target (0.8V-5V) and also that it has digital inputs, so that you can easily attribute a measured current to a certain device state using GPIOs.

  Are you sure? yes | no

Jake Wachlin wrote 02/21/2024 at 14:46 point

Hi Stephan! MetaShunt is now listed on Tindie here: https://www.tindie.com/products/energylabs/metashunt-hdr-current-measurement-tool/. I am still working on getting units ready for shipment, but if you are interested you can sign up for the waitlist there!

  Are you sure? yes | no

Jake Wachlin wrote 12/11/2023 at 19:55 point

Hey @Dan Julio thanks! I am thinking I will make the schematic open source so people can understand the implications of its approach on their measurements. 

The AA battery is used to provide a stable below ground rail for the op-amps so they don't have to operate near their negative rail with all the inconsistencies that can come from operating near a rail of a "rail-to-rail" op-amp

  Are you sure? yes | no

Dan Julio wrote 12/11/2023 at 01:17 point

Good luck with this project, Jack.  It could definitely fill an important niche.  Will any parts of this be open-source?  Certainly would be nice to look at the schematic and understand how you're switching since that's so important in a device like this.  Also, just curious, what does the AA battery do?

  Are you sure? yes | no

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates