Skip to content

Commit e0b9b05

Browse files
committed
feat(examples): Add ESP32 fast reflash example with MD5 check
1 parent dd480bc commit e0b9b05

File tree

10 files changed

+286
-2
lines changed

10 files changed

+286
-2
lines changed

examples/common/bin2array.cmake

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,14 @@ function(create_resources dir output)
1414
file(READ ${bin} filedata HEX)
1515
# Convert hex data for C compatibility
1616
string(REGEX REPLACE "([0-9a-f][0-9a-f])" "0x\\1," filedata ${filedata})
17+
# Compute MD5 hash of the file
18+
execute_process(COMMAND md5sum ${bin} OUTPUT_VARIABLE md5_output)
19+
string(REGEX REPLACE " .*" "" md5_hash ${md5_output})
1720
# Append data to output file
18-
file(APPEND ${output} "const uint8_t ${filename}[] = {${filedata}};\nconst uint32_t ${filename}_size = sizeof(${filename});\n")
21+
file(APPEND ${output}
22+
"const uint8_t ${filename}[] = {${filedata}};\n"
23+
"const uint32_t ${filename}_size = sizeof(${filename});\n"
24+
"const uint8_t ${filename}_md5[] = \"${md5_hash}\";\n"
25+
)
1926
endforeach()
2027
endfunction()

examples/common/example_common.c

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,151 +35,201 @@
3535

3636
extern const uint8_t ESP32_bootloader_bin[];
3737
extern const uint32_t ESP32_bootloader_bin_size;
38+
extern const uint8_t ESP32_bootloader_bin_md5[];
3839
extern const uint8_t ESP32_hello_world_bin[];
3940
extern const uint32_t ESP32_hello_world_bin_size;
41+
extern const uint8_t ESP32_hello_world_bin_md5[];
4042
extern const uint8_t ESP32_partition_table_bin[];
4143
extern const uint32_t ESP32_partition_table_bin_size;
44+
extern const uint8_t ESP32_partition_table_bin_md5[];
4245

4346
extern const uint8_t ESP32_S2_bootloader_bin[];
4447
extern const uint32_t ESP32_S2_bootloader_bin_size;
48+
extern const uint8_t ESP32_S2_bootloader_bin_md5[];
4549
extern const uint8_t ESP32_S2_hello_world_bin[];
4650
extern const uint32_t ESP32_S2_hello_world_bin_size;
51+
extern const uint8_t ESP32_S2_hello_world_bin_md5[];
4752
extern const uint8_t ESP32_S2_partition_table_bin[];
4853
extern const uint32_t ESP32_S2_partition_table_bin_size;
54+
extern const uint8_t ESP32_S2_partition_table_bin_md5[];
4955

5056
extern const uint8_t ESP32_S3_bootloader_bin[];
5157
extern const uint32_t ESP32_S3_bootloader_bin_size;
58+
extern const uint8_t ESP32_S3_bootloader_bin_md5[];
5259
extern const uint8_t ESP32_S3_hello_world_bin[];
5360
extern const uint32_t ESP32_S3_hello_world_bin_size;
61+
extern const uint8_t ESP32_S3_hello_world_bin_md5[];
5462
extern const uint8_t ESP32_S3_partition_table_bin[];
5563
extern const uint32_t ESP32_S3_partition_table_bin_size;
64+
extern const uint8_t ESP32_S3_partition_table_bin_md5[];
5665

5766

5867

5968
extern const uint8_t ESP8266_bootloader_bin[];
6069
extern const uint32_t ESP8266_bootloader_bin_size;
70+
extern const uint8_t ESP8266_bootloader_bin_md5[];
6171
extern const uint8_t ESP8266_hello_world_bin[];
6272
extern const uint32_t ESP8266_hello_world_bin_size;
73+
extern const uint8_t ESP8266_hello_world_bin_md5[];
6374
extern const uint8_t ESP8266_partition_table_bin[];
6475
extern const uint32_t ESP8266_partition_table_bin_size;
76+
extern const uint8_t ESP8266_partition_table_bin_md5[];
6577

