ESPHome 2026.11.0-dev
Loading...
Searching...
No Matches
stm32flash.cpp
Go to the documentation of this file.
1/*
2 stm32flash - Open Source ST STM32 flash program for Arduino
3 Copyright 2010 Geoffrey McRae <geoff@spacevs.com>
4 Copyright 2012-2014 Tormod Volden <debian.tormod@gmail.com>
5
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License
8 as published by the Free Software Foundation; either version 2
9 of the License, or (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19*/
20
22#ifdef USE_SHD_FIRMWARE_DATA
23
24#include <cstdint>
25
26#include "stm32flash.h"
27#include "debug.h"
28
29#include "dev_table.h"
31#include "esphome/core/log.h"
32
33#include <algorithm>
34#include <memory>
35
36namespace {
37
38constexpr uint8_t STM32_ACK = 0x79;
39constexpr uint8_t STM32_NACK = 0x1F;
40constexpr uint8_t STM32_BUSY = 0x76;
41
42constexpr uint8_t STM32_CMD_INIT = 0x7F;
43constexpr uint8_t STM32_CMD_GET = 0x00; /* get the version and command supported */
44constexpr uint8_t STM32_CMD_GVR = 0x01; /* get version and read protection status */
45constexpr uint8_t STM32_CMD_GID = 0x02; /* get ID */
46constexpr uint8_t STM32_CMD_RM = 0x11; /* read memory */
47constexpr uint8_t STM32_CMD_GO = 0x21; /* go */
48constexpr uint8_t STM32_CMD_WM = 0x31; /* write memory */
49constexpr uint8_t STM32_CMD_WM_NS = 0x32; /* no-stretch write memory */
50constexpr uint8_t STM32_CMD_ER = 0x43; /* erase */
51constexpr uint8_t STM32_CMD_EE = 0x44; /* extended erase */
52constexpr uint8_t STM32_CMD_EE_NS = 0x45; /* extended erase no-stretch */
53constexpr uint8_t STM32_CMD_WP = 0x63; /* write protect */
54constexpr uint8_t STM32_CMD_WP_NS = 0x64; /* write protect no-stretch */
55constexpr uint8_t STM32_CMD_UW = 0x73; /* write unprotect */
56constexpr uint8_t STM32_CMD_UW_NS = 0x74; /* write unprotect no-stretch */
57constexpr uint8_t STM32_CMD_RP = 0x82; /* readout protect */
58constexpr uint8_t STM32_CMD_RP_NS = 0x83; /* readout protect no-stretch */
59constexpr uint8_t STM32_CMD_UR = 0x92; /* readout unprotect */
60constexpr uint8_t STM32_CMD_UR_NS = 0x93; /* readout unprotect no-stretch */
61constexpr uint8_t STM32_CMD_CRC = 0xA1; /* compute CRC */
62constexpr uint8_t STM32_CMD_ERR = 0xFF; /* not a valid command */
63
64constexpr uint32_t STM32_RESYNC_TIMEOUT = 35 * 1000; /* milliseconds */
65constexpr uint32_t STM32_MASSERASE_TIMEOUT = 35 * 1000; /* milliseconds */
66constexpr uint32_t STM32_PAGEERASE_TIMEOUT = 5 * 1000; /* milliseconds */
67constexpr uint32_t STM32_BLKWRITE_TIMEOUT = 1 * 1000; /* milliseconds */
68constexpr uint32_t STM32_WUNPROT_TIMEOUT = 1 * 1000; /* milliseconds */
69constexpr uint32_t STM32_WPROT_TIMEOUT = 1 * 1000; /* milliseconds */
70constexpr uint32_t STM32_RPROT_TIMEOUT = 1 * 1000; /* milliseconds */
71constexpr uint32_t DEFAULT_TIMEOUT = 5 * 1000; /* milliseconds */
72
73constexpr uint8_t STM32_CMD_GET_LENGTH = 17; /* bytes in the reply */
74
75/* Reset code for ARMv7-M (Cortex-M3) and ARMv6-M (Cortex-M0)
76 * see ARMv7-M or ARMv6-M Architecture Reference Manual (table B3-8)
77 * or "The definitive guide to the ARM Cortex-M3", section 14.4.
78 */
79constexpr uint8_t STM_RESET_CODE[] = {
80 0x01, 0x49, // ldr r1, [pc, #4] ; (<AIRCR_OFFSET>)
81 0x02, 0x4A, // ldr r2, [pc, #8] ; (<AIRCR_RESET_VALUE>)
82 0x0A, 0x60, // str r2, [r1, #0]
83 0xfe, 0xe7, // endless: b endless
84 0x0c, 0xed, 0x00, 0xe0, // .word 0xe000ed0c <AIRCR_OFFSET> = NVIC AIRCR register address
85 0x04, 0x00, 0xfa, 0x05 // .word 0x05fa0004 <AIRCR_RESET_VALUE> = VECTKEY | SYSRESETREQ
86};
87
88constexpr uint32_t STM_RESET_CODE_SIZE = sizeof(STM_RESET_CODE);
89
90/* RM0360, Empty check
91 * On STM32F070x6 and STM32F030xC devices only, internal empty check flag is
92 * implemented to allow easy programming of the virgin devices by the boot loader. This flag is
93 * used when BOOT0 pin is defining Main Flash memory as the target boot space. When the
94 * flag is set, the device is considered as empty and System memory (boot loader) is selected
95 * instead of the Main Flash as a boot space to allow user to program the Flash memory.
96 * This flag is updated only during Option bytes loading: it is set when the content of the
97 * address 0x08000 0000 is read as 0xFFFF FFFF, otherwise it is cleared. It means a power
98 * on or setting of OBL_LAUNCH bit in FLASH_CR register is needed to clear this flag after
99 * programming of a virgin device to execute user code after System reset.
100 */
101constexpr uint8_t STM_OBL_LAUNCH_CODE[] = {
102 0x01, 0x49, // ldr r1, [pc, #4] ; (<FLASH_CR>)
103 0x02, 0x4A, // ldr r2, [pc, #8] ; (<OBL_LAUNCH>)
104 0x0A, 0x60, // str r2, [r1, #0]
105 0xfe, 0xe7, // endless: b endless
106 0x10, 0x20, 0x02, 0x40, // address: FLASH_CR = 40022010
107 0x00, 0x20, 0x00, 0x00 // value: OBL_LAUNCH = 00002000
108};
109
110constexpr uint32_t STM_OBL_LAUNCH_CODE_SIZE = sizeof(STM_OBL_LAUNCH_CODE);
111
112ESPHOME_LOG_TAG(TAG, "stm32flash");
113
114} // Anonymous namespace
115
116namespace esphome::shelly_dimmer {
117
118namespace {
119
120int flash_addr_to_page_ceil(const stm32_unique_ptr &stm, uint32_t addr) {
121 if (addr < stm->dev->fl_start || addr > stm->dev->fl_end)
122 return 0;
123
124 int page = 0;
125 addr -= stm->dev->fl_start;
126 const auto *psize = stm->dev->fl_ps;
127
128 while (addr >= psize[0]) {
129 addr -= psize[0];
130 page++;
131 if (psize[1])
132 psize++;
133 }
134
135 return addr ? page + 1 : page;
136}
137
138stm32_err_t stm32_get_ack_timeout(const stm32_unique_ptr &stm, uint32_t timeout) {
139 auto *stream = stm->stream;
140 uint8_t rxbyte;
141
142 if (!(stm->flags & STREAM_OPT_RETRY))
143 timeout = 0;
144
145 if (timeout == 0)
146 timeout = DEFAULT_TIMEOUT;
147
148 const uint32_t start_time = millis();
149 do {
150 yield();
151 if (!stream->available()) {
152 if (millis() - start_time < timeout)
153 continue;
154 ESP_LOGD(TAG, "Failed to read ACK timeout=%i", timeout);
155 return STM32_ERR_UNKNOWN;
156 }
157
158 stream->read_byte(&rxbyte);
159
160 if (rxbyte == STM32_ACK)
161 return STM32_ERR_OK;
162 if (rxbyte == STM32_NACK)
163 return STM32_ERR_NACK;
164 if (rxbyte != STM32_BUSY) {
165 ESP_LOGD(TAG, "Got byte 0x%02x instead of ACK", rxbyte);
166 return STM32_ERR_UNKNOWN;
167 }
168 } while (true);
169}
170
171stm32_err_t stm32_get_ack(const stm32_unique_ptr &stm) { return stm32_get_ack_timeout(stm, 0); }
172
173stm32_err_t stm32_send_command_timeout(const stm32_unique_ptr &stm, const uint8_t cmd, const uint32_t timeout) {
174 auto *const stream = stm->stream;
175
176 static constexpr auto BUFFER_SIZE = 2;
177 const uint8_t buf[] = {
178 cmd,
179 static_cast<uint8_t>(cmd ^ 0xFF),
180 };
181 static_assert(sizeof(buf) == BUFFER_SIZE, "Buf expected to be 2 bytes");
182
183 stream->write_array(buf, BUFFER_SIZE);
184 stream->flush();
185
186 stm32_err_t s_err = stm32_get_ack_timeout(stm, timeout);
187 if (s_err == STM32_ERR_OK)
188 return STM32_ERR_OK;
189 if (s_err == STM32_ERR_NACK) {
190 ESP_LOGD(TAG, "Got NACK from device on command 0x%02x", cmd);
191 } else {
192 ESP_LOGD(TAG, "Unexpected reply from device on command 0x%02x", cmd);
193 }
194 return STM32_ERR_UNKNOWN;
195}
196
197stm32_err_t stm32_send_command(const stm32_unique_ptr &stm, const uint8_t cmd) {
198 return stm32_send_command_timeout(stm, cmd, 0);
199}
200
201/* if we have lost sync, send a wrong command and expect a NACK */
202stm32_err_t stm32_resync(const stm32_unique_ptr &stm) {
203 auto *const stream = stm->stream;
204 uint32_t t0 = millis();
205 auto t1 = t0;
206
207 static constexpr auto BUFFER_SIZE = 2;
208 const uint8_t buf[] = {
209 STM32_CMD_ERR,
210 static_cast<uint8_t>(STM32_CMD_ERR ^ 0xFF),
211 };
212 static_assert(sizeof(buf) == BUFFER_SIZE, "Buf expected to be 2 bytes");
213
214 uint8_t ack;
215 while (t1 - t0 < STM32_RESYNC_TIMEOUT) {
216 stream->write_array(buf, BUFFER_SIZE);
217 stream->flush();
218 if (!stream->read_array(&ack, 1)) {
219 t1 = millis();
220 continue;
221 }
222 if (ack == STM32_NACK)
223 return STM32_ERR_OK;
224 t1 = millis();
225 }
226 return STM32_ERR_UNKNOWN;
227}
228
229/*
230 * some command receive reply frame with variable length, and length is
231 * embedded in reply frame itself.
232 * We can guess the length, but if we guess wrong the protocol gets out
233 * of sync.
234 * Use resync for frame oriented interfaces (e.g. I2C) and byte-by-byte
235 * read for byte oriented interfaces (e.g. UART).
236 *
237 * to run safely, data buffer should be allocated for 256+1 bytes
238 *
239 * len is value of the first byte in the frame.
240 */
241stm32_err_t stm32_guess_len_cmd(const stm32_unique_ptr &stm, const uint8_t cmd, uint8_t *const data, unsigned int len) {
242 auto *const stream = stm->stream;
243
244 if (stm32_send_command(stm, cmd) != STM32_ERR_OK)
245 return STM32_ERR_UNKNOWN;
246 if (stm->flags & STREAM_OPT_BYTE) {
247 /* interface is UART-like */
248 if (!stream->read_array(data, 1))
249 return STM32_ERR_UNKNOWN;
250 len = data[0];
251 if (!stream->read_array(data + 1, len + 1))
252 return STM32_ERR_UNKNOWN;
253 return STM32_ERR_OK;
254 }
255
256 const auto ret = stream->read_array(data, len + 2);
257 if (ret && len == data[0])
258 return STM32_ERR_OK;
259 if (!ret) {
260 /* restart with only one byte */
261 if (stm32_resync(stm) != STM32_ERR_OK)
262 return STM32_ERR_UNKNOWN;
263 if (stm32_send_command(stm, cmd) != STM32_ERR_OK)
264 return STM32_ERR_UNKNOWN;
265 if (!stream->read_array(data, 1))
266 return STM32_ERR_UNKNOWN;
267 }
268
269 ESP_LOGD(TAG, "Re sync (len = %d)", data[0]);
270 if (stm32_resync(stm) != STM32_ERR_OK)
271 return STM32_ERR_UNKNOWN;
272
273 len = data[0];
274 if (stm32_send_command(stm, cmd) != STM32_ERR_OK)
275 return STM32_ERR_UNKNOWN;
276
277 if (!stream->read_array(data, len + 2))
278 return STM32_ERR_UNKNOWN;
279 return STM32_ERR_OK;
280}
281
282/*
283 * Some interface, e.g. UART, requires a specific init sequence to let STM32
284 * autodetect the interface speed.
285 * The sequence is only required one time after reset.
286 * This function sends the init sequence and, in case of timeout, recovers
287 * the interface.
288 */
289stm32_err_t stm32_send_init_seq(const stm32_unique_ptr &stm) {
290 auto *const stream = stm->stream;
291
292 stream->write_array(&STM32_CMD_INIT, 1);
293 stream->flush();
294
295 uint8_t byte;
296 bool ret = stream->read_array(&byte, 1);
297 if (ret && byte == STM32_ACK)
298 return STM32_ERR_OK;
299 if (ret && byte == STM32_NACK) {
300 /* We could get error later, but let's continue, for now. */
301 ESP_LOGD(TAG, "Warning: the interface was not closed properly.");
302 return STM32_ERR_OK;
303 }
304 if (!ret) {
305 ESP_LOGD(TAG, "Failed to init device.");
306 return STM32_ERR_UNKNOWN;
307 }
308
309 /*
310 * Check if previous STM32_CMD_INIT was taken as first byte
311 * of a command. Send a new byte, we should get back a NACK.
312 */
313 stream->write_array(&STM32_CMD_INIT, 1);
314 stream->flush();
315
316 ret = stream->read_array(&byte, 1);
317 if (ret && byte == STM32_NACK)
318 return STM32_ERR_OK;
319 ESP_LOGD(TAG, "Failed to init device.");
320 return STM32_ERR_UNKNOWN;
321}
322
323stm32_err_t stm32_mass_erase(const stm32_unique_ptr &stm) {
324 auto *const stream = stm->stream;
325
326 if (stm32_send_command(stm, stm->cmd->er) != STM32_ERR_OK) {
327 ESP_LOGD(TAG, "Can't initiate chip mass erase!");
328 return STM32_ERR_UNKNOWN;
329 }
330
331 /* regular erase (0x43) */
332 if (stm->cmd->er == STM32_CMD_ER) {
333 const auto s_err = stm32_send_command_timeout(stm, 0xFF, STM32_MASSERASE_TIMEOUT);
334 if (s_err != STM32_ERR_OK) {
335 return STM32_ERR_UNKNOWN;
336 }
337 return STM32_ERR_OK;
338 }
339
340 /* extended erase */
341 static constexpr auto BUFFER_SIZE = 3;
342 const uint8_t buf[] = {
343 0xFF, /* 0xFFFF the magic number for mass erase */
344 0xFF,
345 0x00, /* checksum */
346 };
347 static_assert(sizeof(buf) == BUFFER_SIZE, "Expected the buffer to be 3 bytes");
348 stream->write_array(buf, 3);
349 stream->flush();
350
351 const auto s_err = stm32_get_ack_timeout(stm, STM32_MASSERASE_TIMEOUT);
352 if (s_err != STM32_ERR_OK) {
353 ESP_LOGD(TAG, "Mass erase failed. Try specifying the number of pages to be erased.");
354 return STM32_ERR_UNKNOWN;
355 }
356 return STM32_ERR_OK;
357}
358
359template<typename T> std::unique_ptr<T[], void (*)(T *memory)> malloc_array_raii(size_t size) {
360 // Could be constexpr in c++17
361 static const auto DELETOR = [](T *memory) {
362 free(memory); // NOLINT
363 };
364 return std::unique_ptr<T[], decltype(DELETOR)>{static_cast<T *>(malloc(size)), // NOLINT
365 DELETOR};
366}
367
368stm32_err_t stm32_pages_erase(const stm32_unique_ptr &stm, const uint32_t spage, const uint32_t pages) {
369 auto *const stream = stm->stream;
370 uint8_t cs = 0;
371 int i = 0;
372
373 /* The erase command reported by the bootloader is either 0x43, 0x44 or 0x45 */
374 /* 0x44 is Extended Erase, a 2 byte based protocol and needs to be handled differently. */
375 /* 0x45 is clock no-stretching version of Extended Erase for I2C port. */
376 if (stm32_send_command(stm, stm->cmd->er) != STM32_ERR_OK) {
377 ESP_LOGD(TAG, "Can't initiate chip mass erase!");
378 return STM32_ERR_UNKNOWN;
379 }
380
381 /* regular erase (0x43) */
382 if (stm->cmd->er == STM32_CMD_ER) {
383 // Free memory with RAII
384 auto buf = malloc_array_raii<uint8_t>(1 + pages + 1);
385
386 if (!buf)
387 return STM32_ERR_UNKNOWN;
388
389 buf[i++] = pages - 1;
390 cs ^= (pages - 1);
391 for (auto pg_num = spage; pg_num < (pages + spage); pg_num++) {
392 buf[i++] = pg_num;
393 cs ^= pg_num;
394 }
395 buf[i++] = cs;
396 stream->write_array(&buf[0], i);
397 stream->flush();
398
399 const auto s_err = stm32_get_ack_timeout(stm, pages * STM32_PAGEERASE_TIMEOUT);
400 if (s_err != STM32_ERR_OK) {
401 return STM32_ERR_UNKNOWN;
402 }
403 return STM32_ERR_OK;
404 }
405
406 /* extended erase */
407
408 // Free memory with RAII
409 auto buf = malloc_array_raii<uint8_t>(2 + 2 * pages + 1);
410
411 if (!buf)
412 return STM32_ERR_UNKNOWN;
413
414 /* Number of pages to be erased - 1, two bytes, MSB first */
415 uint8_t pg_byte = (pages - 1) >> 8;
416 buf[i++] = pg_byte;
417 cs ^= pg_byte;
418 pg_byte = (pages - 1) & 0xFF;
419 buf[i++] = pg_byte;
420 cs ^= pg_byte;
421
422 for (auto pg_num = spage; pg_num < spage + pages; pg_num++) {
423 pg_byte = pg_num >> 8;
424 cs ^= pg_byte;
425 buf[i++] = pg_byte;
426 pg_byte = pg_num & 0xFF;
427 cs ^= pg_byte;
428 buf[i++] = pg_byte;
429 }
430 buf[i++] = cs;
431 stream->write_array(&buf[0], i);
432 stream->flush();
433
434 const auto s_err = stm32_get_ack_timeout(stm, pages * STM32_PAGEERASE_TIMEOUT);
435 if (s_err != STM32_ERR_OK) {
436 ESP_LOGD(TAG, "Page-by-page erase failed. Check the maximum pages your device supports.");
437 return STM32_ERR_UNKNOWN;
438 }
439
440 return STM32_ERR_OK;
441}
442
443template<typename T> stm32_err_t stm32_check_ack_timeout(const stm32_err_t s_err, const T &&log) {
444 switch (s_err) {
445 case STM32_ERR_OK:
446 return STM32_ERR_OK;
447 case STM32_ERR_NACK:
448 log();
449 [[fallthrough]];
450 default:
451 return STM32_ERR_UNKNOWN;
452 }
453}
454
455/* detect CPU endian */
456bool cpu_le() {
457 static constexpr int N = 1;
458
459 // returns true if little endian
460 return *reinterpret_cast<const char *>(&N) == 1;
461}
462
463uint32_t le_u32(const uint32_t v) {
464 if (!cpu_le())
465 return ((v & 0xFF000000) >> 24) | ((v & 0x00FF0000) >> 8) | ((v & 0x0000FF00) << 8) | ((v & 0x000000FF) << 24);
466 return v;
467}
468
469template<size_t N> void populate_buffer_with_address(uint8_t (&buffer)[N], uint32_t address) {
470 buffer[0] = static_cast<uint8_t>(address >> 24);
471 buffer[1] = static_cast<uint8_t>((address >> 16) & 0xFF);
472 buffer[2] = static_cast<uint8_t>((address >> 8) & 0xFF);
473 buffer[3] = static_cast<uint8_t>(address & 0xFF);
474 buffer[4] = static_cast<uint8_t>(buffer[0] ^ buffer[1] ^ buffer[2] ^ buffer[3]);
475}
476
477template<typename T> stm32_unique_ptr make_stm32_with_deletor(T ptr) {
478 static const auto CLOSE = [](stm32_t *stm32) {
479 if (stm32) {
480 free(stm32->cmd); // NOLINT
481 }
482 free(stm32); // NOLINT
483 };
484
485 // Cleanup with RAII
486 return std::unique_ptr<stm32_t, decltype(CLOSE)>{ptr, CLOSE};
487}
488
489} // Anonymous namespace
490
491/* find newer command by higher code */
492#define newer(prev, a) (((prev) == STM32_CMD_ERR) ? (a) : (((prev) > (a)) ? (prev) : (a)))
493
494stm32_unique_ptr stm32_init(uart::UARTDevice *stream, const uint8_t flags, const char init) {
495 uint8_t buf[257];
496
497 auto stm = make_stm32_with_deletor(static_cast<stm32_t *>(calloc(sizeof(stm32_t), 1))); // NOLINT
498
499 if (!stm) {
500 return make_stm32_with_deletor(nullptr);
501 }
502 stm->stream = stream;
503 stm->flags = flags;
504
505 stm->cmd = static_cast<stm32_cmd_t *>(malloc(sizeof(stm32_cmd_t))); // NOLINT
506 if (!stm->cmd) {
507 return make_stm32_with_deletor(nullptr);
508 }
509 memset(stm->cmd, STM32_CMD_ERR, sizeof(stm32_cmd_t));
510
511 if ((stm->flags & STREAM_OPT_CMD_INIT) && init) {
512 if (stm32_send_init_seq(stm) != STM32_ERR_OK)
513 return make_stm32_with_deletor(nullptr);
514 }
515
516 /* get the version and read protection status */
517 if (stm32_send_command(stm, STM32_CMD_GVR) != STM32_ERR_OK) {
518 return make_stm32_with_deletor(nullptr);
519 }
520
521 /* From AN, only UART bootloader returns 3 bytes */
522 {
523 const auto len = (stm->flags & STREAM_OPT_GVR_ETX) ? 3 : 1;
524 if (!stream->read_array(buf, len))
525 return make_stm32_with_deletor(nullptr);
526
527 stm->version = buf[0];
528 stm->option1 = (stm->flags & STREAM_OPT_GVR_ETX) ? buf[1] : 0;
529 stm->option2 = (stm->flags & STREAM_OPT_GVR_ETX) ? buf[2] : 0;
530 if (stm32_get_ack(stm) != STM32_ERR_OK) {
531 return make_stm32_with_deletor(nullptr);
532 }
533 }
534
535 {
536 const auto len = ([&]() {
537 /* get the bootloader information */
538 if (stm->cmd_get_reply) {
539 for (auto i = 0; stm->cmd_get_reply[i].length; ++i) {
540 if (stm->version == stm->cmd_get_reply[i].version) {
541 return stm->cmd_get_reply[i].length;
542 }
543 }
544 }
545
546 return STM32_CMD_GET_LENGTH;
547 })();
548
549 if (stm32_guess_len_cmd(stm, STM32_CMD_GET, buf, len) != STM32_ERR_OK)
550 return make_stm32_with_deletor(nullptr);
551 }
552
553 const auto stop = buf[0] + 1;
554 stm->bl_version = buf[1];
555 int new_cmds = 0;
556 for (auto i = 1; i < stop; ++i) {
557 const auto val = buf[i + 1];
558 switch (val) {
559 case STM32_CMD_GET:
560 stm->cmd->get = val;
561 break;
562 case STM32_CMD_GVR:
563 stm->cmd->gvr = val;
564 break;
565 case STM32_CMD_GID:
566 stm->cmd->gid = val;
567 break;
568 case STM32_CMD_RM:
569 stm->cmd->rm = val;
570 break;
571 case STM32_CMD_GO:
572 stm->cmd->go = val;
573 break;
574 case STM32_CMD_WM:
575 case STM32_CMD_WM_NS:
576 stm->cmd->wm = newer(stm->cmd->wm, val);
577 break;
578 case STM32_CMD_ER:
579 case STM32_CMD_EE:
580 case STM32_CMD_EE_NS:
581 stm->cmd->er = newer(stm->cmd->er, val);
582 break;
583 case STM32_CMD_WP:
584 case STM32_CMD_WP_NS:
585 stm->cmd->wp = newer(stm->cmd->wp, val);
586 break;
587 case STM32_CMD_UW:
588 case STM32_CMD_UW_NS:
589 stm->cmd->uw = newer(stm->cmd->uw, val);
590 break;
591 case STM32_CMD_RP:
592 case STM32_CMD_RP_NS:
593 stm->cmd->rp = newer(stm->cmd->rp, val);
594 break;
595 case STM32_CMD_UR:
596 case STM32_CMD_UR_NS:
597 stm->cmd->ur = newer(stm->cmd->ur, val);
598 break;
599 case STM32_CMD_CRC:
600 stm->cmd->crc = newer(stm->cmd->crc, val);
601 break;
602 default:
603 if (new_cmds++ == 0) {
604 ESP_LOGD(TAG, "GET returns unknown commands (0x%2x", val);
605 } else {
606 ESP_LOGD(TAG, ", 0x%2x", val);
607 }
608 }
609 }
610 if (new_cmds) {
611 ESP_LOGD(TAG, ")");
612 }
613 if (stm32_get_ack(stm) != STM32_ERR_OK) {
614 return make_stm32_with_deletor(nullptr);
615 }
616
617 if (stm->cmd->get == STM32_CMD_ERR || stm->cmd->gvr == STM32_CMD_ERR || stm->cmd->gid == STM32_CMD_ERR) {
618 ESP_LOGD(TAG, "Error: bootloader did not returned correct information from GET command");
619 return make_stm32_with_deletor(nullptr);
620 }
621
622 /* get the device ID */
623 if (stm32_guess_len_cmd(stm, stm->cmd->gid, buf, 1) != STM32_ERR_OK) {
624 return make_stm32_with_deletor(nullptr);
625 }
626 const auto returned = buf[0] + 1;
627 if (returned < 2) {
628 ESP_LOGD(TAG, "Only %d bytes sent in the PID, unknown/unsupported device", returned);
629 return make_stm32_with_deletor(nullptr);
630 }
631 stm->pid = (buf[1] << 8) | buf[2];
632 if (returned > 2) {
633 ESP_LOGD(TAG, "This bootloader returns %d extra bytes in PID:", returned);
634 for (auto i = 2; i <= returned; i++) {
635 ESP_LOGD(TAG, " %02x", buf[i]);
636 }
637 }
638 if (stm32_get_ack(stm) != STM32_ERR_OK) {
639 return make_stm32_with_deletor(nullptr);
640 }
641
642 stm->dev = DEVICES;
643 while (stm->dev->id != 0x00 && stm->dev->id != stm->pid)
644 ++stm->dev;
645
646 if (!stm->dev->id) {
647 ESP_LOGD(TAG, "Unknown/unsupported device (Device ID: 0x%03x)", stm->pid);
648 return make_stm32_with_deletor(nullptr);
649 }
650
651 return stm;
652}
653
655 const unsigned int len) {
656 auto *const stream = stm->stream;
657
658 if (!len)
659 return STM32_ERR_OK;
660
661 if (len > 256) {
662 ESP_LOGD(TAG, "Error: READ length limit at 256 bytes");
663 return STM32_ERR_UNKNOWN;
664 }
665
666 if (stm->cmd->rm == STM32_CMD_ERR) {
667 ESP_LOGD(TAG, "Error: READ command not implemented in bootloader.");
668 return STM32_ERR_NO_CMD;
669 }
670
671 if (stm32_send_command(stm, stm->cmd->rm) != STM32_ERR_OK)
672 return STM32_ERR_UNKNOWN;
673
674 static constexpr auto BUFFER_SIZE = 5;
675 uint8_t buf[BUFFER_SIZE];
676 populate_buffer_with_address(buf, address);
677
678 stream->write_array(buf, BUFFER_SIZE);
679 stream->flush();
680
681 if (stm32_get_ack(stm) != STM32_ERR_OK)
682 return STM32_ERR_UNKNOWN;
683
684 if (stm32_send_command(stm, len - 1) != STM32_ERR_OK)
685 return STM32_ERR_UNKNOWN;
686
687 if (!stream->read_array(data, len))
688 return STM32_ERR_UNKNOWN;
689
690 return STM32_ERR_OK;
691}
692
694 const unsigned int len) {
695 auto *const stream = stm->stream;
696
697 if (!len)
698 return STM32_ERR_OK;
699
700 if (len > 256) {
701 ESP_LOGD(TAG, "Error: READ length limit at 256 bytes");
702 return STM32_ERR_UNKNOWN;
703 }
704
705 /* must be 32bit aligned */
706 if (address & 0x3) {
707 ESP_LOGD(TAG, "Error: WRITE address must be 4 byte aligned");
708 return STM32_ERR_UNKNOWN;
709 }
710
711 if (stm->cmd->wm == STM32_CMD_ERR) {
712 ESP_LOGD(TAG, "Error: WRITE command not implemented in bootloader.");
713 return STM32_ERR_NO_CMD;
714 }
715
716 /* send the address and checksum */
717 if (stm32_send_command(stm, stm->cmd->wm) != STM32_ERR_OK)
718 return STM32_ERR_UNKNOWN;
719
720 static constexpr auto BUFFER_SIZE = 5;
721 uint8_t buf1[BUFFER_SIZE];
722 populate_buffer_with_address(buf1, address);
723
724 stream->write_array(buf1, BUFFER_SIZE);
725 stream->flush();
726 if (stm32_get_ack(stm) != STM32_ERR_OK)
727 return STM32_ERR_UNKNOWN;
728
729 const unsigned int aligned_len = (len + 3) & ~3;
730 uint8_t buf[256 + 2];
731
732 buf[0] = aligned_len - 1;
733 memcpy(&buf[1], data, len);
734 /* padding data */
735 memset(&buf[1 + len], 0xFF, aligned_len - len);
736 buf[aligned_len + 1] = xor_bytes(buf, aligned_len + 1);
737 stream->write_array(buf, aligned_len + 2);
738 stream->flush();
739
740 const auto s_err = stm32_get_ack_timeout(stm, STM32_BLKWRITE_TIMEOUT);
741 if (s_err != STM32_ERR_OK) {
742 return STM32_ERR_UNKNOWN;
743 }
744 return STM32_ERR_OK;
745}
746
748 if (stm->cmd->uw == STM32_CMD_ERR) {
749 ESP_LOGD(TAG, "Error: WRITE UNPROTECT command not implemented in bootloader.");
750 return STM32_ERR_NO_CMD;
751 }
752
753 if (stm32_send_command(stm, stm->cmd->uw) != STM32_ERR_OK)
754 return STM32_ERR_UNKNOWN;
755
756 return stm32_check_ack_timeout(stm32_get_ack_timeout(stm, STM32_WUNPROT_TIMEOUT),
757 []() { ESP_LOGD(TAG, "Error: Failed to WRITE UNPROTECT"); });
758}
759
761 if (stm->cmd->wp == STM32_CMD_ERR) {
762 ESP_LOGD(TAG, "Error: WRITE PROTECT command not implemented in bootloader.");
763 return STM32_ERR_NO_CMD;
764 }
765
766 if (stm32_send_command(stm, stm->cmd->wp) != STM32_ERR_OK)
767 return STM32_ERR_UNKNOWN;
768
769 return stm32_check_ack_timeout(stm32_get_ack_timeout(stm, STM32_WPROT_TIMEOUT),
770 []() { ESP_LOGD(TAG, "Error: Failed to WRITE PROTECT"); });
771}
772
774 if (stm->cmd->ur == STM32_CMD_ERR) {
775 ESP_LOGD(TAG, "Error: READOUT UNPROTECT command not implemented in bootloader.");
776 return STM32_ERR_NO_CMD;
777 }
778
779 if (stm32_send_command(stm, stm->cmd->ur) != STM32_ERR_OK)
780 return STM32_ERR_UNKNOWN;
781
782 return stm32_check_ack_timeout(stm32_get_ack_timeout(stm, STM32_MASSERASE_TIMEOUT),
783 []() { ESP_LOGD(TAG, "Error: Failed to READOUT UNPROTECT"); });
784}
785
787 if (stm->cmd->rp == STM32_CMD_ERR) {
788 ESP_LOGD(TAG, "Error: READOUT PROTECT command not implemented in bootloader.");
789 return STM32_ERR_NO_CMD;
790 }
791
792 if (stm32_send_command(stm, stm->cmd->rp) != STM32_ERR_OK)
793 return STM32_ERR_UNKNOWN;
794
795 return stm32_check_ack_timeout(stm32_get_ack_timeout(stm, STM32_RPROT_TIMEOUT),
796 []() { ESP_LOGD(TAG, "Error: Failed to READOUT PROTECT"); });
797}
798
800 if (!pages || spage > STM32_MAX_PAGES || ((pages != STM32_MASS_ERASE) && ((spage + pages) > STM32_MAX_PAGES)))
801 return STM32_ERR_OK;
802
803 if (stm->cmd->er == STM32_CMD_ERR) {
804 ESP_LOGD(TAG, "Error: ERASE command not implemented in bootloader.");
805 return STM32_ERR_NO_CMD;
806 }
807
808 if (pages == STM32_MASS_ERASE) {
809 /*
810 * Not all chips support mass erase.
811 * Mass erase can be obtained executing a "readout protect"
812 * followed by "readout un-protect". This method is not
813 * suggested because can hang the target if a debug SWD/JTAG
814 * is connected. When the target enters in "readout
815 * protection" mode it will consider the debug connection as
816 * a tentative of intrusion and will hang.
817 * Erasing the flash page-by-page is the safer way to go.
818 */
819 if (!(stm->dev->flags & F_NO_ME))
820 return stm32_mass_erase(stm);
821
822 pages = flash_addr_to_page_ceil(stm, stm->dev->fl_end);
823 }
824
825 /*
826 * Some device, like STM32L152, cannot erase more than 512 pages in
827 * one command. Split the call.
828 */
829 static constexpr uint32_t MAX_PAGE_SIZE = 512;
830 while (pages) {
831 const auto n = std::min(pages, MAX_PAGE_SIZE);
832 const auto s_err = stm32_pages_erase(stm, spage, n);
833 if (s_err != STM32_ERR_OK)
834 return s_err;
835 spage += n;
836 pages -= n;
837 }
838 return STM32_ERR_OK;
839}
840
841static stm32_err_t stm32_run_raw_code(const stm32_unique_ptr &stm, uint32_t target_address, const uint8_t *code,
842 uint32_t code_size) {
843 static constexpr uint32_t BUFFER_SIZE = 256;
844
845 const auto stack_le = le_u32(0x20002000);
846 const auto code_address_le = le_u32(target_address + 8 + 1); // thumb mode address (!)
847 uint32_t length = code_size + 8;
848
849 /* Must be 32-bit aligned */
850 if (target_address & 0x3) {
851 ESP_LOGD(TAG, "Error: code address must be 4 byte aligned");
852 return STM32_ERR_UNKNOWN;
853 }
854
855 // Could be constexpr in c++17
856 static const auto DELETOR = [](uint8_t *memory) {
857 free(memory); // NOLINT
858 };
859
860 // Free memory with RAII
861 std::unique_ptr<uint8_t, decltype(DELETOR)> mem{static_cast<uint8_t *>(malloc(length)), // NOLINT
862 DELETOR};
863
864 if (!mem)
865 return STM32_ERR_UNKNOWN;
866
867 memcpy(mem.get(), &stack_le, sizeof(stack_le));
868 memcpy(mem.get() + 4, &code_address_le, sizeof(code_address_le));
869 memcpy(mem.get() + 8, code, code_size);
870
871 auto *pos = mem.get();
872 auto address = target_address;
873 while (length > 0) {
874 const auto w = std::min(length, BUFFER_SIZE);
875 if (stm32_write_memory(stm, address, pos, w) != STM32_ERR_OK) {
876 return STM32_ERR_UNKNOWN;
877 }
878
879 address += w;
880 pos += w;
881 length -= w;
882 }
883
884 return stm32_go(stm, target_address);
885}
886
888 auto *const stream = stm->stream;
889
890 if (stm->cmd->go == STM32_CMD_ERR) {
891 ESP_LOGD(TAG, "Error: GO command not implemented in bootloader.");
892 return STM32_ERR_NO_CMD;
893 }
894
895 if (stm32_send_command(stm, stm->cmd->go) != STM32_ERR_OK)
896 return STM32_ERR_UNKNOWN;
897
898 static constexpr auto BUFFER_SIZE = 5;
899 uint8_t buf[BUFFER_SIZE];
900 populate_buffer_with_address(buf, address);
901
902 stream->write_array(buf, BUFFER_SIZE);
903 stream->flush();
904
905 if (stm32_get_ack(stm) != STM32_ERR_OK)
906 return STM32_ERR_UNKNOWN;
907 return STM32_ERR_OK;
908}
909
911 const auto target_address = stm->dev->ram_start;
912
913 if (stm->dev->flags & F_OBLL) {
914 /* set the OBL_LAUNCH bit to reset device (see RM0360, 2.5) */
915 return stm32_run_raw_code(stm, target_address, STM_OBL_LAUNCH_CODE, STM_OBL_LAUNCH_CODE_SIZE);
916 } else {
917 return stm32_run_raw_code(stm, target_address, STM_RESET_CODE, STM_RESET_CODE_SIZE);
918 }
919}
920
922 uint32_t *const crc) {
923 static constexpr auto BUFFER_SIZE = 5;
924 auto *const stream = stm->stream;
925
926 if (address & 0x3 || length & 0x3) {
927 ESP_LOGD(TAG, "Start and end addresses must be 4 byte aligned");
928 return STM32_ERR_UNKNOWN;
929 }
930
931 if (stm->cmd->crc == STM32_CMD_ERR) {
932 ESP_LOGD(TAG, "Error: CRC command not implemented in bootloader.");
933 return STM32_ERR_NO_CMD;
934 }
935
936 if (stm32_send_command(stm, stm->cmd->crc) != STM32_ERR_OK)
937 return STM32_ERR_UNKNOWN;
938
939 {
940 static constexpr auto BUFFER_SIZE = 5;
941 uint8_t buf[BUFFER_SIZE];
942 populate_buffer_with_address(buf, address);
943
944 stream->write_array(buf, BUFFER_SIZE);
945 stream->flush();
946 }
947
948 if (stm32_get_ack(stm) != STM32_ERR_OK)
949 return STM32_ERR_UNKNOWN;
950
951 {
952 static constexpr auto BUFFER_SIZE = 5;
953 uint8_t buf[BUFFER_SIZE];
954 populate_buffer_with_address(buf, address);
955
956 stream->write_array(buf, BUFFER_SIZE);
957 stream->flush();
958 }
959
960 if (stm32_get_ack(stm) != STM32_ERR_OK)
961 return STM32_ERR_UNKNOWN;
962
963 if (stm32_get_ack(stm) != STM32_ERR_OK)
964 return STM32_ERR_UNKNOWN;
965
966 {
967 uint8_t buf[BUFFER_SIZE];
968 if (!stream->read_array(buf, BUFFER_SIZE))
969 return STM32_ERR_UNKNOWN;
970
971 if (buf[4] != (buf[0] ^ buf[1] ^ buf[2] ^ buf[3]))
972 return STM32_ERR_UNKNOWN;
973
974 *crc = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
975 }
976
977 return STM32_ERR_OK;
978}
979
980/*
981 * CRC computed by STM32 is similar to the standard crc32_be()
982 * implemented, for example, in Linux kernel in ./lib/crc32.c
983 * But STM32 computes it on units of 32 bits word and swaps the
984 * bytes of the word before the computation.
985 * Due to byte swap, I cannot use any CRC available in existing
986 * libraries, so here is a simple not optimized implementation.
987 */
988uint32_t stm32_sw_crc(uint32_t crc, uint8_t *buf, unsigned int len) {
989 static constexpr uint32_t CRCPOLY_BE = 0x04c11db7;
990 static constexpr uint32_t CRC_MSBMASK = 0x80000000;
991
992 if (len & 0x3) {
993 ESP_LOGD(TAG, "Buffer length must be multiple of 4 bytes");
994 return 0;
995 }
996
997 while (len) {
998 uint32_t data = *buf++;
999 data |= *buf++ << 8;
1000 data |= *buf++ << 16;
1001 data |= *buf++ << 24;
1002 len -= 4;
1003
1004 crc ^= data;
1005
1006 for (size_t i = 0; i < 32; ++i) {
1007 if (crc & CRC_MSBMASK) {
1008 crc = (crc << 1) ^ CRCPOLY_BE;
1009 } else {
1010 crc = (crc << 1);
1011 }
1012 }
1013 }
1014 return crc;
1015}
1016
1018 static constexpr uint32_t CRC_INIT_VALUE = 0xFFFFFFFF;
1019 static constexpr uint32_t BUFFER_SIZE = 256;
1020
1021 uint8_t buf[BUFFER_SIZE];
1022
1023 if (address & 0x3 || length & 0x3) {
1024 ESP_LOGD(TAG, "Start and end addresses must be 4 byte aligned");
1025 return STM32_ERR_UNKNOWN;
1026 }
1027
1028 if (stm->cmd->crc != STM32_CMD_ERR)
1029 return stm32_crc_memory(stm, address, length, crc);
1030
1031 const auto start = address;
1032 const auto total_len = length;
1033 uint32_t current_crc = CRC_INIT_VALUE;
1034 while (length) {
1035 const auto len = std::min(BUFFER_SIZE, length);
1036 if (stm32_read_memory(stm, address, buf, len) != STM32_ERR_OK) {
1037 ESP_LOGD(TAG, "Failed to read memory at address 0x%08x, target write-protected?", address);
1038 return STM32_ERR_UNKNOWN;
1039 }
1040 current_crc = stm32_sw_crc(current_crc, buf, len);
1041 length -= len;
1042 address += len;
1043
1044 ESP_LOGD(TAG, "\rCRC address 0x%08x (%.2f%%) ", address, (100.0f / (float) total_len) * (float) (address - start));
1045 }
1046 ESP_LOGD(TAG, "Done.");
1047 *crc = current_crc;
1048 return STM32_ERR_OK;
1049}
1050
1051} // namespace esphome::shelly_dimmer
1052
1053#endif // USE_SHD_FIRMWARE_DATA
uint8_t address
Definition bl0906.h:4
bool read_array(uint8_t *data, size_t len)
Definition uart.h:42
void yield(void)
uint16_t flags
uint32_t buffer
Definition gif.cpp:50
ESPHOME_LOG_TAG(TAG, "hw_timer_esp_idf")
int ret
mopeka_std_values val[3]
static void int int int w
Definition display.cpp:62
static void int int int int const uint8_t * ptr
Definition display.cpp:63
std::span< const uint8_t > data
stm32_err_t stm32_wunprot_memory(const stm32_unique_ptr &stm)
stm32_err_t stm32_reset_device(const stm32_unique_ptr &stm)
stm32_unique_ptr stm32_init(uart::UARTDevice *stream, const uint8_t flags, const char init)
constexpr auto STREAM_OPT_CMD_INIT
Definition stm32flash.h:34
constexpr auto STREAM_OPT_RETRY
Definition stm32flash.h:35
struct Stm32 { uart::UARTDevice *stream; uint8_t flags; struct VarlenCmd *cmd_get_reply; uint8_t bl_version; uint8_t version; uint8_t option1, option2; uint16_t pid; stm32_cmd_t *cmd; const stm32_dev_t *dev;} stm32_t
Definition stm32flash.h:88
stm32_err_t stm32_readprot_memory(const stm32_unique_ptr &stm)
stm32_err_t stm32_crc_wrapper(const stm32_unique_ptr &stm, uint32_t address, uint32_t length, uint32_t *crc)
struct Stm32Cmd { uint8_t get; uint8_t gvr; uint8_t gid; uint8_t rm; uint8_t go; uint8_t wm; uint8_t er; uint8_t wp; uint8_t uw; uint8_t rp; uint8_t ur; uint8_t crc;} stm32_cmd_t
Definition stm32flash.h:60
stm32_err_t stm32_write_memory(const stm32_unique_ptr &stm, uint32_t address, const uint8_t *data, const unsigned int len)
constexpr auto STM32_MASS_ERASE
Definition stm32flash.h:46
constexpr auto STM32_MAX_PAGES
Definition stm32flash.h:45
stm32_err_t stm32_runprot_memory(const stm32_unique_ptr &stm)
stm32_err_t stm32_go(const stm32_unique_ptr &stm, const uint32_t address)
stm32_err_t stm32_crc_memory(const stm32_unique_ptr &stm, const uint32_t address, const uint32_t length, uint32_t *const crc)
stm32_err_t stm32_read_memory(const stm32_unique_ptr &stm, const uint32_t address, uint8_t *data, const unsigned int len)
uint32_t stm32_sw_crc(uint32_t crc, uint8_t *buf, unsigned int len)
constexpr auto STREAM_OPT_BYTE
Definition stm32flash.h:32
constexpr auto STREAM_OPT_GVR_ETX
Definition stm32flash.h:33
stm32_err_t stm32_erase_memory(const stm32_unique_ptr &stm, uint32_t spage, uint32_t pages)
std::unique_ptr< stm32_t, void(*)(stm32_t *)> stm32_unique_ptr
Definition stm32flash.h:112
enum Stm32Err { STM32_ERR_OK=0, STM32_ERR_UNKNOWN, STM32_ERR_NACK, STM32_ERR_NO_CMD, } stm32_err_t
Definition stm32flash.h:48
stm32_err_t stm32_wprot_memory(const stm32_unique_ptr &stm)
constexpr uint8_t xor_bytes(const uint8_t *data, size_t len, uint8_t init=0)
XOR the bytes of data with size len, starting from init.
Definition helpers.h:904
const void size_t len
Definition hal.h:68
uint16_t size
Definition helpers.cpp:34
size_t size_t pos
Definition helpers.h:1255
uint32_t IRAM_ATTR HOT millis()
Definition hal.cpp:25
static void uint32_t
uint8_t ack
uint16_t length
Definition tt21100.cpp:0