stlinkv2.py: merge Cortex-M0 support for FSM-55
authorNIIBE Yutaka <gniibe@fsij.org>
Mon, 6 Jul 2015 06:52:04 +0000 (15:52 +0900)
committerNIIBE Yutaka <gniibe@fsij.org>
Mon, 6 Jul 2015 06:52:04 +0000 (15:52 +0900)
ChangeLog
tool/asm-thumb/blank_check.S
tool/asm-thumb/flash_write.S
tool/asm-thumb/opt_bytes_write.S
tool/stlinkv2.py

index bde1a3e..6dc8cb2 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,19 @@
+2015-07-06  Niibe Yutaka  <gniibe@fsij.org>
+
+       Enhancement for FSM-55.
+       * tool/stlinkv2.py (stlinkv2.control_nrst): New.
+       (stlinkv2.get_rdp_key,has_spi_flash,has_protection): New.
+       (stlinkv2.get_core_id): Rename.
+       (stlinkv2.blank_check): Use self.flash_size.
+       (stlinkv2.start): Call control_nrst.  Call get_core_id.
+       Distinguishing chip, and set rdp_key, flash_size and require_nrst.
+       (stlinkv2.flash_write): Use self.flash_block_size.
+       (main): Call control_nrst.
+       (prog_flash_write_body, prog_option_bytes_write_body)
+       (prog_blank_check_body): Support Cortex-M0.
+       (main): Call API V2 halt twice.
+       * tool/asm-thumb/*.S: Updated for Cortex-M0.
+
 2015-06-30  Niibe Yutaka  <gniibe@fsij.org>
 
        * chopstx: Update.
index 567ef23..53befbf 100644 (file)
@@ -1,7 +1,7 @@
 /* ARM Thumb Assembler code */
 // arm-none-eabi-gcc -Wa,-amhls=blank_check.lst -c blank_check.S
 
-       .cpu cortex-m3
+       .cpu cortex-m0
        .thumb
        ldr     r1, .START_ADDR
        ldr     r2, .END_ADDR
index 8f4b16c..66a577d 100644 (file)
@@ -8,11 +8,9 @@
 #define FLASH_SR_OFFSET        0x0c
 #define FLASH_CR_OFFSET        0x10
 
-#define COUNT  0x1000
-
-       .cpu cortex-m3
+       .cpu cortex-m0
        .thumb
-       movw    r2, #COUNT
+       ldr     r2, .SIZE
        ldr     r0, .SRC_ADDR
        ldr     r1, .TARGET_ADDR
        ldr     r4, .FLASH_BASE_ADDR
@@ -35,5 +33,6 @@
        bkpt    #0x00
        .align  2
 .FLASH_BASE_ADDR:      .word 0x40022000
-.SRC_ADDR:             .word 0x20000038
+.SRC_ADDR:             .word 0x2000003C
 .TARGET_ADDR:          .word 0x08000000
+.SIZE:                 .word 0x00000000
index dad89bb..aafcbf9 100644 (file)
@@ -7,11 +7,9 @@
 #define FLASH_SR_OFFSET        0x0c
 #define FLASH_CR_OFFSET        0x10
 
-#define OB_RDP_UNLOCK  0x00a5
-
-       .cpu cortex-m3
+       .cpu cortex-m0
        .thumb
