Skip to content

QSPIFormat: default partition scheme #1058

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
May 6, 2025
193 changes: 143 additions & 50 deletions libraries/STM32H747_System/examples/QSPIFormat/QSPIFormat.ino
Original file line number Diff line number Diff line change
@@ -1,112 +1,205 @@
#include "QSPIFBlockDevice.h"
#include "BlockDevice.h"
#include "MBRBlockDevice.h"
#include "LittleFileSystem.h"
#include "FATFileSystem.h"
#include "wiced_resource.h"
#include "certificates.h"

#ifndef CORE_CM7
#ifndef CORE_CM7
#error Format QSPI flash by uploading the sketch to the M7 core instead of the M4 core.
#endif

using namespace mbed;

QSPIFBlockDevice root(QSPI_SO0, QSPI_SO1, QSPI_SO2, QSPI_SO3, QSPI_SCK, QSPI_CS, QSPIF_POLARITY_MODE_1, 40000000);
mbed::MBRBlockDevice wifi_data(&root, 1);
mbed::MBRBlockDevice ota_data(&root, 2);
mbed::MBRBlockDevice user_data(&root, 3);
mbed::FATFileSystem wifi_data_fs("wlan");
mbed::FATFileSystem ota_data_fs("fs");
mbed::FileSystem * user_data_fs;
BlockDevice* root = BlockDevice::get_default_instance();
MBRBlockDevice wifi_data(root, 1);
MBRBlockDevice ota_data(root, 2);
MBRBlockDevice kvstore_data(root, 3);
MBRBlockDevice user_data(root, 4);
FATFileSystem wifi_data_fs("wlan");
FATFileSystem ota_data_fs("fs");
FileSystem * user_data_fs;

bool waitResponse() {
bool confirmation = false;
bool proceed = false;
while (confirmation == false) {
if (Serial.available()) {
char choice = Serial.read();
switch (choice) {
case 'y':
case 'Y':
confirmation = true;
return true;
proceed = true;
break;
case 'n':
case 'N':
confirmation = true;
return false;
proceed = false;
break;
default:
continue;
}
}
}
return proceed;
}

void printProgress(uint32_t offset, uint32_t size, uint32_t threshold, bool reset) {
static int percent_done = 0;
if (reset == true) {
percent_done = 0;
Serial.println("Flashed " + String(percent_done) + "%");
} else {
uint32_t percent_done_new = offset * 100 / size;
if (percent_done_new >= percent_done + threshold) {
percent_done = percent_done_new;
Serial.println("Flashed " + String(percent_done) + "%");
}
}
}

