Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 65f003a

Browse files
authoredSep 4, 2023
Merge pull request #116 from pennam/sfu-file
Portenta C33 SFU
2 parents 80c9238 + 59d3697 commit 65f003a

File tree

15 files changed

+34186
-0
lines changed

15 files changed

+34186
-0
lines changed
 

‎.github/workflows/compile-examples.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ jobs:
6868
- libraries/Arduino_CAN/examples/CAN1Write
6969
- libraries/RTC/examples/RTC_NTPSync
7070
- libraries/RTC/examples/RTC_Alarm
71+
- libraries/SFU
7172
- board:
7273
fqbn: "arduino-git:renesas:portenta_c33"
7374
additional-sketch-paths: |
@@ -82,6 +83,7 @@ jobs:
8283
- libraries/Arduino_CAN/examples/CAN1Write
8384
- libraries/RTC/examples/RTC_NTPSync
8485
- libraries/RTC/examples/RTC_Alarm
86+
- libraries/SFU
8587
- board:
8688
fqbn: "arduino:renesas_uno:unor4wifi"
8789
additional-sketch-paths: |

‎libraries/SFU/.portenta_only

Whitespace-only changes.
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
This sketch can be used to generate an example binary that can be uploaded to Portenta C33 via OTA.
3+
It needs to be used together with UpdateFromFile.ino
4+
5+
Steps to test OTA on Portenta C33:
6+
1) Upload this sketch or any other sketch (this one lights up the RGB LED with different colours).
7+
2) In the IDE select: Sketch -> Export compiled Binary
8+
3) Upload the exported binary to a server
9+
4) Open the related OTA_*_Portenta.ino sketch, eventually update the OTA_FILE_LOCATION
10+
5) Upload the sketch UpdateFromFile.ino to perform OTA
11+
*/
12+
#include "SFU.h"
13+
14+
void setLed(int blue, int gree, int red) {
15+
if (blue == 1) {
16+
digitalWrite(LEDB, LOW);
17+
}
18+
else {
19+
digitalWrite(LEDB, HIGH);
20+
}
21+
22+
if (gree == 1) {
23+
digitalWrite(LEDG, LOW);
24+
}
25+
else {
26+
digitalWrite(LEDG, HIGH);
27+
}
28+
29+
if (red == 1) {
30+
digitalWrite(LEDR, LOW);
31+
}
32+
else {
33+
digitalWrite(LEDR, HIGH);
34+
}
35+
}
36+
37+
38+
void setup()
39+
{
40+
pinMode(LEDB, OUTPUT);
41+
pinMode(LEDG, OUTPUT);
42+
pinMode(LEDR, OUTPUT);
43+
}
44+
45+
void loop()
46+
{ // Blue LED on
47+
setLed(1, 0, 0);
48+
delay(1000);
49+
// Green LED on
50+
setLed(0, 1, 0);
51+
delay(1000);
52+
// Red LED on
53+
setLed(0, 0, 1);
54+
delay(1000);
55+
}
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/*
2+
* This example demonstrates how to use the SFU to update the firmware of the
3+
* Arduino Portenta C33 using a compressed firmware image stored in the QSPI flash.
4+
* In real applications, you will get the file from the internet and not include it
5+
* in a header file like we do here for simplicity.
6+
*
7+
* Steps:
8+
* 1) Create a sketch for the Portenta C33 and verify
9+
* that it both compiles and works on a board.
10+
* 2) In the IDE select: Sketch -> Export compiled Binary.
11+
* 3) Create an OTA update file utilising the tools 'lzss.py' and 'bin2ota.py' stored in
12+
* https://github.com/arduino-libraries/ArduinoIoTCloud/tree/master/extras/tools .
13+
* A) ./lzss.py --encode SKETCH.bin SKETCH.lzss
14+
* B) ./bin2ota.py PORTENTA_C33 SKETCH.lzss SKETCH.ota
15+
* 4) Create the header file to be included in this Sketch
16+
* xxd -i SKETCH.ota > update.h
17+
* 5) Upload this Sketch to perform the update
18+
*/
19+
20+
/******************************************************************************
21+
* INCLUDE
22+
******************************************************************************/
23+
24+
#include <SFU.h>
25+
#include <BlockDevice.h>
26+
#include <MBRBlockDevice.h>
27+
#include <FATFileSystem.h>
28+
#include <Arduino_DebugUtils.h>
29+
#include "update.h"
30+
31+
BlockDevice* block_device = BlockDevice::get_default_instance();
32+
MBRBlockDevice mbr(block_device, 1);
33+
FATFileSystem fs("ota");
34+
35+
36+
/******************************************************************************
37+
* SETUP/LOOP
38+
******************************************************************************/
39+
40+
void setup()
41+
{
42+
Serial.begin(115200);
43+
while (!Serial) {}
44+
45+
Debug.setDebugLevel(DBG_VERBOSE);
46+
47+
int err = -1;
48+
if ((err = fs.reformat(&mbr)) != 0)
49+
{
50+
DEBUG_ERROR("%s: fs.reformat() failed with %d", __FUNCTION__, err);
51+
return;
52+
}
53+
54+
FILE * file = fopen("/ota/UPDATE.BIN.OTA", "wb");
55+
if (!file)
56+
{
57+
DEBUG_ERROR("%s: fopen() failed", __FUNCTION__);
58+
fclose(file);
59+
return;
60+
}
61+
62+
DEBUG_INFO("Start copy update file on QSPI flash.");
63+
for(int i = 0; i < OTAUsage_ino_PORTENTA_C33_ota_len; i++)
64+
{
65+
char const c = OTAUsage_ino_PORTENTA_C33_ota[i];
66+
67+
if (fwrite(&c, 1, sizeof(c), file) != sizeof(c))
68+
{
69+
DEBUG_ERROR("%s: Writing of firmware image to flash failed", __FUNCTION__);
70+
fclose(file);
71+
return;
72+
}
73+
}
74+
75+
fclose(file);
76+
77+
/* Unmount the filesystem. */
78+
if ((err = fs.unmount()) != 0)
79+
{
80+
DEBUG_ERROR("%s: fs.unmount() failed with %d", __FUNCTION__, err);
81+
return;
82+
}
83+
84+
delay(1000);
85+
86+
DEBUG_INFO("Board reset to trigger the update.");
87+
DEBUG_INFO("Do not reset or disconnect the board.");
88+
DEBUG_INFO("Wait until the RGB LED lights up with different colours.");
89+
NVIC_SystemReset();
90+
}
91+
92+
void loop()
93+
{
94+
95+
}

