Over-The-Air (OTA) Updates with the Arduino Portenta H7

Learn how to perform an OTA update of the firmware on the Arduino Portenta H7

Overview

In this tutorial, you will learn how to use and allow firmware updates via OTA (Over-The-Air) feature with the Arduino Portenta H7. With this tutorial, you will be able to create a binary file to be used with the OTA feature, and use the internal QSPI or a external SD card to accomplish the OTA (Over-The-Air) process.

To proceed with OTA using a SD Card, you will need to use a carrier or shield with a SD card slot, e.g Portenta Breakout, Portenta Vision shield.

Goals

The goals of this tutorial are:

  • Create an OTA file required to use the OTA (Over-The-Air) feature.
  • Use QSPI or SD card storage to load the firmware downloaded using the OTA feature.

Hardware and Software Needed

  • Arduino Portenta H7
  • Arduino IDE 1.8.10+ or Arduino Pro IDE 0.0.4+
  • USB-C type cable (either USB-A to USB-C or USB-C to USB-C)
  • Arduino IoT Cloud and Arduino_Portenta_OTA libraries
  • SD card (optional, you can use QSPI instead)
  • Carrier or shield compatible with the Portenta H7 with a SD Card slot, in case you chose to use the SD Card.

What OTA Means

OTA (Over-The-Air) is a method of distributing wirelessly to end devices to update their firmware, configuration, or security-related protocols. The purpose of this method is to change a device’s behavior or its settings for better performance, for adding new features, or to change its targeted usage.

Instructions

We will explain briefly the steps required to be able to use OTA (Over-The-Air) process with Arduino Portenta H7, in which will consist of firmware OTA file creation and use of preferred storage mode (QSPI or SD card).

Firmware OTA File Creation

We will create the binary file required for the OTA (Over-The-Air) process to be able to be used with either storage option stated previously. For the purpose of this tutorial, we will use the following script to create the binary file.

1/*
2 This sketch can be used to generate an example binary that can be uploaded to Portenta via OTA.
3 It needs to be used together with
4 - 'OTA_Qspi_Flash.ino' if you want to use the Qspi Flash as storage system
5 OR
6 - 'SD_Qspi_Flash.ino' if you want to use the SD card as storage system
7
8 Steps to test OTA on Portenta:
9 1) Upload this sketch or any other sketch (this one lights up the RGB LED with different colours).
10 2) In the IDE select: Sketch -> Export compiled Binary
11 3) Upload the exported binary to a server
12 4) Choose a storage mechanism (SD or QSPI), open the related OTA_*_Portenta.ino sketch,
13 eventually update the OTA_FILE_LOCATION
14 5) Upload the sketch OTA_*_Portenta.ino to perform OTA via SD or QSPI Flash
15*/
16
17void setLed(int blue, int green, int red) {
18 digitalWrite(LEDB, blue);
19 digitalWrite(LEDG, green);
20 digitalWrite(LEDR, red);
21}
22
23
24void setup()
25{
26 pinMode(LEDB, OUTPUT);
27 pinMode(LEDG, OUTPUT);
28 pinMode(LEDR, OUTPUT);
29}
30
31void loop()
32{ //led BLUE ON
33 setLed(1, 0, 0);
34 delay(1000);
35 //led GREEN ON
36 setLed(0, 1, 0);
37 delay(1000);
38 //led RED ON
39 setLed(0, 0, 1);
40 delay(1000);
41}

This script will light up the RGB LED with 3 different colors in sequence. This code will need to be uploaded to the Arduino Portenta H7 firsthand. This is to verify the sketch compiles and is working correctly. After verifying this, in Arduino IDE, you will search for Sketch > Export Compiled Binary.

Exporting Binary for the Sketch
Exporting Binary for the Sketch

With the binary file created, we can now create the ota file needed to complete the process. For this, you will need to have an extra tool which can be found at the following link.

Arduino IoT Cloud Library - Over-The-Air Tools: https://github.com/arduino-libraries/ArduinoIoTCloud/tree/master/extras/tools

You will have to have to extract the library at a preferred location to be able to use the tools. Then you will need to run on the terminal following commands in sequence to be able to create the ota file.

Copy the binary file into the library tool's folder

