stm32l1_flash.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568
  1. /*
  2. * Copyright (C) 2013 Uwe Bonnes
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions
  6. * are met:
  7. *
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. * 3. Neither the name of the copyright holders nor the names of
  14. * contributors may be used to endorse or promote products derived
  15. * from this software without specific prior written permission.
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  18. * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  19. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  20. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  21. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  22. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  23. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  24. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  25. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  26. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  27. * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  28. * SUCH DAMAGE.
  29. *
  30. * For additional information see http://www.ethernut.de/
  31. *
  32. */
  33. #include <stdint.h>
  34. #include <string.h>
  35. #include <cfg/arch.h>
  36. #include <arch/cm3.h>
  37. #include <dev/iap_flash.h>
  38. #if defined(MCU_STM32L1)
  39. #include <arch/cm3/stm/vendor/stm32l1xx.h>
  40. #else
  41. #warning "STM32 family has no L1 compatible FLASH/EEPROM"
  42. #endif
  43. /*Sectors are the unit for write protection, pages for erase */
  44. #define FLASH_SECTOR_SIZE (1<<12)
  45. #define FLASH_SECTOR_MASK 0xfffff000
  46. #define FLASH_SECTOR_SHIFT 12
  47. #define FLASH_PAGE_SIZE (1<<8)
  48. #define FLASH_PAGE_MASK 0xffffff00
  49. #define FLASH_PAGE_SHIFT 8
  50. #define ERASED_PATTERN_32 0
  51. #if defined (STM32L1XX_MDP)
  52. #define FLASH_SIZE_REG 0x1ff800cc
  53. static uint32_t pagelist[32] = { 0 };
  54. #elif defined (STM32L1XX_HD)
  55. #define FLASH_SIZE_REG 0x1ff800cc
  56. static uint32_t pagelist[48] = { 0 };
  57. #elif defined (STM32L1XX_XL)
  58. #define FLASH_SIZE_REG 0x1ff800cc
  59. static uint32_t pagelist[64] = { 0 };
  60. #else
  61. #define FLASH_SIZE_REG 0x1ff8004c
  62. static uint32_t pagelist[16] = { 0 };
  63. #endif
  64. uint8_t pagelist_init_done = 0;
  65. volatile uint32_t *pagelist_bb;
  66. #define FLASH_PEKEY1 0x89abcdef
  67. #define FLASH_PEKEY2 0x02030405
  68. #define FLASH_PRGKEY1 0x8c9daebf
  69. #define FLASH_PRGKEY2 0x13141516
  70. #define FLASH_OPTKEY1 0xfbead9c8
  71. #define FLASH_OPTKEY2 0x24252627
  72. void FlashUntouch(void)
  73. {
  74. memset(pagelist, 0, sizeof(pagelist));
  75. pagelist_init_done = 1;
  76. pagelist_bb = CM3BB_BASE(pagelist);
  77. }
  78. uint32_t IapFlashEnd(void)
  79. {
  80. uint16_t size;
  81. size = *(__I uint16_t *) FLASH_SIZE_REG;
  82. uint32_t retval = FLASH_BASE - 1;
  83. #if defined (STM32L1XX_MDP) || defined (STM32L1XX_HD) || defined (STM32L1XX_)
  84. if (((*(__I uint32_t *)0xe0042000) & 0xfff) == 0x436) {
  85. if (size == 0)
  86. retval += 384 * 1024;
  87. else
  88. retval += 256 * 1024;
  89. }
  90. #endif
  91. retval += size * 1024;
  92. return retval;
  93. }
  94. /*!
  95. * \brief Unlocks the FLASH Program Erase Controller.
  96. * \retval 0 on success, FLASH_LOCKED else.
  97. */
  98. static FLASH_Status FLASH_Unlock( void )
  99. {
  100. FLASH->PEKEYR = FLASH_PEKEY1;
  101. FLASH->PEKEYR = FLASH_PEKEY2;
  102. if (FLASH->PECR & FLASH_PECR_PELOCK)
  103. return FLASH_LOCKED;
  104. FLASH->PRGKEYR = FLASH_PRGKEY1;
  105. FLASH->PRGKEYR = FLASH_PRGKEY2;
  106. return (FLASH->PECR & FLASH_PECR_PRGLOCK)?FLASH_LOCKED:FLASH_COMPLETE;
  107. }
  108. /*!
  109. * \brief Waits for a Flash operation to complete or a TIMEOUT to occur.
  110. * \param Timeout: FLASH progamming Timeout in Microseconds
  111. *
  112. * \retval FLASH Status: FLASH_COMPLETE or appropriate error.
  113. */
  114. static FLASH_Status FLASH_GetStatus(void)
  115. {
  116. FLASH_Status rs = FLASH_COMPLETE;
  117. /* Decode the Flash Status
  118. * Check BSY last, so maybe it has completed meanwhile*/
  119. if (FLASH->SR & (FLASH_SR_SIZERR |FLASH_SR_PGAERR))
  120. rs = FLASH_ERROR_PG;
  121. else if (FLASH->SR & FLASH_SR_WRPERR)
  122. rs = FLASH_ERROR_WRP;
  123. else if (FLASH->SR & FLASH_SR_BSY)
  124. rs = FLASH_BUSY;
  125. /* Return the Flash Status */
  126. return rs;
  127. }
  128. /*!
  129. * \brief Waits for a Flash operation to complete
  130. *
  131. * \retval FLASH Status: FLASH_COMPLETE or appropriate error.
  132. * Every flash access stalls while FLASH erase/program is running
  133. * The erase/program process however will finish at some point
  134. * and may indicate failure then
  135. */
  136. static FLASH_Status FlashWaitReady(void)
  137. {
  138. FLASH_Status status;
  139. do
  140. status = FLASH_GetStatus();
  141. while(status == FLASH_BUSY);
  142. /* Return the operation status */
  143. return status;
  144. }
  145. /*!
  146. * \brief Erase specified FLASH sector. Use "Program memory page erase"
  147. *
  148. * \param sector Sector to erase.
  149. *
  150. * \return FLASH Status: FLASH_COMPLETE or appropriate error.
  151. */
  152. static FLASH_Status FlashErasePage(void *address_in_page)
  153. {
  154. FLASH_Status rs = FLASH_COMPLETE;
  155. uint32_t first_address_in_page = (uint32_t)address_in_page & FLASH_PAGE_MASK;
  156. uint32_t *page = (uint32_t*)first_address_in_page;
  157. uint32_t current_page = ((uint32_t)address_in_page - FLASH_BASE) >> FLASH_PAGE_SHIFT;
  158. int i;
  159. /* Check, if page really needs erase */
  160. for(i = 0; i < FLASH_PAGE_SIZE >> 2; i++) {
  161. if (page[i] != ERASED_PATTERN_32)
  162. break;
  163. }
  164. if ( i >= FLASH_PAGE_SIZE >> 2)
  165. rs = FLASH_COMPLETE;
  166. else {
  167. /* Wait for last operation to be completed */
  168. rs = FlashWaitReady();
  169. if(rs == FLASH_COMPLETE) {
  170. FLASH->PECR = FLASH_PECR_ERASE;
  171. FLASH->PECR = FLASH_PECR_ERASE | FLASH_PECR_PROG;
  172. rs = FlashWaitReady();
  173. if (rs != FLASH_COMPLETE)
  174. return rs;
  175. *(uint32_t*) first_address_in_page = 0;
  176. rs = FlashWaitReady();
  177. FLASH->PECR = 0;
  178. }
  179. }
  180. if (rs == FLASH_COMPLETE )
  181. pagelist_bb[current_page] = 1;
  182. /* Return the Erase Status */
  183. return rs;
  184. }
  185. /*!
  186. * \brief Program any data to FLASH.
  187. *
  188. * It always erases the page, eventually keeping old content
  189. *
  190. * \param dst Pointer to address anywhere in FLASH.
  191. * \param src Pointer to source data. With SRC == NULL, the region
  192. * is checked for write protection
  193. * \param len Number of bytes to be written/checked.
  194. * \param mode Erase mode (Always, on first access to block, never).
  195. *
  196. * \return FLASH Status: FLASH_COMPLETE or appropriate error.
  197. */
  198. FLASH_Status IapFlashWrite( void* dst, void* src, size_t len,
  199. FLASH_ERASE_MODE mode)
  200. {
  201. FLASH_Status rs = FLASH_COMPLETE;
  202. uint32_t sector_start, sector_end;
  203. int i;
  204. void *wptr = dst;
  205. void *rptr = src;
  206. uint32_t length = len;
  207. volatile uint32_t *wrpr_bb = CM3BBADDR(FLASH_R_BASE, FLASH_TypeDef, WRPR , 0);
  208. volatile uint32_t *wrpr1_bb = CM3BBADDR(FLASH_R_BASE, FLASH_TypeDef, WRPR1, 0);
  209. if (len == 0)
  210. return FLASH_COMPLETE;
  211. /* Check top boundary */
  212. if ((((uint32_t)dst - 1 + len) > IapFlashEnd()) ||
  213. ((uint32_t)dst < FLASH_BASE))
  214. {
  215. return FLASH_BOUNDARY;
  216. }
  217. if ((rs = FLASH_Unlock()) != FLASH_COMPLETE)
  218. {
  219. /* Unlocking failed for any reason */
  220. return FLASH_LOCKED;
  221. }
  222. /* Check for write protected sectors */
  223. sector_start = ((uint32_t)dst - FLASH_BASE) >> FLASH_SECTOR_SHIFT;
  224. sector_end = ((uint32_t)dst + len - FLASH_BASE) >> FLASH_SECTOR_SHIFT;
  225. for (i = sector_start; i < sector_end; i++) {
  226. if (i < 32) {
  227. if (wrpr_bb[i]) {
  228. rs = FLASH_ERROR_WRP;
  229. goto done;
  230. }
  231. }
  232. else {
  233. if (wrpr1_bb[i - 32]) {
  234. rs = FLASH_ERROR_WRP;
  235. goto done;
  236. }
  237. }
  238. }
  239. if (src == NULL) {
  240. /* Only a check for write protection was requested */
  241. rs = FLASH_COMPLETE;
  242. goto done;
  243. }
  244. if (pagelist_init_done == 0)
  245. FlashUntouch();
  246. while( (length) && (rs==FLASH_COMPLETE))
  247. {
  248. uint32_t current_page = ((uint32_t)wptr - FLASH_BASE) >> FLASH_PAGE_SHIFT;
  249. uint32_t current_length = length;
  250. uint32_t offset_in_page = (uint32_t)wptr & ~FLASH_PAGE_MASK;
  251. uint8_t page_buffer[FLASH_PAGE_SIZE];
  252. if (offset_in_page + current_length > FLASH_PAGE_SIZE)
  253. current_length = FLASH_PAGE_SIZE - offset_in_page;
  254. if ((offset_in_page == 0) && (current_length == FLASH_PAGE_SIZE)) {
  255. /* Handle full page writes */
  256. volatile uint32_t *cwptr = (uint32_t*) wptr;
  257. volatile uint32_t *crptr = (uint32_t*) rptr;
  258. /* Check if content really changed */
  259. rs = memcmp(page_buffer, (void*)((uint32_t)wptr & FLASH_PAGE_MASK), FLASH_PAGE_SIZE);
  260. if (rs == 0)
  261. continue;
  262. rs = FlashErasePage(wptr);
  263. if (rs != FLASH_COMPLETE)
  264. goto done;
  265. for (i = 0; i < FLASH_PAGE_SIZE >> 2; i++)
  266. cwptr[i] = crptr[i];
  267. rs = FlashWaitReady();
  268. if(rs != FLASH_COMPLETE)
  269. goto done;
  270. wptr += current_length;
  271. rptr += current_length;
  272. length -= current_length;
  273. continue;
  274. }
  275. else { /* Handle partial page writes */
  276. uint8_t page_buffer[FLASH_PAGE_SIZE];
  277. int do_page_erase;
  278. do_page_erase = ((mode == FLASH_ERASE_ALWAYS) ||
  279. ((mode != FLASH_ERASE_NEVER) &&
  280. (pagelist_bb[current_page] == 0)));
  281. if (do_page_erase)
  282. memset(page_buffer, (uint8_t) ERASED_PATTERN_32, FLASH_PAGE_SIZE);
  283. else {
  284. rs = memcmp(rptr, wptr, current_length);
  285. if (rs == 0)
  286. goto chunk_done;
  287. if ((offset_in_page & 3 ) || (current_length & 3)) {
  288. memcpy(page_buffer,
  289. (void*)((uint32_t)wptr & FLASH_PAGE_MASK),
  290. FLASH_PAGE_SIZE);
  291. }
  292. else
  293. {
  294. volatile uint32_t *cwptr = (uint32_t*)wptr;
  295. volatile uint32_t *crptr = (uint32_t*)rptr;
  296. int n_words = current_length >> 2;
  297. for (i = 0; i < n_words; i++) {
  298. /* We can only write dwords with all bit flashed
  299. * or the flash erased!*/
  300. if ((crptr[i] != ~ERASED_PATTERN_32) ||
  301. (cwptr[i] != ERASED_PATTERN_32))
  302. break;
  303. }
  304. if ( i < n_words) {
  305. /* Copy old content for pattern reason */
  306. memcpy(page_buffer,
  307. (void*)((uint32_t)wptr & FLASH_PAGE_MASK),
  308. FLASH_PAGE_SIZE);
  309. }
  310. else {
  311. for (i = 0; i < n_words; i++)
  312. if (cwptr[i] != crptr[i])
  313. cwptr[i] = crptr[i];
  314. rs = FlashWaitReady();
  315. if(rs != FLASH_COMPLETE)
  316. goto done;
  317. goto chunk_done;
  318. }
  319. }
  320. }
  321. memcpy(page_buffer + offset_in_page, rptr, current_length);
  322. rs = FlashErasePage(wptr);
  323. if (rs != FLASH_COMPLETE)
  324. goto done;
  325. /* Program the sector */
  326. rs = FlashWaitReady();
  327. if (rs != FLASH_COMPLETE)
  328. goto done;
  329. else
  330. {
  331. int i;
  332. volatile uint32_t *cwptr =
  333. (uint32_t*) ((uint32_t)wptr & FLASH_PAGE_MASK);
  334. volatile uint32_t *crptr = (uint32_t*) page_buffer;
  335. for (i=0; i < (FLASH_PAGE_SIZE >> 2); i++)
  336. if (cwptr[i] != crptr[i])
  337. cwptr[i] = crptr[i];
  338. rs = FlashWaitReady();
  339. if(rs != FLASH_COMPLETE)
  340. goto done;
  341. }
  342. chunk_done:
  343. wptr += current_length;
  344. rptr += current_length;
  345. length -= current_length;
  346. }
  347. }
  348. /* Check the written data */
  349. wptr = dst;
  350. rptr = src;
  351. length = len;
  352. /* Align flash access to 4 Byte Boundary*/
  353. while (length && ((uint32_t)wptr & FLASH_PAGE_MASK)) {
  354. if(*(volatile uint8_t*)wptr++ != *(uint8_t*)rptr++) {
  355. rs = FLASH_COMPARE;
  356. goto done;
  357. }
  358. length--;
  359. }
  360. /* Now compare 32-bit at a time*/
  361. while (length > 3) {
  362. if(*(volatile uint32_t*)wptr != *(uint32_t*)rptr) {
  363. rs = FLASH_COMPARE;
  364. goto done;
  365. }
  366. length -= 4;
  367. wptr += +4;
  368. rptr += +4;
  369. }
  370. while (length) {
  371. if((*(volatile uint8_t*)wptr++) != *(uint8_t*)rptr++) {
  372. rs = FLASH_COMPARE;
  373. goto done;
  374. }
  375. length--;
  376. }
  377. /* Lock the FLASH again */
  378. done:
  379. FLASH->PECR = FLASH_PECR_PELOCK;
  380. return rs;
  381. }
  382. /*!
  383. * \brief Try to protect/unprotect the requested flash region.
  384. *
  385. * \param dst Pointer to address anywhere in FLASH.
  386. * \param len Length of region in bytes.
  387. * \param ena 0 disables write protection anything else write-protects.
  388. *
  389. * \return FLASH_Status: FLASH_COMPLETE or appropriate error.
  390. */
  391. FLASH_Status IapFlashWriteProtect(void *dst, size_t len, int ena)
  392. {
  393. uint32_t sector_start, sector_end;
  394. int i;
  395. uint32_t optcr;
  396. FLASH_Status rs = FLASH_COMPLETE;
  397. uint32_t flash_end_addr = IapFlashEnd();
  398. uint8_t nwrpr;
  399. uint32_t cwrpr;
  400. uint32_t wrpr = FLASH->WRPR; /* Old write protection state */
  401. volatile uint32_t *wrpr_bb = CM3BB_BASE(&wrpr);
  402. #if defined (STM32L1XX_MDP) || defined (STM32L1XX_HD) || defined (STM32L1XX_XL)
  403. uint32_t wrpr1[3] = {FLASH->WRPR1, FLASH->WRPR2, FLASH->WRPR3} ; /* Old write protection state */
  404. volatile uint32_t *wrpr1_bb = CM3BB_BASE(wrpr1);
  405. #endif
  406. /* Check boundaries */
  407. if ((((uint32_t)dst + len) > flash_end_addr) || ((uint32_t)dst < FLASH_BASE))
  408. {
  409. return FLASH_BOUNDARY;
  410. }
  411. if (len == 0)
  412. return FLASH_COMPLETE;
  413. /* Wait for last operation to be completed */
  414. rs = FlashWaitReady();
  415. if(rs != FLASH_COMPLETE)
  416. return rs;
  417. FLASH->OPTKEYR = FLASH_OPTKEY1;
  418. FLASH->OPTKEYR = FLASH_OPTKEY2;
  419. optcr = FLASH->PECR;
  420. if (optcr & FLASH_PECR_OPTLOCK)
  421. return FLASH_ERROR_PG;
  422. sector_start = (uint32_t) dst & FLASH_PAGE_MASK;
  423. sector_end = ((uint32_t) dst +len -1) & FLASH_PAGE_MASK;
  424. if(ena)
  425. ena = 1;
  426. else
  427. ena = 0;
  428. for (i = sector_start; i <= sector_end; i++) {
  429. if (i < 32) {
  430. wrpr_bb[i] = ena;
  431. }
  432. #if defined (STM32L1XX_MDP) || defined (STM32L1XX_HD)|| defined (STM32L1XX_XL)
  433. else {
  434. wrpr1_bb[i - 32] = ena;
  435. }
  436. #endif
  437. }
  438. FLASH->PEKEYR = FLASH_PEKEY1;
  439. FLASH->PEKEYR = FLASH_PEKEY2;
  440. if (FLASH->PECR & FLASH_PECR_PELOCK)
  441. return FLASH_LOCKED;
  442. FLASH->OPTKEYR = FLASH_OPTKEY1;
  443. FLASH->OPTKEYR = FLASH_OPTKEY2;
  444. if (FLASH->PECR & FLASH_PECR_OPTLOCK) {
  445. FLASH->PECR |= FLASH_PECR_PELOCK;
  446. return FLASH_ERROR_PG;
  447. }
  448. if (sector_start < 16) {
  449. nwrpr = wrpr >> 8;
  450. cwrpr = ~nwrpr << 8 | nwrpr;
  451. nwrpr = wrpr ;
  452. cwrpr = cwrpr << 16 | ~nwrpr << 8 | nwrpr;
  453. OB->WRP01 = cwrpr;
  454. /* pm0062 tells to clear option byte errors */
  455. FLASH->SR = FLASH_SR_OPTVERRUSR | FLASH_SR_OPTVERR;
  456. }
  457. if ((sector_start >= 16) || (sector_end < 32)) {
  458. nwrpr = wrpr >> 24;
  459. cwrpr = ~nwrpr << 8 | nwrpr;
  460. nwrpr = wrpr >> 16;
  461. cwrpr = cwrpr << 16 | ~nwrpr << 8 | nwrpr;
  462. OB->WRP23 = cwrpr;
  463. FLASH->SR = FLASH_SR_OPTVERRUSR | FLASH_SR_OPTVERR;
  464. }
  465. #if defined (STM32L1XX_MDP) || defined (STM32L1XX_HD) || defined (STM32L1XX_XL)
  466. if ((sector_start >= 32) || (sector_end < 48)) {
  467. nwrpr = wrpr1[0] >> 8;
  468. cwrpr = ~nwrpr << 8 | nwrpr;
  469. nwrpr = wrpr1[0];
  470. cwrpr = cwrpr << 16 | ~nwrpr << 8 | nwrpr;
  471. OB->WRP45 = cwrpr;
  472. FLASH->SR = FLASH_SR_OPTVERRUSR | FLASH_SR_OPTVERR;
  473. }
  474. if ((sector_start >= 48) || (sector_end < 64)) {
  475. nwrpr = wrpr1[0] >> 24;
  476. cwrpr = ~nwrpr << 8 | nwrpr;
  477. nwrpr = wrpr1[0] >> 16;
  478. cwrpr = cwrpr << 16 | ~nwrpr << 8 | nwrpr;
  479. OB->WRP67 = cwrpr;
  480. FLASH->SR = FLASH_SR_OPTVERRUSR | FLASH_SR_OPTVERR;
  481. }
  482. #endif
  483. #if defined (STM32L1XX_HD) || defined (STM32L1XX_XL)
  484. if ((sector_start >= 64) || (sector_end < 80)) {
  485. nwrpr = wrpr1[1] >> 8;
  486. cwrpr = ~nwrpr << 8 | nwrpr;
  487. nwrpr = wrpr1[1];
  488. cwrpr = cwrpr << 16 | ~nwrpr << 8 | nwrpr;
  489. OB->WRP89 = cwrpr;
  490. FLASH->SR = FLASH_SR_OPTVERRUSR | FLASH_SR_OPTVERR;
  491. }
  492. if ((sector_start >= 80) || (sector_end < 96)) {
  493. nwrpr = wrpr1[1] >> 24;
  494. cwrpr = ~nwrpr << 8 | nwrpr;
  495. nwrpr = wrpr1[1] >> 16;
  496. cwrpr = cwrpr << 16 | ~nwrpr << 8 | nwrpr;
  497. OB->WRP1011 = cwrpr;
  498. FLASH->SR = FLASH_SR_OPTVERRUSR | FLASH_SR_OPTVERR;
  499. }
  500. #endif
  501. #if defined (STM32L1XX_XL)
  502. if ((sector_start >= 80) || (sector_end < 96)) {
  503. nwrpr = wrpr1[2] >> 8;
  504. cwrpr = ~nwrpr << 8 | nwrpr;
  505. nwrpr = wrpr1[2];
  506. cwrpr = cwrpr << 16 | ~nwrpr << 8 | nwrpr;
  507. OB->WRP89 = cwrpr;
  508. FLASH->SR = FLASH_SR_OPTVERRUSR | FLASH_SR_OPTVERR;
  509. }
  510. if ((sector_start >= 80) || (sector_end < 96)) {
  511. nwrpr = wrpr1[2] >> 24;
  512. cwrpr = ~nwrpr << 8 | nwrpr;
  513. nwrpr = wrpr1[2] >> 16;
  514. cwrpr = cwrpr << 16 | ~nwrpr << 8 | nwrpr;
  515. OB->WRP1011 = cwrpr;
  516. FLASH->SR = FLASH_SR_OPTVERRUSR | FLASH_SR_OPTVERR;
  517. }
  518. #endif
  519. /* Wait for last operation to be completed */
  520. rs = FlashWaitReady();
  521. FLASH->PECR |= FLASH_PECR_PELOCK;
  522. return rs;
  523. }