‎libraries/SFU/examples/UpdateFromFile/update.h

Lines changed: 27256 additions & 0 deletions
Large diffs are not rendered by default.

‎libraries/SFU/extra/loader/loader.ino

Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
/*
2+
Portenta C33 - 2nd stage bootloader
3+
4+
The sketch checks for available update files on QSPI system partion
5+
or SD card and try to update the Sketch
6+
7+
Build (release) with arduino-cli:
8+
# arduino-cli compile --export-binaries --clean --verbose -b arduino-git:renesas:portenta_c33 --build-property "build.extra_flags=-DNO_USB -DPORTENTA_C33_SFU_BUILD"
9+
Build (debug) with arduino-cli:
10+
# arduino-cli compile --export-binaries --clean --verbose -b arduino-git:renesas:portenta_c33 --build-property "build.extra_flags=-DNO_USB -DPORTENTA_C33_SFU_DEBUG_OTA -DPORTENTA_C33_SFU_BUILD"
11+
Export loader binary:
12+
# xxd -i build/arduino-git.renesas.portenta_c33/loader.ino.bin | grep -E '0x' > ../../src/c33.h
13+
14+
This example code is in the public domain.
15+
*/
16+
#include <BlockDevice.h>
17+
#include <MBRBlockDevice.h>
18+
#include <CodeFlashBlockDevice.h>
19+
#include <FATFileSystem.h>
20+
#include "ota.h"
21+
22+
#ifdef PORTENTA_C33_SFU_SDCARD_OTA
23+
#include <SDCardBlockDevice.h>
24+
#endif
25+
26+
#ifdef PORTENTA_C33_SFU_DEBUG_OTA
27+
#include <Arduino_DebugUtils.h>
28+
#endif
29+
30+
/* Key code for writing PRCR register. */
31+
#define BSP_PRV_PRCR_KEY (0xA500U)
32+
#define BSP_PRV_PRCR_PRC1_UNLOCK ((BSP_PRV_PRCR_KEY) | 0x2U)
33+
#define BSP_PRV_PRCR_LOCK ((BSP_PRV_PRCR_KEY) | 0x0U)
34+
35+
#define BSP_PRV_BITS_PER_WORD (32)
36+
37+
#define SKETCH_FLASH_OFFSET (64 * 1024)
38+
39+
#define FULL_UPDATE_FILE_PATH "/ota/UPDATE.BIN"
40+
#define FULL_UPDATE_FILE_PATH_OTA FULL_UPDATE_FILE_PATH ".OTA"
41+
42+
#define VERSION 1
43+
44+
#ifdef PORTENTA_C33_SFU_SDCARD_OTA
45+
SDCardBlockDevice sd(PIN_SDHI_CLK, PIN_SDHI_CMD, PIN_SDHI_D0, PIN_SDHI_D1, PIN_SDHI_D2, PIN_SDHI_D3, PIN_SDHI_CD, PIN_SDHI_WP);
46+
#endif
47+
48+
BlockDevice* qspi = BlockDevice::get_default_instance();
49+
CodeFlashBlockDevice& cf = CodeFlashBlockDevice::getInstance();
50+
MBRBlockDevice sys_bd(qspi, 1);
51+
FATFileSystem sys_fs("ota");
52+
53+
void setup() {
54+
55+
#ifdef PORTENTA_C33_SFU_DEBUG_OTA
56+
Serial.begin(115200);
57+
while(!Serial);
58+
Debug.setDebugOutputStream(&Serial);
59+
Debug.setDebugLevel(DBG_VERBOSE);
60+
DEBUG_INFO("SFU version: %d", VERSION);
61+
#endif
62+
63+
qspi->init();
64+
int err = sys_fs.mount(&sys_bd);
65+
if (!err) {
66+
#ifdef PORTENTA_C33_SFU_DEBUG_OTA
67+
DEBUG_INFO("Try QSPI OTA");
68+
#endif
69+
try_ota();
70+
} else {
71+
#ifdef PORTENTA_C33_SFU_DEBUG_OTA
72+
DEBUG_ERROR("Cannot mount QSPI filesystem. Error: %d", err);
73+
#endif
74+
}
75+
76+
#ifdef PORTENTA_C33_SFU_SDCARD_OTA
77+
sd.init();
78+
err = sys_fs.mount(&sd);
79+
if (!err) {
80+
#ifdef PORTENTA_C33_SFU_DEBUG_OTA
81+
DEBUG_INFO("Try SD OTA");
82+
#endif
83+
try_ota();
84+
} else {
85+
#ifdef PORTENTA_C33_SFU_DEBUG_OTA
86+
DEBUG_ERROR("Cannot mount SDCARD filesystem. Error: %d", err);
87+
#endif
88+
}
89+
#endif
90+
91+
int app_valid = (((*(uint32_t *) SKETCH_FLASH_OFFSET + POST_APPLICATION_ADDR) & 0xFF000000) == 0x20000000);
92+
if (app_valid) {
93+
#ifdef PORTENTA_C33_SFU_DEBUG_OTA
94+
DEBUG_INFO("Booting application @ 0x%x", SKETCH_FLASH_OFFSET + POST_APPLICATION_ADDR);
95+
#endif
96+
boot5(SKETCH_FLASH_OFFSET + POST_APPLICATION_ADDR);
97+
} else {
98+
#ifdef PORTENTA_C33_SFU_DEBUG_OTA
99+
DEBUG_INFO("Application not found");
100+
#endif
101+
}
102+
}
103+
104+
void loop() {
105+
106+
}
107+
108+
void boot5(uint32_t address) {
109+
110+
R_SYSTEM->PRCR = (uint16_t) BSP_PRV_PRCR_PRC1_UNLOCK;
111+
R_BSP_MODULE_STOP(FSP_IP_USBFS, 0);
112+
R_BSP_MODULE_STOP(FSP_IP_USBHS, 0);
113+
R_SYSTEM->PRCR = (uint16_t) BSP_PRV_PRCR_LOCK;
114+
115+
/* Disable MSP monitoring. */
116+
#if BSP_FEATURE_TZ_HAS_TRUSTZONE
117+
__set_MSPLIM(0);
118+
#else
119+
R_MPU_SPMON->SP[0].CTL = 0;
120+
#endif
121+
122+
__disable_irq(); // Note: remember to enable IRQ in application
123+
__DSB();
124+
__ISB();
125+
126+
// Disable SysTick
127+
SysTick->CTRL = 0;
128+
129+
SCB->VTOR = address;
130+
131+
// Cleanup NVIC
132+
for (size_t i = 0U; i < BSP_ICU_VECTOR_MAX_ENTRIES / BSP_PRV_BITS_PER_WORD; i++)
133+
{
134+
NVIC->ICER[i] = 0xFF;
135+
}
136+
137+
uint32_t mainStackPointer = *(volatile uint32_t *)(address);
138+
__set_MSP(mainStackPointer);
139+
uint32_t programResetHandlerAddress = *(volatile uint32_t *) (address + 4);
140+
void (* programResetHandler)(void) = (void (*)(void)) programResetHandlerAddress;
141+
programResetHandler();
142+
}
143+
144+
int try_ota(void) {
145+
FILE *update_file;
146+
FILE *target_file;
147+
148+
update_file = fopen(FULL_UPDATE_FILE_PATH_OTA, "rb");
149+
if (update_file) {
150+
#ifdef PORTENTA_C33_SFU_DEBUG_OTA
151+
DEBUG_INFO("Compressed update file found");
152+
#endif
153+
target_file = fopen(FULL_UPDATE_FILE_PATH, "wb");
154+
if (!target_file) {
155+
#ifdef PORTENTA_C33_SFU_DEBUG_OTA
156+
DEBUG_ERROR("Error creating file for decompression");
157+
#endif
158+
return -1;
159+
}
160+
int err = verify_decompress(update_file, target_file);
161+
fclose(update_file);
162+
fclose(target_file);
163+
remove(FULL_UPDATE_FILE_PATH_OTA);
164+
} else {
165+
#ifdef PORTENTA_C33_SFU_DEBUG_OTA
166+
DEBUG_INFO("Compressed update file not found");
167+
#endif
168+
}
169+
170+
update_file = fopen(FULL_UPDATE_FILE_PATH, "rb");
171+
if (update_file) {
172+
#ifdef PORTENTA_C33_SFU_DEBUG_OTA
173+
DEBUG_INFO("Update file found");
174+
#endif
175+
int err = verify_flash(update_file);
176+
fclose(update_file);
177+
remove(FULL_UPDATE_FILE_PATH);
178+
} else {
179+
#ifdef PORTENTA_C33_SFU_DEBUG_OTA
180+
DEBUG_INFO("Update file not found");
181+
#endif
182+
}
183+
}
184+
185+
int verify_decompress(FILE* update_file, FILE* target_file) {
186+
int err = verify_header(update_file);
187+
if (err) {
188+
#ifdef PORTENTA_C33_SFU_DEBUG_OTA
189+
DEBUG_ERROR("Error during header verification: %d", err);
190+
#endif
191+
return err;
192+
}
193+
err = decompress(update_file, target_file, nullptr);
194+
return err;
195+
}
196+
197+
int verify_flash(FILE* file) {
198+
int err = verify_sketch(file);
199+
if (err != 0) {
200+
#ifdef PORTENTA_C33_SFU_DEBUG_OTA
201+
DEBUG_ERROR("Error during sketch verification: %d", err);
202+
#endif
203+
return err;
204+
}
205+
err = flash(file, &cf, SKETCH_FLASH_OFFSET + POST_APPLICATION_ADDR);
206+
return err;
207+
}