1// Mac/Linux
2cp OTA_Usage_Portenta.ino.PORTENTA_H7_M7.bin ~/Arduino/libraries/ArduinoIoTCloud/extras/tools/
3
4// Windows
5copy OTA_Usage_Portenta.ino.PORTENTA_H7_M7.bin <userPath>/Documents/Arduino/libraries/ArduinoIoTCloud/extras/tools/

Go inside that directory

1// Mac/Linux
2cd ~/Arduino/libraries/ArduinoIoTCloud/extras/tools
3
4// Windows
5cd <yourUserPath>/Documents/Arduino/libraries/ArduinoIoTCloud/extras/tools

Encode your binary file into

OTA_Usage_Portenta.ino.PORTENTA_H7_M7.lzss

1// Mac/Linux
2./lzss.py --encode OTA_Usage_Portenta.ino.PORTENTA_H7_M7.bin OTA_Usage_Portenta.ino.PORTENTA_H7_M7.lzss
3
4// Windows
5lzss.py --encode OTA_Usage_Portenta.ino.PORTENTA_H7_M7.bin OTA_Usage_Portenta.ino.PORTENTA_H7_M7.lzss

Convert your encoded file into

.ota
format

1// Mac/Linux
2./bin2ota.py [PORTENTA_H7_M7] OTA_Usage_Portenta.ino.PORTENTA_H7_M7.lzss OTA_Usage_Portenta.ino.PORTENTA_H7_M7.ota
3
4// Windows
5bin2ota.py [PORTENTA_H7_M7] OTA_Usage_Portenta.ino.PORTENTA_H7_M7.lzss OTA_Usage_Portenta.ino.PORTENTA_H7_M7.ota

We are using

OTA_Usage_Portenta.ino.PORTENTA_H7_M7
as a sketch name and for facilitated identification of the file. After this you will have the
.ota
file of the sketch that we would like to use with the OTA process.

Now you have two options to choose, use QSPI, or use an SD Card to storage your OTA file. You can use the left side index to jump to the option that you may need.

QSPI Storage Mode

Setting Up

To use internal QSPI storage for downloading the binary file via OTA (Over-The-Air), you will only need the Arduino Portenta H7 board connected to the computer with the Arduino IDE. With it, you will need to have selected the Arduino Portenta H7 (M7 Core) with the Flash split of 1MB M7 + 1MB M4 for the purpose of this tutorial and the corresponding port.

Arduino Portenta H7 Board Connection
Arduino Portenta H7 Board Connection

Writing the Script

To proceed with a OTA using the QSPI flash, you can open the sketch from Examples >Arduino_Portenta_OTA > OTA_Qspi_Flash.

Do not forget to fill your Wi-Fi AP SSID, and password on the

arduino_secrets.h
tab.

This sketch will connect to your Wi-Fi, check if the OTA feature is available by checking the installed firmware on your Portenta.

Then prepare the OTA storage, download the .ota file from the internet, decompress it, reset the board so after the reboot it will swipe the new firmware, and you will notice it by checking the Built-in LED flashing on red, green and blue.

SD Card Storage Mode

Setting Up

To use the SD card as the preferred OTA (Over-The-Air) storage device, we will use the Arduino Portenta Vision Shield and Portenta H7 connected via HD (High-Density) Connectors.

Arduino Portenta H7 with Vision Shield (Ethernet)

With this, you will need the Arduino Portenta H7 board connected to the computer with the Arduino IDE. You will need to have selected the Arduino Portenta H7 (M7 Core) with the Flash split of 1MB M7 + 1MB M4 for the purpose of this tutorial and the corresponding port.

Writing the Script

As same as QSPI storage mode, to proceed with a OTA using the SD Card, you can open the sketch from Examples > Arduino_Portenta_OTA > OTA_SD_Portenta.

Do not forget to fill your Wi-Fi AP SSID, and password on the

arduino_secrets.h
tab.

This sketch will connect to your Wi-Fi, check if the OTA feature is available by checking the installed firmware on your Portenta.

Then prepare the OTA storage, download the .ota file from the internet, decompress it, reset the board so after the reboot it will swipe the new firmware, and you will notice it by checking the Built-in LED flashing on red, green and blue.

Testing the Code

Having successfully uploaded the code and completed the OTA process, you will be able to see the Arduino Portenta H7 blinking LED with Red, Blue, Green in a cyclic manner. You will also be able to see in the Serial monitor provided by Arduino IDE process log for more details.

