A demonstration of a simple bootloader with SD card. Binary folder already contains precompiled SimpleBootloader for Nucleo-F767ZI under MbedOS 6.15.1. Firmware example for bootloader is here - https://os.mbed.com/users/JohnnyK/code/FirmwareForSimpleBootloader/

Binary folder already contains precompiled SimpleBootloader for Nucleo-F767ZI

main.cpp

Committer:
JohnnyK
Date:
2021-12-08
Revision:
1:84522765c238
Parent:
0:58ebce14a984

File content as of revision 1:84522765c238:

/* 
 * Tested with Nudleo-F767Zi and Nudleo-F429ZI
 * Builded with Mbed Studio 1.4.3
 */

#include "mbed.h" //MbedOS 6.15.1
#include "SDBlockDevice.h"
#include "FATFileSystem.h"
#include "KVStore.h"
#include "kvstore_global_api.h"
#include <string>

#define SD_MOUNT_PATH      "sd"
#define FIRMWARE_PATH      "/" SD_MOUNT_PATH "/"

#if !defined(POST_APPLICATION_ADDR)
#error "target.restrict_size must be set for your target in mbed_app.json"
#endif

//Pin order: MOSI, MISO, SCK, CS
SDBlockDevice sd(PC_12, PC_11, PC_10, PC_9); //with a problem of init a sd card can be required add "sd.INIT_FREQUENCY": 100000 to Mbed_app.json
FATFileSystem fs(SD_MOUNT_PATH);
FlashIAP flash;

void apply_update(FILE *file, uint32_t address);

int main()
{
    printf("Bootloader starts!\n");
    printf("About to start the application at 0x%x\r\n", POST_APPLICATION_ADDR);
    ThisThread::sleep_for(500ms);
    printf("Bootloader's SD card operations start!\n");
    // Init
    if (0 != sd.init()) {
        printf("SD card is not present or init failed!\n");
    }else{
        // Set the frequency
        if ( 0 != sd.frequency(5000000)) {
            printf("Error setting frequency \n");
        }
        //Mounting the filesystem...
        fflush(stdout);
        if (0 != fs.mount(&sd)){ 
            printf("Mount failed!\n");    
        }else{
        // Display the root directory
            printf("Opening the root directory... ");
            fflush(stdout);
            DIR *d = opendir(SD_MOUNT_PATH);
            printf("%s\n", (!d ? "Fail :(" : "OK"));
            if(d){
                printf("Firmware files on the SD cards:\n");
                while (true) {
                    struct dirent *e = readdir(d);
                    if(!e) break;
                    if(e->d_type == 0x5) printf("%s\n", e->d_name);
                } 
                printf("Closing the root directory... ");
                fflush(stdout);
                printf("%s\n", (closedir(d) < 0 ? "Fail :(" : "OK"));
                char str[10];
                string strr;
                FILE *firmware;
                
                char kv_key[] = {"/kv/key"};
                char kv_value[10];
                kv_info_t info;
                
                while(true){
                    printf("Please, select one of available files!\n");
                    scanf("%10s",str); 
                    printf("Your request is %s!\n", str);
                    kv_get_info(kv_key, &info);
                    kv_get(kv_key, kv_value, info.size, 0);
                    bool check = true;
                    for(int i=0;str[i]!='\0';i++){
                        if(str[i]!=kv_value[i]) 
                        check = false; 
                    }
                    if(check){
                        printf("This firmware is already loaded!\n");
                        break;
                    }else{
                        printf("Finding...");
                        strr = FIRMWARE_PATH + string(str, 10);
                        firmware = fopen(strr.c_str(), "r");
                        printf(" %s\n", (!firmware ? "Fail :(" : "OK"));
                        if(firmware){
                            apply_update(firmware, POST_APPLICATION_ADDR);
                            kv_set(kv_key, str, strlen(str), 0);
                            printf("Closing the firmware file...");
                            fflush(stdout);
                            printf("%s\n", (fclose(firmware) < 0 ? "Fail :(" : "OK"));
                            break;
                        }else{
                            printf("The %s not exist on the SD card.\nTry it again!\n", str);
                        }
                    }
                }
            }else{
                printf("A DIR fail!\n");
            }        
            fs.unmount();
        }
        sd.deinit();
    }
    printf("SD card operations end!\nStarting application...\n"); 
    ThisThread::sleep_for(800ms);
    mbed_start_application(POST_APPLICATION_ADDR);
}

void apply_update(FILE *file, uint32_t address)
{
    fseek(file, 0, SEEK_END);
    long len = ftell(file);
    printf("Firmware size is %ld bytes\r\n", len);
    fseek(file, 0, SEEK_SET);
  
    flash.init();

    const uint32_t page_size = flash.get_page_size();
    char *page_buffer = new char[page_size];
    uint32_t addr = address;
    uint32_t next_sector = addr + flash.get_sector_size(addr);
    bool sector_erased = false;
    size_t pages_flashed = 0;
    uint32_t percent_done = 0;
    while (true) {

        // Read data for this page
        memset(page_buffer, 0, sizeof(char) * page_size);
        int size_read = fread(page_buffer, 1, page_size, file);
        if (size_read <= 0) {
            break;
        }

        // Erase this page if it hasn't been erased
        if (!sector_erased) {
            flash.erase(addr, flash.get_sector_size(addr));
            sector_erased = true;
        }

        // Program page
        flash.program(page_buffer, addr, page_size);

        addr += page_size;
        if (addr >= next_sector) {
            next_sector = addr + flash.get_sector_size(addr);
            sector_erased = false;
        }

        if (++pages_flashed % 3 == 0) {
            uint32_t percent_done_new = ftell(file) * 100 / len;
            if (percent_done != percent_done_new) {
                percent_done = percent_done_new;
                printf("Flashed %3ld%%\r", percent_done);
            }
        }
    }
    printf("Flashed 100%%\r\n");

    delete[] page_buffer;

    flash.deinit();
}