-       movw    r0, #OB_RDP_UNLOCK
+       ldr     r0, .OPTION_BYTES
        ldr     r1, .TARGET_ADDR
        ldr     r2, .FLASH_BASE_ADDR
        mov     r3, #FLASH_CR_OPTPG
 1:     ldr     r0, [r2, #FLASH_SR_OFFSET]
        tst     r0, r4
        bne     1b
+       add     r1, #2
+       mov     r0, #255
+       strh    r0, [r1]
+2:     ldr     r0, [r2, #FLASH_SR_OFFSET]
+       tst     r0, r4
+       bne     2b
        mov     r0, #0
        str     r0, [r2, #FLASH_CR_OFFSET]
        bkpt    #0x00
        .align  2
 .FLASH_BASE_ADDR:      .word 0x40022000
 .TARGET_ADDR:          .word 0x1FFFF800
+.OPTION_BYTES:         .word 0x00000000
index 2a2e0d3..bbe188b 100755 (executable)
@@ -3,7 +3,7 @@
 """
 stlinkv2.py - a tool to control ST-Link/V2
 
-Copyright (C) 2012, 2013 Free Software Initiative of Japan
+Copyright (C) 2012, 2013, 2015 Free Software Initiative of Japan
 Author: NIIBE Yutaka <gniibe@fsij.org>
 
 This file is a part of Gnuk, a GnuPG USB Token implementation.
@@ -31,11 +31,17 @@ from colorama import init as colorama_init, Fore, Back, Style
 
 # Assumes only single ST-Link/V2 device is attached to computer.
 
+CORE_ID_CORTEX_M3=0x1ba01477
+CORE_ID_CORTEX_M0=0x0bb11477
+
+CHIP_ID_STM32F103=0x20036410
+
 
 GPIOA=0x40010800
 GPIOB=0x40010C00
 OPTION_BYTES_ADDR=0x1ffff800
-RDP_KEY=0x00a5                  # Unlock readprotection
+RDP_KEY_F1=0x00a5                  # Unlock readprotection
+RDP_KEY_F0=0x00aa                  # Unlock readprotection
 FLASH_BASE_ADDR=0x40022000
 
 FLASH_KEYR=    FLASH_BASE_ADDR+0x04
@@ -62,44 +68,45 @@ FLASH_CR_STRT=   0x0040
 FLASH_CR_LOCK=   0x0080
 FLASH_CR_OPTWRE= 0x0200
 
+FLASH_SIZE_F1=0x20000 # 128KiB
+FLASH_SIZE_F0=0x4000  # 16KiB
 
 SPI1= 0x40013000
 
 def uint32(v):
     return v[0] + (v[1]<<8) + (v[2]<<16) + (v[3]<<24)
 
-## HERE comes: "movw r2,#SIZE" instruction
-prog_flash_write_body = "\x0A\x48" + "\x0B\x49" + \
-    "\x08\x4C" + "\x01\x25" + "\x14\x26" + "\x00\x27" + "\x25\x61" + \
+prog_flash_write_body = "\x0D\x4A" + "\x0B\x48" + "\x0B\x49" + \
+    "\x09\x4C" + "\x01\x25" + "\x14\x26" + "\x00\x27" + "\x25\x61" + \
     "\xC3\x5B" + "\xCB\x53" + "\xE3\x68" + "\x2B\x42" + "\xFC\xD1" + \
     "\x33\x42" + "\x02\xD1" + "\x02\x37" + "\x97\x42" + "\xF5\xD1" + \
-    "\x00\x27" + "\x27\x61" + "\x00\xBE" +  "\x00\x20\x02\x40" + \
-    "\x38\x00\x00\x20"
-#   .SRC_ADDR: 0x20000038
+    "\x00\x27" + "\x27\x61" + "\x00\xBE" + "\xC0\x46" + "\x00\x20\x02\x40" + \
+    "\x3C\x00\x00\x20"
+#   .SRC_ADDR: 0x2000003C
 ## HERE comes: target_addr in 4-byte
 #   .TARGET_ADDR
+## HERE comes: size in 4-byte
+#   .SIZE
 
 def gen_prog_flash_write(addr,size):
-    return pack("<BBBB", (0x40 | (size&0xf000)>>12), (0xf2 | (size&0x0800)>>9),
-                (size & 0x00ff), (0x02 | ((size&0x0700) >> 4))) + \
-                prog_flash_write_body + pack("<I", addr)
-
+    return prog_flash_write_body + pack("<I", addr) + pack("<I", size)
 
-## HERE comes: "movw r0,#VAL" instruction
-prog_option_bytes_write_body = "\x06\x49" + "\x05\x4A" + "\x10\x23" + \
-    "\x01\x24" + "\x13\x61" + "\x08\x80" + "\xD0\x68" + "\x20\x42" + \
-    "\xFC\xD1" + "\x00\x20" + "\x10\x61" + "\x00\xBE" + "\x00\x20\x02\x40"
+prog_option_bytes_write_body = "\x0B\x48" + "\x0A\x49" + "\x08\x4A" + \
+     "\x10\x23" + "\x01\x24" + "\x13\x61" + "\x08\x80" + "\xD0\x68" + \
+     "\x20\x42" + "\xFC\xD1" + "\x02\x31" + "\xFF\x20" + "\x08\x80" + \
+     "\xD0\x68" + "\x20\x42" + "\xFC\xD1" + "\x00\x20" + "\x10\x61" + \
+     "\x00\xBE" + "\xC0\x46" + "\x00\x20\x02\x40"
 ## HERE comes: target_addr in 4-byte
 #   .TARGET_ADDR
+## HERE comes: option_bytes in 4-byte
+#   .OPTION_BYTES
 
 def gen_prog_option_bytes_write(addr,val):
-    return pack("<BBBB", (0x40 | (val&0xf000)>>12), (0xf2 | (val&0x0800)>>9),
-                (val & 0x00ff), (0x00 | ((val&0x0700) >> 4))) + \
-                prog_option_bytes_write_body + pack("<I", addr)
+    return prog_option_bytes_write_body + pack("<I", addr) + pack("<I", val)
 
 prog_blank_check_body = "\x04\x49" + "\x05\x4A" + "\x08\x68" + "\x01\x30" + \
     "\x02\xD1" + "\x04\x31" + "\x91\x42" + "\xF9\xD1" + "\x00\xBE" + \
-    "\x00\xBF" + "\x00\x00\x00\x08"
+    "\xC0\x46" + "\x00\x00\x00\x08"
 ## HERE comes: end_addr in 4-byte
 # .END_ADDR
 
@@ -108,7 +115,8 @@ def gen_prog_blank_check(size):
 
 
 SRAM_ADDRESS=0x20000000
-BLOCK_SIZE=16384                # Should be less than (20KiB - 0x0038)
+FLASH_BLOCK_SIZE_F1=16384       # Should be less than (20KiB - 0x0038)
+FLASH_BLOCK_SIZE_F0=2048        # Should be less than (4KiB - 0x0038)
 BLOCK_WRITE_TIMEOUT=80          # Increase this when you increase BLOCK_SIZE
 
 
@@ -219,11 +227,14 @@ class stlinkv2(object):
     def write_debug_reg(self, addr, value):
         return self.execute_get("\xf2\x35" + pack('<II', addr, value), 2)
 
+    def control_nrst(self, value):
+        return self.execute_get("\xf2\x3c" + pack('<B', value), 2)
+
     def run(self):
         v = self.execute_get("\xf2\x09\x00", 2)
         return (v[1] << 8) + v[0]
 
-    def core_id(self):
+    def get_core_id(self):
         v = self.execute_get("\xf2\x22\x00", 4)
         return v[0] + (v[1]<<8) + (v[2]<<16) + (v[3]<<24)
 
@@ -309,7 +320,7 @@ class stlinkv2(object):
         return (self.read_memory_u32(FLASH_OBR) & 0x0002) != 0
 
     def blank_check(self):
-        prog = gen_prog_blank_check(0x20000) # 128KiB  XXX: table lookup???
+        prog = gen_prog_blank_check(self.flash_size)
         self.write_memory(SRAM_ADDRESS, prog)
         self.write_reg(15, SRAM_ADDRESS)
         self.run()
@@ -398,8 +409,8 @@ class stlinkv2(object):
 
         off = 0
         while True:
-            if len(data[off:]) > BLOCK_SIZE:
-                size = BLOCK_SIZE
+            if len(data[off:]) > self.flash_block_size:
+                size = self.flash_block_size
                 self.flash_write_internal(addr, data, off, size)
                 off = off + size
                 addr = addr + size
@@ -467,6 +478,7 @@ class stlinkv2(object):
             self.exit_from_dfu()
         new_mode = self.stl_mode()
         print "Change ST-Link/V2 mode %04x -> %04x" % (mode, new_mode)
+        self.control_nrst(2)
         self.enter_swd()
         s = self.get_status()
         if s != 0x0080:
@@ -483,6 +495,38 @@ class stlinkv2(object):
         if mode != 2:
             raise ValueError("Failed to switch debug mode.", mode)
 
+        self.core_id = self.get_core_id()
+        if self.core_id == CORE_ID_CORTEX_M3:
+            self.chip_id = self.read_memory_u32(0xE0042000)
+        elif self.core_id == CORE_ID_CORTEX_M0:
+            self.chip_id = 0
+        else:
+            raise ValueError("Unknown core ID", self.core_id)
+        if self.chip_id == CHIP_ID_STM32F103:
+            self.rdp_key = RDP_KEY_F1
+            self.flash_size = FLASH_SIZE_F1
+            self.flash_block_size = FLASH_BLOCK_SIZE_F1
+            self.require_nrst = False
+            self.external_spi_flash = True
+            self.protection_feature = True
+        else:
+            self.rdp_key = RDP_KEY_F0
+            self.flash_size = FLASH_SIZE_F0
+            self.flash_block_size = FLASH_BLOCK_SIZE_F0
+            self.require_nrst = True
+            self.external_spi_flash = False
+            self.protection_feature = False
+        return (self.core_id, self.chip_id)
+
+    def get_rdp_key(self):
+        return self.rdp_key
+
+    def has_spi_flash(self):
+        return self.external_spi_flash
+
+    def has_protection(self):
+        return self.protection_feature
+
 
 USB_VENDOR_ST=0x0483            # 0x0483 SGS Thomson Microelectronics
 USB_VENDOR_STLINKV2=0x3748      # 0x3748 ST-LINK/V2
@@ -538,9 +582,7 @@ def main(show_help, erase_only, no_protect, spi_flash_check,
         raise ValueError("No ST-Link/V2 device found.", None)
 
     print "ST-Link/V2 version info: %d %d %d" % stl.version()
-    stl.start()
-    core_id = stl.core_id()
-    chip_id = stl.read_memory_u32(0xE0042000)
+    (core_id, chip_id) = stl.start()
 
     # FST-01 chip id: 0x20036410
     print "CORE: %08x, CHIP_ID: %08x" % (core_id, chip_id)
@@ -553,11 +595,13 @@ def main(show_help, erase_only, no_protect, spi_flash_check,
 
     option_bytes = stl.option_bytes_read()
     print "Option bytes: %08x" % option_bytes
-    if (option_bytes & 0xff) == RDP_KEY:
+    rdp_key = stl.get_rdp_key()
+    if (option_bytes & 0xff) == rdp_key:
         ob_protection_enable = False
     else:
         ob_protection_enable = True
 
+    stl.control_nrst(2)
     stl.enter_debug()
     status = stl.get_status()
     if status != 0x0081:
@@ -565,6 +609,8 @@ def main(show_help, erase_only, no_protect, spi_flash_check,
         #                   DCB_DHCSR    DBGKEY|C_HALT|C_DEBUGEN
         stl.write_debug_reg(0xE000EDF0, 0xA05F0003)
         status = stl.get_status()
+        stl.write_debug_reg(0xE000EDF0, 0xA05F0003)
+        status = stl.get_status()
         if status != 0x0081:
             raise ValueError("Status of core is not halt.", status)
 
@@ -602,14 +648,14 @@ def main(show_help, erase_only, no_protect, spi_flash_check,
             stl.reset_sys()
             stl.option_bytes_erase()
         stl.reset_sys()
-        stl.option_bytes_write(OPTION_BYTES_ADDR,RDP_KEY)
+        stl.option_bytes_write(OPTION_BYTES_ADDR,rdp_key)
         stl.usb_disconnect()
         time.sleep(0.100)
         stl.finish_gpio()
         print "Flash ROM read protection disabled.  Reset the board, now."
         return 0
 
-    if spi_flash_check:
+    if spi_flash_check and stl.has_spi_flash():
         stl.spi_flash_init()
         id = stl.spi_flash_read_id()
         print "SPI Flash ROM ID: %06x" % id
@@ -646,12 +692,13 @@ def main(show_help, erase_only, no_protect, spi_flash_check,
         off = off + blk_size
     compare(data, data_received)
 
-    if not no_protect:
+    if not no_protect and stl.has_protection():
         print "PROTECT"
         stl.option_bytes_erase()
         print "Flash ROM read protection enabled.  Reset the board to enable protection."
 
     if reset_after_successful_write:
+        stl.control_nrst(2)
         stl.usb_disconnect()
         stl.reset_sys()
         stl.run()