void setup() {

Serial.begin(115200);
while (!Serial);

Serial.println("Available partition schemes:");
Serial.println("\nPartition scheme 1");
Serial.println("Partition 1: WiFi firmware and certificates 1MB");
Serial.println("Partition 2: OTA and user data 13MB");
Serial.println("\nPartition scheme 2");
Serial.println("\nWARNING! Running the sketch all the content of the QSPI flash will be erased.");
Serial.println("The following partitions will be created:");
Serial.println("Partition 1: WiFi firmware and certificates 1MB");
Serial.println("Partition 2: OTA 5MB");
Serial.println("Partition 3: User data 8MB"),
Serial.println("\nDo you want to use partition scheme 1? Y/[n]");
Serial.println("If No, partition scheme 2 will be used.");
bool default_scheme = waitResponse();

Serial.println("\nWARNING! Running the sketch all the content of the QSPI flash will be erased.");
Serial.println("Partition 3: Provisioning KVStore 1MB");
Serial.println("Partition 4: User data / OPTA PLC runtime 7MB"),
Serial.println("Do you want to proceed? Y/[n]");

if (true == waitResponse()) {
mbed::MBRBlockDevice::partition(&root, 1, 0x0B, 0, 1024 * 1024);
if(default_scheme) {
mbed::MBRBlockDevice::partition(&root, 3, 0x0B, 14 * 1024 * 1024, 14 * 1024 * 1024);
mbed::MBRBlockDevice::partition(&root, 2, 0x0B, 1024 * 1024, 14 * 1024 * 1024);
// use space from 15.5MB to 16 MB for another fw, memory mapped
if (root->init() != BD_ERROR_OK) {
Serial.println(F("Error: QSPI init failure."));
return;
}

Serial.println("Do you want to perform a full erase of the QSPI flash before proceeding? Y/[n]");
if (true == waitResponse()) {
root->erase(0x0, root->size());
} else {
mbed::MBRBlockDevice::partition(&root, 2, 0x0B, 1024 * 1024, 6 * 1024 * 1024);
mbed::MBRBlockDevice::partition(&root, 3, 0x0B, 6 * 1024 * 1024, 14 * 1024 * 1024);
// use space from 15.5MB to 16 MB for another fw, memory mapped
// Erase only the first sector containing the MBR
root->erase(0x0, root->get_erase_size());
}

MBRBlockDevice::partition(root, 1, 0x0B, 0, 1 * 1024 * 1024);
MBRBlockDevice::partition(root, 2, 0x0B, 1 * 1024 * 1024, 6 * 1024 * 1024);
MBRBlockDevice::partition(root, 3, 0x0B, 6 * 1024 * 1024, 7 * 1024 * 1024);
MBRBlockDevice::partition(root, 4, 0x0B, 7 * 1024 * 1024, 14 * 1024 * 1024);
// use space from 15.5MB to 16 MB for another fw, memory mapped

bool reformat = true;
if(!wifi_data_fs.mount(&wifi_data)) {
Serial.println("\nPartition 1 already contains a filesystem, do you want to reformat it? Y/[n]");
wifi_data_fs.unmount();

reformat = waitResponse();
}

int err = wifi_data_fs.reformat(&wifi_data);
if (err) {
if (reformat && wifi_data_fs.reformat(&wifi_data)) {
Serial.println("Error formatting WiFi partition");
return;
}

err = ota_data_fs.reformat(&ota_data);
if (err) {

bool restore = true;
if (reformat) {
Serial.println("\nDo you want to restore the WiFi firmware and certificates? Y/[n]");
restore = waitResponse();
}

if (reformat && restore) {
flashWiFiFirmwareAndCertificates();
}

reformat = true;
if(!ota_data_fs.mount(&ota_data)) {
Serial.println("\nPartition 2 already contains a filesystem, do you want to reformat it? Y/[n]");
ota_data_fs.unmount();

reformat = waitResponse();
}

if (reformat && ota_data_fs.reformat(&ota_data)) {
Serial.println("Error formatting OTA partition");
return;
}

if(!default_scheme) {
Serial.println("\nDo you want to use LittleFS to format user data partition? Y/[n]");
Serial.println("If No, FatFS will be used to format user partition.");
Serial.println("\nDo you want to use LittleFS to format user data partition? Y/[n]");
Serial.println("If No, FatFS will be used to format user partition.");
Serial.println("Note: LittleFS is not supported by the OPTA PLC runtime.");
if (true == waitResponse()) {
Serial.println("Formatting user partition with LittleFS.");
user_data_fs = new mbed::LittleFileSystem("user");
} else {
Serial.println("Formatting user partition with FatFS.");
user_data_fs = new mbed::FATFileSystem("user");
}

if (true == waitResponse()) {
Serial.println("Formatting user partition with LittleFS.");
user_data_fs = new mbed::LittleFileSystem("user");
} else {
Serial.println("Formatting user partition with FatFS.");
user_data_fs = new mbed::FATFileSystem("user");
}
reformat = true;
if(!user_data_fs->mount(&user_data)) {
Serial.println("\nPartition 4 already contains a filesystem, do you want to reformat it? Y/[n]");
user_data_fs->unmount();

err = user_data_fs->reformat(&user_data);
if (err) {
Serial.println("Error formatting user partition");
return;
}
reformat = waitResponse();
}

if (reformat && user_data_fs->reformat(&user_data)) {
Serial.println("Error formatting user partition");
return;
}

Serial.println("\nQSPI Flash formatted!");
}

Serial.println("It's now safe to reboot or disconnect your board.");
}

void flashWiFiFirmwareAndCertificates() {
extern const unsigned char wifi_firmware_image_data[];
FILE* fp = fopen("/wlan/4343WA1.BIN", "wb");
const uint32_t file_size = 421098;
uint32_t chunck_size = 1024;
uint32_t byte_count = 0;

Serial.println("Flashing WiFi firmware");
printProgress(byte_count, file_size, 10, true);
while (byte_count < file_size) {
if(byte_count + chunck_size > file_size)
chunck_size = file_size - byte_count;
int ret = fwrite(&wifi_firmware_image_data[byte_count], chunck_size, 1, fp);
if (ret != 1) {
Serial.println("Error writing firmware data");
break;
}
byte_count += chunck_size;
printProgress(byte_count, file_size, 10, false);
}
fclose(fp);

fp = fopen("/wlan/cacert.pem", "wb");

Serial.println("Flashing certificates");
chunck_size = 128;
byte_count = 0;
printProgress(byte_count, cacert_pem_len, 10, true);
while (byte_count < cacert_pem_len) {
if(byte_count + chunck_size > cacert_pem_len)
chunck_size = cacert_pem_len - byte_count;
int ret = fwrite(&cacert_pem[byte_count], chunck_size, 1 ,fp);
if (ret != 1) {
Serial.println("Error writing certificates");
break;
}
byte_count += chunck_size;
printProgress(byte_count, cacert_pem_len, 10, false);
}
fclose(fp);
}

void loop() {

}