‎libraries/SFU/extra/loader/lzss.cpp

Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
/*
2+
lzss.cpp
3+
Original code from LZSS encoder-decoder (Haruhiko Okumura; public domain)
4+
5+
https://oku.edu.mie-u.ac.jp/~okumura/compression/lzss.c
6+
*/
7+
8+
/**************************************************************************************
9+
INCLUDE
10+
**************************************************************************************/
11+
12+
#include "lzss.h"
13+
14+
/**************************************************************************************
15+
DEFINE
16+
**************************************************************************************/
17+
18+
#define EI 11 /* typically 10..13 */
19+
#define EJ 4 /* typically 4..5 */
20+
#define P 1 /* If match length <= P then output one character */
21+
#define N (1 << EI) /* buffer size */
22+
#define F ((1 << EJ) + 1) /* lookahead buffer size */
23+
24+
#define LZSS_EOF (-1)
25+
26+
#define FPUTC_BUF_SIZE (64)
27+
#define FGETC_BUF_SIZE (64)
28+
29+
/**************************************************************************************
30+
GLOBAL VARIABLES
31+
**************************************************************************************/
32+
33+
static uint32_t LZSS_FILE_SIZE = 0;
34+
static FILE * update_file = 0;
35+
static FILE * target_file = 0;
36+
37+
int bit_buffer = 0, bit_mask = 128;
38+
unsigned char buffer[N * 2];
39+
40+
static char write_buf[FPUTC_BUF_SIZE];
41+
static size_t write_buf_num_bytes = 0;
42+
static size_t bytes_written_fputc = 0;
43+
static SFUWatchdogResetFuncPointer wdog_feed_func = 0;
44+
45+
/**************************************************************************************
46+
PUBLIC FUNCTIONS
47+
**************************************************************************************/
48+
49+
void lzss_init(FILE * update_file_ptr, FILE * target_file_ptr, uint32_t const lzss_file_size, SFUWatchdogResetFuncPointer wdog_feed_func_ptr)
50+
{
51+
update_file = update_file_ptr;
52+
target_file = target_file_ptr;
53+
LZSS_FILE_SIZE = lzss_file_size;
54+
wdog_feed_func = wdog_feed_func_ptr;
55+
}
56+
57+
void lzss_flush()
58+
{
59+
bytes_written_fputc += write_buf_num_bytes;
60+
61+
if (wdog_feed_func)
62+
wdog_feed_func();
63+
64+
fwrite(write_buf, 1, write_buf_num_bytes, target_file);
65+
66+
write_buf_num_bytes = 0;
67+
}
68+
69+
/**************************************************************************************
70+
PRIVATE FUNCTIONS
71+
**************************************************************************************/
72+
73+
void lzss_fputc(int const c)
74+
{
75+
/* Buffer the decompressed data into a buffer so
76+
* we can perform block writes and don't need to
77+
* write every byte singly on the flash (which
78+
* wouldn't be possible anyway).
79+
*/
80+
write_buf[write_buf_num_bytes] = static_cast<char>(c);
81+
write_buf_num_bytes++;
82+
83+
/* The write buffer is full of decompressed
84+
* data, write it to the flash now.
85+
*/
86+
if (write_buf_num_bytes == FPUTC_BUF_SIZE)
87+
lzss_flush();
88+
}
89+
90+
int lzss_fgetc()
91+
{
92+
static uint8_t read_buf[FGETC_BUF_SIZE];
93+
static size_t read_buf_pos = FGETC_BUF_SIZE;
94+
static size_t bytes_read_fgetc = 0;
95+
static size_t bytes_read_from_modem = 0;
96+
97+
/* lzss_file_size is set within SSUBoot:main
98+
* and contains the size of the LZSS file. Once
99+
* all those bytes have been read its time to return
100+
* LZSS_EOF in order to signal that the end of
101+
* the file has been reached.
102+
*/
103+
if (bytes_read_fgetc == LZSS_FILE_SIZE)
104+
return LZSS_EOF;
105+
106+
/* If there is no data left to be read from the read buffer
107+
* than read a new block and store it into the read buffer.
108+
*/
109+
if (read_buf_pos == FGETC_BUF_SIZE)
110+
{
111+
/* Read the next block from the flash memory. */
112+
bytes_read_from_modem += fread(read_buf, 1, FGETC_BUF_SIZE, update_file);
113+
/* Reset the read buffer position. */
114+
read_buf_pos = 0;
115+
}
116+
117+
uint8_t const c = read_buf[read_buf_pos];
118+
read_buf_pos++;
119+
bytes_read_fgetc++;
120+
121+
return c;
122+
}
123+
124+
/**************************************************************************************
125+
LZSS FUNCTIONS
126+
**************************************************************************************/
127+
128+
void putbit1(void)
129+
{
130+
bit_buffer |= bit_mask;
131+
if ((bit_mask >>= 1) == 0) {
132+
lzss_fputc(bit_buffer);
133+
bit_buffer = 0; bit_mask = 128;
134+
}
135+
}
136+
137+
void putbit0(void)
138+
{
139+
if ((bit_mask >>= 1) == 0) {
140+
lzss_fputc(bit_buffer);
141+
bit_buffer = 0; bit_mask = 128;
142+
}
143+
}
144+
145+
void output1(int c)
146+
{
147+
int mask;
148+
149+
putbit1();
150+
mask = 256;
151+
while (mask >>= 1) {
152+
if (c & mask) putbit1();
153+
else putbit0();
154+
}
155+
}
156+
157+
void output2(int x, int y)
158+
{
159+
int mask;
160+
161+
putbit0();
162+
mask = N;
163+
while (mask >>= 1) {
164+
if (x & mask) putbit1();
165+
else putbit0();
166+
}
167+
mask = (1 << EJ);
168+
while (mask >>= 1) {
169+
if (y & mask) putbit1();
170+
else putbit0();
171+
}
172+
}
173+
174+
int getbit(int n) /* get n bits */
175+
{
176+
int i, x;
177+
static int buf, mask = 0;
178+
179+
x = 0;
180+
for (i = 0; i < n; i++) {
181+
if (mask == 0) {
182+
if ((buf = lzss_fgetc()) == LZSS_EOF) return LZSS_EOF;
183+
mask = 128;
184+
}
185+
x <<= 1;
186+
if (buf & mask) x++;
187+
mask >>= 1;
188+
}
189+
return x;
190+
}
191+
192+
void lzss_decode(void)
193+
{
194+
int i, j, k, r, c;
195+
196+
for (i = 0; i < N - F; i++) buffer[i] = ' ';
197+
r = N - F;
198+
while ((c = getbit(1)) != LZSS_EOF) {
199+
if (c) {
200+
if ((c = getbit(8)) == LZSS_EOF) break;
201+
lzss_fputc(c);
202+
buffer[r++] = c; r &= (N - 1);
203+
} else {
204+
if ((i = getbit(EI)) == LZSS_EOF) break;
205+
if ((j = getbit(EJ)) == LZSS_EOF) break;
206+
for (k = 0; k <= j + 1; k++) {
207+
c = buffer[(i + k) & (N - 1)];
208+
lzss_fputc(c);
209+
buffer[r++] = c; r &= (N - 1);
210+
}
211+
}
212+
}
213+
}

