]> git.gag.com Git - fw/stlink/blobdiff - src/stlink-common.c
Support for STM32L1 medium-plus chips with chip id 0x427
[fw/stlink] / src / stlink-common.c
index 702536aed28306977ab20debe861bb793980d01f..2b208bc549f81a1cdbcdfb27c7e31696c557c575 100644 (file)
 #include "stlink-common.h"
 #include "uglylogging.h"
 
+#ifndef _WIN32
+#define O_BINARY 0
+#endif
+
+
 #define LOG_TAG __FILE__
 #define DLOG(format, args...)         ugly_log(UDEBUG, LOG_TAG, format, ## args)
 #define ILOG(format, args...)         ugly_log(UINFO, LOG_TAG, format, ## args)
@@ -25,6 +30,7 @@
 
 /* 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
 
@@ -36,6 +42,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
@@ -445,6 +452,22 @@ int stlink_load_device_params(stlink_t *sl) {
         sl->flash_size = 0x100000; /* Use maximum, User must care!*/
     } else if (sl->chip_id == STM32_CHIPID_F4) {
                sl->flash_size = 0x100000;                      //todo: RM0090 error; size register same address as unique ID
+    } else if (sl->chip_id == STM32_CHIPID_L1_MEDIUM || sl->chip_id == STM32_CHIPID_L1_MEDIUM_PLUS) {
+        // if the flash size is zero, we assume it is 128k, if not we calculate the real value
+        uint32_t flash_size = stlink_read_debug32(sl,params->flash_size_reg) & 0xffff;
+        if ( flash_size == 0 ) {
+            sl->flash_size = 128 * 1024;
+        } else {
+            sl->flash_size = flash_size * 1024;
+        }
+    } else if ((sl->chip_id & 0xFFF) == STM32_CHIPID_L1_HIGH) {
+        uint32_t flash_size = stlink_read_debug32(sl, params->flash_size_reg) & 0x1;
+        // 0 is 384k and 1 is 256k
+        if ( flash_size == 0 ) {
+            sl->flash_size = 384 * 1024;
+        } else {
+            sl->flash_size = 256 * 1024;
+        }
     } else {
         uint32_t flash_size = stlink_read_debug32(sl, params->flash_size_reg) & 0xffff;
         sl->flash_size = flash_size * 1024;
@@ -541,7 +564,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);
 }
@@ -551,7 +574,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);
 }
@@ -561,7 +584,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);
 }
