RoadTest: Arduino Portenta H7 Development Board
Author: salmanfarisvp
Creation date:
Evaluation Type: Development Boards & Tools
Did you receive all parts the manufacturer stated would be included in the package?: True
What other parts do you consider comparable to this product?: TM32 Nucleo-144 STM32H7A3ZI Cortex-M7 Development Board, Teensy 4.1 Development Board, ESP32.
What were the biggest problems encountered?: Finding materials for utilizing CPU power.
Detailed Review:
Arduino has a new variant of tools called "Pro", which specially for industrial applications where they need more computing/CPU power, connectivity overall need a robust system, unlike other Arduino dev boards this one is meant for high fidelity applications. Pro is a great platform if you want to scale your prototype into the product level, and it includes hardware, firmware, connectivity, dashboard, data visualizations, algorithms and connection to the existing business logic.
The Arduino Portenta H7 is part of the Arduino’s series of high-performance industry-rated boards, which have two asymmetric cores to simultaneously run high-level code such as protocol stacks, machine learning or even interpreted languages like MicroPython or JavaScript along with low-level real-time tasks. It can either be running like any other embedded microcontroller board or as the main processor of an embedded computer. Portenta can easily run processes created with TensorFlow™ Lite, you could have one of the cores computing a computer vision algorithm on the fly, while the other could be making low-level operations like controlling a motor, or acting as a user interface.
Some of the possible Portenta application are:
Two Parallel Cores:
H7's main processor is the dual-core STM32H747 including a Cortex® M7 running at 480 MHz and a Cortex® M4 running at 240 MHz. The two cores communicate via a Remote Procedure Call mechanism that allows calling functions on the other processor seamlessly. Both processors share all the on-chip peripherals and can run:
Graphics Accelerator
Probably one of the most exciting features of the Portenta H7 is the possibility of connecting an external monitor to build your own dedicated embedded computer with a user interface. This is possible thanks to the STM32H747 processor's on-chip GPU, the Chrom-ART Accelerator™. Besides the GPU, the chip includes a dedicated JPEG encoder and decoder.
A new standard for pinouts
The Portenta family adds two 80 pin high-density connectors at the bottom of the board. This ensures scalability for a wide range of applications by simply upgrading your Portenta board to the one suiting your needs.
On-Board Connectivity
The onboard wireless module allows to simultaneously manage WiFi and Bluetooth® connectivity. The WiFi interface can be operated as an Access Point, as a Station or as a dual-mode simultaneous AP/STA and can handle up to 65 Mbps transfer rate. Bluetooth® interface supports Bluetooth Classic and BLE. It is also possible to expose a series of different wired interfaces like UART, SPI, Ethernet, or I2C, both through some of the MKR styled connectors, or through the new Arduino industrial 80 pin connector pair
USB-C Multipurpose Connector
The board's programming connector is a USB-C port that can also be used to power the board, as a USB Hub, to connect a DisplayPort monitor, or to deliver power to OTG connected devices.
Multiple options in one board
The default Arduino Portenta H7 (codename H7-15EUNWAD) that comes with:
The Portenta H7 is equipped with two Arm Cortex ST processors (Cortex-M4 and Cortex-M7) which run the Mbed OS. Mbed OS is an embedded real-time operating system (RTOS) designed specifically for microcontrollers to run IoT applications on low power. The Arduino core for the Portenta H7 sits on top of the Mbed OS and allows to develop applications using Mbed OS APIs which handle for example storage, connectivity, security and another hardware interfacing.
The Portenta H7 follows the Arduino MKR form factor but enhanced with the Portenta family 80 pin high-density connector. Learn more about the board's pinout by reading the board's pinout documentation.
Portenta comes with a
The I2C port, also referred to as the Eslov self-identification port within Arduino, comes with SDA, SCL, GND, +5V, and an extra digital pin meant to send an alarm to the otherwise plain I2C devices connected to it. The pinout is shown in the following image:
Getting Started
In the box, 1x Arduino portenta H7, 1x external antenna, 1x papper docuement.
note that, the portenta comes without the header pins, I soldered it my self for ease of use,
There is an Arduino official page, that includes all the setup instructions. https://www.arduino.cc/pro/tutorials/portenta-h7
When I receive new hardware, I'll try to run the hello world program a.k.a blink, since there is many programming platform support, I started from officially mentioned Arduino IOT Cloud IDE.
Started with IOT Cloud.
The website is very minimal and easy to find information.
These are the IoT Cloud supporting platforms. Src: https://www.arduino.cc/en/IoT/HomePage
as mentioned on the page, I tried to program the board. first, we need to flash the IoT cloud bootloader and we need to install an extension to the community the web page to Arduino.
It was easy to connect, first, we just need to select the board from the list.
After that, we need to connect the portenta to a computer over the USB C to USB -A port, then we need to install the Arduino IOT cloud plugin in the computer.
After that, the webpage will try to upload the sketch to Arduino, then immediately it shows on the dashboard.
I complied a blink sketch, but the upload failed.
it showing there is a plugin connection, even though I installed the plugin and restarted the browser.
but after compilation, I couldn't upload the sketch to Arduino, the communication is not establishing, I tried to restart the browser, restart the computer ..etc, but no luck.
I tried to upload the sketch with the https://create.arduino.cc/ , but after the compilation, I couldn't find the port.
update: After re-installing the plugin, The Web IDE is working fie.
After that, I tried the normal Arduino IDE, and it's worked well.
In the Arduino ide, when we install the portenta board manager, it comes with some useful libraries.
I tried the bootloader info sketch from the example menu.
I'll try to run simultaneously on different cores of the Portenta board that blinks the RGB LED in two different colours based on the official tutorial.
Cortex® M7 & M4
The on-board Arm Cortex processor comes with two cores (Cortex® M7 and M4), with slightly different architectures and clock speeds. The M7 runs at 480 MHz and the architecture is designed to separate Instruction and Data buses to optimize CPU latency.
The M4 runs at 240 MHz and the architecture supports the ART™ accelerator (a block that speeds up instruction fetching accesses of the Cortex-M4 core to the D1-domain internal memories). The higher clock rate of the M7 makes it suitable to handle complex processing tasks such as data storage, debugging or handling input/output peripherals at a higher efficiency compared to the M4.
The dual-core processor of the Portenta H7 sets it apart from other single-core Arduino boards by allowing true multitasking, faster data processing capabilities, enhanced processing power and application partitioning.
The blink_RedLed_m7.ino sketch will set the built-in RGB LED on the board to read and blink it with a delay of 500 ms. The blink_GreenLed_M4.ino sketch will access the green LED in the RGB led and blink it with a delay of 200 ms. Both the cores will be executing the corresponding sketch file simultaneously and as a result, both the green and red LED blink, however, at different intervals.
We can also combine these two sketch files into one by taking advantage of the preprocessor directives '#ifdef'. This way you can program different behaviours for both cores by using the same program.
int myLED; void setup() { randomSeed(analogRead(0)); #ifdef CORE_CM7 bootM4(); myLED = LEDB; // built-in blue LED #endif #ifdef CORE_CM4 myLED = LEDG; // built-in greeen LED #endif pinMode(myLED, OUTPUT); } void loop() { digitalWrite(myLED, LOW); // turn the LED on delay(200); digitalWrite(myLED, HIGH); // turn the LED off delay( rand() % 2000 + 1000); // wait for a random amount of time between 1 and 3 seconds. }
WiFi Networking - Portenta H7 as a WiFi Access Point
Portenta H7 comes with an on-board WiFi and a Bluetooth Module that allows developing IoT applications that require wireless connectivity and Internet access.
The Portenta H7 features a Murata 1DX, which is a high-performance chipset which supports WiFi 802.11b/g/n + Bluetooth 5.1 BR/EDR/LE up to 65Mbps PHY data rate on WiFi and 3Mbps PHY data rate on Bluetooth. This module helps to configure the Portenta into three different modes of operation - an Access Point, a Station, or both. In this tutorial, we will only focus on the access point configuration.
When the board is configured to operate as an access point, it can create its own wireless LAN ( WLAN ) network. In this mode, the board transmits and receives signals at 2.4 GHz allowing other electronic devices with WiFi capabilities using the same bandwidth to connect to the board.
in order to use the wifi capability, we need to flash the wifi firmware first to do that, we need to upload PortentaWiFiFirmwareUpdater.info
Web Server Example
Here the sketch will make Arduino as a web server and serve a basic webpage, will web page is just a simple HTML page with buttons to toggle the LED states. The way in which the web page works is: Whenever a button on the web page is pressed, the client device (in this case your phone) sends a HTTP GET request to a URL denoted by a letter, in this case H or L (H stands for HIGH, L stands for LOW) followed by the LED color that should be turned on or off r, g or b. For example to turn on the red LED the URL is /Hr . Once the server receives this request it changes the corresponding LED state, closes the connection and continues to listen to next requests.
#include <WiFi.h> #include "arduino_secrets.h" ///////please enter your sensitive data in the Secret tab/arduino_secrets.h char ssid[] = SECRET_SSID; // your network SSID (name) char pass[] = SECRET_PASS; // your network password (use for WPA, or use as key for WEP) int keyIndex = 0; // your network key Index number (needed only for WEP) int status = WL_IDLE_STATUS; WiFiServer server(80); void setup() { // put your setup code here, to run once: Serial.begin(9600); while (!Serial) { ; // wait for serial port to connect. Needed for native USB port only } Serial.println("Access Point Web Server"); pinMode(LEDR,OUTPUT); pinMode(LEDG,OUTPUT); pinMode(LEDB,OUTPUT); // by default the local IP address of will be 192.168.3.1 // you can override it with the following: // WiFi.config(IPAddress(10, 0, 0, 1)); if(strlen(pass) < 8){ Serial.println("Creating access point failed"); Serial.println("The WiFi password must be at least 8 characters long"); // don't continue while(true); } // print the network name (SSID); Serial.print("Creating access point named: "); Serial.println(ssid); //Create the Access point status = WiFi.beginAP(ssid,pass); if(status != WL_AP_LISTENING){ Serial.println("Creating access point failed"); // don't continue while (true); } // wait 10 seconds for connection: delay(10000); // start the web server on port 80 server.begin(); // you're connected now, so print out the status printWiFiStatus(); } void loop() { // compare the previous status to the current status if (status != WiFi.status()) { // it has changed update the variable status = WiFi.status(); if (status == WL_AP_CONNECTED) { // a device has connected to the AP Serial.println("Device connected to AP"); } else { // a device has disconnected from the AP, and we are back in listening mode Serial.println("Device disconnected from AP"); } } WiFiClient client = server.available(); // listen for incoming clients if (client) { // if you get a client, Serial.println("new client"); // print a message out the serial port String currentLine = ""; // make a String to hold incoming data from the client while (client.connected()) { // loop while the client's connected if (client.available()) { // if there's bytes to read from the client, char c = client.read(); // read a byte, then Serial.write(c); // print it out the serial monitor if (c == '\n') { // if the byte is a newline character // if the current line is blank, you got two newline characters in a row. // that's the end of the client HTTP request, so send a response: if (currentLine.length() == 0) { // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK) // and a content-type so the client knows what's coming, then a blank line: client.println("HTTP/1.1 200 OK"); client.println("Content-type:text/html"); client.println(); // the content of the HTTP response follows the header: client.print("<html><head>"); client.print("<style>"); client.print("* { font-family: sans-serif;}"); client.print("body { padding: 2em; font-size: 2em; text-align: center;}"); client.print("a { -webkit-appearance: button;-moz-appearance: button;appearance: button;text-decoration: none;color: initial; padding: 25px;} #red{color:red;} #green{color:green;} #blue{color:blue;}"); client.print("</style></head>"); client.print("<body><h1> LED CONTROLS </h1>"); client.print("<h2><span id=\"red\">RED </span> LED </h2>"); client.print("<a href=\"/Hr\">ON</a> <a href=\"/Lr\">OFF</a>"); client.print("<h2> <span id=\"green\">GREEN</span> LED </h2>"); client.print("<a href=\"/Hg\">ON</a> <a href=\"/Lg\">OFF</a>"); client.print("<h2> <span id=\"blue\">BLUE</span> LED </h2>"); client.print("<a href=\"/Hb\">ON</a> <a href=\"/Lb\">OFF</a>"); client.print("</body></html>"); // The HTTP response ends with another blank line: client.println(); // break out of the while loop: break; } else { // if you got a newline, then clear currentLine: currentLine = ""; } } else if (c != '\r') { // if you got anything else but a carriage return character, currentLine += c; // add it to the end of the currentLine } // Check to see if the client request was "GET /H" or "GET /L": if (currentLine.endsWith("GET /Hr")) { digitalWrite(LEDR, LOW); // GET /Hr turns the Red LED on } if (currentLine.endsWith("GET /Lr")) { digitalWrite(LEDR, HIGH); // GET /Lr turns the Red LED off } if (currentLine.endsWith("GET /Hg")){ digitalWrite(LEDG, LOW); // GET /Hg turns the Green LED on } if (currentLine.endsWith("GET /Lg")){ digitalWrite(LEDG, HIGH); // GET /Hg turns the Green LED on } if (currentLine.endsWith("GET /Hb")){ digitalWrite(LEDB, LOW); // GET /Hg turns the Green LED on } if (currentLine.endsWith("GET /Lb")){ digitalWrite(LEDB, HIGH); // GET /Hg turns the Green LED on } } } // close the connection: client.stop(); Serial.println("client disconnected"); } } void printWiFiStatus() { // print the SSID of the network you're attached to: Serial.print("SSID: "); Serial.println(WiFi.SSID()); // print your WiFi shield's IP address: IPAddress ip = WiFi.localIP(); Serial.print("IP Address: "); Serial.println(ip); // print where to go in a browser: Serial.print("To see this page in action, open a browser to http://"); Serial.println(ip); }
After uploading the sketch, search wifi in your mobile or laptop also keep open the serial monitor.
Open the browser and got to 192.168.3.1 .
#include <WiFi.h> #include "arduino_secrets.h" ///////please enter your sensitive data in the Secret tab/arduino_secrets.h char ssid[] = SECRET_SSID; // your network SSID (name) char pass[] = SECRET_PASS; // your network password (use for WPA, or use as key for WEP) int keyIndex = 0; // your network key Index number (needed only for WEP) int status = WL_IDLE_STATUS; WiFiServer server(80); void setup() { // put your setup code here, to run once: Serial.begin(9600); while (!Serial) { ; // wait for serial port to connect. Needed for native USB port only } Serial.println("Access Point Web Server"); pinMode(LEDR,OUTPUT); pinMode(LEDG,OUTPUT); pinMode(LEDB,OUTPUT); // by default the local IP address of will be 192.168.3.1 // you can override it with the following: // WiFi.config(IPAddress(10, 0, 0, 1)); if(strlen(pass) < 8){ Serial.println("Creating access point failed"); Serial.println("The WiFi password must be at least 8 characters long"); // don't continue while(true); } // print the network name (SSID); Serial.print("Creating access point named: "); Serial.println(ssid); //Create the Access point status = WiFi.beginAP(ssid,pass); if(status != WL_AP_LISTENING){ Serial.println("Creating access point failed"); // don't continue while (true); } // wait 10 seconds for connection: delay(10000); // start the web server on port 80 server.begin(); // you're connected now, so print out the status printWiFiStatus(); } void loop() { // compare the previous status to the current status if (status != WiFi.status()) { // it has changed update the variable status = WiFi.status(); if (status == WL_AP_CONNECTED) { // a device has connected to the AP Serial.println("Device connected to AP"); } else { // a device has disconnected from the AP, and we are back in listening mode Serial.println("Device disconnected from AP"); } } WiFiClient client = server.available(); // listen for incoming clients if (client) { // if you get a client, Serial.println("new client"); // print a message out the serial port String currentLine = ""; // make a String to hold incoming data from the client while (client.connected()) { // loop while the client's connected if (client.available()) { // if there's bytes to read from the client, char c = client.read(); // read a byte, then Serial.write(c); // print it out the serial monitor if (c == '\n') { // if the byte is a newline character // if the current line is blank, you got two newline characters in a row. // that's the end of the client HTTP request, so send a response: if (currentLine.length() == 0) { // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK) // and a content-type so the client knows what's coming, then a blank line: client.println("HTTP/1.1 200 OK"); client.println("Content-type:text/html"); client.println(); // the content of the HTTP response follows the header: client.print("<html><head>"); client.print("<style>"); client.print("* { font-family: sans-serif;}"); client.print("body { padding: 2em; font-size: 2em; text-align: center;}"); client.print("a { -webkit-appearance: button;-moz-appearance: button;appearance: button;text-decoration: none;color: initial; padding: 25px;} #red{color:red;} #green{color:green;} #blue{color:blue;}"); client.print("</style></head>"); client.print("<body><h1> LED CONTROLS </h1>"); client.print("<h2><span id=\"red\">RED </span> LED </h2>"); client.print("<a href=\"/Hr\">ON</a> <a href=\"/Lr\">OFF</a>"); client.print("<h2> <span id=\"green\">GREEN</span> LED </h2>"); client.print("<a href=\"/Hg\">ON</a> <a href=\"/Lg\">OFF</a>"); client.print("<h2> <span id=\"blue\">BLUE</span> LED </h2>"); client.print("<a href=\"/Hb\">ON</a> <a href=\"/Lb\">OFF</a>"); client.print("</body></html>"); // The HTTP response ends with another blank line: client.println(); // break out of the while loop: break; } else { // if you got a newline, then clear currentLine: currentLine = ""; } } else if (c != '\r') { // if you got anything else but a carriage return character, currentLine += c; // add it to the end of the currentLine } // Check to see if the client request was "GET /H" or "GET /L": if (currentLine.endsWith("GET /Hr")) { digitalWrite(LEDR, LOW); // GET /Hr turns the Red LED on } if (currentLine.endsWith("GET /Lr")) { digitalWrite(LEDR, HIGH); // GET /Lr turns the Red LED off } if (currentLine.endsWith("GET /Hg")){ digitalWrite(LEDG, LOW); // GET /Hg turns the Green LED on } if (currentLine.endsWith("GET /Lg")){ digitalWrite(LEDG, HIGH); // GET /Hg turns the Green LED on } if (currentLine.endsWith("GET /Hb")){ digitalWrite(LEDB, LOW); // GET /Hg turns the Green LED on } if (currentLine.endsWith("GET /Lb")){ digitalWrite(LEDB, HIGH); // GET /Hg turns the Green LED on } } } // close the connection: client.stop(); Serial.println("client disconnected"); } } void printWiFiStatus() { // print the SSID of the network you're attached to: Serial.print("SSID: "); Serial.println(WiFi.SSID()); // print your WiFi shield's IP address: IPAddress ip = WiFi.localIP(); Serial.print("IP Address: "); Serial.println(ip); // print where to go in a browser: Serial.print("To see this page in action, open a browser to http://"); Serial.println(ip); }
BLE Connectivity on Portenta H7
The onboard WiFi/Bluetooth module of the H7 offers low energy Bluetooth functionality that gives the board the flexibility to be easily connected to devices which also support BLE such as the Arduino Nano 33 IoT or most modern smartphones. Compared to classic Bluetooth, Low Energy Bluetooth is intended to provide considerably reduced power consumption and cost while maintaining a similar communication range.
To use the BLE, we need to use the "Arduino BLE" lib.
To install the library go to Tools -> Manage Libraries... type ArduinoBLE and click Install. Make sure you install ArduinoBLE version 1.1.3 or higher.
#include <ArduinoBLE.h> BLEService ledService("19b10000-e8f2-537e-4f6c-d104768a1214"); // BLE LED Switch Characteristic - custom 128-bit UUID, read and writable by central BLEByteCharacteristic switchCharacteristic("19b10000-e8f2-537e-4f6c-d104768a1214", BLERead | BLEWrite); const int ledPin = LED_BUILTIN; // Pin to use for the LED void setup() { Serial.begin(9600); //while (!Serial); // Uncomment to wait for serial port to connect. // Set LED pin to output mode pinMode(ledPin, OUTPUT); digitalWrite(ledPin, HIGH); // Begin initialization if (!BLE.begin()) { Serial.println("Starting BLE failed!"); digitalWrite(LEDR, LOW); delay(1000); digitalWrite(LEDR, HIGH); // Stop if BLE couldn't be initialized. while (1); } // Set advertised local name and service UUID: BLE.setLocalName("LED-Portenta-01"); BLE.setAdvertisedService(ledService); // Add the characteristic to the service ledService.addCharacteristic(switchCharacteristic); // Add service BLE.addService(ledService); // Set the initial value for the characeristic: switchCharacteristic.writeValue(0); // start advertising BLE.advertise(); digitalWrite(LEDB, LOW); delay(1000); digitalWrite(LEDB, HIGH); Serial.println("BLE LED Control ready"); } void loop() { // Listen for BLE peripherals to connect: BLEDevice central = BLE.central(); // If a central is connected to peripheral: if (central) { Serial.print("Connected to central: "); // Print the central's MAC address: Serial.println(central.address()); digitalWrite(LEDB, HIGH); delay(100); digitalWrite(LEDB, LOW); delay(100); digitalWrite(LEDB, HIGH); // While the central is still connected to peripheral: while (central.connected()) { // If the remote device wrote to the characteristic, // Use the value to control the LED: if (switchCharacteristic.written()) { if (switchCharacteristic.value()) { // Any value other than 0 Serial.println("LED on"); digitalWrite(ledPin, LOW); // Will turn the Portenta LED on } else { Serial.println("LED off"); digitalWrite(ledPin, HIGH); // Will turn the Portenta LED off } } } // When the central disconnects, print it out: Serial.print("Disconnected from central: "); Serial.println(central.address()); digitalWrite(LEDB, HIGH); delay(100); digitalWrite(LEDB, LOW); delay(100); digitalWrite(LEDB, HIGH); } }
After uploading the sketch, I got this error "Starting BLE failed"
I tried to update the bootloader, with using update_bootloader.ino sketch.
Ipgradation completed!. After uploading new bootloader, the BLE service is not initiating, still getting error. The official docs mentioned the error
If something went wrong you will see the message
Starting BLE failed!
In that case update the Arduino BLE library (in the Library Manager) and the board (in the Board Manager) to the latest version and try again.
but I was using the latest BLE lib and Portenta board definition. I'll update the status here if found any solution.
I tried to get the ARDUINO PORTENTA VISION SHIELD. if you are planning to buy the Portenta then you should definitely consider purchasing the vision shield.
Thank You Element14 and Arduino to organize this road test, I really enjoyed it, you could also ship the vision shield with the kit since the form factor is very different and vision shield have many possibilities, and way it was a great experience for me and hope you can improve the system from my review.
Top Comments
Nice road test report.
Are you planning to use this device in a project?
DAB