Skip to content

Commit f679bde

Browse files
committed
Tutorial documentation update
1 parent 79b1bb5 commit f679bde

File tree

3 files changed

+233
-17
lines changed

3 files changed

+233
-17
lines changed
-39.1 KB
Loading
34.9 KB
Loading

content/hardware/04.pro/boards/portenta-h7/tutorials/over-the-air-update/content.md

Lines changed: 233 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ difficulty: intermediate
55
tags:
66
- OTA
77
- Over-The-Air
8-
- Wi-Fi
8+
- Wi-Fi®
99
- Cloud
1010
author: 'Taddy Chung, José Bagur'
1111
libraries:
@@ -38,9 +38,9 @@ The goals of this tutorial are:
3838
## Hardware and Software Needed
3939

4040
- [Arduino Portenta H7](https://store.arduino.cc/portenta-h7)
41-
- Operating System: Linux, macOS, or Windows (with Python 3 installed)
41+
- Operating System: Linux, macOS, or Windows (with Python® 3 installed)
4242
- Arduino IDE 1.8.10+ or Arduino IDE 2.0+
43-
- USB-C® cable (either USB-A to USB-C® or USB-C® to USB-C®)
43+
- USB-C® cable (either USB-A to USB-C or USB-C to USB-C)
4444
- [Arduino_Portenta_OTA library](https://github.com/arduino-libraries/Arduino_Portenta_OTA)
4545
- SD card (optional, you can use QSPI instead)
4646
- Carrier or shield compatible with the Portenta H7 with an SD card slot (if using SD card method)
@@ -101,15 +101,15 @@ void loop()
101101
}
102102
```
103103
104-
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 first. This is to verify whether the sketch compiles and works correctly. After verifying this, in the Arduino IDE, you will search for **Sketch > Export Compiled Binary**.
104+
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 first. This is to verify whether the sketch compiles and works correctly. After verifying this, in the Arduino IDE, navigate to **Sketch > Export Compiled Binary** (or use the keyboard shortcut **Alt+Ctrl+S**).
105105
106106
![Exporting Binary for the Sketch](assets/binary_export.png)
107107
108108
With the binary file ready, you can now create the OTA file needed to enable the Over-The-Air process.
109109
110110
### Creating the OTA File
111111
112-
To create the OTA file, you will need a macOS, Linux, or Windows environment with Python 3 installed.
112+
To create the OTA file, you will need a macOS, Linux, or Windows environment with Python® 3 installed.
113113
114114
Once you have a compatible environment, you will need the tools which can be found at the following link:
115115
@@ -146,24 +146,24 @@ Convert your encoded file into `.ota` format
146146

147147
You can use `OTA_Usage_Portenta.ino.PORTENTA_H7_M7` as a sketch name for easier identification of the file. After this, you will have the `.ota` file of the sketch that you will use with the OTA process.
148148

149-
### Installing Python 3 On Linux
149+
### Installing Python® 3 On Linux
150150

151-
If you are using Linux and cannot run the **`bin2ota.py`** script, you may need to install [Python 3](https://www.python.org/) and the necessary modules. To do this, execute the following command on your **Linux terminal**:
151+
If you are using Linux and cannot run the **`bin2ota.py`** script, you may need to install [Python® 3](https://www.python.org/) and the necessary modules. To do this, execute the following command on your **Linux terminal**:
152152

153153
```bash
154154
sudo apt install python-is-python3
155155
```
156156

157-
You will also need to install the **`crccheck`** module for Python by following these instructions:
157+
You will also need to install the **`crccheck`** module for Python® by following these instructions:
158158

159-
Installing pip on python:
159+
Installing pip on Python®:
160160

161161
```bash
162162
//Necessary to install python modules:
163163
sudo apt install python3-pip
164164
```
165165

166-
Installing the `crccheck` necessary module on python:
166+
Installing the `crccheck` necessary module on Python®:
167167

168168
```bash
169169
//Necessary to run the script:
@@ -206,17 +206,24 @@ If you are going to use the example OTA file provided in this tutorial, you don'
206206

207207
#### Setting Up
208208

209-
To use the 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](https://www.arduino.cc/en/software). You will need to select the **Arduino Portenta H7 (M7 Core)** with the Flash split of **1 MB M7 + 1 MB M4** for the purpose of this tutorial and the corresponding port.
209+
To use the 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](https://www.arduino.cc/en/software).
210+
211+
Before uploading the OTA sketch, configure the following settings in the Arduino IDE via the **Tools** menu:
212+
213+
- **Board**: Select `Arduino Portenta H7`
214+
- **Flash split**: Select `1MB M7 + 1MB M4`
215+
- **Target core**: Select `Main Core` (M7 core)
216+
- **Port**: Select the appropriate COM port for your Portenta H7
210217

211218
![Arduino Portenta H7 Board Connection](assets/portenta_h7_board_selection.png)
212219

213220
#### Writing the Script
214221

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

217-
***Do not forget to fill in your Wi-Fi AP SSID and password in the `arduino_secrets.h` tab.***
224+
***Do not forget to fill in your Wi-Fi® AP SSID and password in the `arduino_secrets.h` tab.***
218225

219-
This sketch will connect to your Wi-Fi, verify whether the OTA feature is available by checking the installed firmware on your Portenta.
226+
This sketch will connect to your Wi-Fi®, verify whether the OTA feature is available by checking the installed firmware on your Portenta.
220227

221228
Then prepare the OTA storage, download the .ota file from the internet, decompress it, reset the board so that after the reboot, it will apply the new firmware
222229

@@ -228,15 +235,20 @@ To use the **SD card** as the preferred OTA (Over-The-Air) storage device, you c
228235

229236
![Arduino Portenta H7 with Portenta Vision Shield - Ethernet](assets/portenta_h7_plus_vision_shield.svg)
230237

231-
You will need to select the **Arduino Portenta H7 (M7 Core)** with the Flash split of **1 MB M7 + 1 MB M4** for the purpose of this tutorial and the corresponding port.
238+
Before uploading the OTA sketch, configure the following settings in the Arduino IDE via the **Tools** menu:
239+
240+
- **Board**: Select `Arduino Portenta H7`
241+
- **Flash split**: Select `1MB M7 + 1MB M4`
242+
- **Target core**: Select `Main Core` (M7 core)
243+
- **Port**: Select the appropriate COM port for your Portenta H7
232244

233245
#### Writing the Script
234246

235247
Similar to the QSPI storage mode, to proceed with OTA using the SD Card, you can open the sketch from **Examples > Arduino_Portenta_OTA > OTA_SD_Portenta**.
236248

237-
***Do not forget to fill in your Wi-Fi AP SSID and password in the `arduino_secrets.h` tab.***
249+
***Do not forget to fill in your Wi-Fi® AP SSID and password in the `arduino_secrets.h` tab.***
238250

239-
This sketch will connect to your Wi-Fi, verify whether the OTA feature is available by checking the installed firmware on your Portenta.
251+
This sketch will connect to your Wi-Fi®, verify whether the OTA feature is available by checking the installed firmware on your Portenta.
240252

241253
Then prepare the OTA storage, download the .ota file from the internet, decompress it, reset the board so that after the reboot, it will apply the new firmware
242254

@@ -537,9 +549,213 @@ void loop()
537549
}
538550
```
539551

552+
## Understanding LZSS Compression and Decompression
553+
554+
For those interested in the underlying compression mechanism or optimizing download performance, you can explore different decompression methods.
555+
556+
The standard OTA examples use a two-step process:
557+
558+
1. Download the compressed `.ota` file to storage
559+
2. Decompress the file before firmware update
560+
561+
However, the `Arduino_Portenta_OTA` library also supports **on-the-fly decompression**, where the file is decompressed as it's being downloaded, which can be more efficient for certain use cases.
562+
563+
The following example shows both methods and allows you to compare their performance:
564+
565+
```cpp
566+
/*
567+
* This example demonstrates how to download a lzss file and decompress it in two ways:
568+
* -1 download the file on the filesystem and then decompress the downloaded file on the filesystem
569+
* -2 download and decompress the file on the fly
570+
* this sketch also provides a comparison in terms of speed and execution time
571+
*
572+
*/
573+
574+
/******************************************************************************
575+
* INCLUDE
576+
******************************************************************************/
577+
578+
#include <Arduino_Portenta_OTA.h>
579+
580+
#include <WiFi.h>
581+
582+
#include "arduino_secrets.h"
583+
#include <decompress/lzss.h>
584+
585+
/******************************************************************************
586+
* CONSTANT
587+
******************************************************************************/
588+
589+
/* Please enter your sensitive data in the Secret tab/arduino_secrets.h */
590+
static char const SSID[] = SECRET_SSID; /* your network SSID (name) */
591+
static char const PASS[] = SECRET_PASS; /* your network password (use for WPA, or use as key for WEP) */
592+
593+
594+
#if defined(ARDUINO_NICLA_VISION)
595+
static char const URL_FILE[] = "https://downloads.arduino.cc/ota/OTA_Usage_Portenta.ino.NICLA_VISION.ota";
596+
#elif defined(ARDUINO_PORTENTA_H7_M7)
597+
static char const URL_FILE[] = "https://downloads.arduino.cc/ota/OTA_Usage_Portenta.ino.PORTENTA_H7_M7.ota";
598+
#elif defined(ARDUINO_OPTA)
599+
static char const URL_FILE[] = "https://downloads.arduino.cc/ota/OTA_Usage_Portenta.ino.OPTA.ota";
600+
#elif defined(ARDUINO_GIGA)
601+
static char const URL_FILE[] = "https://downloads.arduino.cc/ota/OTA_Usage_Portenta.ino.GIGA.ota";
602+
#else
603+
#error "Board not supported"
604+
#endif
605+
606+
static char const DOWNLOAD_DESTINATION[] = "/fs/UPDATE.BIN.LZSS";
607+
static char const DECOMPRESSED_DESTINATION[] = "/fs/UPDATE.BIN";
608+
609+
LZSSDecoder *decoder = nullptr;
610+
FILE* download_target = nullptr;
611+
612+
/******************************************************************************
613+
* SETUP/LOOP
614+
******************************************************************************/
615+
void decompress_on_the_fly_cbk(const char*, uint32_t);
616+
void putc_file(const uint8_t c);
617+
618+
void setup() {
619+
Serial.begin(115200);
620+
while (!Serial) {}
621+
622+
if (WiFi.status() == WL_NO_SHIELD)
623+
{
624+
Serial.println("Communication with WiFi module failed!");
625+
return;
626+
}
627+
628+
int status = WL_IDLE_STATUS;
629+
while (status != WL_CONNECTED)
630+
{
631+
Serial.print ("Attempting to connect to '");
632+
Serial.print (SSID);
633+
Serial.println("'");
634+
status = WiFi.begin(SSID, PASS);
635+
if(status != WL_CONNECTED) {
636+
delay(10000);
637+
}
638+
}
639+
Serial.print ("You're connected to '");
640+
Serial.print (WiFi.SSID());
641+
Serial.println("'");
642+
643+
// Init fs
644+
mbed::BlockDevice * _bd_raw_qspi = mbed::BlockDevice::get_default_instance();;
645+
auto _bd_qspi = new mbed::MBRBlockDevice(_bd_raw_qspi, 2);
646+
auto _fs_qspi = new mbed::FATFileSystem("fs");
647+
int const err_mount = _fs_qspi->mount(_bd_qspi);
648+
if (err_mount) {
649+
Serial.print("Error while mounting the filesystem. Err = ");
650+
Serial.println(err_mount);
651+
return;
652+
}
653+
654+
MbedSocketClass * socket = static_cast<MbedSocketClass*>(&WiFi);
655+
remove(DOWNLOAD_DESTINATION);
656+
remove(DECOMPRESSED_DESTINATION);
657+
658+
uint32_t start;
659+
int bytes;
660+
float elapsed, speed;
661+
start = millis();
662+
Serial.println("Starting download to QSPI ...");
663+
bytes = socket->download(URL_FILE, DOWNLOAD_DESTINATION, true /* is_https */);
664+
if (bytes <= 0)
665+
{
666+
Serial.print ("MbedSocketClass::download failed with error code ");
667+
Serial.println(bytes);
668+
return;
669+
}
670+
Serial.print (bytes);
671+
Serial.println(" bytes stored.");
672+
673+
elapsed = (millis()-start)/1000.0; // elapsed expressed in seconds
674+
speed = (bytes/elapsed)/1024;
675+
676+
Serial.print("download elapsed ");
677+
Serial.print(elapsed);
678+
Serial.print("s speed: ");
679+
Serial.print(speed);
680+
Serial.println("KBps");
681+
682+
FILE* downloaded_file = fopen(DOWNLOAD_DESTINATION, "rb");
683+
FILE* decompressed_file = fopen(DECOMPRESSED_DESTINATION, "wb");
684+
685+
start = millis();
686+
lzss_init(downloaded_file, decompressed_file, bytes, nullptr);
687+
688+
lzss_decode();
689+
/* Write the data remaining in the write buffer to
690+
* the file.
691+
*/
692+
lzss_flush();
693+
694+
elapsed = (millis()-start)/1000.0; // elapsed expressed in seconds
695+
696+
Serial.print("decompress elapsed ");
697+
Serial.print(elapsed);
698+
Serial.print("s");
699+
Serial.print(" size ");
700+
Serial.println(ftell(decompressed_file));
701+
702+
fclose(downloaded_file);
703+
fclose(decompressed_file);
704+
705+
// On the fly decompression
706+
remove(DOWNLOAD_DESTINATION);
707+
remove(DECOMPRESSED_DESTINATION);
708+
709+
download_target = fopen(DECOMPRESSED_DESTINATION, "wb");
710+
decoder = new LZSSDecoder(putc_file);
711+
712+
Serial.println("Starting download & decompress on the fly");
713+
start = millis();
714+
bytes = socket->download(URL_FILE, true /* is_https */, decompress_on_the_fly_cbk);
715+
if (bytes <= 0)
716+
{
717+
Serial.print ("MbedSocketClass::download failed with error code ");
718+
Serial.println(bytes);
719+
return;
720+
}
721+
722+
Serial.print("downloaded ");
723+
Serial.print(bytes);
724+
Serial.print(" bytes ");
725+
726+
elapsed = (millis()-start)/1000.0; // elapsed expressed in seconds
727+
speed = (bytes/elapsed)/1024;
728+
729+
Serial.print (ftell(download_target));
730+
Serial.println(" bytes stored.");
731+
732+
Serial.print("download elapsed ");
733+
Serial.print(elapsed);
734+
Serial.print("s speed: ");
735+
Serial.print(speed);
736+
Serial.println("KBps");
737+
738+
delete decoder;
739+
fclose(download_target);
740+
}
741+
742+
void loop() {
743+
}
744+
745+
void decompress_on_the_fly_cbk(const char* buffer, uint32_t size) {
746+
decoder->decompress((uint8_t*)buffer, size);
747+
}
748+
749+
void putc_file(const uint8_t c) {
750+
fwrite(&c, 1, 1, download_target);
751+
}
752+
753+
754+
```
755+
540756
## Troubleshooting
541757
542758
For troubleshooting issues that might have arisen while following the tutorial, you can use the following tips to solve the issue.
543759
544-
- If there has been an issue with the Wi-Fi module, it means the device may have lost the Wi-Fi firmware partition. To solve this, you will have to use the **WiFiFirmwareUpdater** sketch found in the Arduino IDE examples to fix the issue.
760+
- If there has been an issue with the Wi-Fi® module, it means the device may have lost the Wi-Fi® firmware partition. To solve this, you will have to use the **WiFiFirmwareUpdater** sketch found in the Arduino IDE examples to fix the issue.
545761
- QSPI storage may throw error -3 while running the Portenta H7 OTA QSPI example. To fix this, you can use the guide on [Reading and Writing Flash Memory](https://docs.arduino.cc/tutorials/portenta-h7/reading-writing-flash-memory) in the section **Programming the QSPI Flash**. At this point, run the example again, and the error -3 (OTA Storage initialization error) should be resolved.

0 commit comments

Comments
 (0)