[ merge ] Andreas Seltenreich <uwi7@rz.uni-karlsruhe.de> patches
[fw/stlink] / src / stlink-common.c
index 217c01faf7dd2a02edd0d73b411f9f8b7f66d905..033cb527275b6a791d3c4ae973c4631d2ff3715c 100644 (file)
 #define DLOG(format, args...)         ugly_log(UDEBUG, LOG_TAG, format, ## args)
 #define ILOG(format, args...)         ugly_log(UINFO, LOG_TAG, format, ## args)
 #define WLOG(format, args...)         ugly_log(UWARN, LOG_TAG, format, ## args)
+#define ELOG(format, args...)         ugly_log(UERROR, LOG_TAG, format, ## args)
 #define fatal(format, args...)        ugly_log(UFATAL, LOG_TAG, format, ## args)
 
 /* todo: stm32l15xxx flash memory, pm0062 manual */
 
 /* stm32f FPEC flash controller interface, pm0063 manual */
 // TODO - all of this needs to be abstracted out....
+// STM32F05x is identical, based on RM0091 (DM00031936, Doc ID 018940 Rev 2, August 2012)
 #define FLASH_REGS_ADDR 0x40022000
 #define FLASH_REGS_SIZE 0x28
 
@@ -35,6 +37,7 @@
 #define FLASH_OBR (FLASH_REGS_ADDR + 0x1c)
 #define FLASH_WRPR (FLASH_REGS_ADDR + 0x20)
 
+// For STM32F05x, the RDPTR_KEY may be wrong, but as it is not used anywhere...
 #define FLASH_RDPTR_KEY 0x00a5
 #define FLASH_KEY1 0x45670123
 #define FLASH_KEY2 0xcdef89ab
