Skip to content

Add Second Stage Bootloader (SBU) for MKRNB 1500 #549

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 6 commits into from
Jul 22, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 96 additions & 0 deletions libraries/SBU/examples/SBU_LoadBinary/SBU_LoadBinary.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
#include <MKRNB.h>
#include <SBU.h>

static char const BINARY[] =
{
#include "Binary.h"
};

static char const CHECK_FILE[] =
{
"OK"
};

static constexpr char CHECK_FILE_NAME[] = "UPDATE.OK";

NBFileUtils fileUtils;
bool update_available = false;

void setup() {
Serial.begin(9600);
while(!Serial) { }

unsigned long const start = millis();
for(unsigned long now = millis(); !Serial && ((now - start) < 5000); now = millis()) { };

Serial.print("Accessing SARA Filesystem... ");
if(!fileUtils.begin(false)) {
Serial.println("failed.");
return;

}
Serial.println("OK");
Serial.print("Writing \"UPDATE.BIN\" ... ");

uint32_t bytes_to_write = sizeof(BINARY);
Serial.print("Size of BINARY: ");
Serial.println(bytes_to_write);
int index = 0;
bool append = false;
int new_bytes = 0;
//int bytes_written = 0;

for (int i=0; i<(bytes_to_write/512); i++) {
auto new_bytes = fileUtils.downloadFile("UPDATE.BIN", BINARY+index, 512, append);
if (new_bytes != 512) {
Serial.print("New_bytes = ");
Serial.print(new_bytes);
Serial.println(" != 512");
}
index = index + new_bytes;
append = true;
}
if ((bytes_to_write%512)!=0) {
auto new_bytes = fileUtils.downloadFile("UPDATE.BIN", BINARY+index, bytes_to_write%512, append);
if (new_bytes != bytes_to_write%512) {
Serial.print("Last bytes read = ");
Serial.print(new_bytes);
Serial.print(". They should have been ");
Serial.println(bytes_to_write%512);
}
index = index + new_bytes;
}

if(index != bytes_to_write) {
Serial.print("Written only ");
Serial.println(index); //bytes_written
Serial.print(bytes_to_write);
Serial.println(" should have been written. System is restarting...");
delay(100);
NVIC_SystemReset();

} else {
Serial.print("Download complete! ");
Serial.print(index);
Serial.println(" bytes written");

auto status = 0;
while (status != 2) {
status = fileUtils.createFile(CHECK_FILE_NAME, CHECK_FILE, 2);
delay(100);
}

Serial.println("Please type \"restart\" to apply the update");
update_available = true;
}

}

void loop() {
if (update_available == true) {
String command = Serial.readStringUntil('\n');
if (command.indexOf("restart") >= 0) {
NVIC_SystemReset();
}
}
}
48 changes: 48 additions & 0 deletions libraries/SBU/examples/SBU_Usage/SBU_Usage.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
Usage
This example demonstrates how to use the SAMD SBU library to update a
sketch on any Arduino MKR board via the storage on the SARA-R410M module.
This sketch prints out the current date and time.
Steps to update sketch:
1) Upload this sketch or another sketch that includes the SBU library
2) Update the sketch as desired. For this example the sketch prints out
the compiled date and time.
3) In the IDE select: Sketch -> Export compiled Binary
4) Open the location of the sketch and convert the .bin file to a C byte array.
cat SKETCH.bin | xxd --include > Binary.h
5) Copy Binary.h file from the sketch's folder to the SBU_LoadBinary sketch
and load it to the SARA-R410M via SBU_LoadBinary sketch.
*/

/*
Include the SBU library

This will add some code to the sketch before setup() is called
to check if UPDATE.BIN and UPDATE.OK are present on the storage of
the SARA-R410M module. If this check is positive UPDATE.BIN is used to update
the sketch running on the board.
After this UPDATE.BIN and UPDATE.OK are deleted from the flash.
*/


#include <SBU.h>

void setup()
{
Serial.begin(9600);
while (!Serial) { }
// wait a bit
delay(1000);
String message;
message += "Sketch compile date and time: ";
message += __DATE__;
message += " ";
message += __TIME__;
// print out the sketch compile date and time on the serial port
Serial.println(message);
}