6678
extern const uint8_t ESP32_H4_bootloader_bin[];
6779
extern const uint32_t ESP32_H4_bootloader_bin_size;
80+
extern const uint8_t ESP32_H4_bootloader_bin_md5[];
6881
extern const uint8_t ESP32_H4_hello_world_bin[];
6982
extern const uint32_t ESP32_H4_hello_world_bin_size;
83+
extern const uint8_t ESP32_H4_hello_world_bin_md5[];
7084
extern const uint8_t ESP32_H4_partition_table_bin[];
7185
extern const uint32_t ESP32_H4_partition_table_bin_size;
86+
extern const uint8_t ESP32_H4_partition_table_bin_md5[];
7287

7388
extern const uint8_t ESP32_H2_bootloader_bin[];
7489
extern const uint32_t ESP32_H2_bootloader_bin_size;
90+
extern const uint8_t ESP32_H2_bootloader_bin_md5[];
7591
extern const uint8_t ESP32_H2_hello_world_bin[];
7692
extern const uint32_t ESP32_H2_hello_world_bin_size;
93+
extern const uint8_t ESP32_H2_hello_world_bin_md5[];
7794
extern const uint8_t ESP32_H2_partition_table_bin[];
7895
extern const uint32_t ESP32_H2_partition_table_bin_size;
96+
extern const uint8_t ESP32_H2_partition_table_bin_md5[];
7997

8098
extern const uint8_t ESP32_C2_bootloader_bin[];
8199
extern const uint32_t ESP32_C2_bootloader_bin_size;
100+
extern const uint8_t ESP32_C2_bootloader_bin_md5[];
82101
extern const uint8_t ESP32_C2_hello_world_bin[];
83102
extern const uint32_t ESP32_C2_hello_world_bin_size;
103+
extern const uint8_t ESP32_C2_hello_world_bin_md5[];
84104
extern const uint8_t ESP32_C2_partition_table_bin[];
85105
extern const uint32_t ESP32_C2_partition_table_bin_size;
106+
extern const uint8_t ESP32_C2_partition_table_bin_md5[];
86107

87108
extern const uint8_t ESP32_C3_bootloader_bin[];
88109
extern const uint32_t ESP32_C3_bootloader_bin_size;
110+
extern const uint8_t ESP32_C3_bootloader_bin_md5[];
89111
extern const uint8_t ESP32_C3_hello_world_bin[];
90112
extern const uint32_t ESP32_C3_hello_world_bin_size;
113+
extern const uint8_t ESP32_C3_hello_world_bin_md5[];
91114
extern const uint8_t ESP32_C3_partition_table_bin[];
92115
extern const uint32_t ESP32_C3_partition_table_bin_size;
116+
extern const uint8_t ESP32_C3_partition_table_bin_md5[];
93117

94118
extern const uint8_t ESP32_C6_bootloader_bin[];
95119
extern const uint32_t ESP32_C6_bootloader_bin_size;
120+
extern const uint8_t ESP32_C6_bootloader_bin_md5[];
96121
extern const uint8_t ESP32_C6_hello_world_bin[];
97122
extern const uint32_t ESP32_C6_hello_world_bin_size;
123+
extern const uint8_t ESP32_C6_hello_world_bin_md5[];
98124
extern const uint8_t ESP32_C6_partition_table_bin[];
99125
extern const uint32_t ESP32_C6_partition_table_bin_size;
126+
extern const uint8_t ESP32_C6_partition_table_bin_md5[];
100127

