Powering MKR WiFi 1010 with Batteries

Learn how to power the MKR WiFi 1010 with batteries, and how to use the low-power features of the board.

Introduction

The MKR WiFi 1010 board is designed to run on a Li-Po battery.

Your MKR board has all the circuitry to use a Li-Po battery, charging it when there is power coming from VIN or USB, or using it as main power supply when there is no other source available. If you are going to use a Li-Po battery, it is useful to understand how to reduce power consumption using the ArduinoLowPower Library and the Wi-Fi LowPowerMode. Some simple practices will make your project battery friendly.


Hardware & Software Needed

  • Arduino MKR WiFI 1010
  • Li-Po battery 1024 mAh minimum, JST PH connector
  • Pushbutton NO
  • Power source with micro-USB cable
  • Arduino IDE (offline and online versions available)
  • Arduino SAMD core installed, follow this link for instructions
  • WiFiNINA library (explained later in this tutorial)

Circuit

Circuit with board, Li-Po battery and a button.
Circuit with board, Li-Po battery and a button.

Schematic

Schematic of our circuit.
Schematic of our circuit.


Letā€™s Start!

This tutorial is more of a conceptual one than a practical one, because there is not much we are going to do on the hardware side: just connect your Li-Po battery to the connector and see the board spring up to life. This happens if the battery is charged at some level and it is unlikely that your battery is so discharged that it wonā€™t power up the MKR WiFi 1010. The pushbutton, used for one of the sketches goes between D8 and GND.

The first step is to connect the board to a source of energy, this can be your computer or a phone charger. In both cases there will be a cable that ends with a micro USB that goes into the MKR WiFi 1010 socket. A standard 500 mA supply is ok and will charge your battery in a number of hours that is proportional to the capacity of the battery. The circuit is designed to provide 4.2V and 512 mAh; with a typical C/2 charge/discharge rating of the cells, this is the reason why we suggest a 1024 mAh minimum capacity. The hours taken for the charge are therefore the capacity divided by the charging current. You can find batteries with different C values depending on their chemistry and application, but the ones available for powering microcontroller boards are usually rated at C/2. Operating the Li-Po battery within its specs will grant it a long and cool (no heating) life.

LiPo battery with JST PH connector.
LiPo battery with JST PH connector.

When the battery is charging, you will see the charging LED lit. When no charge is going on, either because the battery is full or the charging timeout has been reached, that LED is off while the Power LED stays on.

At this point our MKR WiFi 1010 is still connected to a power supply through the micro-USB port and the Li-Po cell is just connected but not used.

As soon as we disconnect the USB power, the battery power kicks in and we have an uninterrupted supply to all the components on the board. This is important to understand: no reset is needed when going from one power source to another, so you can be creative in your charging solutions, like solar cells, wind turbines, bicycle dynamos and so on. Just remember that the VIN and USB expect a clean and constant 5V (no more, no less).

We can now go to the software part and start checking the availability in our programming environment, of the two libraries we need:

Go to Sketch > Include Library > Manage Librariesā€¦ and the Library manager will open. Type in the search box the name of each library, as written above, and check if they are already installed (you see the ā€œINSTALLEDā€ label near the name), or alternatively just install the latest version.

Install the Arduino Low Power library.
Install the Arduino Low Power library.

When installing the Arduino Low Power Lib, it will automatically check if you have the RTCZero Lib, which is a dependency. This is a great feature of the latest lib manager.

Install the RTCZero library.
Install the RTCZero library.

Now everything is ready to begin the testing.

The NINA module can just turn off the WiFi, but has no deep sleep mode, while the SAMD microcontroller has one. This means that we have different levels of power saving.

Use

WiFi.lowPowerMode()

  • This is an automatically managed mode where the Wi-Fi NINA Module reduces its power drain, bringing the overall power consumption to 30mA. Any incoming data is received and the device regularly sends out to the beacon signal, each 100ms, to keep the AP connection alive.

Use

WiFi.end()

  • If
    WiFi.begin()
    was used to connect to an access point, the connection will be disconnected. If
    WiFi.beginAP()
    was used before to create an access point, the
    WiFi.end()
    will stop listening it too. In both cases we need to reinitialize the module and restore the connection with one of the two APIs.

Use

LowPower.sleep()

  • Puts the MCU in sleep mode. The sleep mode allows power optimization with a slower wakeup time. Only the chosen peripherals are on.

Use

LowPower.deepSleep()

  • Puts the MCU in deep sleep mode. The deep sleep mode allows power optimization with the slowest wake-up time. All but the RTC peripherals are stopped. The CPU can wakeup only using RTC or wakeup on interrupt capable pins.

You find full reference for these APIs in the libraries documentation: here for WiFiNINA and here for ArduinoLowPower.

These APIs can be combined, one for each type, to achieve the power saving you are looking for. Each one has its pros and cons, especially in terms of how long it take to get back the full functionalities versus the minimum mA used. As a reference, just the green power LED near the USB connector, consumes around 8 mA.

We begin with the typical sleep mode of the microcontroller and a manual pushbutton to wake it up.

This sketch demonstrates the usage of External Interrupts (on pins) to wakeup the SAMD21 of the MKR WiFi 1010 in sleep mode.

Sleep modes allow a significant drop in the power usage of a board while it does nothing waiting for an event to happen. Battery powered application can take advantage of these modes to enhance battery life significantly.

NOTE: if the processor is sleeping, a new sketch can't be uploaded. To overcome this, manually reset the board (usually with a single or double tap to the RESET button).

