Skip to content

Commit 23d740d

Browse files
committed
update doc
1 parent b64cc5e commit 23d740d

File tree

2 files changed

+304
-1
lines changed

2 files changed

+304
-1
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ The idea is not new: [Tasmota also uses a SafeBoot partition](https://tasmota.gi
2626
- [Options matrix](#options-matrix)
2727
- [Default board options](#default-board-options)
2828

29-
[![](https://mathieu.carbou.me/MycilaSafeBoot/safeboot-ssid.jpeg)](https://mathieu.carbou.me/MycilaSafeBoot/safeboot-ssid.jpeg)
29+
![](https://private-user-images.githubusercontent.com/61346/426535795-7eda5f6e-7900-4380-921f-8e54fb2b2e2c.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3NDI5MDgwOTEsIm5iZiI6MTc0MjkwNzc5MSwicGF0aCI6Ii82MTM0Ni80MjY1MzU3OTUtN2VkYTVmNmUtNzkwMC00MzgwLTkyMWYtOGU1NGZiMmIyZTJjLnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNTAzMjUlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjUwMzI1VDEzMDMxMVomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPThkNTVjMTJjNzZmNzdiYWZkZjkxZWE4ZTkxOWM4MTQ1MzliZTFhNzRkZmU5NzY5MTk2MWJmMjQyYzJiN2Y1OTAmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.7vsJcZDQrAa4Z_G4R663ENGhQDNTleVThGd6x8GAnGo)
3030

3131
## Overview
3232

docs/index.md

Lines changed: 303 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,263 @@ The idea is not new: [Tasmota also uses a SafeBoot partition](https://tasmota.gi
2626
- [Options matrix](#options-matrix)
2727
- [Default board options](#default-board-options)
2828

29+
![](https://private-user-images.githubusercontent.com/61346/426535795-7eda5f6e-7900-4380-921f-8e54fb2b2e2c.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3NDI5MDgwOTEsIm5iZiI6MTc0MjkwNzc5MSwicGF0aCI6Ii82MTM0Ni80MjY1MzU3OTUtN2VkYTVmNmUtNzkwMC00MzgwLTkyMWYtOGU1NGZiMmIyZTJjLnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNTAzMjUlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjUwMzI1VDEzMDMxMVomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPThkNTVjMTJjNzZmNzdiYWZkZjkxZWE4ZTkxOWM4MTQ1MzliZTFhNzRkZmU5NzY5MTk2MWJmMjQyYzJiN2Y1OTAmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.7vsJcZDQrAa4Z_G4R663ENGhQDNTleVThGd6x8GAnGo)
30+
31+
## Overview
32+
33+
Usually, a normal partition table when supporting OTA updates on a 4MB ESP32 looks like this:
34+
35+
```
36+
# Name, Type, SubType, Offset, Size, Flags
37+
nvs, data, nvs, 0x9000, 0x5000,
38+
otadata, data, ota, 0xE000, 0x2000,
39+
app0, app, ota_0, 0x10000, 0x1F0000,
40+
app1, app, ota_1, 0x200000, 0x1F0000,
41+
spiffs, data, spiffs, 0x3F0000, 0x10000,
42+
```
43+
44+
which can also be written as:
45+
46+
```
47+
# Name ,Type ,SubType ,Offset ,Size ,Flags
48+
nvs ,data ,nvs ,36K ,20K ,
49+
otadata ,data ,ota ,56K ,8K ,
50+
app0 ,app ,ota_0 ,64K ,1984K ,
51+
app1 ,app ,ota_1 ,2048K ,1984K ,
52+
spiffs ,data ,spiffs ,4032K ,64K ,
53+
```
54+
55+
Because of the need to have 2 partitions with the same size, the firmware is then limited to only 2MB in this case when the ESP has 4MB flash.
56+
2MB is left unused (the OTA process will switch to the updated partition once completed).
57+
58+
**A SafeBoot partition is a small bootable recovery partition allowing you to flash the firmware.**
59+
Consequently, the firmware can take all the remaining space on the flash.
60+
61+
**The SafeBoot partition is 655360 bytes only.**
62+
63+
**Example for 4MB partition** with a SafeBoot partition and an application size of 3MB:
64+
65+
```
66+
# Name, Type, SubType, Offset, Size, Flags
67+
nvs, data, nvs, 0x9000, 0x5000,
68+
otadata, data, ota, 0xE000, 0x2000,
69+
safeboot, app, factory, 0x10000, 0xA0000,
70+
app, app, ota_0, 0xB0000, 0x330000,
71+
spiffs, data, spiffs, 0x3E0000, 0x10000,
72+
coredump, data, coredump, 0x3F0000, 0x10000,
73+
```
74+
75+
which can also be written as:
76+
77+
```
78+
# Name ,Type ,SubType ,Offset ,Size ,Flags
79+
nvs ,data ,nvs ,36K ,20K ,
80+
otadata ,data ,ota ,56K ,8K ,
81+
safeboot ,app ,factory ,64K ,640K ,
82+
app ,app ,ota_0 ,704K ,3264K ,
83+
spiffs ,data ,spiffs ,3968K ,64K ,
84+
coredump ,data ,coredump ,4032K ,64K ,
85+
```
86+
87+
**Example for 8Mb partition** with a SafeBoot partition and an application size of 7MB:
88+
89+
```
90+
# Name, Type, SubType, Offset, Size, Flags
91+
nvs, data, nvs, 0x9000, 0x5000,
92+
otadata, data, ota, 0xE000, 0x2000,
93+
safeboot, app, factory, 0x10000, 0xA0000,
94+
app, app, ota_0, 0xB0000, 0x730000,
95+
spiffs data, spiffs, 0x7E0000, 0x10000,
96+
coredump, data, coredump, 0x7F0000, 0x10000,
97+
```
98+
99+
which can also be written as:
100+
101+
```
102+
# Name ,Type ,SubType ,Offset ,Size ,Flags
103+
nvs ,data ,nvs ,36K ,20K ,
104+
otadata ,data ,ota ,56K ,8K ,
105+
safeboot ,app ,factory ,64K ,640K ,
106+
app ,app ,ota_0 ,704K ,7312K ,
107+
spiffs ,data ,spiffs ,8128K ,64K ,
108+
coredump ,data ,coredump ,8192K ,64K ,
109+
```
110+
111+
The SafeBoot partition is also automatically booted when the firmware is missing.
112+
113+
## How it works
114+
115+
1. When a user wants to update the app firmware, we have to tell the app to reboot in recovery mode.
116+
117+
2. Once booted in recovery mode, an Access Point is created with the SSID `SafeBoot`.
118+
119+
[![](https://mathieu.carbou.me/MycilaSafeBoot/safeboot-ssid.jpeg)](https://mathieu.carbou.me/MycilaSafeBoot/safeboot-ssid.jpeg)
120+
121+
3. Connect to the Access Point.
122+
123+
4. Now, you can flash the new firmware, either with `ArduinoOTA` or from the web page by going to `http://192.168.4.1`
124+
125+
5. After the flash is successful, the ESP will reboot in the new firmware.
126+
127+
SafeBoot partition also supports [MycilaESPConnect](https://github.com/mathieucarbou/MycilaESPConnect), which means if your application saves some network settings (WiFi SSID, Ethernet or WiFi static IP, etc), they will be reused.
128+
129+
## How to integrate the SafeBoot in your project
130+
131+
In the PIO file, some settings are added to specify the partition table and the SafeBoot location and the script to generate the factory image.
132+
133+
```ini
134+
extra_scripts = post:factory.py
135+
board_build.partitions = partitions-4MB-safeboot.csv
136+
board_build.app_partition_name = app
137+
custom_safeboot_url = https://github.com/mathieucarbou/MycilaSafeBoot/releases/download/latest/safeboot-esp32dev.bin
138+
```
139+
140+
It is also possible to point to a folder if you download the SafeBoot project locally:
141+
142+
```ini
143+
custom_safeboot_dir = ../../tools/SafeBoot
144+
```
145+
146+
It is also possible to point to a pre-downloaded safeoot image:
147+
148+
```ini
149+
custom_safeboot_file = safeboot.bin
150+
```
151+
152+
You can find in the [Project Releases](https://github.com/mathieucarbou/MycilaSafeBoot/releases) the list of available SafeBoot images, with the Python script to add to your build.
153+
154+
## How to build the SafeBoot firmware image
155+
156+
Go inside `tools/SafeBoot` and run:
157+
158+
```bash
159+
> pio run -e esp32dev
160+
```
161+
162+
If your board does not exist, you can specify it like this:
163+
164+
```bash
165+
> SAFEBOOT_BOARD=my-board pio run -e safeboot
166+
```
167+
168+
`SAFEBOOT_BOARD` is the environment variable to specify the board to build the SafeBoot firmware for.
169+
170+
At the end you should see these lines:
171+
172+
```
173+
Firmware size valid: 619744 <= 655360
174+
SafeBoot firmware created: /Users/mat/Data/Workspace/me/MycilaSafeBoot/.pio/build/dev/safeboot.bin
175+
```
176+
177+
## SafeBoot Example
178+
179+
Go inside `examples/App` and execute:
180+
181+
```bash
182+
> pio run
183+
```
184+
185+
You should see at the end of the build something like:
186+
187+
```
188+
Generating factory image for serial flashing
189+
Downloading SafeBoot image from https://github.com/mathieucarbou/MycilaSafeBoot/releases/download/latest/safeboot-esp32dev.bin
190+
Offset | File
191+
- 0x1000 | /Users/mat/Data/Workspace/me/MycilaSafeBoot/examples/App/.pio/build/esp32dev/bootloader.bin
192+
- 0x8000 | /Users/mat/Data/Workspace/me/MycilaSafeBoot/examples/App/.pio/build/esp32dev/partitions.bin
193+
- 0xe000 | /Users/mat/.platformio/packages/framework-arduinoespressif32@src-17df1753722b7b9e1913598420d4e038/tools/partitions/boot_app0.bin
194+
- 0x10000 | /Users/mat/Data/Workspace/me/MycilaSafeBoot/examples/App/.pio/build/esp32dev/safeboot.bin
195+
- 0xb0000 | /Users/mat/Data/Workspace/me/MycilaSafeBoot/examples/App/.pio/build/esp32dev/firmware.bin
196+
197+
[...]
198+
199+
Wrote 0x1451a0 bytes to file /Users/mat/Data/Workspace/me/MycilaSafeBoot/examples/App/.pio/build/esp32dev/firmware.factory.bin, ready to flash to offset 0x0
200+
Factory image generated: /Users/mat/Data/Workspace/me/MycilaSafeBoot/examples/App/.pio/build/esp32dev/firmware.factory.bin
201+
```
202+
203+
the `factory.py` script generates a complete factory image named `firmware.factory.bin` with all this content.
204+
205+
Flash this factory image on an ESP32:
206+
207+
```bash
208+
esptool.py write_flash 0x0 .pio/build/esp32dev/firmware.factory.bin
209+
```
210+
211+
Restart the ESP.
212+
The app loads, shows a button to restart in SafeBoot mode.
213+
After clicking on it, the ESP will reboot into SafeBoot mode.
214+
From there, you can access the web page to flash a new firmware, even from another application.
215+
216+
## How to reboot in SafeBoot mode from the app
217+
218+
You can use [MycilaSystem](https://github.com/mathieucarbou/MycilaSystem):
219+
220+
```cpp
221+
#include <MycilaSystem.h>
222+
223+
espConnect.saveConfiguration(); // if you want to save ESPConnect settings for network
224+
Mycila::System::restartFactory("safeboot");
225+
```
226+
227+
or this custom code:
228+
229+
```cpp
230+
#include <esp_ota_ops.h>
231+
#include <esp_partition.h>
232+
233+
const esp_partition_t* partition = esp_partition_find_first(esp_partition_type_t::ESP_PARTITION_TYPE_APP, esp_partition_subtype_t::ESP_PARTITION_SUBTYPE_APP_FACTORY, partitionName);
234+
if (partition) {
235+
esp_ota_set_boot_partition(partition);
236+
esp_restart();
237+
return true;
238+
} else {
239+
ESP_LOGE("SafeBoot", "SafeBoot partition not found");
240+
return false;
241+
}
242+
```
243+
244+
## Configuration options to manage build size
245+
246+
Squezing everything into the SafeBoot partition (655360 bytes only) is a tight fit especially on ethernet enabled boards.
247+
248+
Disabling the logging capabilites saves about 12 kbytes in the final build. Just comment out `SAFEBOOT_LOGGING` in `platformio.ini`.
249+
250+
```ini
251+
; -D SAFEBOOT_LOGGING
252+
```
253+
254+
Disabling mDNS saves about 24 kbytes. Enable both [...]\_NO_DNS options in `platformio.ini` to reduce the build size:
255+
256+
```ini
257+
-D ESPCONNECT_NO_MDNS
258+
-D MYCILA_SAFEBOOT_NO_MDNS# MycilaSafeBoot
259+
260+
[![Latest Release](https://img.shields.io/github/release/mathieucarbou/MycilaSafeBoot.svg)](https://GitHub.com/mathieucarbou/MycilaSafeBoot/releases/)
261+
[![Download](https://img.shields.io/badge/Download-safeboot-green.svg)](https://github.com/mathieucarbou/MycilaSafeBoot/releases)
262+
263+
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
264+
[![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-2.1-4baaaa.svg)](code_of_conduct.md)
265+
266+
[![Build](https://github.com/mathieucarbou/MycilaSafeBoot/actions/workflows/build.yml/badge.svg)](https://github.com/mathieucarbou/MycilaSafeBoot/actions/workflows/build.yml)
267+
[![GitHub latest commit](https://badgen.net/github/last-commit/mathieucarbou/MycilaSafeBoot)](https://GitHub.com/mathieucarbou/MycilaSafeBoot/commit/)
268+
[![Gitpod Ready-to-Code](https://img.shields.io/badge/Gitpod-Ready--to--Code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/mathieucarbou/MycilaSafeBoot)
269+
270+
MycilaSafeBoot is a Web OTA recovery partition for ESP32 / Arduino.
271+
272+
It allows to have only one application partition to use the maximum available flash size.
273+
274+
The idea is not new: [Tasmota also uses a SafeBoot partition](https://tasmota.github.io/docs/Safeboot/).
275+
276+
- [Overview](#overview)
277+
- [How it works](#how-it-works)
278+
- [How to integrate the SafeBoot in your project](#how-to-integrate-the-safeboot-in-your-project)
279+
- [How to build the SafeBoot firmware image](#how-to-build-the-safeboot-firmware-image)
280+
- [SafeBoot Example](#safeboot-example)
281+
- [How to reboot in SafeBoot mode from the app](#how-to-reboot-in-safeboot-mode-from-the-app)
282+
- [Configuration options to manage build size](#configuration-options-to-manage-build-size)
283+
- [Options matrix](#options-matrix)
284+
- [Default board options](#default-board-options)
285+
29286
[![](https://mathieu.carbou.me/MycilaSafeBoot/safeboot-ssid.jpeg)](https://mathieu.carbou.me/MycilaSafeBoot/safeboot-ssid.jpeg)
30287

31288
## Overview
@@ -301,3 +558,49 @@ Disabling mDNS saves about 24 kbytes. Enable both [...]\_NO_DNS options in `plat
301558
| wemos_d1_uno32 ||||
302559
| wipy3 ||||
303560
| wt32-eth01 ||||
561+
562+
```
563+
564+
### Options matrix
565+
566+
| Board | mDNS: on, logger: on | mDNS: on, logger: off | mDNS: off, logger: off |
567+
| -------------------- | -------------------- | --------------------- | ---------------------- |
568+
| denky_d4 | NOT SUPPORTED | OK | OK |
569+
| esp32-c3-devkitc-02 | OK | OK | OK |
570+
| esp32-c6-devkitc-1 | NOT SUPPORTED | NOT SUPPORTED | OK |
571+
| esp32-gateway | NOT SUPPORTED | OK | OK |
572+
| esp32-poe | NOT SUPPORTED | NOT SUPPORTED | OK |
573+
| esp32-poe-iso | NOT SUPPORTED | NOT SUPPORTED | OK |
574+
| esp32-s2-saola-1 | OK | OK | OK |
575+
| esp32-s3-devkitc-1 | OK | OK | OK |
576+
| esp32-solo1 | OK | OK | OK |
577+
| esp32dev | OK | OK | OK |
578+
| esp32s3box | OK | OK | OK |
579+
| lilygo-t-eth-lite-s3 | OK | OK | OK |
580+
| lolin_s2_mini | OK | OK | OK |
581+
| tinypico | NOT SUPPORTED | OK | OK |
582+
| wemos_d1_uno32 | OK | OK | OK |
583+
| wipy3 | NOT SUPPORTED | OK | OK |
584+
| wt32-eth01 | NOT SUPPORTED | NOT SUPPORTED | OK |
585+
586+
## Default board options
587+
588+
| Board | mDNS | Logging |
589+
| :------------------- | :--: | :-----: |
590+
| denky_d4 | ✅ | ❌ |
591+
| esp32-c3-devkitc-02 | ✅ | ✅ |
592+
| esp32-c6-devkitc-1 | ❌ | ❌ |
593+
| esp32-gateway | ✅ | ❌ |
594+
| esp32-poe | ❌ | ❌ |
595+
| esp32-poe-iso | ❌ | ❌ |
596+
| esp32-s2-saola-1 | ✅ | ✅ |
597+
| esp32-s3-devkitc-1 | ✅ | ✅ |
598+
| esp32-solo1 | ✅ | ✅ |
599+
| esp32dev | ✅ | ✅ |
600+
| esp32s3box | ✅ | ✅ |
601+
| lilygo-t-eth-lite-s3 | ✅ | ✅ |
602+
| lolin_s2_mini | ✅ | ✅ |
603+
| tinypico | ✅ | ❌ |
604+
| wemos_d1_uno32 | ✅ | ✅ |
605+
| wipy3 | ✅ | ❌ |
606+
| wt32-eth01 | ❌ | ❌ |

0 commit comments

Comments
 (0)