Arduino Portenta H7 OTA Completion with Cyclic RGB Blink

Arduino Portenta H7 OTA QSPI Serial Monitor Log
Arduino Portenta H7 OTA QSPI Serial Monitor Log

Arduino Portenta H7 OTA SD Card Serial Monitor Log
Arduino Portenta H7 OTA SD Card Serial Monitor Log

Conclusion

You have now learned how to use the OTA feature provided by the Arduino Portenta H7, by updating its firmware. You will now be able to create the OTA file with the sketch designed by yourself, and use this to update Arduino Portenta H7’s firmware via OTA (Over-The-Air) feature with either QSPI or SD card storage mechanism.

Next Steps

Now with the OTA capability in place, you can now design future-proof system based on Arduino Portenta H7 or try different system disciplines using the OTA capability.

Full Sketches

The complete script is as follows.

QSPI Storage Mode

1#include <Arduino_Portenta_OTA.h>
2#include <WiFi.h>
3#include "arduino_secrets.h"
4
5static char const SSID[] = SSID_NAME; /* your network SSID (name) */
6static char const PASS[] = SSID_PASS; /* your network password (use for WPA, or use as key for WEP) */
7
8static char const OTA_FILE_LOCATION[] = "http://downloads.arduino.cc/ota/OTA_Usage_Portenta.ino.PORTENTA_H7_M7.ota";
9
10void setup()
11{
12 Serial.begin(115200);
13 while (!Serial) {}
14
15 if (WiFi.status() == WL_NO_SHIELD)
16 {
17 Serial.println("Communication with WiFi module failed!");
18 return;
19 }
20
21 int status = WL_IDLE_STATUS;
22 while (status != WL_CONNECTED)
23 {
24 Serial.print ("Attempting to connect to '");
25 Serial.print (SSID);
26 Serial.println("'");
27 status = WiFi.begin(SSID, PASS);
28 delay(10000);
29 }
30 Serial.print ("You're connected to '");
31 Serial.print (WiFi.SSID());
32 Serial.println("'");
33
34 Arduino_Portenta_OTA_QSPI ota(QSPI_FLASH_FATFS_MBR, 2);
35 Arduino_Portenta_OTA::Error ota_err = Arduino_Portenta_OTA::Error::None;
36
37 if (!ota.isOtaCapable())
38 {
39 Serial.println("Higher version bootloader required to perform OTA.");
40 Serial.println("Please update the bootloader.");
41 Serial.println("File -> Examples -> STM32H747_System -> STM32H747_updateBootloader");
42 return;
43 }
44
45 Serial.println("Initializing OTA storage");
46 if ((ota_err = ota.begin()) != Arduino_Portenta_OTA::Error::None)
47 {
48 Serial.print ("Arduino_Portenta_OTA::begin() failed with error code ");
49 Serial.println((int)ota_err);
50 return;
51 }
52
53 Serial.println("Starting download to QSPI ...");
54 int const ota_download = ota.download(OTA_FILE_LOCATION, false /* is_https */);
55 if (ota_download <= 0)
56 {
57 Serial.print ("Arduino_Portenta_OTA_QSPI::download failed with error code ");
58 Serial.println(ota_download);
59 return;
60 }
61 Serial.print (ota_download);
62 Serial.println(" bytes stored.");
63
64
65 Serial.println("Decompressing LZSS compressed file ...");
66 int const ota_decompress = ota.decompress();
67 if (ota_decompress < 0)
68 {
69 Serial.print("Arduino_Portenta_OTA_QSPI::decompress() failed with error code");
70 Serial.println(ota_decompress);
71 return;
72 }
73 Serial.print(ota_decompress);
74 Serial.println(" bytes decompressed.");
75
76
77 Serial.println("Storing parameters for firmware update in bootloader accessible non-volatile memory ...");
78 if ((ota_err = ota.update()) != Arduino_Portenta_OTA::Error::None)
79 {
80 Serial.print ("ota.update() failed with error code ");
81 Serial.println((int)ota_err);
82 return;
83 }
84
85 Serial.println("Performing a reset after which the bootloader will update the firmware.");
86 Serial.println("Hint: Portenta H7 LED will blink Red-Blue-Green.");
87 delay(1000); /* Make sure the serial message gets out before the reset. */
88 ota.reset();
89}
90
91void loop()
92{
93}

SD Card Storage Mode