void loop()
{
// add you own code here
}
102 changes: 102 additions & 0 deletions libraries/SBU/extras/SBUBoot/SBUBoot.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/*
Copyright (c) 2020 Arduino LLC. All right reserved.

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include <FlashStorage.h>
#include <MKRNB.h>

#define SBU_START 0x2000
#define SBU_SIZE 0x8000

#define SKETCH_START (uint32_t*)(SBU_START + SBU_SIZE)

static constexpr char UPDATE_FILE_NAME[] = "UPDATE.BIN";
static constexpr char CHECK_FILE_NAME[] = "UPDATE.OK";

FlashClass mcu_flash;

NBFileUtils fileUtils(true);

extern "C" void __libc_init_array(void);

int main()
{
init();

__libc_init_array();

delay(1);

constexpr size_t blockSize = 512;
fileUtils.begin();

bool update_success = false;

// Try to update only if update file
// has been download successfully.

if (fileUtils.listFile(CHECK_FILE_NAME)) {
uint32_t updateSize = fileUtils.listFile(UPDATE_FILE_NAME);
uint32_t tot_bytes = 0;
uint32_t read_bytes = 0;

if (updateSize > SBU_SIZE) {
updateSize = updateSize - SBU_SIZE;
size_t cycles = (updateSize / blockSize);
size_t spare_bytes = (updateSize % blockSize);
/* Erase the MCU flash */
uint32_t flash_address = (uint32_t)SKETCH_START;
mcu_flash.erase((void*)flash_address, updateSize);

for (auto i = 0; i < cycles; i++) {
uint8_t block[blockSize] { 0 };
digitalWrite(LED_BUILTIN, LOW);
read_bytes = fileUtils.readBlock(UPDATE_FILE_NAME, (i * blockSize) + SBU_SIZE, blockSize, block);
digitalWrite(LED_BUILTIN, HIGH);
mcu_flash.write((void*)flash_address, block, read_bytes);
flash_address += read_bytes;
tot_bytes += read_bytes;
}

if (spare_bytes){
uint8_t block[spare_bytes] { 0 };
digitalWrite(LED_BUILTIN, LOW);
read_bytes = fileUtils.readBlock(UPDATE_FILE_NAME, tot_bytes + SBU_SIZE, spare_bytes, block);
digitalWrite(LED_BUILTIN, HIGH);
mcu_flash.write((void*)flash_address, block, read_bytes);
flash_address += read_bytes;
}
update_success = true;
}
if (update_success) {
fileUtils.deleteFile(UPDATE_FILE_NAME);
fileUtils.deleteFile(CHECK_FILE_NAME);
}
}

boot:
/* Jump to the sketch */
__set_MSP(*SKETCH_START);

/* Reset vector table address */
SCB->VTOR = ((uint32_t)(SKETCH_START) & SCB_VTOR_TBLOFF_Msk);

/* Address of Reset_Handler is written by the linker at the beginning of the .text section (see linker script) */
uint32_t resetHandlerAddress = (uint32_t) * (SKETCH_START + 1);
/* Jump to reset handler */
asm("bx %0"::"r"(resetHandlerAddress));
}
23 changes: 23 additions & 0 deletions libraries/SBU/extras/SBUBoot/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/bin/sh -x

#Sara R410M
ARDUINO=arduino
SKETCH_NAME="SBUBoot.ino"
SKETCH="$PWD/$SKETCH_NAME"
BUILD_PATH="$PWD/build"
OUTPUT_PATH="../../src/boot"

if [[ "$OSTYPE" == "darwin"* ]]; then
ARDUINO="/Applications/Arduino.app/Contents/MacOS/Arduino"
fi

buildSBUBootSketch() {
BOARD=$1
DESTINATION=$2

$ARDUINO --verify --board $BOARD --preserve-temp-files --pref build.path="$BUILD_PATH" $SKETCH
cat "$BUILD_PATH/$SKETCH_NAME.bin" | xxd -include > $DESTINATION
rm -rf "$BUILD_PATH"
}

buildSBUBootSketch "arduino:samd:mkrnb1500" "$OUTPUT_PATH/mkrnb1500.h"
17 changes: 17 additions & 0 deletions libraries/SBU/keywords.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#######################################
# Syntax Coloring Map For SBU
#######################################

#######################################
# Datatypes (KEYWORD1)
#######################################

SBU KEYWORD1

#######################################
# Methods and Functions (KEYWORD2)
#######################################

#######################################
# Constants (LITERAL1)
#######################################
9 changes: 9 additions & 0 deletions libraries/SBU/library.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
name=SBU
version=1.0.0
author=Arduino
maintainer=Arduino <[email protected]>
sentence=Update the sketch on your Arduino MKRNB1500 from SARA-R410M flash.
paragraph=
category=Other
url=
architectures=samd
30 changes: 30 additions & 0 deletions libraries/SBU/src/SBU.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
Copyright (c) 2020 Arduino LLC. All right reserved.

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include <Arduino.h>

#include "SBU.h"

__attribute__ ((section(".sketch_boot")))
unsigned char SBU_BOOT[0x8000] = {
#if defined(ARDUINO_SAMD_MKRNB1500)
#include "boot/mkrnb1500.h"
#else
#error "Unsupported board!"
#endif
};
24 changes: 24 additions & 0 deletions libraries/SBU/src/SBU.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
Copyright (c) 2020 Arduino LLC. All right reserved.

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/

#ifndef _SBU_H_INCLUDED
#define _SBU_H_INCLUDED

/* Nothing to do */

#endif /* _SBU_H_INCLUDED */
Loading