1#include <ArduinoLowPower.h>
2// Number of blinks per repetition
3// Declare it volatile since it's incremented inside an interrupt
4volatile int repetitions = 1;
5// Pin used to trigger a wakeup
6const int pin = 8;
7void setup() {
8 pinMode(LED_BUILTIN, OUTPUT);
9 // Attach a wakeup interrupt on pin 8, calling repetitionsIncrease when the device is woken up
10 LowPower.attachInterruptWakeup(pin, repetitionsIncrease, CHANGE);
11}
12void loop() {
13 for (int i = 0; i < repetitions; i++) {
14 digitalWrite(LED_BUILTIN, HIGH);
15 delay(500);
16 digitalWrite(LED_BUILTIN, LOW);
17 delay(500);
18 }
19 // Triggers an infinite sleep (the device will be woken up only by the registered wakeup sources)
20 // The power consumption of the chip will drop consistently
21 LowPower.sleep();
22}
23void repetitionsIncrease() {
24 // This function will be called once on device wakeup
25 // You can do some little operations here (like changing variables which will be used in the loop)
26 // Remember to avoid calling delay() and long running functions since this functions executes in interrupt context
27 repetitions ++;
28}

In the next example we set the microcontroller to sleep for 8 seconds, when it wakes up, it does a double LED blink and goes back to sleep. This could be done using delay() to achieve the same result, but in this case the power consumption is much lower.

1#include <ArduinoLowPower.h>
2
3void setup() {
4 pinMode(LED_BUILTIN, OUTPUT);
5 // Uncomment this function if you wish to attach function dummy when RTC wakes up the chip
6 // LowPower.attachInterruptWakeup(RTC_ALARM_WAKEUP, dummy, CHANGE);
7}
8
9void loop() {
10 digitalWrite(LED_BUILTIN, HIGH);
11 delay(500);
12 digitalWrite(LED_BUILTIN, LOW);
13 delay(500);
14 digitalWrite(LED_BUILTIN, HIGH);
15 delay(500);
16 digitalWrite(LED_BUILTIN, LOW);
17 delay(500);
18 // Triggers a 2000 ms sleep (the device will be woken up only by the registered wakeup sources and by internal RTC)
19 // The power consumption of the chip will drop consistently
20 LowPower.sleep(8000);
21}
22
23void dummy() {
24 // This function will be called once on device wakeup
25 // You can do some little operations here (like changing variables which will be used in the loop)
26 // Remember to avoid calling delay() and long running functions since this functions executes in interrupt context
27}

WiFi.lowPowerMode() is capable of putting the Wi-Fi NINA module in a self managed low power mode. The data is transmitted and received, while the beacon is transmitted at regular intervals to keep the AP mode effective. To use this feature, it is enough to put this API in your sketch after the initialization procedure of the WiFi. Please note that there is no parameter passed to the function; to disable this low power mode you need to use the WiFi.noLowPowerMode() function.

In the following example we keep asking the content of the home page of example.org every 20 seconds, allowing the NINA module to manage its power consumption autonomously.

1#include <WiFiNINA.h>
2
3#include "arduino_secrets.h"
4///////please enter your sensitive data in the Secret tab/arduino_secrets.h
5char ssid[] = SECRET_SSID; // your network SSID (name)
6char pass[] = SECRET_PASS; // your network password (use for WPA, or use as key for WEP)
7int keyIndex = 0; // your network key Index number (needed only for WEP)
8
9int status = WL_IDLE_STATUS;
10
11WiFiClient client; // Initialize the Wifi client library
12
13char server[] = "example.org"; // server address:
14
15unsigned long lastConnectionTime = 0; // last time you connected to the server, in milliseconds
16const unsigned long postingInterval = 20000; // delay between updates, in milliseconds
17
18void setup() {
19 Serial.begin(9600);
20 while (!Serial) {
21 ; // wait for serial port to connect. Needed for native USB port only
22 }
23
24 if (WiFi.status() == WL_NO_MODULE) { // check for the WiFi module:
25 Serial.println("Communication with WiFi module failed!");
26 // don't continue
27 while (true);
28 }
29
30 while (status != WL_CONNECTED) {
31 Serial.print("Attempting to connect to SSID: ");
32 Serial.println(ssid);
33 // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
34 status = WiFi.begin(ssid, pass);
35 WiFi.lowPowerMode(); // ENABLE WiFi Low Power Mode
36 delay(5000);
37 }
38}
39
40void loop() {
41 while (client.available()) {
42 char c = client.read();
43 Serial.write(c);
44 }
45
46 if (millis() - lastConnectionTime > postingInterval) {
47 httpRequest();
48 }
49
50}
51
52void httpRequest() {
53 // close any connection before send a new request.
54 // This will free the socket on the Nina module
55 client.stop();
56
57 // if there's a successful connection:
58 if (client.connect(server, 80)) {
59 Serial.println("connecting...");
60 client.println("GET / HTTP/1.1");
61 client.println("Host: example.org");
62 client.println("User-Agent: ArduinoWiFi/1.1");
63 client.println("Connection: close");
64 client.println();
65
66 lastConnectionTime = millis();
67 } else {
68 Serial.println("connection failed");
69 }
70}

The consumption of the NINA module alone can go down at around 30mA and this has to be added to the other components on your board.

A more radical way to reduce the consumption of the NINA module is to use WiFi.end() that turns off the radio part of the module. The microcontroller inside the module is still using some power, but this is the lowest level of consumption possible. This function in your sketch closes any active connection and requires a full restart of the initialization process: WiFi.begin() or WiFi.beginAP() are required to restore the connections.

Conclusion

The four APIs covered in this tutorial allow you to minimize the power consumption of the MKR WiFi 1010 and get the most out of your rechargeable battery. The declared battery capacity, divided by the power used by the board will give you the expected number of hours your circuit can run on a single charge. To assess the real mA used we suggest that you use some of the nice and cheap USB power monitors available on the market.