‎libraries/SFU/extra/loader/lzss.h

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
lzss.h
3+
Copyright (c) 2023 Arduino SA. All right reserved.
4+
5+
This library is free software; you can redistribute it and/or
6+
modify it under the terms of the GNU Lesser General Public
7+
License as published by the Free Software Foundation; either
8+
version 2.1 of the License, or (at your option) any later version.
9+
10+
This library is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
Lesser General Public License for more details.
14+
15+
You should have received a copy of the GNU Lesser General Public
16+
License along with this library; if not, write to the Free Software
17+
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18+
*/
19+
20+
#ifndef SSU_LZSS_H_
21+
#define SSU_LZSS_H_
22+
23+
/**************************************************************************************
24+
INCLUDE
25+
**************************************************************************************/
26+
27+
#include <stdint.h>
28+
#include <stdio.h>
29+
30+
typedef void(*SFUWatchdogResetFuncPointer)(void);
31+
32+
/**************************************************************************************
33+
FUNCTION DEFINITION
34+
**************************************************************************************/
35+
36+
void lzss_init(FILE * update_file_ptr, FILE * target_file_ptr, uint32_t const lzss_file_size, SFUWatchdogResetFuncPointer wdog_feed_func_ptr);
37+
void lzss_decode();
38+
void lzss_flush();
39+
40+
#endif /* SSU_LZSS_H_ */

