+}
+
+uint32_t stlink_calculate_pagesize(stlink_t *sl, uint32_t flashaddr){
+ if(sl->chip_id == STM32F4_CHIP_ID) {
+ uint32_t sector=calculate_F4_sectornum(flashaddr);
+ if (sector<4) sl->flash_pgsz=0x4000;
+ else if(sector<5) sl->flash_pgsz=0x10000;
+ else sl->flash_pgsz=0x20000;
+ }
+ return (sl->flash_pgsz);
+}
+
+/**
+ * Erase a page of flash, assumes sl is fully populated with things like chip/core ids
+ * @param sl stlink context
+ * @param flashaddr an address in the flash page to erase
+ * @return 0 on success -ve on failure
+ */
+int stlink_erase_flash_page(stlink_t *sl, stm32_addr_t flashaddr)
+{
+ if (sl->chip_id == STM32F4_CHIP_ID)
+ {
+ /* wait for ongoing op to finish */
+ wait_flash_busy(sl);
+
+ /* unlock if locked */
+ unlock_flash_if(sl);
+
+ /* select the page to erase */
+ // calculate the actual page from the address
+ uint32_t sector=calculate_F4_sectornum(flashaddr);
+
+ fprintf(stderr, "EraseFlash - Sector:0x%x Size:0x%x\n", sector, stlink_calculate_pagesize(sl, flashaddr));
+ write_flash_cr_snb(sl, sector);
+
+ /* start erase operation */
+ set_flash_cr_strt(sl);
+
+ /* wait for completion */
+ wait_flash_busy(sl);
+
+ /* relock the flash */
+ //todo: fails to program if this is in
+ lock_flash(sl);
+#if DEBUG_FLASH
+ fprintf(stdout, "Erase Final CR:0x%x\n", read_flash_cr(sl));
+#endif
+ }
+ else if (sl->core_id == STM32L_CORE_ID)
+ {
+
+ uint32_t val;
+
+ /* disable pecr protection */
+ stlink_write_debug32(sl, STM32L_FLASH_PEKEYR, 0x89abcdef);
+ stlink_write_debug32(sl, STM32L_FLASH_PEKEYR, 0x02030405);
+
+ /* check pecr.pelock is cleared */
+ val = stlink_read_debug32(sl, STM32L_FLASH_PECR);
+ if (val & (1 << 0))
+ {
+ WLOG("pecr.pelock not clear (%#x)\n", val);
+ return -1;
+ }
+
+ /* unlock program memory */
+ stlink_write_debug32(sl, STM32L_FLASH_PRGKEYR, 0x8c9daebf);
+ stlink_write_debug32(sl, STM32L_FLASH_PRGKEYR, 0x13141516);
+
+ /* check pecr.prglock is cleared */
+ val = stlink_read_debug32(sl, STM32L_FLASH_PECR);
+ if (val & (1 << 1))
+ {
+ WLOG("pecr.prglock not clear (%#x)\n", val);
+ return -1;
+ }
+
+ /* unused: unlock the option byte block */
+#if 0
+ stlink_write_debug32(sl, STM32L_FLASH_OPTKEYR, 0xfbead9c8);
+ stlink_write_debug32(sl, STM32L_FLASH_OPTKEYR, 0x24252627);
+
+ /* check pecr.optlock is cleared */
+ val = stlink_read_debug32(sl, STM32L_FLASH_PECR);
+ if (val & (1 << 2))
+ {
+ fprintf(stderr, "pecr.prglock not clear\n");
+ return -1;
+ }
+#endif
+
+ /* set pecr.{erase,prog} */
+ val |= (1 << 9) | (1 << 3);
+ stlink_write_debug32(sl, STM32L_FLASH_PECR, val);
+
+#if 0 /* fix_to_be_confirmed */
+
+ /* wait for sr.busy to be cleared
+ MP: Test shows that busy bit is not set here. Perhaps, PM0062 is
+ wrong and we do not need to wait here for clearing the busy bit.
+ TEXANE: ok, if experience says so and it works for you, we comment
+ it. If someone has a problem, please drop an email.
+ */
+ while ((stlink_read_debug32(sl, STM32L_FLASH_SR) & (1 << 0)) != 0)
+ {
+ }
+
+#endif /* fix_to_be_confirmed */
+
+ /* write 0 to the first word of the page to be erased */
+ stlink_write_debug32(sl, flashaddr, 0);
+
+ /* MP: It is better to wait for clearing the busy bit after issuing
+ page erase command, even though PM0062 recommends to wait before it.
+ Test shows that a few iterations is performed in the following loop
+ before busy bit is cleared.*/
+ while ((stlink_read_debug32(sl, STM32L_FLASH_SR) & (1 << 0)) != 0)
+ {
+ }
+
+ /* reset lock bits */
+ val = stlink_read_debug32(sl, STM32L_FLASH_PECR)
+ | (1 << 0) | (1 << 1) | (1 << 2);
+ stlink_write_debug32(sl, STM32L_FLASH_PECR, val);
+ }
+ else if (sl->core_id == STM32VL_CORE_ID)
+ {