+}
+
+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)
+{
+ ILOG("Erasing flash page at addr: %#x\n", 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 */
+ write_uint32(sl->q_buf, 0x89abcdef);
+ stlink_write_mem32(sl, STM32L_FLASH_PEKEYR, sizeof(uint32_t));
+ write_uint32(sl->q_buf, 0x02030405);
+ stlink_write_mem32(sl, STM32L_FLASH_PEKEYR, sizeof(uint32_t));
+
+ /* check pecr.pelock is cleared */
+ stlink_read_mem32(sl, STM32L_FLASH_PECR, sizeof(uint32_t));
+ val = read_uint32(sl->q_buf, 0);
+ if (val & (1 << 0))
+ {
+ WLOG("pecr.pelock not clear (%#x)\n", val);
+ return -1;
+ }
+
+ /* unlock program memory */
+ write_uint32(sl->q_buf, 0x8c9daebf);
+ stlink_write_mem32(sl, STM32L_FLASH_PRGKEYR, sizeof(uint32_t));
+ write_uint32(sl->q_buf, 0x13141516);
+ stlink_write_mem32(sl, STM32L_FLASH_PRGKEYR, sizeof(uint32_t));
+
+ /* check pecr.prglock is cleared */
+ stlink_read_mem32(sl, STM32L_FLASH_PECR, sizeof(uint32_t));
+ val = read_uint32(sl->q_buf, 0);
+ if (val & (1 << 1))
+ {
+ WLOG("pecr.prglock not clear (%#x)\n", val);
+ return -1;
+ }
+
+ /* unused: unlock the option byte block */
+#if 0
+ write_uint32(sl->q_buf, 0xfbead9c8);
+ stlink_write_mem32(sl, STM32L_FLASH_OPTKEYR, sizeof(uint32_t));
+ write_uint32(sl->q_buf, 0x24252627);
+ stlink_write_mem32(sl, STM32L_FLASH_OPTKEYR, sizeof(uint32_t));
+
+ /* check pecr.optlock is cleared */
+ stlink_read_mem32(sl, STM32L_FLASH_PECR, sizeof(uint32_t));
+ val = read_uint32(sl->q_buf, 0);
+ if (val & (1 << 2))
+ {
+ fprintf(stderr, "pecr.prglock not clear\n");
+ return -1;
+ }
+#endif
+
+ /* set pecr.{erase,prog} */
+ val |= (1 << 9) | (1 << 3);
+ write_uint32(sl->q_buf, val);
+ stlink_write_mem32(sl, STM32L_FLASH_PECR, sizeof(uint32_t));
+
+ /* wait for sr.busy to be cleared */
+ while (1)
+ {
+ stlink_read_mem32(sl, STM32L_FLASH_SR, sizeof(uint32_t));
+ if ((read_uint32(sl->q_buf, 0) & (1 << 0)) == 0) break ;
+ }
+
+ /* write 0 to the first word of the page to be erased */
+ memset(sl->q_buf, 0, sizeof(uint32_t));
+ stlink_write_mem32(sl, flashaddr, sizeof(uint32_t));
+
+ /* reset lock bits */
+ stlink_read_mem32(sl, STM32L_FLASH_PECR, sizeof(uint32_t));
+ val = read_uint32(sl->q_buf, 0) | (1 << 0) | (1 << 1) | (1 << 2);
+ write_uint32(sl->q_buf, val);
+ stlink_write_mem32(sl, STM32L_FLASH_PECR, sizeof(uint32_t));
+ }
+ else if (sl->core_id == STM32VL_CORE_ID)
+ {