‎libraries/SFU/extra/loader/ota.cpp

Lines changed: 308 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,308 @@
1+
/*
2+
ota.cpp
3+
Copyright (c) 2023 Arduino SA. All right reserved.
4+
5+
This library is free software; you can redistribute it and/or
6+
modify it under the terms of the GNU Lesser General Public
7+
License as published by the Free Software Foundation; either
8+
version 2.1 of the License, or (at your option) any later version.
9+
10+
This library is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
Lesser General Public License for more details.
14+
15+
You should have received a copy of the GNU Lesser General Public
16+
License along with this library; if not, write to the Free Software
17+
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18+
*/
19+
20+
#define _GNU_SOURCE
21+
#include <string.h>
22+
#include "ota.h"
23+
24+
#ifdef PORTENTA_C33_SFU_DEBUG_OTA
25+
#include <Arduino_DebugUtils.h>
26+
#endif
27+
28+
29+
static const uint32_t crc_table[256] = {
30+
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
31+
0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
32+
0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
33+
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
34+
0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
35+
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
36+
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
37+
0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
38+
0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
39+
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
40+
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
41+
0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
42+
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
43+
0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
44+
0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
45+
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
46+
0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
47+
0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
48+
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
49+
0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
50+
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
51+
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
52+
0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
53+
0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
54+
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
55+
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
56+
0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
57+
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
58+
0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
59+
0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
60+
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
61+
0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
62+
};
63+
64+
union HeaderVersion
65+
{
66+
struct __attribute__((packed))
67+
{
68+
uint32_t header_version : 6;
69+
uint32_t compression : 1;
70+
uint32_t signature : 1;
71+
uint32_t spare : 4;
72+
uint32_t payload_target : 4;
73+
uint32_t payload_major : 8;
74+
uint32_t payload_minor : 8;
75+
uint32_t payload_patch : 8;
76+
uint32_t payload_build_num : 24;
77+
} field;
78+
uint8_t buf[sizeof(field)];
79+
static_assert(sizeof(buf) == 8, "Error: sizeof(HEADER.VERSION) != 8");
80+
};
81+
82+
union
83+
{
84+
struct __attribute__((packed))
85+
{
86+
uint32_t len;
87+
uint32_t crc32;
88+
uint32_t magic_number;
89+
HeaderVersion hdr_version;
90+
} header;
91+
uint8_t buf[sizeof(header)];
92+
static_assert(sizeof(buf) == 20, "Error: sizeof(HEADER) != 20");
93+
} ota_header;
94+
95+
96+
/**************************************************************************************
97+
FUNCTIONS
98+
**************************************************************************************/
99+
100+
uint32_t crc_update(uint32_t crc, const void * data, size_t data_len)
101+
{
102+
const unsigned char *d = (const unsigned char *)data;
103+
unsigned int tbl_idx;
104+
105+
while (data_len--) {
106+
tbl_idx = (crc ^ *d) & 0xff;
107+
crc = (crc_table[tbl_idx] ^ (crc >> 8)) & 0xffffffff;
108+
d++;
109+
}
110+
111+
return crc & 0xffffffff;
112+
}
113+
114+
int verify_header(FILE* update_file) {
115+
116+
uint32_t crc32, bytes_read;
117+
uint8_t crc_buf[128];
118+
119+
fseek(update_file, 0, SEEK_END);
120+
long update_file_size = ftell(update_file);
121+
fseek(update_file, 0, SEEK_SET);
122+
123+
#ifdef PORTENTA_C33_SFU_DEBUG_OTA
124+
DEBUG_INFO("Reading OTA header..");
125+
#endif
126+
127+
/* Read the OTA header ... */
128+
fread(ota_header.buf, 1, sizeof(ota_header.buf), update_file);
129+
130+
/* ... and check first length ... */
131+
if (ota_header.header.len != (update_file_size - sizeof(ota_header.header.len) - sizeof(ota_header.header.crc32))) {
132+
#ifdef PORTENTA_C33_SFU_DEBUG_OTA
133+
DEBUG_ERROR("Wrong length");
134+
#endif
135+
return -1;
136+
}
137+
138+
/* ... and the CRC second ... rewind to start of CRC verified header ... */
139+
fseek(update_file, sizeof(ota_header.header.len) + sizeof(ota_header.header.crc32), SEEK_SET);
140+
/* ... initialize CRC ... */
141+
crc32 = 0xFFFFFFFF;
142+
/* ... and calculate over file ... */
143+
for(bytes_read = 0;
144+
bytes_read < (ota_header.header.len - sizeof(crc_buf));
145+
bytes_read += sizeof(crc_buf))
146+
{
147+
fread(crc_buf, 1, sizeof(crc_buf), update_file);
148+
crc32 = crc_update(crc32, crc_buf, sizeof(crc_buf));
149+
}
150+
fread(crc_buf, 1, ota_header.header.len - bytes_read, update_file);
151+
crc32 = crc_update(crc32, crc_buf, ota_header.header.len - bytes_read);
152+
/* ... then finalise ... */
153+
crc32 ^= 0xFFFFFFFF;
154+
/* ... and compare. */
155+
if (ota_header.header.crc32 != crc32) {
156+
#ifdef PORTENTA_C33_SFU_DEBUG_OTA
157+
DEBUG_ERROR("Wrong crc32\n");
158+
#endif
159+
return -2;
160+
}
161+
162+
if (ota_header.header.magic_number != 0x23410068) /* 2341:005E = VID/PID Portenta C33 */
163+
{
164+
#ifdef PORTENTA_C33_SFU_DEBUG_OTA
165+
DEBUG_ERROR("Wrong magic\n");
166+
#endif
167+
return -3;
168+
}
169+
return 0;
170+
}
171+
172+
173+
int decompress(FILE* update_file, FILE* target_file, SFUWatchdogResetFuncPointer wdog_feed_func_ptr) {
174+
175+
fseek(update_file, 0, SEEK_END);
176+
long update_file_size = ftell(update_file);
177+
fseek(update_file, sizeof(ota_header.buf), SEEK_SET);
178+
179+
uint32_t const LZSS_FILE_SIZE = update_file_size - sizeof(ota_header.buf);
180+
181+
#ifdef PORTENTA_C33_SFU_DEBUG_OTA
182+
DEBUG_INFO("Decompressing OTA binary..");
183+
#endif
184+
185+
lzss_init(update_file, target_file, LZSS_FILE_SIZE, wdog_feed_func_ptr);
186+
lzss_decode();
187+
lzss_flush();
188+
189+
return 0;
190+
}
191+
192+
int verify_sketch(FILE* file) {
193+
const uint32_t page_size = 4096;
194+
char *page_buffer = new char[page_size];
195+
196+
#ifdef PORTENTA_C33_SFU_DEBUG_OTA
197+
DEBUG_INFO("Veryfing OTA binary..");
198+
#endif
199+
200+
fseek(file, 0, SEEK_END);
201+
// Skip the first POST_APPLICATION_ADDR bytes
202+
long len = ftell(file) - POST_APPLICATION_ADDR;
203+
204+
if (len < 0) {
205+
#ifdef PORTENTA_C33_SFU_DEBUG_OTA
206+
DEBUG_ERROR("OTA binary invalid length: %d", len);
207+
#endif
208+
delete[] page_buffer;
209+
return -1;
210+
}
211+
212+
fseek(file, 0, SEEK_SET);
213+
int size_read = 0;
214+
while (size_read < POST_APPLICATION_ADDR) {
215+
memset(page_buffer, 0, sizeof(char) * page_size);
216+
size_read += fread(page_buffer, 1, page_size, file);
217+
if (memmem((const char*)page_buffer, page_size, "SFU version", 11) != NULL) {
218+
#ifdef PORTENTA_C33_SFU_DEBUG_OTA
219+
DEBUG_ERROR("OTA binary signature string found\n");
220+
#endif
221+
break;
222+
}
223+
}
224+
if (size_read >= POST_APPLICATION_ADDR) {
225+
#ifdef PORTENTA_C33_SFU_DEBUG_OTA
226+
DEBUG_ERROR("OTA binary does not contain SFU, won't flash it\n");
227+
#endif
228+
delete[] page_buffer;
229+
return -2;
230+
}
231+
delete[] page_buffer;
232+
return 0;
233+
}
234+
235+
int flash(FILE *file, CodeFlashBlockDevice* cf, uint32_t address)
236+
{
237+
const uint32_t page_size = cf->get_program_size();
238+
char *page_buffer = new char[page_size];
239+
240+
#ifdef PORTENTA_C33_SFU_DEBUG_OTA
241+
DEBUG_INFO("Flashing OTA binary..");
242+
#endif
243+
244+
cf->init();
245+
fseek(file, 0, SEEK_END);
246+
long len = ftell(file) - POST_APPLICATION_ADDR;
247+
248+
fseek(file, POST_APPLICATION_ADDR, SEEK_SET);
249+
250+
uint32_t addr = address;
251+
uint32_t size = 0;
252+
uint32_t next_sector = addr + cf->get_erase_size(addr);
253+
bool sector_erased = false;
254+
size_t pages_flashed = 0;
255+
uint32_t percent_done = 0;
256+
while (true) {
257+
258+
if(size >= len) {
259+
#ifdef PORTENTA_C33_SFU_DEBUG_OTA
260+
DEBUG_INFO("Flashed 100%%");
261+
#endif
262+
break;
263+
}
264+
265+
// Read data for this page
266+
memset(page_buffer, 0, sizeof(char) * page_size);
267+
int size_read = fread(page_buffer, 1, page_size, file);
268+
if (size_read <= 0) {
269+
#ifdef PORTENTA_C33_SFU_DEBUG_OTA
270+
DEBUG_ERROR("Error reading %d bytes from OTA binary", size_read);
271+
#endif
272+
break;
273+
}
274+
275+
// Erase this page if it hasn't been erased
276+
if (!sector_erased) {
277+
cf->erase(addr, cf->get_erase_size(addr));
278+
sector_erased = true;
279+
}
280+
281+
// Program page
282+
cf->program(page_buffer, addr, page_size);
283+
284+
addr += page_size;
285+
size += page_size;
286+
if (addr >= next_sector) {
287+
next_sector = addr + cf->get_erase_size(addr);
288+
sector_erased = false;
289+
}
290+
291+
if (++pages_flashed % 3 == 0) {
292+
uint32_t percent_done_new = (ftell(file) - POST_APPLICATION_ADDR )* 100 / len;
293+
if (percent_done != percent_done_new) {
294+
percent_done = percent_done_new;
295+
#ifdef PORTENTA_C33_SFU_DEBUG_OTA
296+
DEBUG_INFO("Flashed %3ld%%", percent_done);
297+
#endif
298+
}
299+
}
300+
}
301+
302+
303+
delete[] page_buffer;
304+
305+
cf->deinit();
306+
307+
return 0;
308+
}

