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