1#include <Arduino_Portenta_OTA.h>
2#include <WiFi.h>
3#include "arduino_secrets.h"
4
5static char const SSID[] = SSID_NAME; /* your network SSID (name) */
6static char const PASS[] = SSID_PASS; /* your network password (use for WPA, or use as key for WEP) */
7
8static char const OTA_FILE_LOCATION[] = "http://downloads.arduino.cc/ota/OTA_Usage_Portenta.ino.PORTENTA_H7_M7.ota";
9
10void setup()
11{
12 Serial.begin(115200);
13 while (!Serial) {}
14
15 if (WiFi.status() == WL_NO_SHIELD)
16 {
17 Serial.println("Communication with WiFi module failed!");
18 return;
19 }
20
21 int status = WL_IDLE_STATUS;
22 while (status != WL_CONNECTED)
23 {
24 Serial.print ("Attempting to connect to '");
25 Serial.print (SSID);
26 Serial.println("'");
27 status = WiFi.begin(SSID, PASS);
28 delay(10000);
29 }
30 Serial.print ("You're connected to '");
31 Serial.print (WiFi.SSID());
32 Serial.println("'");
33
34 Arduino_Portenta_OTA_SD ota(SD_FATFS_MBR, 1);
35 Arduino_Portenta_OTA::Error ota_err = Arduino_Portenta_OTA::Error::None;
36
37 if (!ota.isOtaCapable())
38 {
39 Serial.println("Higher version bootloader required to perform OTA.");
40 Serial.println("Please update the bootloader.");
41 Serial.println("File -> Examples -> STM32H747_System -> STM32H747_updateBootloader ");
42 return;
43 }
44
45 Serial.println("Initializing OTA storage");
46 if ((ota_err = ota.begin()) != Arduino_Portenta_OTA::Error::None)
47 {
48 Serial.print ("Arduino_Portenta_OTA::begin() failed with error code ");
49 Serial.println((int)ota_err);
50 return;
51 }
52
53
54 Serial.println("Starting download to SD ...");
55 int const ota_download = ota.download(OTA_FILE_LOCATION, false /* is_https */);
56 if (ota_download <= 0)
57 {
58 Serial.print ("Arduino_Portenta_OTA_SD::download failed with error code ");
59 Serial.println(ota_download);
60 return;
61 }
62 Serial.print (ota_download);
63 Serial.println(" bytes stored.");
64
65
66 Serial.println("Decompressing LZSS compressed file ...");
67 int const ota_decompress = ota.decompress();
68 if (ota_decompress < 0)
69 {
70 Serial.print("Arduino_Portenta_OTA_SD::decompress() failed with error code");
71 Serial.println(ota_decompress);
72 return;
73 }
74 Serial.print(ota_decompress);
75 Serial.println(" bytes decompressed.");
76
77
78 Serial.println("Storing parameters for firmware update in bootloader accessible non-volatile memory");
79 if ((ota_err = ota.update()) != Arduino_Portenta_OTA::Error::None)
80 {
81 Serial.print ("Arduino_Portenta_OTA::update() failed with error code ");
82 Serial.println((int)ota_err);
83 return;
84 }
85
86 Serial.println("Performing a reset after which the bootloader will update the firmware.");
87 Serial.println("Hint: Portenta H7 LED will blink Red-Blue-Green.");
88 delay(1000);
89 ota.reset();
90}
91
92void loop()
93{
94}

Troubleshooting

For troubleshooting the issues that might have arose following the tutorial, you can use following tips to solve the issue.

  • If it logs there has been an issue with Wi-Fi module, means the device may have suffered from losing the Wi-Fi firmware partition. To solve this, you will have to use PortentaWiFiFirmwareupdater sketch found on Arduino IDE examples to fix the issue.
  • QSPI storage may throw error -3 while running Portenta H7 OTA QSPI example. To fix this you can use this guide of Reading and Writing Flash Memory in the section Programming the QSPI Flash. After this, run the example and it should have been solved by eliminating error -3 (OTA Storage initialization error).

Contribute to Arduino

Join the community and suggest improvements to this article via GitHub. Make sure to read out contribution policy before making your pull request.

Missing something?

Check out our store and get what you need to follow this tutorial.

Suggest Changes

The content on docs.arduino.cc is facilitated through a public GitHub repository. You can read more on how to contribute in the contribution policy.