‎libraries/SFU/extra/loader/ota.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
ota.h
3+
Copyright (c) 2023 Arduino SA. All right reserved.
4+
5+
This library is free software; you can redistribute it and/or
6+
modify it under the terms of the GNU Lesser General Public
7+
License as published by the Free Software Foundation; either
8+
version 2.1 of the License, or (at your option) any later version.
9+
10+
This library is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
Lesser General Public License for more details.
14+
15+
You should have received a copy of the GNU Lesser General Public
16+
License along with this library; if not, write to the Free Software
17+
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18+
*/
19+
20+
#ifndef SFU_OTA_H_
21+
#define SFU_OTA_H_
22+
23+
#include <CodeFlashBlockDevice.h>
24+
#include "lzss.h"
25+
26+
#define POST_APPLICATION_ADDR (0x20000)
27+
28+
int verify_header(FILE* update_file);
29+
int decompress(FILE* update_file, FILE* target_file, SFUWatchdogResetFuncPointer wdog_feed_func_ptr);
30+
int verify_sketch(FILE* file);
31+
int flash(FILE *file, CodeFlashBlockDevice* flash, uint32_t address);
32+
33+
#endif

‎libraries/SFU/library.properties

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
name=SFU
2+
version=1.0.0
3+
author=Arduino
4+
maintainer=Arduino <info@arduino.cc>
5+
sentence=Second stage bootloader for Portenta C33
6+
paragraph=
7+
category=Other
8+
url=https://www.arduino.cc/en/Reference/SFU
9+
architectures=renesas_portenta,renesas