@@ -755,7 +778,7 @@ static int map_file(mapped_file_t* mf, const char* path) {
     int error = -1;
     struct stat st;
 
-    const int fd = open(path, O_RDONLY);
+    const int fd = open(path, O_RDONLY | O_BINARY);
     if (fd == -1) {
         fprintf(stderr, "open(%s) == -1\n", path);
         return -1;
@@ -827,6 +850,7 @@ int stlink_fwrite_sram
     size_t off;
     mapped_file_t mf = MAPPED_FILE_INITIALIZER;
 
+
     if (map_file(&mf, path) == -1) {
         fprintf(stderr, "map_file() == -1\n");
         return -1;
@@ -847,7 +871,6 @@ int stlink_fwrite_sram
         fprintf(stderr, "unaligned addr or size\n");
         goto on_error;
     }
-
     /* do the copy by 1k blocks */
     for (off = 0; off < mf.len; off += 1024) {
         size_t size = 1024;
@@ -888,7 +911,8 @@ 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  || sl->chip_id == STM32_CHIPID_L1_MEDIUM_PLUS
+                                     || sl->chip_id == STM32_CHIPID_L1_HIGH) ? 0:0xff;
 
     const int fd = open(path, O_RDWR | O_TRUNC | O_CREAT, 00700);
     if (fd == -1) {
@@ -1013,30 +1037,35 @@ int stlink_erase_flash_page(stlink_t *sl, stm32_addr_t flashaddr)
 #if DEBUG_FLASH
        fprintf(stdout, "Erase Final CR:0x%x\n", read_flash_cr(sl));
 #endif
-  } else if (sl->chip_id == STM32_CHIPID_L1_MEDIUM) {
+  } else if (sl->chip_id == STM32_CHIPID_L1_MEDIUM || sl->chip_id == STM32_CHIPID_L1_MEDIUM_PLUS
+               || sl->chip_id == STM32_CHIPID_L1_HIGH) {
 
     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 */
+    /* check if the locks are set */
     val = stlink_read_debug32(sl, STM32L_FLASH_PECR);
-    if (val & (1 << 0)) {
-      WLOG("pecr.pelock not clear (%#x)\n", val);
-      return -1;
-    }
+    if((val & (1<<0))||(val & (1<<1))) {
+        /* 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);
+        /* 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;
+        /* 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 */
@@ -1083,7 +1112,10 @@ 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 
+            || sl->chip_id == STM32_CHIPID_F37x) {
     /* wait for ongoing op to finish */
     wait_flash_busy(sl);
 
@@ -1115,7 +1147,8 @@ int stlink_erase_flash_page(stlink_t *sl, stm32_addr_t flashaddr)
 }
 
 int stlink_erase_flash_mass(stlink_t *sl) {
-    if (sl->chip_id == STM32_CHIPID_L1_MEDIUM) {
+    if (sl->chip_id == STM32_CHIPID_L1_MEDIUM || sl->chip_id == STM32_CHIPID_L1_MEDIUM_PLUS 
+       || sl->chip_id == STM32_CHIPID_L1_HIGH) {
         /* erase each page */
         int i = 0, num_pages = sl->flash_size/sl->flash_pgsz;
         for (i = 0; i < num_pages; i++) {
@@ -1191,6 +1224,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
@@ -1237,15 +1318,19 @@ int write_loader_to_sram(stlink_t *sl, stm32_addr_t* addr, size_t* size) {
     const uint8_t* loader_code;
     size_t loader_size;
 
-    if (sl->chip_id == STM32_CHIPID_L1_MEDIUM) { /* stm32l */
+    if (sl->chip_id == STM32_CHIPID_L1_MEDIUM || sl->chip_id == STM32_CHIPID_L1_MEDIUM_PLUS
+               || sl->chip_id == STM32_CHIPID_L1_HIGH ) { /* stm32l */
         loader_code = loader_code_stm32l;
         loader_size = sizeof(loader_code_stm32l);
-    } else if (sl->core_id == STM32VL_CORE_ID) {
+    } else if (sl->core_id == STM32VL_CORE_ID || sl->chip_id == STM32_CHIPID_F3  || sl->chip_id == STM32_CHIPID_F37x) {
         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);
+    } else if (sl->chip_id == STM32_CHIPID_F0 || sl->chip_id == STM32_CHIPID_F0_SMALL) {
+        loader_code = loader_code_stm32f0;
+        loader_size = sizeof(loader_code_stm32f0);
     } else {
         ELOG("unknown coreid, not sure what flash loader to use, aborting!: %x\n", sl->core_id);
         return -1;
@@ -1362,7 +1447,7 @@ int stm32l1_write_half_pages(stlink_t *sl, stm32_addr_t addr, uint8_t* base, uns
     return 0;
 }
 
-int stlink_write_flash(stlink_t *sl, stm32_addr_t addr, uint8_t* base, unsigned len) {
+int stlink_write_flash(stlink_t *sl, stm32_addr_t addr, uint8_t* base, uint32_t len) {
     size_t off;
     flash_loader_t fl;
     ILOG("Attempting to write %d (%#x) bytes to stm32 address: %u (%#x)\n",
@@ -1474,7 +1559,8 @@ int stlink_write_flash(stlink_t *sl, stm32_addr_t addr, uint8_t* base, unsigned
 
     }  //STM32F4END
 
-    else if (sl->chip_id == STM32_CHIPID_L1_MEDIUM)    {
+    else if (sl->chip_id == STM32_CHIPID_L1_MEDIUM || sl->chip_id == STM32_CHIPID_L1_MEDIUM_PLUS
+               || sl->chip_id == STM32_CHIPID_L1_HIGH ) {
        /* use fast word write. todo: half page. */
        uint32_t val;
 
@@ -1580,8 +1666,8 @@ 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  || sl->chip_id == STM32_CHIPID_F37x) {
+        ILOG("Starting Flash write for VL/F0 core id\n");
         /* flash loader initialization */
         if (init_flash_loader(sl, &fl) == -1) {
             ELOG("init_flash_loader() == -1\n");
@@ -1630,7 +1716,8 @@ int stlink_fwrite_flash(stlink_t *sl, const char* path, stm32_addr_t addr) {
     /* write the file in flash at addr */
     int err;
     unsigned int num_empty = 0, index;
-    unsigned char erased_pattern =(sl->chip_id == STM32_CHIPID_L1_MEDIUM)?0:0xff;
+    unsigned char erased_pattern =(sl->chip_id == STM32_CHIPID_L1_MEDIUM || sl->chip_id == STM32_CHIPID_L1_MEDIUM_PLUS
+       || sl->chip_id == STM32_CHIPID_L1_HIGH )?0:0xff;
     mapped_file_t mf = MAPPED_FILE_INITIALIZER;
     if (map_file(&mf, path) == -1) {
         ELOG("map_file() == -1\n");
@@ -1668,7 +1755,8 @@ int run_flash_loader(stlink_t *sl, flash_loader_t* fl, stm32_addr_t target, cons
         return -1;
     }
 
-    if (sl->chip_id == STM32_CHIPID_L1_MEDIUM) {
+    if (sl->chip_id == STM32_CHIPID_L1_MEDIUM  || sl->chip_id == STM32_CHIPID_L1_MEDIUM_PLUS
+       || sl->chip_id == STM32_CHIPID_L1_HIGH ) {
 
         size_t count = size / sizeof(uint32_t);
         if (size % sizeof(uint32_t)) ++count;
@@ -1679,7 +1767,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  || sl->chip_id == STM32_CHIPID_F37x) {
 
         size_t count = size / sizeof(uint16_t);
         if (size % sizeof(uint16_t)) ++count;
@@ -1710,20 +1798,22 @@ int run_flash_loader(stlink_t *sl, flash_loader_t* fl, stm32_addr_t target, cons
     /* run loader */
     stlink_run(sl);
 
-#define WAIT_ROUNDS 1000
+#define WAIT_ROUNDS 10000
     /* wait until done (reaches breakpoint) */
     for (i = 0; i < WAIT_ROUNDS; i++) {
+        usleep(10);
         if (is_core_halted(sl))
             break;
     }
 
     if (i >= WAIT_ROUNDS) {
-        fatal("flash loader run error\n");
+        ELOG("flash loader run error\n");
         return -1;
     }
 
     /* check written byte count */
-    if (sl->chip_id == STM32_CHIPID_L1_MEDIUM) {
+    if (sl->chip_id == STM32_CHIPID_L1_MEDIUM || sl->chip_id == STM32_CHIPID_L1_MEDIUM_PLUS
+       || sl->chip_id == STM32_CHIPID_L1_HIGH ) {
 
       size_t count = size / sizeof(uint32_t);
       if (size % sizeof(uint32_t)) ++count;
@@ -1734,7 +1824,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  || sl->chip_id == STM32_CHIPID_F37x) {
 
       stlink_read_reg(sl, 2, &rr);
       if (rr.r[2] != 0) {