flash.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643
  1. /************************************************************************************
  2. * Copyright (C) 2011 Uros Platise. All rights reserved.
  3. * Author: Uros Platise <uros.platise@isotel.eu>
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. *
  9. * 1. Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * 2. Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in
  13. * the documentation and/or other materials provided with the
  14. * distribution.
  15. * 3. Neither the name NuttX nor the names of its contributors may be
  16. * used to endorse or promote products derived from this software
  17. * without specific prior written permission.
  18. *
  19. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  20. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  21. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  22. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  23. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  24. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  25. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  26. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  27. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  28. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  29. * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  30. * POSSIBILITY OF SUCH DAMAGE.
  31. *
  32. ************************************************************************************/
  33. /*
  34. * This file is free software: you can redistribute it and/or modify it
  35. * under the terms of the GNU General Public License as published by the
  36. * Free Software Foundation, either version 3 of the License, or
  37. * (at your option) any later version.
  38. *
  39. * This file is distributed in the hope that it will be useful, but
  40. * WITHOUT ANY WARRANTY; without even the implied warranty of
  41. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  42. * See the GNU General Public License for more details.
  43. *
  44. * You should have received a copy of the GNU General Public License along
  45. * with this program. If not, see <http://www.gnu.org/licenses/>.
  46. *
  47. * Modified for use in AP_HAL by Andrew Tridgell and Siddharth Bharat Purohit
  48. */
  49. #include "flash.h"
  50. #include "hal.h"
  51. #include <string.h>
  52. #include "stm32_util.h"
  53. // #pragma GCC optimize("O0")
  54. /*
  55. this driver has been tested with STM32F427 and STM32F412
  56. */
  57. #ifndef HAL_NO_FLASH_SUPPORT
  58. #ifndef BOARD_FLASH_SIZE
  59. #error "You must define BOARD_FLASH_SIZE in kbyte"
  60. #endif
  61. #define KB(x) ((x*1024))
  62. // Refer Flash memory map in the User Manual to fill the following fields per microcontroller
  63. #define STM32_FLASH_BASE 0x08000000
  64. #define STM32_FLASH_SIZE KB(BOARD_FLASH_SIZE)
  65. // optionally disable interrupts during flash writes
  66. #define STM32_FLASH_DISABLE_ISR 0
  67. // the 2nd bank of flash needs to be handled differently
  68. #define STM32_FLASH_BANK2_START (STM32_FLASH_BASE+0x00080000)
  69. #if defined(STM32F4)
  70. #if BOARD_FLASH_SIZE == 512
  71. #define STM32_FLASH_NPAGES 8
  72. static const uint32_t flash_memmap[STM32_FLASH_NPAGES] = { KB(16), KB(16), KB(16), KB(16), KB(64),
  73. KB(128), KB(128), KB(128) };
  74. #elif BOARD_FLASH_SIZE == 1024
  75. #define STM32_FLASH_NPAGES 12
  76. static const uint32_t flash_memmap[STM32_FLASH_NPAGES] = { KB(16), KB(16), KB(16), KB(16), KB(64),
  77. KB(128), KB(128), KB(128), KB(128), KB(128), KB(128), KB(128) };
  78. #elif BOARD_FLASH_SIZE == 2048
  79. #define STM32_FLASH_NPAGES 24
  80. static const uint32_t flash_memmap[STM32_FLASH_NPAGES] = { KB(16), KB(16), KB(16), KB(16), KB(64),
  81. KB(128), KB(128), KB(128), KB(128), KB(128), KB(128), KB(128),
  82. KB(16), KB(16), KB(16), KB(16), KB(64),
  83. KB(128), KB(128), KB(128), KB(128), KB(128), KB(128), KB(128)};
  84. #else
  85. #error "BOARD_FLASH_SIZE invalid"
  86. #endif
  87. #elif defined(STM32F7)
  88. #if BOARD_FLASH_SIZE == 1024
  89. #define STM32_FLASH_NPAGES 8
  90. static const uint32_t flash_memmap[STM32_FLASH_NPAGES] = { KB(32), KB(32), KB(32), KB(32), KB(128), KB(256), KB(256), KB(256) };
  91. #elif BOARD_FLASH_SIZE == 2048
  92. #define STM32_FLASH_NPAGES 12
  93. static const uint32_t flash_memmap[STM32_FLASH_NPAGES] = { KB(32), KB(32), KB(32), KB(32), KB(128), KB(256), KB(256), KB(256),
  94. KB(256), KB(256), KB(256), KB(256) };
  95. #else
  96. #error "BOARD_FLASH_SIZE invalid"
  97. #endif
  98. #elif defined(STM32H7)
  99. #define STM32_FLASH_NPAGES (BOARD_FLASH_SIZE / 128)
  100. #define STM32_FLASH_FIXED_PAGE_SIZE 128
  101. #elif defined(STM32F1)
  102. #define STM32_FLASH_NPAGES BOARD_FLASH_SIZE
  103. #define STM32_FLASH_FIXED_PAGE_SIZE 1
  104. #else
  105. #error "Unsupported processor for flash.c"
  106. #endif
  107. // keep a cache of the page addresses
  108. #ifndef STM32_FLASH_FIXED_PAGE_SIZE
  109. static uint32_t flash_pageaddr[STM32_FLASH_NPAGES];
  110. static bool flash_pageaddr_initialised;
  111. #endif
  112. static bool flash_keep_unlocked;
  113. #ifndef FLASH_KEY1
  114. #define FLASH_KEY1 0x45670123
  115. #endif
  116. #ifndef FLASH_KEY2
  117. #define FLASH_KEY2 0xCDEF89AB
  118. #endif
  119. /* Some compiler options will convert short loads and stores into byte loads
  120. * and stores. We don't want this to happen for IO reads and writes!
  121. */
  122. /* # define getreg16(a) (*(volatile uint16_t *)(a)) */
  123. static inline uint16_t getreg16(unsigned int addr)
  124. {
  125. uint16_t retval;
  126. __asm__ __volatile__("\tldrh %0, [%1]\n\t" : "=r"(retval) : "r"(addr));
  127. return retval;
  128. }
  129. /* define putreg16(v,a) (*(volatile uint16_t *)(a) = (v)) */
  130. static inline void putreg16(uint16_t val, unsigned int addr)
  131. {
  132. __asm__ __volatile__("\tstrh %0, [%1]\n\t": : "r"(val), "r"(addr));
  133. }
  134. /* # define getreg32(a) (*(volatile uint32_t *)(a)) */
  135. static inline uint32_t getreg32(unsigned int addr)
  136. {
  137. uint32_t retval;
  138. __asm__ __volatile__("\tldr %0, [%1]\n\t" : "=r"(retval) : "r"(addr));
  139. return retval;
  140. }
  141. /* define putreg32(v,a) */
  142. static inline void putreg32(uint32_t val, unsigned int addr)
  143. {
  144. *(volatile uint32_t *)(addr) = val;
  145. }
  146. static void stm32_flash_wait_idle(void)
  147. {
  148. __DSB();
  149. #if defined(STM32H7)
  150. while ((FLASH->SR1 & (FLASH_SR_BSY|FLASH_SR_QW|FLASH_SR_WBNE)) ||
  151. (FLASH->SR2 & (FLASH_SR_BSY|FLASH_SR_QW|FLASH_SR_WBNE))) {
  152. // nop
  153. }
  154. #else
  155. while (FLASH->SR & FLASH_SR_BSY) {
  156. // nop
  157. }
  158. #endif
  159. }
  160. static void stm32_flash_clear_errors(void)
  161. {
  162. #if defined(STM32H7)
  163. FLASH->CCR1 = ~0;
  164. FLASH->CCR2 = ~0;
  165. #else
  166. FLASH->SR = 0xF3;
  167. #endif
  168. }
  169. static void stm32_flash_unlock(void)
  170. {
  171. if (flash_keep_unlocked) {
  172. return;
  173. }
  174. stm32_flash_wait_idle();
  175. #if defined(STM32H7)
  176. if (FLASH->CR1 & FLASH_CR_LOCK) {
  177. /* Unlock sequence */
  178. FLASH->KEYR1 = FLASH_KEY1;
  179. FLASH->KEYR1 = FLASH_KEY2;
  180. }
  181. if (FLASH->CR2 & FLASH_CR_LOCK) {
  182. /* Unlock sequence */
  183. FLASH->KEYR2 = FLASH_KEY1;
  184. FLASH->KEYR2 = FLASH_KEY2;
  185. }
  186. #else
  187. if (FLASH->CR & FLASH_CR_LOCK) {
  188. /* Unlock sequence */
  189. FLASH->KEYR = FLASH_KEY1;
  190. FLASH->KEYR = FLASH_KEY2;
  191. }
  192. #endif
  193. #ifdef FLASH_ACR_DCEN
  194. // disable the data cache - see stm32 errata 2.1.11
  195. FLASH->ACR &= ~FLASH_ACR_DCEN;
  196. #endif
  197. }
  198. void stm32_flash_lock(void)
  199. {
  200. if (flash_keep_unlocked) {
  201. return;
  202. }
  203. #if defined(STM32H7)
  204. if (FLASH->SR1 & FLASH_SR_QW) {
  205. FLASH->CR1 |= FLASH_CR_FW;
  206. }
  207. if (FLASH->SR2 & FLASH_SR_QW) {
  208. FLASH->CR2 |= FLASH_CR_FW;
  209. }
  210. stm32_flash_wait_idle();
  211. FLASH->CR1 |= FLASH_CR_LOCK;
  212. FLASH->CR2 |= FLASH_CR_LOCK;
  213. #else
  214. stm32_flash_wait_idle();
  215. FLASH->CR |= FLASH_CR_LOCK;
  216. #endif
  217. #ifdef FLASH_ACR_DCEN
  218. // reset and re-enable the data cache - see stm32 errata 2.1.11
  219. FLASH->ACR |= FLASH_ACR_DCRST;
  220. FLASH->ACR &= ~FLASH_ACR_DCRST;
  221. FLASH->ACR |= FLASH_ACR_DCEN;
  222. #endif
  223. }
  224. /*
  225. get the memory address of a page
  226. */
  227. uint32_t stm32_flash_getpageaddr(uint32_t page)
  228. {
  229. if (page >= STM32_FLASH_NPAGES) {
  230. return 0;
  231. }
  232. #if defined(STM32_FLASH_FIXED_PAGE_SIZE)
  233. return STM32_FLASH_BASE + page * STM32_FLASH_FIXED_PAGE_SIZE * 1024;
  234. #else
  235. if (!flash_pageaddr_initialised) {
  236. uint32_t address = STM32_FLASH_BASE;
  237. uint8_t i;
  238. for (i = 0; i < STM32_FLASH_NPAGES; i++) {
  239. flash_pageaddr[i] = address;
  240. address += stm32_flash_getpagesize(i);
  241. }
  242. flash_pageaddr_initialised = true;
  243. }
  244. return flash_pageaddr[page];
  245. #endif
  246. }
  247. /*
  248. get size in bytes of a page
  249. */
  250. uint32_t stm32_flash_getpagesize(uint32_t page)
  251. {
  252. #if defined(STM32_FLASH_FIXED_PAGE_SIZE)
  253. (void)page;
  254. return STM32_FLASH_FIXED_PAGE_SIZE * 1024;
  255. #else
  256. return flash_memmap[page];
  257. #endif
  258. }
  259. /*
  260. return total number of pages
  261. */
  262. uint32_t stm32_flash_getnumpages()
  263. {
  264. return STM32_FLASH_NPAGES;
  265. }
  266. bool stm32_flash_ispageerased(uint32_t page)
  267. {
  268. uint32_t addr;
  269. uint32_t count;
  270. if (page >= STM32_FLASH_NPAGES) {
  271. return false;
  272. }
  273. for (addr = stm32_flash_getpageaddr(page), count = stm32_flash_getpagesize(page);
  274. count; count -= 4, addr += 4) {
  275. uint32_t v = getreg32(addr);
  276. if (v != 0xffffffff) {
  277. return false;
  278. }
  279. }
  280. return true;
  281. }
  282. /*
  283. erase a page
  284. */
  285. bool stm32_flash_erasepage(uint32_t page)
  286. {
  287. if (page >= STM32_FLASH_NPAGES) {
  288. return false;
  289. }
  290. #if STM32_FLASH_DISABLE_ISR
  291. syssts_t sts = chSysGetStatusAndLockX();
  292. #endif
  293. stm32_flash_wait_idle();
  294. stm32_flash_unlock();
  295. // clear any previous errors
  296. stm32_flash_clear_errors();
  297. #if defined(STM32H7)
  298. if (page < 8) {
  299. // first bank
  300. FLASH->SR1 = ~0;
  301. stm32_flash_wait_idle();
  302. uint32_t snb = page << 8;
  303. // use 32 bit operations
  304. FLASH->CR1 = FLASH_CR_PSIZE_1 | snb | FLASH_CR_SER;
  305. FLASH->CR1 |= FLASH_CR_START;
  306. while (FLASH->SR1 & FLASH_SR_QW) ;
  307. } else {
  308. // second bank
  309. FLASH->SR2 = ~0;
  310. stm32_flash_wait_idle();
  311. uint32_t snb = (page-8) << 8;
  312. // use 32 bit operations
  313. FLASH->CR2 = FLASH_CR_PSIZE_1 | snb | FLASH_CR_SER;
  314. FLASH->CR2 |= FLASH_CR_START;
  315. while (FLASH->SR2 & FLASH_SR_QW) ;
  316. }
  317. #elif defined(STM32F1)
  318. FLASH->CR = FLASH_CR_PER;
  319. FLASH->AR = stm32_flash_getpageaddr(page);
  320. FLASH->CR |= FLASH_CR_STRT;
  321. #elif defined(STM32F4) || defined(STM32F7)
  322. // the snb mask is not contiguous, calculate the mask for the page
  323. uint8_t snb = (((page % 12) << 3) | ((page / 12) << 7));
  324. // use 32 bit operations
  325. FLASH->CR = FLASH_CR_PSIZE_1 | snb | FLASH_CR_SER;
  326. FLASH->CR |= FLASH_CR_STRT;
  327. #else
  328. #error "Unsupported MCU"
  329. #endif
  330. stm32_flash_wait_idle();
  331. stm32_cacheBufferInvalidate((void*)stm32_flash_getpageaddr(page), stm32_flash_getpagesize(page));
  332. stm32_flash_lock();
  333. #if STM32_FLASH_DISABLE_ISR
  334. chSysRestoreStatusX(sts);
  335. #endif
  336. return stm32_flash_ispageerased(page);
  337. }
  338. #if defined(STM32H7)
  339. /*
  340. the H7 needs special handling, and only writes 32 bytes at a time
  341. */
  342. static bool stm32h7_flash_write32(uint32_t addr, const void *buf)
  343. {
  344. volatile uint32_t *CR, *CCR, *SR;
  345. if (addr - STM32_FLASH_BASE < 8 * STM32_FLASH_FIXED_PAGE_SIZE * 1024) {
  346. CR = &FLASH->CR1;
  347. CCR = &FLASH->CCR1;
  348. SR = &FLASH->SR1;
  349. } else {
  350. CR = &FLASH->CR2;
  351. CCR = &FLASH->CCR2;
  352. SR = &FLASH->SR2;
  353. }
  354. stm32_flash_wait_idle();
  355. *CCR = ~0;
  356. *CR |= FLASH_CR_PG;
  357. const uint32_t *v = (const uint32_t *)buf;
  358. uint8_t i;
  359. for (i=0; i<8; i++) {
  360. while (*SR & (FLASH_SR_BSY|FLASH_SR_QW)) ;
  361. putreg32(*v, addr);
  362. v++;
  363. addr += 4;
  364. }
  365. __DSB();
  366. stm32_flash_wait_idle();
  367. *CCR = ~0;
  368. *CR &= ~FLASH_CR_PG;
  369. return true;
  370. }
  371. static bool stm32_flash_write_h7(uint32_t addr, const void *buf, uint32_t count)
  372. {
  373. uint8_t *b = (uint8_t *)buf;
  374. if ((count & 0x1F) || (addr & 0x1F)) {
  375. // only allow 256 bit aligned writes
  376. return false;
  377. }
  378. stm32_flash_unlock();
  379. while (count >= 32) {
  380. if (!stm32h7_flash_write32(addr, b)) {
  381. return false;
  382. }
  383. // check contents
  384. if (memcmp((void *)addr, b, 32) != 0) {
  385. stm32_flash_lock();
  386. return false;
  387. }
  388. addr += 32;
  389. count -= 32;
  390. b += 32;
  391. }
  392. stm32_flash_lock();
  393. return true;
  394. }
  395. #endif // STM32H7
  396. #if defined(STM32F4) || defined(STM32F7)
  397. static bool stm32_flash_write_f4f7(uint32_t addr, const void *buf, uint32_t count)
  398. {
  399. uint8_t *b = (uint8_t *)buf;
  400. /* STM32 requires half-word access */
  401. if (count & 1) {
  402. return false;
  403. }
  404. if ((addr+count) >= STM32_FLASH_BASE+STM32_FLASH_SIZE) {
  405. return false;
  406. }
  407. /* Get flash ready and begin flashing */
  408. if (!(RCC->CR & RCC_CR_HSION)) {
  409. return false;
  410. }
  411. #if STM32_FLASH_DISABLE_ISR
  412. syssts_t sts = chSysGetStatusAndLockX();
  413. #endif
  414. stm32_flash_unlock();
  415. // clear previous errors
  416. stm32_flash_clear_errors();
  417. stm32_flash_wait_idle();
  418. // do as much as possible with 32 bit writes
  419. while (count >= 4 && (addr & 3) == 0) {
  420. FLASH->CR &= ~(FLASH_CR_PSIZE);
  421. FLASH->CR |= FLASH_CR_PSIZE_1 | FLASH_CR_PG;
  422. const uint32_t v1 = *(uint32_t *)b;
  423. putreg32(v1, addr);
  424. // ensure write ordering with cache
  425. __DSB();
  426. stm32_flash_wait_idle();
  427. const uint32_t v2 = getreg32(addr);
  428. if (v2 != v1) {
  429. FLASH->CR &= ~(FLASH_CR_PG);
  430. goto failed;
  431. }
  432. count -= 4;
  433. b += 4;
  434. addr += 4;
  435. }
  436. // the rest as 16 bit
  437. while (count >= 2) {
  438. FLASH->CR &= ~(FLASH_CR_PSIZE);
  439. FLASH->CR |= FLASH_CR_PSIZE_0 | FLASH_CR_PG;
  440. putreg16(*(uint16_t *)b, addr);
  441. // ensure write ordering with cache
  442. __DSB();
  443. stm32_flash_wait_idle();
  444. if (getreg16(addr) != *(uint16_t *)b) {
  445. FLASH->CR &= ~(FLASH_CR_PG);
  446. goto failed;
  447. }
  448. count -= 2;
  449. b += 2;
  450. addr += 2;
  451. }
  452. FLASH->CR &= ~(FLASH_CR_PG);
  453. stm32_flash_lock();
  454. #if STM32_FLASH_DISABLE_ISR
  455. chSysRestoreStatusX(sts);
  456. #endif
  457. return true;
  458. failed:
  459. stm32_flash_lock();
  460. #if STM32_FLASH_DISABLE_ISR
  461. chSysRestoreStatusX(sts);
  462. #endif
  463. return false;
  464. }
  465. #endif // STM32F4 || STM32F7
  466. uint32_t _flash_fail_line;
  467. uint32_t _flash_fail_addr;
  468. uint32_t _flash_fail_count;
  469. uint8_t *_flash_fail_buf;
  470. #if defined(STM32F1)
  471. static bool stm32_flash_write_f1(uint32_t addr, const void *buf, uint32_t count)
  472. {
  473. uint8_t *b = (uint8_t *)buf;
  474. /* STM32 requires half-word access */
  475. if (count & 1) {
  476. _flash_fail_line = __LINE__;
  477. return false;
  478. }
  479. if ((addr+count) >= STM32_FLASH_BASE+STM32_FLASH_SIZE) {
  480. _flash_fail_line = __LINE__;
  481. return false;
  482. }
  483. #if STM32_FLASH_DISABLE_ISR
  484. syssts_t sts = chSysGetStatusAndLockX();
  485. #endif
  486. stm32_flash_unlock();
  487. stm32_flash_wait_idle();
  488. // program in 16 bit steps
  489. while (count >= 2) {
  490. FLASH->CR = FLASH_CR_PG;
  491. putreg16(*(uint16_t *)b, addr);
  492. stm32_flash_wait_idle();
  493. FLASH->CR = 0;
  494. if (getreg16(addr) != *(uint16_t *)b) {
  495. _flash_fail_line = __LINE__;
  496. _flash_fail_addr = addr;
  497. _flash_fail_count = count;
  498. _flash_fail_buf = b;
  499. goto failed;
  500. }
  501. count -= 2;
  502. b += 2;
  503. addr += 2;
  504. }
  505. stm32_flash_lock();
  506. #if STM32_FLASH_DISABLE_ISR
  507. chSysRestoreStatusX(sts);
  508. #endif
  509. return true;
  510. failed:
  511. stm32_flash_lock();
  512. #if STM32_FLASH_DISABLE_ISR
  513. chSysRestoreStatusX(sts);
  514. #endif
  515. return false;
  516. }
  517. #endif // STM32F1
  518. bool stm32_flash_write(uint32_t addr, const void *buf, uint32_t count)
  519. {
  520. #if defined(STM32F1)
  521. return stm32_flash_write_f1(addr, buf, count);
  522. #elif defined(STM32F4) || defined(STM32F7)
  523. return stm32_flash_write_f4f7(addr, buf, count);
  524. #elif defined(STM32H7)
  525. return stm32_flash_write_h7(addr, buf, count);
  526. #else
  527. #error "Unsupported MCU"
  528. #endif
  529. }
  530. void stm32_flash_keep_unlocked(bool set)
  531. {
  532. if (set && !flash_keep_unlocked) {
  533. stm32_flash_unlock();
  534. flash_keep_unlocked = true;
  535. } else if (!set && flash_keep_unlocked) {
  536. flash_keep_unlocked = false;
  537. stm32_flash_lock();
  538. }
  539. }
  540. #endif // HAL_NO_FLASH_SUPPORT