‎libraries/SFU/src/SFU.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*
2+
SFU.h
3+
Copyright (c) 2023 Arduino SA. All right reserved.
4+
5+
This library is free software; you can redistribute it and/or
6+
modify it under the terms of the GNU Lesser General Public
7+
License as published by the Free Software Foundation; either
8+
version 2.1 of the License, or (at your option) any later version.
9+
10+
This library is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
Lesser General Public License for more details.
14+
15+
You should have received a copy of the GNU Lesser General Public
16+
License along with this library; if not, write to the Free Software
17+
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18+
*/
19+
20+
#include "SFU.h"
21+
22+
const unsigned char SFU[0x20000] __attribute__ ((section(".second_stage_ota"), used)) = {
23+
#include "c33.h"
24+
};

‎libraries/SFU/src/SFU.h

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
SFU.h
3+
Copyright (c) 2023 Arduino SA. All right reserved.
4+
5+
This library is free software; you can redistribute it and/or
6+
modify it under the terms of the GNU Lesser General Public
7+
License as published by the Free Software Foundation; either
8+
version 2.1 of the License, or (at your option) any later version.
9+
10+
This library is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13+
Lesser General Public License for more details.
14+
15+
You should have received a copy of the GNU Lesser General Public
16+
License along with this library; if not, write to the Free Software
17+
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18+
*/
19+
20+
#ifndef _SFU_H_
21+
#define _SFU_H_
22+
23+
#include "Arduino.h"
24+
25+
class SFU {
26+
public:
27+
static int begin();
28+
static int download(const char* url);
29+
static int apply();
30+
};
31+
32+
#endif // _SFU_H_

‎libraries/SFU/src/c33.h

Lines changed: 5910 additions & 0 deletions
Large diffs are not rendered by default.

‎variants/PORTENTA_C33/fsp.ld

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,8 @@ SECTIONS
145145
__tz_FLASH_S = ABSOLUTE(FLASH_START);
146146
__ROM_Start = .;
147147

148+
KEEP (*(.second_stage_ota))
149+
148150
/* Even though the vector table is not 256 entries (1KB) long, we still allocate that much
149151
* space because ROM registers are at address 0x400 and there is very little space
150152
* in between. */

0 commit comments

Comments
 (0)
Please sign in to comment.