101128
void get_example_binaries(target_chip_t target, example_binaries_t *bins)
102129
{
103130
if (target == ESP8266_CHIP) {
104131
bins->boot.data = ESP8266_bootloader_bin;
105132
bins->boot.size = ESP8266_bootloader_bin_size;
133+
bins->boot.md5 = ESP8266_bootloader_bin_md5;
106134
bins->boot.addr = BOOTLOADER_ADDRESS_V0;
107135
bins->part.data = ESP8266_partition_table_bin;
108136
bins->part.size = ESP8266_partition_table_bin_size;
137+
bins->part.md5 = ESP8266_partition_table_bin_md5;
109138
bins->part.addr = PARTITION_ADDRESS;
110139
bins->app.data = ESP8266_hello_world_bin;
111140
bins->app.size = ESP8266_hello_world_bin_size;
141+
bins->app.md5 = ESP8266_hello_world_bin_md5;
112142
bins->app.addr = APPLICATION_ADDRESS;
113143
} else if (target == ESP32_CHIP) {
114144
bins->boot.data = ESP32_bootloader_bin;
115145
bins->boot.size = ESP32_bootloader_bin_size;
146+
bins->boot.md5 = ESP32_bootloader_bin_md5;
116147
bins->boot.addr = BOOTLOADER_ADDRESS_V0;
117148
bins->part.data = ESP32_partition_table_bin;
118149
bins->part.size = ESP32_partition_table_bin_size;
150+
bins->part.md5 = ESP32_partition_table_bin_md5;
119151
bins->part.addr = PARTITION_ADDRESS;
120152
bins->app.data = ESP32_hello_world_bin;
121153
bins->app.size = ESP32_hello_world_bin_size;
154+
bins->app.md5 = ESP32_hello_world_bin_md5;
122155
bins->app.addr = APPLICATION_ADDRESS;
123156
} else if (target == ESP32S2_CHIP) {
124157
bins->boot.data = ESP32_S2_bootloader_bin;
125158
bins->boot.size = ESP32_S2_bootloader_bin_size;
159+
bins->boot.md5 = ESP32_S2_bootloader_bin_md5;
126160
bins->boot.addr = BOOTLOADER_ADDRESS_V0;
127161
bins->part.data = ESP32_S2_partition_table_bin;
128162
bins->part.size = ESP32_S2_partition_table_bin_size;
163+
bins->part.md5 = ESP32_S2_partition_table_bin_md5;
129164
bins->part.addr = PARTITION_ADDRESS;
130165
bins->app.data = ESP32_S2_hello_world_bin;
131166
bins->app.size = ESP32_S2_hello_world_bin_size;
167+
bins->app.md5 = ESP32_S2_hello_world_bin_md5;
132168
bins->app.addr = APPLICATION_ADDRESS;
133169
} else if (target == ESP32H2_CHIP) {
134170
bins->boot.data = ESP32_H2_bootloader_bin;
135171
bins->boot.size = ESP32_H2_bootloader_bin_size;
172+
bins->boot.md5 = ESP32_H2_bootloader_bin_md5;
136173
bins->boot.addr = BOOTLOADER_ADDRESS_V1;
137174
bins->part.data = ESP32_H2_partition_table_bin;
138175
bins->part.size = ESP32_H2_partition_table_bin_size;
176+
bins->part.md5 = ESP32_H2_partition_table_bin_md5;
139177
bins->part.addr = PARTITION_ADDRESS;
140178
bins->app.data = ESP32_H2_hello_world_bin;
141179
bins->app.size = ESP32_H2_hello_world_bin_size;
180+
bins->app.md5 = ESP32_H2_hello_world_bin_md5;
142181
bins->app.addr = APPLICATION_ADDRESS;
143182
} else if (target == ESP32C2_CHIP) {
144183
bins->boot.data = ESP32_C2_bootloader_bin;
145184
bins->boot.size = ESP32_C2_bootloader_bin_size;
185+
bins->boot.md5 = ESP32_C2_bootloader_bin_md5;
146186
bins->boot.addr = BOOTLOADER_ADDRESS_V1;
147187
bins->part.data = ESP32_C2_partition_table_bin;
148188
bins->part.size = ESP32_C2_partition_table_bin_size;
189+
bins->part.md5 = ESP32_C2_partition_table_bin_md5;
149190
bins->part.addr = PARTITION_ADDRESS;
150191
bins->app.data = ESP32_C2_hello_world_bin;
151192
bins->app.size = ESP32_C2_hello_world_bin_size;
193+
bins->app.md5 = ESP32_C2_hello_world_bin_md5;
152194
bins->app.addr = APPLICATION_ADDRESS;
153195
} else if (target == ESP32C3_CHIP) {
154196
bins->boot.data = ESP32_C3_bootloader_bin;
155197
bins->boot.size = ESP32_C3_bootloader_bin_size;
198+
bins->boot.md5 = ESP32_C3_bootloader_bin_md5;
156199
bins->boot.addr = BOOTLOADER_ADDRESS_V1;
157200
bins->part.data = ESP32_C3_partition_table_bin;
158201
bins->part.size = ESP32_C3_partition_table_bin_size;
202+
bins->part.md5 = ESP32_C3_partition_table_bin_md5;
159203
bins->part.addr = PARTITION_ADDRESS;
160204
bins->app.data = ESP32_C3_hello_world_bin;
161205
bins->app.size = ESP32_C3_hello_world_bin_size;
206+
bins->app.md5 = ESP32_C3_hello_world_bin_md5;
162207
bins->app.addr = APPLICATION_ADDRESS;
163208
} else if (target == ESP32C6_CHIP) {
164209
bins->boot.data = ESP32_C6_bootloader_bin;
165210
bins->boot.size = ESP32_C6_bootloader_bin_size;
211+
bins->boot.md5 = ESP32_C6_bootloader_bin_md5;
166212
bins->boot.addr = BOOTLOADER_ADDRESS_V1;
167213
bins->part.data = ESP32_C6_partition_table_bin;
168214
bins->part.size = ESP32_C6_partition_table_bin_size;
215+
bins->part.md5 = ESP32_C6_partition_table_bin_md5;
169216
bins->part.addr = PARTITION_ADDRESS;
170217
bins->app.data = ESP32_C6_hello_world_bin;
171218
bins->app.size = ESP32_C6_hello_world_bin_size;
219+
bins->app.md5 = ESP32_C6_hello_world_bin_md5;
172220
bins->app.addr = APPLICATION_ADDRESS;
173-
174221
} else if (target == ESP32S3_CHIP) {
175222
bins->boot.data = ESP32_S3_bootloader_bin;
176223
bins->boot.size = ESP32_S3_bootloader_bin_size;
224+
bins->boot.md5 = ESP32_S3_bootloader_bin_md5;
177225
bins->boot.addr = BOOTLOADER_ADDRESS_V1;
178226
bins->part.data = ESP32_S3_partition_table_bin;
179227
bins->part.size = ESP32_S3_partition_table_bin_size;
228+
bins->part.md5 = ESP32_S3_partition_table_bin_md5;
180229
bins->part.addr = PARTITION_ADDRESS;
181230
bins->app.data = ESP32_S3_hello_world_bin;
182231
bins->app.size = ESP32_S3_hello_world_bin_size;
232+
bins->app.md5 = ESP32_S3_hello_world_bin_md5;
183233
bins->app.addr = APPLICATION_ADDRESS;
184234
} else {
185235
abort();

examples/common/example_common.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ typedef struct {
2323
const uint8_t *data;
2424
uint32_t size;
2525
uint32_t addr;
26+
const uint8_t *md5;
2627
} partition_attr_t;
2728

2829
typedef struct {
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# The following lines of boilerplate have to be in your project's CMakeLists
2+
# in this exact order for cmake to work correctly
3+
cmake_minimum_required(VERSION 3.5)
4+
5+
set(EXTRA_COMPONENT_DIRS ../../)
6+
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
7+
project(esp-serial-flasher)
8+
9+
# There are issues with ESP-IDF 4.4 and -Wunused-parameter
10+
if ("${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}" VERSION_GREATER "4.4")
11+
idf_component_get_property(flasher esp-serial-flasher COMPONENT_LIB)
12+
13+
target_compile_options(${flasher}
14+
PRIVATE
15+
-Wunused-parameter
16+
-Wshadow
17+
)
18+
endif()
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
# Flash multiple partitions if MD5 mismatch example
2+
3+
## Overview
4+
5+
This example demonstrates how to flash an Espressif SoC (target) from another MCU (host) using `esp_serial_flasher`. The process is optimized by checking the MD5 hash of each partition before flashing and only flashing the binaries if there is a mismatch, indicating that the binary is not already flashed. Two ESP32 chips are used in this case. Binaries to be flashed from the host MCU to the Espressif SoC can be found in [binaries](../binaries/) folder and are converted into C-array during the build process.
6+
7+
The following steps are performed in order to re-program the target's memory:
8+
9+
1. UART1 through which the new binary will be transferred is initialized.
10+
2. The host puts the target device into boot mode and tries to connect by calling `esp_loader_connect()`.
11+
3. The binary file is opened, its MD5 and size is acquired, as it has to be known before flashing.
12+
4. Then `esp_loader_flash_start()` is called to enter the flashing mode and erase the amount of memory to be flashed.
13+
5. `esp_loader_flash_write()` function is called repeatedly until the whole binary image is transferred, but only if the MD5 hash does not match the existing partition.
14+
15+
Note: In addition to the steps mentioned above, `esp_loader_change_transmission_rate()` is called after the connection is established in order to increase the flashing speed. This does not apply to the ESP8266, as its bootloader does not support this command. However, the ESP8266 is capable of detecting the baud rate during the connection phase and can be changed before calling `esp_loader_connect()`, if necessary.
16+
17+
## Connection configuration
18+
19+
In the majority of cases, the `ESP_LOADER_CONNECT_DEFAULT` helper macro is used to initialize the `loader_connect_args_t` data structure passed to `esp_loader_connect()`. This helper macro sets the maximum time to wait for a response and the number of retrials. For more detailed information, refer to the [serial protocol](https://docs.espressif.com/projects/esptool/en/latest/esp32s3/advanced-topics/serial-protocol.html).
20+
21+
## Hardware Required
22+
23+
* Two development boards with the ESP32 SoC (e.g., ESP32-DevKitC, ESP-WROVER-KIT, etc.).
24+
* One or two USB cables for power supply and programming.
25+
* Cables to connect the host to the target according to the table below.
26+
27+
## Hardware connection
28+
29+
The table below shows the connection between the two ESP32 devices.
30+
31+
| ESP32 (host) | ESP32 (target) |
32+
|:------------:|:-------------:|
33+
| IO26 | IO0 |
34+
| IO25 | RESET |
35+
| IO4 | RX0 |
36+
| IO5 | TX0 |
37+
38+
Note: The interconnection is the same for ESP32, ESP32-S2, and ESP8266 targets.
39+
40+
## Build and flash
41+
42+
To run the example, type the following command:
43+
44+
```CMake
45+
idf.py -p PORT flash monitor
46+
```
47+
48+
(To exit the serial monitor, type ``Ctrl-]``.)
49+
50+
See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/stable/esp32/index.html) for full steps to configure and use ESP-IDF to build projects.
51+
52+
## Configuration
53+
54+
For details about available configuration options, please refer to the top-level [README.md](../../README.md).
55+
Compile definitions can be specified on the command line when running `idf.py`, for example:
56+
57+
```
58+
idf.py build -DMD5_ENABLED=1
59+
```
60+
Binaries to be flashed are placed in a separate folder (binaries.c) for each possible target and converted to C-array. Without explicitly enabling MD5 check, flash integrity verification is disabled by default.
61+
62+
## Example output
63+
64+
Here is the example's console output:
65+
66+
```
67+
...
68+
Connected to target
69+
Transmission rate changed.
70+
I (1211) serial_flasher: Bootloader MD5 match, skipping...
71+
I (1221) serial_flasher: Partition table MD5 match, skipping...
72+
I (1401) serial_flasher: Application MD5 match, skipping...
73+
I (1401) serial_flasher: Done!
74+
I (2001) serial_flasher: ********************************************
75+
I (2001) serial_flasher: *** Logs below are print from slave .... ***
76+
I (2001) serial_flasher: ********************************************
77+
Hello world!
78+
```
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
set(srcs main.c ../../common/example_common.c)
2+
set(include_dirs . ../../common)
3+
4+
idf_component_register(SRCS ${srcs}
5+
INCLUDE_DIRS ${include_dirs})
6+
set(target ${COMPONENT_LIB})
7+
8+
# Embed binaries into the app.
9+
# In ESP-IDF this can also be done using EMBED_FILES option of idf_component_register.
10+
# Here an external tool is used to make file embedding similar with other ports.
11+
include(${CMAKE_CURRENT_LIST_DIR}/../../common/bin2array.cmake)
12+
create_resources(${CMAKE_CURRENT_LIST_DIR}/../../binaries/Hello-world ${CMAKE_BINARY_DIR}/binaries.c)
13+
set_property(SOURCE ${CMAKE_BINARY_DIR}/binaries.c PROPERTY GENERATED 1)
14+
target_sources(${target} PRIVATE ${CMAKE_BINARY_DIR}/binaries.c)

0 commit comments

Comments
 (0)