@@ -134,23 +137,23 @@ static inline uint32_t read_flash_obr(stlink_t *sl) {
 }
 
 static inline uint32_t read_flash_cr(stlink_t *sl) {
-        uint32_t res;
-       if((sl->chip_id==STM32_CHIPID_F2) ||(sl->chip_id==STM32_CHIPID_F4))
-               res = stlink_read_debug32(sl, FLASH_F4_CR);
-       else
-               res = stlink_read_debug32(sl, FLASH_CR);
+    uint32_t res;
+    if ((sl->chip_id == STM32_CHIPID_F2) || (sl->chip_id == STM32_CHIPID_F4))
+        res = stlink_read_debug32(sl, FLASH_F4_CR);
+    else
+        res = stlink_read_debug32(sl, FLASH_CR);
 #if DEBUG_FLASH
-       fprintf(stdout, "CR:0x%x\n", res);
+    fprintf(stdout, "CR:0x%x\n", res);
 #endif
-       return res;
+    return res;
 }
 
 static inline unsigned int is_flash_locked(stlink_t *sl) {
     /* return non zero for true */
-       if((sl->chip_id == STM32_CHIPID_F2) ||(sl->chip_id == STM32_CHIPID_F4))
-               return read_flash_cr(sl) & (1 << FLASH_F4_CR_LOCK);
-       else
-               return read_flash_cr(sl) & (1 << FLASH_CR_LOCK);
+    if ((sl->chip_id == STM32_CHIPID_F2) || (sl->chip_id == STM32_CHIPID_F4))
+        return read_flash_cr(sl) & (1 << FLASH_F4_CR_LOCK);
+    else
+        return read_flash_cr(sl) & (1 << FLASH_CR_LOCK);
 }
 
 static void unlock_flash(stlink_t *sl) {
@@ -159,14 +162,13 @@ static void unlock_flash(stlink_t *sl) {
        an invalid sequence results in a definitive lock of
        the FPEC block until next reset.
      */
-    if((sl->chip_id == STM32_CHIPID_F2) ||(sl->chip_id == STM32_CHIPID_F4)) {
+    if ((sl->chip_id == STM32_CHIPID_F2) || (sl->chip_id == STM32_CHIPID_F4)) {
        stlink_write_debug32(sl, FLASH_F4_KEYR, FLASH_KEY1);
-               stlink_write_debug32(sl, FLASH_F4_KEYR, FLASH_KEY2);
-    }
-       else {
+        stlink_write_debug32(sl, FLASH_F4_KEYR, FLASH_KEY2);
+    } else {
        stlink_write_debug32(sl, FLASH_KEYR, FLASH_KEY1);
-               stlink_write_debug32(sl, FLASH_KEYR, FLASH_KEY2);
-       }
+        stlink_write_debug32(sl, FLASH_KEYR, FLASH_KEY2);
+    }
 
 }
 
@@ -185,11 +187,10 @@ static int unlock_flash_if(stlink_t *sl) {
 }
 
 static void lock_flash(stlink_t *sl) {
-    if((sl->chip_id == STM32_CHIPID_F2) ||(sl->chip_id == STM32_CHIPID_F4)) {
+    if ((sl->chip_id == STM32_CHIPID_F2) || (sl->chip_id == STM32_CHIPID_F4)) {
        const uint32_t n = read_flash_cr(sl) | (1 << FLASH_F4_CR_LOCK);
        stlink_write_debug32(sl, FLASH_F4_CR, n);
-    }
-    else {
+    } else {
         /* write to 1 only. reset by hw at unlock sequence */
         const uint32_t n = read_flash_cr(sl) | (1 << FLASH_CR_LOCK);
         stlink_write_debug32(sl, FLASH_CR, n);
@@ -198,12 +199,11 @@ static void lock_flash(stlink_t *sl) {
 
 
 static void set_flash_cr_pg(stlink_t *sl) {
-    if((sl->chip_id == STM32_CHIPID_F2) ||(sl->chip_id == STM32_CHIPID_F4)) {
+    if ((sl->chip_id == STM32_CHIPID_F2) || (sl->chip_id == STM32_CHIPID_F4)) {
                uint32_t x = read_flash_cr(sl);
                x |= (1 << FLASH_CR_PG);
        stlink_write_debug32(sl, FLASH_F4_CR, x);
-    }
-    else {
+    } else {
         const uint32_t n = 1 << FLASH_CR_PG;
         stlink_write_debug32(sl, FLASH_CR, n);
     }
@@ -211,7 +211,7 @@ static void set_flash_cr_pg(stlink_t *sl) {
 
 static void __attribute__((unused)) clear_flash_cr_pg(stlink_t *sl) {
     const uint32_t n = read_flash_cr(sl) & ~(1 << FLASH_CR_PG);
-    if((sl->chip_id == STM32_CHIPID_F2) ||(sl->chip_id == STM32_CHIPID_F4))
+    if ((sl->chip_id == STM32_CHIPID_F2) || (sl->chip_id == STM32_CHIPID_F4))
        stlink_write_debug32(sl, FLASH_F4_CR, n);
     else
         stlink_write_debug32(sl, FLASH_CR, n);
@@ -228,7 +228,7 @@ static void __attribute__((unused)) clear_flash_cr_per(stlink_t *sl) {
 }
 
 static void set_flash_cr_mer(stlink_t *sl) {
-    if((sl->chip_id == STM32_CHIPID_F2) ||(sl->chip_id == STM32_CHIPID_F4))
+    if ((sl->chip_id == STM32_CHIPID_F2) || (sl->chip_id == STM32_CHIPID_F4))
         stlink_write_debug32(sl, FLASH_F4_CR,
                              stlink_read_debug32(sl, FLASH_F4_CR) | (1 << FLASH_CR_MER));
     else
@@ -237,7 +237,7 @@ static void set_flash_cr_mer(stlink_t *sl) {
 }
 
 static void __attribute__((unused)) clear_flash_cr_mer(stlink_t *sl) {
-    if((sl->chip_id == STM32_CHIPID_F2) ||(sl->chip_id == STM32_CHIPID_F4))
+    if ((sl->chip_id == STM32_CHIPID_F2) || (sl->chip_id == STM32_CHIPID_F4))
         stlink_write_debug32(sl, FLASH_F4_CR,
                              stlink_read_debug32(sl, FLASH_F4_CR) & ~(1 << FLASH_CR_MER));
     else
@@ -246,17 +246,14 @@ static void __attribute__((unused)) clear_flash_cr_mer(stlink_t *sl) {
 }
 
 static void set_flash_cr_strt(stlink_t *sl) {
-       if((sl->chip_id == STM32_CHIPID_F2) ||(sl->chip_id == STM32_CHIPID_F4))
-       {
-               uint32_t x = read_flash_cr(sl);
-               x |= (1 << FLASH_F4_CR_STRT);
-               stlink_write_debug32(sl, FLASH_F4_CR, x);
-       }
-       else {
-           stlink_write_debug32(
-                sl, FLASH_CR,
-                stlink_read_debug32(sl,FLASH_CR) |(1 << FLASH_CR_STRT) );
-       }
+    if ((sl->chip_id == STM32_CHIPID_F2) || (sl->chip_id == STM32_CHIPID_F4)) {
+        uint32_t x = read_flash_cr(sl);
+        x |= (1 << FLASH_F4_CR_STRT);
+        stlink_write_debug32(sl, FLASH_F4_CR, x);
+    } else {
+        stlink_write_debug32(sl, FLASH_CR,
+                             stlink_read_debug32(sl, FLASH_CR) | (1 << FLASH_CR_STRT) );
+    }
 }
 
 static inline uint32_t read_flash_acr(stlink_t *sl) {
@@ -264,20 +261,20 @@ static inline uint32_t read_flash_acr(stlink_t *sl) {
 }
 
 static inline uint32_t read_flash_sr(stlink_t *sl) {
-       uint32_t res;
-       if((sl->chip_id == STM32_CHIPID_F2) ||(sl->chip_id == STM32_CHIPID_F4))
-               res = stlink_read_debug32(sl, FLASH_F4_SR);
-       else
-               res = stlink_read_debug32(sl, FLASH_SR);
+    uint32_t res;
+    if ((sl->chip_id == STM32_CHIPID_F2) || (sl->chip_id == STM32_CHIPID_F4))
+        res = stlink_read_debug32(sl, FLASH_F4_SR);
+    else
+        res = stlink_read_debug32(sl, FLASH_SR);
     //fprintf(stdout, "SR:0x%x\n", *(uint32_t*) sl->q_buf);
     return res;
 }
 
 static inline unsigned int is_flash_busy(stlink_t *sl) {
-       if((sl->chip_id == STM32_CHIPID_F2) ||(sl->chip_id == STM32_CHIPID_F4))
-               return read_flash_sr(sl) & (1 << FLASH_F4_SR_BSY);
-       else
-               return read_flash_sr(sl) & (1 << FLASH_SR_BSY);
+    if ((sl->chip_id == STM32_CHIPID_F2) || (sl->chip_id == STM32_CHIPID_F4))
+        return read_flash_sr(sl) & (1 << FLASH_F4_SR_BSY);
+    else
+        return read_flash_sr(sl) & (1 << FLASH_SR_BSY);
 }
 
 static void wait_flash_busy(stlink_t *sl) {
@@ -290,8 +287,7 @@ static void wait_flash_busy_progress(stlink_t *sl) {
     int i = 0;
     fprintf(stdout, "Mass erasing");
     fflush(stdout);
-    while (is_flash_busy(sl))
-    {
+    while (is_flash_busy(sl)) {
         usleep(10000);
         i++;
         if (i % 100 == 0) {
@@ -427,11 +423,11 @@ int stlink_load_device_params(stlink_t *sl) {
     /* Fix chip_id for F4 rev A errata , Read CPU ID, as CoreID is the same for F2/F4*/
     if (sl->chip_id == 0x411) {
         uint32_t cpuid = stlink_read_debug32(sl, 0xE000ED00);
-        if((cpuid  & 0xfff0) == 0xc240)
+        if ((cpuid  & 0xfff0) == 0xc240)
             sl->chip_id = 0x413;
     }
 
-    for(size_t i = 0; i < sizeof(devices) / sizeof(devices[0]); i++) {
+    for (size_t i = 0; i < sizeof(devices) / sizeof(devices[0]); i++) {
         if(devices[i].chip_id == sl->chip_id) {
             params = &devices[i];
             break;
@@ -547,7 +543,7 @@ void stlink_write_mem32(stlink_t *sl, uint32_t addr, uint16_t len) {
     DLOG("*** stlink_write_mem32 %u bytes to %#x\n", len, addr);
     if (len % 4 != 0) {
         fprintf(stderr, "Error: Data length doesn't have a 32 bit alignment: +%d byte.\n", len % 4);
-        return;
+        abort();
     }
     sl->backend->write_mem32(sl, addr, len);
 }
@@ -557,7 +553,7 @@ void stlink_read_mem32(stlink_t *sl, uint32_t addr, uint16_t len) {
     if (len % 4 != 0) { // !!! never ever: fw gives just wrong values
         fprintf(stderr, "Error: Data length doesn't have a 32 bit alignment: +%d byte.\n",
                 len % 4);
-        return;
+        abort();
     }
     sl->backend->read_mem32(sl, addr, len);
 }
@@ -567,7 +563,7 @@ void stlink_write_mem8(stlink_t *sl, uint32_t addr, uint16_t len) {
     if (len > 0x40 ) { // !!! never ever: Writing more then 0x40 bytes gives unexpected behaviour
         fprintf(stderr, "Error: Data length > 64: +%d byte.\n",
                 len);
-        return;
+        abort();
     }
     sl->backend->write_mem8(sl, addr, len);
 }
@@ -894,7 +890,7 @@ int stlink_fread(stlink_t* sl, const char* path, stm32_addr_t addr, size_t size)
     int error = -1;
     size_t off;
     int num_empty = 0;
-    unsigned char erased_pattern =(sl->chip_id == STM32_CHIPID_L1_MEDIUM)?0:0xff;
+    unsigned char erased_pattern = (sl->chip_id == STM32_CHIPID_L1_MEDIUM)?0:0xff;
 
     const int fd = open(path, O_RDWR | O_TRUNC | O_CREAT, 00700);
     if (fd == -1) {
@@ -976,7 +972,7 @@ uint32_t calculate_F4_sectornum(uint32_t flashaddr){
 }
 
 uint32_t stlink_calculate_pagesize(stlink_t *sl, uint32_t flashaddr){
-       if((sl->chip_id == STM32_CHIPID_F2) ||(sl->chip_id == STM32_CHIPID_F4)) {
+       if ((sl->chip_id == STM32_CHIPID_F2) || (sl->chip_id == STM32_CHIPID_F4)) {
                uint32_t sector=calculate_F4_sectornum(flashaddr);
                if (sector<4) sl->flash_pgsz=0x4000;
                else if(sector<5) sl->flash_pgsz=0x10000;
@@ -993,7 +989,7 @@ uint32_t stlink_calculate_pagesize(stlink_t *sl, uint32_t flashaddr){
  */
 int stlink_erase_flash_page(stlink_t *sl, stm32_addr_t flashaddr)
 {
-  if ((sl->chip_id == STM32_CHIPID_F2) ||(sl->chip_id == STM32_CHIPID_F4)) {
+  if ((sl->chip_id == STM32_CHIPID_F2) || (sl->chip_id == STM32_CHIPID_F4)) {
     /* wait for ongoing op to finish */
     wait_flash_busy(sl);
 
@@ -1089,7 +1085,7 @@ int stlink_erase_flash_page(stlink_t *sl, stm32_addr_t flashaddr)
     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) {
+  } else if (sl->core_id == STM32VL_CORE_ID || sl->core_id == STM32F0_CORE_ID || sl->chip_id == STM32_CHIPID_F3) {
     /* wait for ongoing op to finish */
     wait_flash_busy(sl);
 
@@ -1111,7 +1107,7 @@ int stlink_erase_flash_page(stlink_t *sl, stm32_addr_t flashaddr)
     /* relock the flash */
     lock_flash(sl);
   } else {
-    WLOG("unknown coreid: %x\n", sl->core_id);
+    WLOG("unknown coreid %x, page erase failed\n", sl->core_id);
     return -1;
   }
 
@@ -1197,6 +1193,54 @@ int write_loader_to_sram(stlink_t *sl, stm32_addr_t* addr, size_t* size) {
         0x00, 0x20, 0x02, 0x40, /* STM32_FLASH_BASE: .word 0x40022000 */
     };
 
+    /* flashloaders/stm32f0.s -- thumb1 only, same sequence as for STM32VL, bank ignored */
+    static const uint8_t loader_code_stm32f0[] = {
+#if 1
+        /*
+         * These two NOPs here are a safety precaution, added by Pekka Nikander
+         * while debugging the STM32F05x support.  They may not be needed, but
+         * there were strange problems with simpler programs, like a program
+         * that had just a breakpoint or a program that first moved zero to register r2
+         * and then had a breakpoint.  So, it appears safest to have these two nops.
+         *
+         * Feel free to remove them, if you dare, but then please do test the result
+         * rigorously.  Also, if you remove these, it may be a good idea first to
+         * #if 0 them out, with a comment when these were taken out, and to remove
+         * these only a few months later...  But YMMV.
+         */
+        0x00, 0x30, //     nop     /* add r0,#0 */
+        0x00, 0x30, //     nop     /* add r0,#0 */
+#endif
+        0x0A, 0x4C, //     ldr     r4, STM32_FLASH_BASE
+        0x01, 0x25, //     mov     r5, #1            /*  FLASH_CR_PG, FLASH_SR_BUSY */
+        0x04, 0x26, //     mov     r6, #4            /*  PGERR  */
+                    // write_half_word:
+        0x23, 0x69, //     ldr     r3, [r4, #16]     /*  FLASH->CR   */
+        0x2B, 0x43, //     orr     r3, r5
+        0x23, 0x61, //     str     r3, [r4, #16]     /*  FLASH->CR |= FLASH_CR_PG */
+        0x03, 0x88, //     ldrh    r3, [r0]          /*  r3 = *sram */
+        0x0B, 0x80, //     strh    r3, [r1]          /*  *flash = r3 */
+                    // busy:
+        0xE3, 0x68, //     ldr    r3, [r4, #12]     /*  FLASH->SR  */
+        0x2B, 0x42, //     tst    r3, r5            /*  FLASH_SR_BUSY  */
+        0xFC, 0xD0, //     beq    busy
+
+        0x33, 0x42, //     tst    r3, r6            /*  PGERR  */
+        0x04, 0xD1, //     bne    exit
+
+        0x02, 0x30, //     add     r0, r0, #2        /*  sram += 2  */
+        0x02, 0x31, //     add     r1, r1, #2        /*  flash += 2  */
+        0x01, 0x3A, //     sub     r2, r2, #0x01     /*  count--  */
+        0x00, 0x2A, //     cmp     r2, #0
+        0xF0, 0xD1, //     bne    write_half_word
+                    // exit:
+        0x23, 0x69, //     ldr     r3, [r4, #16]     /*  FLASH->CR  */
+        0xAB, 0x43, //     bic     r3, r5
+        0x23, 0x61, //     str     r3, [r4, #16]     /*  FLASH->CR &= ~FLASH_CR_PG  */
+        0x00, 0xBE, //     bkpt        #0x00
+        0x00, 0x20, 0x02, 0x40, /* STM32_FLASH_BASE: .word 0x40022000 */
+    };
+
     static const uint8_t loader_code_stm32l[] = {
 
         /* openocd.git/contrib/loaders/flash/stm32lx.S
@@ -1244,17 +1288,20 @@ int write_loader_to_sram(stlink_t *sl, stm32_addr_t* addr, size_t* size) {
     size_t loader_size;
 
     if (sl->chip_id == STM32_CHIPID_L1_MEDIUM) { /* stm32l */
-      loader_code = loader_code_stm32l;
-      loader_size = sizeof(loader_code_stm32l);
-    } else if (sl->core_id == STM32VL_CORE_ID) {
-      loader_code = loader_code_stm32vl;
-      loader_size = sizeof(loader_code_stm32vl);
+        loader_code = loader_code_stm32l;
+        loader_size = sizeof(loader_code_stm32l);
+    } else if (sl->core_id == STM32VL_CORE_ID || sl->chip_id == STM32_CHIPID_F3) {
+        loader_code = loader_code_stm32vl;
+        loader_size = sizeof(loader_code_stm32vl);
     } else if (sl->chip_id == STM32_CHIPID_F2 || sl->chip_id == STM32_CHIPID_F4) {
-      loader_code = loader_code_stm32f4;
-      loader_size = sizeof(loader_code_stm32f4);
+        loader_code = loader_code_stm32f4;
+        loader_size = sizeof(loader_code_stm32f4);
+    } else if (sl->chip_id == STM32_CHIPID_F0) {
+        loader_code = loader_code_stm32f0;
+        loader_size = sizeof(loader_code_stm32f0);
     } else {
-      WLOG("unknown coreid, not sure what flash loader to use, aborting!: %x\n", sl->core_id);
-      return -1;
+        ELOG("unknown coreid, not sure what flash loader to use, aborting!: %x\n", sl->core_id);
+        return -1;
     }
 
     memcpy(sl->q_buf, loader_code, loader_size);
@@ -1309,7 +1356,7 @@ int stlink_verify_write_flash(stlink_t *sl, stm32_addr_t address, uint8_t *data,
         stlink_read_mem32(sl, address + off, aligned_size);
 
         if (memcmp(sl->q_buf, data + off, cmp_size)) {
-            WLOG("Verification of flash failed at offset: %zd\n", off);
+            ELOG("Verification of flash failed at offset: %zd\n", off);
             return -1;
         }
     }
@@ -1376,19 +1423,22 @@ int stlink_write_flash(stlink_t *sl, stm32_addr_t addr, uint8_t* base, unsigned
     /* check addr range is inside the flash */
     stlink_calculate_pagesize(sl, addr);
     if (addr < sl->flash_base) {
-        WLOG("addr too low %#x < %#x\n", addr, sl->flash_base);
+        ELOG("addr too low %#x < %#x\n", addr, sl->flash_base);
         return -1;
     } else if ((addr + len) < addr) {
-        WLOG("addr overruns\n");
+        ELOG("addr overruns\n");
         return -1;
     } else if ((addr + len) > (sl->flash_base + sl->flash_size)) {
-        WLOG("addr too high\n");
+        ELOG("addr too high\n");
         return -1;
-    } else if ((addr & 1) || (len & 1)) {
-        WLOG("unaligned addr or size\n");
+    } else if (addr & 1) {
+        ELOG("unaligned addr 0x%x\n", addr);
         return -1;
+    } else if (len & 1) {
+        WLOG("unaligned len 0x%x -- padding with zero\n", len);
+        len += 1;
     } else if (addr & (sl->flash_pgsz - 1)) {
-        WLOG("addr not a multiple of pagesize, not supported\n");
+        ELOG("addr not a multiple of pagesize, not supported\n");
         return -1;
     }
 
@@ -1399,7 +1449,7 @@ int stlink_write_flash(stlink_t *sl, stm32_addr_t addr, uint8_t* base, unsigned
     for (off = 0; off < len; off += stlink_calculate_pagesize(sl, addr + off)) {
         /* addr must be an addr inside the page */
         if (stlink_erase_flash_page(sl, addr + off) == -1) {
-            WLOG("Failed to erase_flash_page(%#zx) == -1\n", addr + off);
+            ELOG("Failed to erase_flash_page(%#zx) == -1\n", addr + off);
             return -1;
         }
         fprintf(stdout,"\rFlash page at addr: 0x%08lx erased",
@@ -1411,13 +1461,13 @@ int stlink_write_flash(stlink_t *sl, stm32_addr_t addr, uint8_t* base, unsigned
     ILOG("Finished erasing %d pages of %d (%#x) bytes\n",
         page_count, sl->flash_pgsz, sl->flash_pgsz);
 
-    if ((sl->chip_id == STM32_CHIPID_F2) ||(sl->chip_id == STM32_CHIPID_F4)) {
+    if ((sl->chip_id == STM32_CHIPID_F2) || (sl->chip_id == STM32_CHIPID_F4)) {
        /* todo: check write operation */
 
         ILOG("Starting Flash write for F2/F4\n");
         /* flash loader initialization */
         if (init_flash_loader(sl, &fl) == -1) {
-            WLOG("init_flash_loader() == -1\n");
+            ELOG("init_flash_loader() == -1\n");
             return -1;
         }
 
@@ -1437,7 +1487,7 @@ int stlink_write_flash(stlink_t *sl, stm32_addr_t addr, uint8_t* base, unsigned
             printf("size: %zu\n", size);
 
             if (run_flash_loader(sl, &fl, addr + off, base + off, size) == -1) {
-                WLOG("run_flash_loader(%#zx) failed! == -1\n", addr + off);
+                ELOG("run_flash_loader(%#zx) failed! == -1\n", addr + off);
                 return -1;
             }
 
@@ -1583,11 +1633,11 @@ int stlink_write_flash(stlink_t *sl, stm32_addr_t addr, uint8_t* base, unsigned
        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) {
-        ILOG("Starting Flash write for VL core id\n");
+    } else if (sl->core_id == STM32VL_CORE_ID || sl->core_id == STM32F0_CORE_ID || sl->chip_id == STM32_CHIPID_F3) {
+        ILOG("Starting Flash write for VL/F0 core id\n");
         /* flash loader initialization */
         if (init_flash_loader(sl, &fl) == -1) {
-            WLOG("init_flash_loader() == -1\n");
+            ELOG("init_flash_loader() == -1\n");
             return -1;
         }
 
@@ -1602,7 +1652,7 @@ int stlink_write_flash(stlink_t *sl, stm32_addr_t addr, uint8_t* base, unsigned
             set_flash_cr_pg(sl);
             //DLOG("Finished setting flash cr pg, running loader!\n");
             if (run_flash_loader(sl, &fl, addr + off, base + off, size) == -1) {
-                WLOG("run_flash_loader(%#zx) failed! == -1\n", addr + off);
+                ELOG("run_flash_loader(%#zx) failed! == -1\n", addr + off);
                 return -1;
             }
             lock_flash(sl);
@@ -1615,7 +1665,7 @@ int stlink_write_flash(stlink_t *sl, stm32_addr_t addr, uint8_t* base, unsigned
         }
         fprintf(stdout, "\n");
     } else {
-        WLOG("unknown coreid, not sure how to write: %x\n", sl->core_id);
+        ELOG("unknown coreid, not sure how to write: %x\n", sl->core_id);
         return -1;
     }
 
@@ -1636,7 +1686,7 @@ int stlink_fwrite_flash(stlink_t *sl, const char* path, stm32_addr_t addr) {
     unsigned char erased_pattern =(sl->chip_id == STM32_CHIPID_L1_MEDIUM)?0:0xff;
     mapped_file_t mf = MAPPED_FILE_INITIALIZER;
     if (map_file(&mf, path) == -1) {
-        WLOG("map_file() == -1\n");
+        ELOG("map_file() == -1\n");
         return -1;
     }
     for(index = 0; index < mf.len; index ++) {
@@ -1667,7 +1717,7 @@ int run_flash_loader(stlink_t *sl, flash_loader_t* fl, stm32_addr_t target, cons
     // FIXME This can never return -1
     if (write_buffer_to_sram(sl, fl, buf, size) == -1) {
         // IMPOSSIBLE!
-        WLOG("write_buffer_to_sram() == -1\n");
+        ELOG("write_buffer_to_sram() == -1\n");
         return -1;
     }
 
@@ -1682,7 +1732,7 @@ int run_flash_loader(stlink_t *sl, flash_loader_t* fl, stm32_addr_t target, cons
         stlink_write_reg(sl, count, 2); /* count (32 bits words) */
         stlink_write_reg(sl, fl->loader_addr, 15); /* pc register */
 
-    } else if (sl->core_id == STM32VL_CORE_ID) {
+    } else if (sl->core_id == STM32VL_CORE_ID || sl->core_id == STM32F0_CORE_ID || sl->chip_id == STM32_CHIPID_F3) {
 
         size_t count = size / sizeof(uint16_t);
         if (size % sizeof(uint16_t)) ++count;
@@ -1706,20 +1756,22 @@ int run_flash_loader(stlink_t *sl, flash_loader_t* fl, stm32_addr_t target, cons
         stlink_write_reg(sl, fl->loader_addr, 15); /* pc register */
 
     } else {
-        fprintf(stderr, "unknown coreid: 0x%x\n", sl->core_id);
+        fprintf(stderr, "unknown coreid 0x%x, don't know what flash loader to use\n", sl->core_id);
         return -1;
     }
 
     /* run loader */
     stlink_run(sl);
 
+#define WAIT_ROUNDS 1000
     /* wait until done (reaches breakpoint) */
-    while ((is_core_halted(sl) == 0) && (i <1000)) {
-        i++;
+    for (i = 0; i < WAIT_ROUNDS; i++) {
+        if (is_core_halted(sl))
+            break;
     }
 
-    if ( i > 999) {
-        fprintf(stderr, "run error\n");
+    if (i >= WAIT_ROUNDS) {
+        fatal("flash loader run error\n");
         return -1;
     }
 
@@ -1735,7 +1787,7 @@ int run_flash_loader(stlink_t *sl, flash_loader_t* fl, stm32_addr_t target, cons
         return -1;
       }
 
-    } else if (sl->core_id == STM32VL_CORE_ID) {
+    } else if (sl->core_id == STM32VL_CORE_ID || sl->core_id == STM32F0_CORE_ID || sl->chip_id == STM32_CHIPID_F3) {
 
       stlink_read_reg(sl, 2, &rr);
       if (rr.r[2] != 0) {
@@ -1743,17 +1795,17 @@ int run_flash_loader(stlink_t *sl, flash_loader_t* fl, stm32_addr_t target, cons
         return -1;
       }
 
-       } else if (sl->chip_id == STM32_CHIPID_F2 || sl->chip_id == STM32_CHIPID_F4) {
+    } else if (sl->chip_id == STM32_CHIPID_F2 || sl->chip_id == STM32_CHIPID_F4) {
 
-               stlink_read_reg(sl, 2, &rr);
-               if (rr.r[2] != 0) {
-                       fprintf(stderr, "write error, count == %u\n", rr.r[2]);
-                       return -1;
-               }
+        stlink_read_reg(sl, 2, &rr);
+        if (rr.r[2] != 0) {
+            fprintf(stderr, "write error, count == %u\n", rr.r[2]);
+            return -1;
+        }
 
     } else {
 
-      fprintf(stderr, "unknown coreid: 0x%x\n", sl->core_id);
+      fprintf(stderr, "unknown coreid 0x%x, can't check written byte count\n", sl->core_id);
       return -1;
 
     }