Hello community,

here is the log from the commit of package stm32flash for openSUSE:Factory 
checked in at 2016-08-29 15:42:52
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/stm32flash (Old)
 and      /work/SRC/openSUSE:Factory/.stm32flash.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "stm32flash"

Changes:
--------
--- /work/SRC/openSUSE:Factory/stm32flash/stm32flash.changes    2015-11-16 
18:51:36.000000000 +0100
+++ /work/SRC/openSUSE:Factory/.stm32flash.new/stm32flash.changes       
2016-08-29 15:46:14.000000000 +0200
@@ -1,0 +2,19 @@
+Sat Aug 13 09:49:11 UTC 2016 - kkae...@suse.com
+
+- add upstream fixes
+  * Fix for device 0x442: System memory start address:
+    0001-Fix-for-device-0x442-System-memory-start-address.patch
+  * dev_table: Mark 0x417, 0x429, 0x427 for no mass-erase
+    0003-dev_table-Mark-0x417-0x429-0x427-for-no-mass-erase.patch
+
+-------------------------------------------------------------------
+Sat Aug 13 09:37:54 UTC 2016 - kkae...@suse.com
+
+- Update to 0.5
+  * support for multiple bank sizes
+  * improved serial port support on Windows
+  * improved erase functionality
+  * improved hex parser
+  * many new devices and device info corrections
+
+-------------------------------------------------------------------

Old:
----
  stm32flash-0.4.tar.gz

New:
----
  0001-Fix-for-device-0x442-System-memory-start-address.patch
  0003-dev_table-Mark-0x417-0x429-0x427-for-no-mass-erase.patch
  stm32flash-0.5.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ stm32flash.spec ++++++
--- /var/tmp/diff_new_pack.WFKX0O/_old  2016-08-29 15:46:17.000000000 +0200
+++ /var/tmp/diff_new_pack.WFKX0O/_new  2016-08-29 15:46:17.000000000 +0200
@@ -1,7 +1,7 @@
 #
 # spec file for package stm32flash
 #
-# Copyright (c) 2015 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2016 SUSE LINUX GmbH, Nuernberg, Germany.
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -17,15 +17,19 @@
 
 
 Name:           stm32flash
-Version:        0.4
+Version:        0.5
 Release:        0
 Summary:        Flash Program for the STM32 Bootloader
 License:        GPL-2.0+
 Group:          Hardware/Other
-Url:            https://code.google.com/p/stm32flash/
+Url:            https://sourceforge.net/p/stm32flash/wiki/Home
 Source:         %{name}-%{version}.tar.gz
+# PATCH-FIX-UPSTREAM
+Patch1:         0001-Fix-for-device-0x442-System-memory-start-address.patch
+# PATCH-FIX-UPSTREAM
+Patch2:         0003-dev_table-Mark-0x417-0x429-0x427-for-no-mass-erase.patch
 # PATCH-FIX-OPENSUSE stm32flash-i2c-tools-headers-clash.patch sbra...@suse.cz 
-- Prevent clash between i2c.h and i2c-dev.h defining the same.
-Patch:          stm32flash-i2c-tools-headers-clash.patch
+Patch3:         stm32flash-i2c-tools-headers-clash.patch
 BuildRequires:  i2c-tools
 BuildRoot:      %{_tmppath}/%{name}-%{version}-build
 
@@ -50,8 +54,10 @@
 
 %prep
 %setup -q -n %{name}
+%patch1 -p1
+%patch2 -p1
 %if 0%{?suse_version} < 1315 || 0%{?suse_version} == 1320
-%patch -p1
+%patch3 -p1
 %endif
 
 %build

++++++ 0001-Fix-for-device-0x442-System-memory-start-address.patch ++++++
>From 5361ed8259c9db5cf306c7cf5194af06732cb130 Mon Sep 17 00:00:00 2001
From: Amir Hammad <amir.ham...@streamunlimited.com>
Date: Fri, 11 Dec 2015 15:46:03 +0100
Subject: [PATCH 1/3] Fix for device 0x442: System memory start address

RM0091(rev.8.): page 50: STM32F0xx memory boundary addresses (continued)
also RM0360 (rev.3) : page 39: STM32F0x0 memory boundary addresses (continued)

0x1FFFC800 -> 0x1FFFD800

Signed-off-by: Amir Hammad <amir.ham...@streamunlimited.com>
---
 dev_table.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/dev_table.c b/dev_table.c
index f4ada72..50fb64e 100755
--- a/dev_table.c
+++ b/dev_table.c
@@ -59,7 +59,7 @@ const stm32_dev_t devices[] = {
        /* ID   "name"                              SRAM-address-range      
FLASH-address-range    PPS  PSize   Option-byte-addr-range  
System-mem-addr-range   Flags */
        /* F0 */
        {0x440, "STM32F030x8/F05xxx"              , 0x20000800, 0x20002000, 
0x08000000, 0x08010000,  4, p_1k  , 0x1FFFF800, 0x1FFFF80F, 0x1FFFEC00, 
0x1FFFF800, 0},
-       {0x442, "STM32F030xC/F09xxx"              , 0x20001800, 0x20008000, 
0x08000000, 0x08040000,  2, p_2k  , 0x1FFFF800, 0x1FFFF80F, 0x1FFFC800, 
0x1FFFF800, F_OBLL},
+       {0x442, "STM32F030xC/F09xxx"              , 0x20001800, 0x20008000, 
0x08000000, 0x08040000,  2, p_2k  , 0x1FFFF800, 0x1FFFF80F, 0x1FFFD800, 
0x1FFFF800, F_OBLL},
        {0x444, "STM32F03xx4/6"                   , 0x20000800, 0x20001000, 
0x08000000, 0x08008000,  4, p_1k  , 0x1FFFF800, 0x1FFFF80F, 0x1FFFEC00, 
0x1FFFF800, 0},
        {0x445, "STM32F04xxx/F070x6"              , 0x20001800, 0x20001800, 
0x08000000, 0x08008000,  4, p_1k  , 0x1FFFF800, 0x1FFFF80F, 0x1FFFC400, 
0x1FFFF800, 0},
        {0x448, "STM32F070xB/F071xx/F72xx"        , 0x20001800, 0x20004000, 
0x08000000, 0x08020000,  2, p_2k  , 0x1FFFF800, 0x1FFFF80F, 0x1FFFC800, 
0x1FFFF800, 0},
-- 
2.9.2

++++++ 0003-dev_table-Mark-0x417-0x429-0x427-for-no-mass-erase.patch ++++++
>From 8c4aa650bffaf98e96d1b6065ab6e76c43150d8a Mon Sep 17 00:00:00 2001
From: Tormod Volden <debian.tor...@gmail.com>
Date: Fri, 6 May 2016 16:04:13 +0200
Subject: [PATCH 3/3] dev_table: Mark 0x417, 0x429, 0x427 for no mass-erase

These have been reported to not support mass-erase:
STM32L151xx-A -> chip ID 0x429
STM32L152RCT  -> chip ID 0x427
STM32L051xx   -> chip ID 0x417

Thanks to Dieter Deppenaffe for reporting.

https://sourceforge.net/p/stm32flash/tickets/87/

Signed-off-by: Tormod Volden <debian.tor...@gmail.com>
---
 dev_table.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/dev_table.c b/dev_table.c
index 50fb64e..7e1c53c 100755
--- a/dev_table.c
+++ b/dev_table.c
@@ -92,12 +92,12 @@ const stm32_dev_t devices[] = {
        {0x449, "STM32F74xxx/75xxx"               , 0x20004000, 0x20050000, 
0x08000000, 0x08100000,  1, f7    , 0x1FFF0000, 0x1FFF001F, 0x1FF00000, 
0x1FF0EDC0, 0},
        /* L0 */
        {0x425, "STM32L031xx/041xx"               , 0x20001000, 0x20002000, 
0x08000000, 0x08008000, 32, p_128 , 0x1FF80000, 0x1FF8001F, 0x1FF00000, 
0x1FF01000, 0},
-       {0x417, "STM32L05xxx/06xxx"               , 0x20001000, 0x20002000, 
0x08000000, 0x08010000, 32, p_128 , 0x1FF80000, 0x1FF8001F, 0x1FF00000, 
0x1FF01000, 0},
+       {0x417, "STM32L05xxx/06xxx"               , 0x20001000, 0x20002000, 
0x08000000, 0x08010000, 32, p_128 , 0x1FF80000, 0x1FF8001F, 0x1FF00000, 
0x1FF01000, F_NO_ME},
        {0x447, "STM32L07xxx/08xxx"               , 0x20002000, 0x20005000, 
0x08000000, 0x08030000, 32, p_128 , 0x1FF80000, 0x1FF8001F, 0x1FF00000, 
0x1FF02000, 0},
        /* L1 */
        {0x416, "STM32L1xxx6(8/B)"                , 0x20000800, 0x20004000, 
0x08000000, 0x08020000, 16, p_256 , 0x1FF80000, 0x1FF8001F, 0x1FF00000, 
0x1FF01000, F_NO_ME},
-       {0x429, "STM32L1xxx6(8/B)A"               , 0x20001000, 0x20008000, 
0x08000000, 0x08020000, 16, p_256 , 0x1FF80000, 0x1FF8001F, 0x1FF00000, 
0x1FF01000, 0},
-       {0x427, "STM32L1xxxC"                     , 0x20001000, 0x20008000, 
0x08000000, 0x08040000, 16, p_256 , 0x1FF80000, 0x1FF8001F, 0x1FF00000, 
0x1FF02000, 0},
+       {0x429, "STM32L1xxx6(8/B)A"               , 0x20001000, 0x20008000, 
0x08000000, 0x08020000, 16, p_256 , 0x1FF80000, 0x1FF8001F, 0x1FF00000, 
0x1FF01000, F_NO_ME},
+       {0x427, "STM32L1xxxC"                     , 0x20001000, 0x20008000, 
0x08000000, 0x08040000, 16, p_256 , 0x1FF80000, 0x1FF8001F, 0x1FF00000, 
0x1FF02000, F_NO_ME},
        {0x436, "STM32L1xxxD"                     , 0x20001000, 0x2000C000, 
0x08000000, 0x08060000, 16, p_256 , 0x1FF80000, 0x1FF8009F, 0x1FF00000, 
0x1FF02000, 0},
        {0x437, "STM32L1xxxE"                     , 0x20001000, 0x20014000, 
0x08000000, 0x08080000, 16, p_256 , 0x1FF80000, 0x1FF8009F, 0x1FF00000, 
0x1FF02000, F_NO_ME},
        /* L4 */
-- 
2.9.2

++++++ stm32flash-0.4.tar.gz -> stm32flash-0.5.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/stm32flash/AUTHORS new/stm32flash/AUTHORS
--- old/stm32flash/AUTHORS      2014-07-15 23:59:06.000000000 +0200
+++ new/stm32flash/AUTHORS      2016-02-08 18:28:56.000000000 +0100
@@ -17,3 +17,11 @@
 Brian Silverman
 Georg Hofmann
 Luis Rodrigues
+Jeff Epler
+Alexander O. Anisimov
+Seth LaForge
+Johan Hellman
+Matthias Weisser
+Tilman Sauerbeck
+Mateusz SpychaƂa
+Ernst Schwab
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/stm32flash/INSTALL new/stm32flash/INSTALL
--- old/stm32flash/INSTALL      1970-01-01 01:00:00.000000000 +0100
+++ new/stm32flash/INSTALL      2016-02-09 17:16:39.000000000 +0100
@@ -0,0 +1,16 @@
+
+Building stm32flash
+
+A set of static makefiles is provided that should work on most operating
+systems with a standard build environment, for instance GNU make and gcc.
+
+1. Build executable
+
+       make
+
+2. Install executable and manual page (optional)
+
+       make install
+
+   The install location base can be set with the PREFIX flag (default
+   is /usr/local), e.g. make install PREFIX=/opt
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/stm32flash/Makefile new/stm32flash/Makefile
--- old/stm32flash/Makefile     2014-08-09 01:08:11.000000000 +0200
+++ new/stm32flash/Makefile     2016-01-26 23:45:05.000000000 +0100
@@ -19,7 +19,7 @@
 
 serial_platform.o: serial_posix.c serial_w32.c
 
-parsers/parsers.a:
+parsers/parsers.a: force
        cd parsers && $(MAKE) parsers.a
 
 stm32flash: $(OBJS) $(LIBOBJS)
@@ -35,4 +35,6 @@
        $(INSTALL) -d $(DESTDIR)$(PREFIX)/share/man/man1
        $(INSTALL) -m 644 stm32flash.1 $(DESTDIR)$(PREFIX)/share/man/man1
 
-.PHONY: all clean install
+force:
+
+.PHONY: all clean install force
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/stm32flash/TODO new/stm32flash/TODO
--- old/stm32flash/TODO 2014-07-15 23:59:06.000000000 +0200
+++ new/stm32flash/TODO 2015-12-04 21:30:57.000000000 +0100
@@ -1,7 +1,4 @@
 
-stm32:
-- Add support for variable page size
-
 AUTHORS:
 - Add contributors from Geoffrey's commits
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/stm32flash/dev_table.c new/stm32flash/dev_table.c
--- old/stm32flash/dev_table.c  2014-10-03 23:35:08.000000000 +0200
+++ new/stm32flash/dev_table.c  2016-02-08 18:28:56.000000000 +0100
@@ -1,7 +1,7 @@
 /*
   stm32flash - Open Source ST STM32 flash program for *nix
   Copyright (C) 2010 Geoffrey McRae <ge...@spacevs.com>
-  Copyright (C) 2014 Antonio Borneo <borneo.anto...@gmail.com>
+  Copyright (C) 2014-2015 Antonio Borneo <borneo.anto...@gmail.com>
 
   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License
@@ -20,51 +20,91 @@
 
 #include "stm32.h"
 
+#define SZ_128 0x00000080
+#define SZ_256 0x00000100
+#define SZ_1K  0x00000400
+#define SZ_2K  0x00000800
+#define SZ_16K 0x00004000
+#define SZ_32K 0x00008000
+#define SZ_64K 0x00010000
+#define SZ_128K        0x00020000
+#define SZ_256K        0x00040000
+
+/*
+ * Page-size for page-by-page flash erase.
+ * Arrays are zero terminated; last non-zero value is automatically repeated
+ */
+
+/* fixed size pages */
+static uint32_t p_128[] = { SZ_128, 0 };
+static uint32_t p_256[] = { SZ_256, 0 };
+static uint32_t p_1k[]  = { SZ_1K,  0 };
+static uint32_t p_2k[]  = { SZ_2K,  0 };
+/* F2 and F4 page size */
+static uint32_t f2f4[]  = { SZ_16K, SZ_16K, SZ_16K, SZ_16K, SZ_64K, SZ_128K, 0 
};
+/* F4 dual bank page size */
+static uint32_t f4db[]  = {
+       SZ_16K, SZ_16K, SZ_16K, SZ_16K, SZ_64K, SZ_128K, SZ_128K, SZ_128K,
+       SZ_16K, SZ_16K, SZ_16K, SZ_16K, SZ_64K, SZ_128K, 0
+};
+/* F7 page size */
+static uint32_t f7[]    = { SZ_32K, SZ_32K, SZ_32K, SZ_32K, SZ_128K, SZ_256K, 
0 };
+
 /*
  * Device table, corresponds to the "Bootloader device-dependant parameters"
  * table in ST document AN2606.
  * Note that the option bytes upper range is inclusive!
  */
 const stm32_dev_t devices[] = {
+       /* ID   "name"                              SRAM-address-range      
FLASH-address-range    PPS  PSize   Option-byte-addr-range  
System-mem-addr-range   Flags */
        /* F0 */
-       {0x440, "STM32F051xx"       , 0x20001000, 0x20002000, 0x08000000, 
0x08010000,  4, 1024, 0x1FFFF800, 0x1FFFF80B, 0x1FFFEC00, 0x1FFFF800},
-       {0x444, "STM32F030/F031"    , 0x20001000, 0x20002000, 0x08000000, 
0x08010000,  4, 1024, 0x1FFFF800, 0x1FFFF80B, 0x1FFFEC00, 0x1FFFF800},
-       {0x445, "STM32F042xx"       , 0x20001800, 0x20001800, 0x08000000, 
0x08008000,  4, 1024, 0x1FFFF800, 0x1FFFF80F, 0x1FFFC400, 0x1FFFF800},
-       {0x448, "STM32F072xx"       , 0x20001800, 0x20004000, 0x08000000, 
0x08020000,  2, 2048, 0x1FFFF800, 0x1FFFF80F, 0x1FFFC800, 0x1FFFF800},
+       {0x440, "STM32F030x8/F05xxx"              , 0x20000800, 0x20002000, 
0x08000000, 0x08010000,  4, p_1k  , 0x1FFFF800, 0x1FFFF80F, 0x1FFFEC00, 
0x1FFFF800, 0},
+       {0x442, "STM32F030xC/F09xxx"              , 0x20001800, 0x20008000, 
0x08000000, 0x08040000,  2, p_2k  , 0x1FFFF800, 0x1FFFF80F, 0x1FFFC800, 
0x1FFFF800, F_OBLL},
+       {0x444, "STM32F03xx4/6"                   , 0x20000800, 0x20001000, 
0x08000000, 0x08008000,  4, p_1k  , 0x1FFFF800, 0x1FFFF80F, 0x1FFFEC00, 
0x1FFFF800, 0},
+       {0x445, "STM32F04xxx/F070x6"              , 0x20001800, 0x20001800, 
0x08000000, 0x08008000,  4, p_1k  , 0x1FFFF800, 0x1FFFF80F, 0x1FFFC400, 
0x1FFFF800, 0},
+       {0x448, "STM32F070xB/F071xx/F72xx"        , 0x20001800, 0x20004000, 
0x08000000, 0x08020000,  2, p_2k  , 0x1FFFF800, 0x1FFFF80F, 0x1FFFC800, 
0x1FFFF800, 0},
        /* F1 */
-       {0x412, "Low-density"       , 0x20000200, 0x20002800, 0x08000000, 
0x08008000,  4, 1024, 0x1FFFF800, 0x1FFFF80F, 0x1FFFF000, 0x1FFFF800},
-       {0x410, "Medium-density"    , 0x20000200, 0x20005000, 0x08000000, 
0x08020000,  4, 1024, 0x1FFFF800, 0x1FFFF80F, 0x1FFFF000, 0x1FFFF800},
-       {0x414, "High-density"      , 0x20000200, 0x20010000, 0x08000000, 
0x08080000,  2, 2048, 0x1FFFF800, 0x1FFFF80F, 0x1FFFF000, 0x1FFFF800},
-       {0x420, "Medium-density VL" , 0x20000200, 0x20002000, 0x08000000, 
0x08020000,  4, 1024, 0x1FFFF800, 0x1FFFF80F, 0x1FFFF000, 0x1FFFF800},
-       {0x428, "High-density VL"   , 0x20000200, 0x20008000, 0x08000000, 
0x08080000,  2, 2048, 0x1FFFF800, 0x1FFFF80F, 0x1FFFF000, 0x1FFFF800},
-       {0x418, "Connectivity line" , 0x20001000, 0x20010000, 0x08000000, 
0x08040000,  2, 2048, 0x1FFFF800, 0x1FFFF80F, 0x1FFFB000, 0x1FFFF800},
-       {0x430, "XL-density"        , 0x20000800, 0x20018000, 0x08000000, 
0x08100000,  2, 2048, 0x1FFFF800, 0x1FFFF80F, 0x1FFFE000, 0x1FFFF800},
-       /* Note that F2 and F4 devices have sectors of different page sizes
-           and only the first sectors (of one page size) are included here */
+       {0x412, "STM32F10xxx Low-density"         , 0x20000200, 0x20002800, 
0x08000000, 0x08008000,  4, p_1k  , 0x1FFFF800, 0x1FFFF80F, 0x1FFFF000, 
0x1FFFF800, 0},
+       {0x410, "STM32F10xxx Medium-density"      , 0x20000200, 0x20005000, 
0x08000000, 0x08020000,  4, p_1k  , 0x1FFFF800, 0x1FFFF80F, 0x1FFFF000, 
0x1FFFF800, 0},
+       {0x414, "STM32F10xxx High-density"        , 0x20000200, 0x20010000, 
0x08000000, 0x08080000,  2, p_2k  , 0x1FFFF800, 0x1FFFF80F, 0x1FFFF000, 
0x1FFFF800, 0},
+       {0x420, "STM32F10xxx Medium-density VL"   , 0x20000200, 0x20002000, 
0x08000000, 0x08020000,  4, p_1k  , 0x1FFFF800, 0x1FFFF80F, 0x1FFFF000, 
0x1FFFF800, 0},
+       {0x428, "STM32F10xxx High-density VL"     , 0x20000200, 0x20008000, 
0x08000000, 0x08080000,  2, p_2k  , 0x1FFFF800, 0x1FFFF80F, 0x1FFFF000, 
0x1FFFF800, 0},
+       {0x418, "STM32F105xx/F107xx"              , 0x20001000, 0x20010000, 
0x08000000, 0x08040000,  2, p_2k  , 0x1FFFF800, 0x1FFFF80F, 0x1FFFB000, 
0x1FFFF800, 0},
+       {0x430, "STM32F10xxx XL-density"          , 0x20000800, 0x20018000, 
0x08000000, 0x08100000,  2, p_2k  , 0x1FFFF800, 0x1FFFF80F, 0x1FFFE000, 
0x1FFFF800, 0},
        /* F2 */
-       {0x411, "STM32F2xx"         , 0x20002000, 0x20020000, 0x08000000, 
0x08100000,  4, 16384, 0x1FFFC000, 0x1FFFC00F, 0x1FFF0000, 0x1FFF77DF},
+       {0x411, "STM32F2xxxx"                     , 0x20002000, 0x20020000, 
0x08000000, 0x08100000,  1, f2f4  , 0x1FFFC000, 0x1FFFC00F, 0x1FFF0000, 
0x1FFF7800, 0},
        /* F3 */
-       {0x432, "STM32F373/8"       , 0x20001400, 0x20008000, 0x08000000, 
0x08040000,  2, 2048, 0x1FFFF800, 0x1FFFF80F, 0x1FFFD800, 0x1FFFF800},
-       {0x422, "F302xB/303xB/358"  , 0x20001400, 0x20010000, 0x08000000, 
0x08040000,  2, 2048, 0x1FFFF800, 0x1FFFF80F, 0x1FFFD800, 0x1FFFF800},
-       {0x439, "STM32F302x4(6/8)"  , 0x20001800, 0x20004000, 0x08000000, 
0x08040000,  2, 2048, 0x1FFFF800, 0x1FFFF80F, 0x1FFFD800, 0x1FFFF800},
-       {0x438, "F303x4/334/328"    , 0x20001800, 0x20003000, 0x08000000, 
0x08040000,  2, 2048, 0x1FFFF800, 0x1FFFF80F, 0x1FFFD800, 0x1FFFF800},
+       {0x432, "STM32F373xx/F378xx"              , 0x20001400, 0x20008000, 
0x08000000, 0x08040000,  2, p_2k  , 0x1FFFF800, 0x1FFFF80F, 0x1FFFD800, 
0x1FFFF800, 0},
+       {0x422, "STM32F302xB(C)/F303xB(C)/F358xx" , 0x20001400, 0x2000A000, 
0x08000000, 0x08040000,  2, p_2k  , 0x1FFFF800, 0x1FFFF80F, 0x1FFFD800, 
0x1FFFF800, 0},
+       {0x439, "STM32F301xx/F302x4(6/8)/F318xx"  , 0x20001800, 0x20004000, 
0x08000000, 0x08010000,  2, p_2k  , 0x1FFFF800, 0x1FFFF80F, 0x1FFFD800, 
0x1FFFF800, 0},
+       {0x438, "STM32F303x4(6/8)/F334xx/F328xx"  , 0x20001800, 0x20003000, 
0x08000000, 0x08010000,  2, p_2k  , 0x1FFFF800, 0x1FFFF80F, 0x1FFFD800, 
0x1FFFF800, 0},
+       {0x446, "STM32F302xD(E)/F303xD(E)/F398xx" , 0x20001800, 0x20010000, 
0x08000000, 0x08080000,  2, p_2k  , 0x1FFFF800, 0x1FFFF80F, 0x1FFFD800, 
0x1FFFF800, 0},
        /* F4 */
-       {0x413, "STM32F40/1"        , 0x20002000, 0x20020000, 0x08000000, 
0x08100000,  4, 16384, 0x1FFFC000, 0x1FFFC00F, 0x1FFF0000, 0x1FFF77DF},
-       /* 0x419 is also used for STM32F429/39 but with other bootloader ID... 
*/
-       {0x419, "STM32F427/37"      , 0x20002000, 0x20030000, 0x08000000, 
0x08100000,  4, 16384, 0x1FFFC000, 0x1FFFC00F, 0x1FFF0000, 0x1FFF77FF},
-       {0x423, "STM32F401xB(C)"    , 0x20003000, 0x20010000, 0x08000000, 
0x08100000,  4, 16384, 0x1FFFC000, 0x1FFFC00F, 0x1FFF0000, 0x1FFF77FF},
-       {0x433, "STM32F401xD(E)"    , 0x20003000, 0x20018000, 0x08000000, 
0x08100000,  4, 16384, 0x1FFFC000, 0x1FFFC00F, 0x1FFF0000, 0x1FFF77FF},
+       {0x413, "STM32F40xxx/41xxx"               , 0x20003000, 0x20020000, 
0x08000000, 0x08100000,  1, f2f4  , 0x1FFFC000, 0x1FFFC00F, 0x1FFF0000, 
0x1FFF7800, 0},
+       {0x419, "STM32F42xxx/43xxx"               , 0x20003000, 0x20030000, 
0x08000000, 0x08200000,  1, f4db  , 0x1FFEC000, 0x1FFFC00F, 0x1FFF0000, 
0x1FFF7800, 0},
+       {0x423, "STM32F401xB(C)"                  , 0x20003000, 0x20010000, 
0x08000000, 0x08040000,  1, f2f4  , 0x1FFFC000, 0x1FFFC00F, 0x1FFF0000, 
0x1FFF7800, 0},
+       {0x433, "STM32F401xD(E)"                  , 0x20003000, 0x20018000, 
0x08000000, 0x08080000,  1, f2f4  , 0x1FFFC000, 0x1FFFC00F, 0x1FFF0000, 
0x1FFF7800, 0},
+       {0x458, "STM32F410xx"                     , 0x20003000, 0x20008000, 
0x08000000, 0x08020000,  1, f2f4  , 0x1FFFC000, 0x1FFFC00F, 0x1FFF0000, 
0x1FFF7800, 0},
+       {0x431, "STM32F411xx"                     , 0x20003000, 0x20020000, 
0x08000000, 0x08080000,  1, f2f4  , 0x1FFFC000, 0x1FFFC00F, 0x1FFF0000, 
0x1FFF7800, 0},
+       {0x421, "STM32F446xx"                     , 0x20003000, 0x20020000, 
0x08000000, 0x08080000,  1, f2f4  , 0x1FFFC000, 0x1FFFC00F, 0x1FFF0000, 
0x1FFF7800, 0},
+       {0x434, "STM32F469xx"                     , 0x20003000, 0x20060000, 
0x08000000, 0x08200000,  1, f4db  , 0x1FFEC000, 0x1FFFC00F, 0x1FFF0000, 
0x1FFF7800, 0},
+       /* F7 */
+       {0x449, "STM32F74xxx/75xxx"               , 0x20004000, 0x20050000, 
0x08000000, 0x08100000,  1, f7    , 0x1FFF0000, 0x1FFF001F, 0x1FF00000, 
0x1FF0EDC0, 0},
        /* L0 */
-       {0x417, "L05xxx/06xxx"      , 0x20001000, 0x20002000, 0x08000000, 
0x08010000, 32,  128, 0x1FF80000, 0x1FF8000F, 0x1FF00000, 0x1FF01000},
+       {0x425, "STM32L031xx/041xx"               , 0x20001000, 0x20002000, 
0x08000000, 0x08008000, 32, p_128 , 0x1FF80000, 0x1FF8001F, 0x1FF00000, 
0x1FF01000, 0},
+       {0x417, "STM32L05xxx/06xxx"               , 0x20001000, 0x20002000, 
0x08000000, 0x08010000, 32, p_128 , 0x1FF80000, 0x1FF8001F, 0x1FF00000, 
0x1FF01000, 0},
+       {0x447, "STM32L07xxx/08xxx"               , 0x20002000, 0x20005000, 
0x08000000, 0x08030000, 32, p_128 , 0x1FF80000, 0x1FF8001F, 0x1FF00000, 
0x1FF02000, 0},
        /* L1 */
-       {0x416, "L1xxx6(8/B)"       , 0x20000800, 0x20004000, 0x08000000, 
0x08020000, 16,  256, 0x1FF80000, 0x1FF8000F, 0x1FF00000, 0x1FF01000},
-       {0x429, "L1xxx6(8/B)A"      , 0x20001000, 0x20008000, 0x08000000, 
0x08020000, 16,  256, 0x1FF80000, 0x1FF8000F, 0x1FF00000, 0x1FF01000},
-       {0x427, "L1xxxC"            , 0x20001000, 0x20008000, 0x08000000, 
0x08020000, 16,  256, 0x1FF80000, 0x1FF8000F, 0x1FF00000, 0x1FF02000},
-       {0x436, "L1xxxD"            , 0x20001000, 0x2000C000, 0x08000000, 
0x08060000, 16,  256, 0x1ff80000, 0x1ff8000F, 0x1FF00000, 0x1FF02000},
-       {0x437, "L1xxxE"            , 0x20001000, 0x20014000, 0x08000000, 
0x08060000, 16,  256, 0x1ff80000, 0x1ff8000F, 0x1FF00000, 0x1FF02000},
+       {0x416, "STM32L1xxx6(8/B)"                , 0x20000800, 0x20004000, 
0x08000000, 0x08020000, 16, p_256 , 0x1FF80000, 0x1FF8001F, 0x1FF00000, 
0x1FF01000, F_NO_ME},
+       {0x429, "STM32L1xxx6(8/B)A"               , 0x20001000, 0x20008000, 
0x08000000, 0x08020000, 16, p_256 , 0x1FF80000, 0x1FF8001F, 0x1FF00000, 
0x1FF01000, 0},
+       {0x427, "STM32L1xxxC"                     , 0x20001000, 0x20008000, 
0x08000000, 0x08040000, 16, p_256 , 0x1FF80000, 0x1FF8001F, 0x1FF00000, 
0x1FF02000, 0},
+       {0x436, "STM32L1xxxD"                     , 0x20001000, 0x2000C000, 
0x08000000, 0x08060000, 16, p_256 , 0x1FF80000, 0x1FF8009F, 0x1FF00000, 
0x1FF02000, 0},
+       {0x437, "STM32L1xxxE"                     , 0x20001000, 0x20014000, 
0x08000000, 0x08080000, 16, p_256 , 0x1FF80000, 0x1FF8009F, 0x1FF00000, 
0x1FF02000, F_NO_ME},
+       /* L4 */
+       {0x415, "STM32L476xx/486xx"               , 0x20003100, 0x20018000, 
0x08000000, 0x08100000,  1, p_2k  , 0x1FFF7800, 0x1FFFF80F, 0x1FFF0000, 
0x1FFF7000, 0},
        /* These are not (yet) in AN2606: */
-       {0x641, "Medium_Density PL" , 0x20000200, 0x00005000, 0x08000000, 
0x08020000,  4, 1024, 0x1FFFF800, 0x1FFFF80F, 0x1FFFF000, 0x1FFFF800},
-       {0x9a8, "STM32W-128K"       , 0x20000200, 0x20002000, 0x08000000, 
0x08020000,  1, 1024, 0, 0, 0, 0},
-       {0x9b0, "STM32W-256K"       , 0x20000200, 0x20004000, 0x08000000, 
0x08040000,  1, 2048, 0, 0, 0, 0},
+       {0x641, "Medium_Density PL"               , 0x20000200, 0x20005000, 
0x08000000, 0x08020000,  4, p_1k  , 0x1FFFF800, 0x1FFFF80F, 0x1FFFF000, 
0x1FFFF800, 0},
+       {0x9a8, "STM32W-128K"                     , 0x20000200, 0x20002000, 
0x08000000, 0x08020000,  4, p_1k  , 0x08040800, 0x0804080F, 0x08040000, 
0x08040800, 0},
+       {0x9b0, "STM32W-256K"                     , 0x20000200, 0x20004000, 
0x08000000, 0x08040000,  4, p_2k  , 0x08040800, 0x0804080F, 0x08040000, 
0x08040800, 0},
        {0x0}
 };
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/stm32flash/i2c.c new/stm32flash/i2c.c
--- old/stm32flash/i2c.c        2014-09-19 00:16:02.000000000 +0200
+++ new/stm32flash/i2c.c        2015-11-28 14:37:58.000000000 +0100
@@ -32,7 +32,7 @@
 #include "port.h"
 
 
-#if defined(__WIN32__) || defined(__CYGWIN__) || defined(__APPLE__)
+#if !defined(__linux__)
 
 static port_err_t i2c_open(struct port_interface *port,
                           struct port_options *ops)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/stm32flash/init.c new/stm32flash/init.c
--- old/stm32flash/init.c       2014-09-19 00:16:02.000000000 +0200
+++ new/stm32flash/init.c       2016-02-08 23:58:03.000000000 +0100
@@ -20,6 +20,7 @@
 
 
 #include <ctype.h>
+#include <errno.h>
 #include <fcntl.h>
 #include <stdint.h>
 #include <stdio.h>
@@ -35,9 +36,10 @@
 struct gpio_list {
        struct gpio_list *next;
        int gpio;
+       int input; /* 1 if direction of gpio should be changed back to input. */
+       int exported; /* 0 if gpio should be unexported. */
 };
 
-
 static int write_to(const char *filename, const char *value)
 {
        int fd, ret;
@@ -64,15 +66,45 @@
        return 0;
 }
 #else
+static int read_from(const char *filename, char *buf, size_t len)
+{
+       int fd, ret;
+       ssize_t n = 0;
+
+       fd = open(filename, O_RDONLY);
+       if (fd < 0) {
+               fprintf(stderr, "Cannot open file \"%s\"\n", filename);
+               return 0;
+       }
+
+       do {
+               ret = read(fd, buf + n, len - n);
+               if (ret < 0) {
+                       if (errno == EINTR || errno == EAGAIN || errno == 
EWOULDBLOCK)
+                               continue; /* try again */
+                       fprintf(stderr, "Error reading in file \"%s\"\n", 
filename);
+                       close(fd);
+                       return 0;
+               }
+               n += ret;
+       } while (n < len && ret);
+
+       close(fd);
+       return n;
+}
+
 static int drive_gpio(int n, int level, struct gpio_list **gpio_to_release)
 {
        char num[16]; /* sized to carry MAX_INT */
        char file[48]; /* sized to carry longest filename */
+       char dir;
        struct stat buf;
        struct gpio_list *new;
        int ret;
+       int exported = 1;
+       int input = 0;
 
-       sprintf(file, "/sys/class/gpio/gpio%d/direction", n);
+       sprintf(file, "/sys/class/gpio/gpio%d/value", n);
        ret = stat(file, &buf);
        if (ret) {
                /* file miss, GPIO not exported yet */
@@ -85,12 +117,25 @@
                        fprintf(stderr, "GPIO %d not available\n", n);
                        return 0;
                }
+               exported = 0;
+       }
+
+       sprintf(file, "/sys/class/gpio/gpio%d/direction", n);
+       ret = stat(file, &buf);
+       if (!ret)
+               if (read_from(file, &dir, sizeof(dir)))
+                       if (dir == 'i')
+                               input = 1;
+
+       if (exported == 0 || input == 1) {
                new = (struct gpio_list *)malloc(sizeof(struct gpio_list));
                if (new == NULL) {
                        fprintf(stderr, "Out of memory\n");
                        return 0;
                }
                new->gpio = n;
+               new->exported = exported;
+               new->input = input;
                new->next = *gpio_to_release;
                *gpio_to_release = new;
        }
@@ -99,12 +144,20 @@
 }
 #endif
 
-static int release_gpio(int n)
+static int release_gpio(int n, int input, int exported)
 {
        char num[16]; /* sized to carry MAX_INT */
+       char file[48]; /* sized to carry longest filename */
 
        sprintf(num, "%d", n);
-       return write_to("/sys/class/gpio/unexport", num);
+       if (input) {
+               sprintf(file, "/sys/class/gpio/gpio%d/direction", n);
+               write_to(file, "in");
+       }
+       if (!exported)
+               write_to("/sys/class/gpio/unexport", num);
+
+       return 1;
 }
 
 static int gpio_sequence(struct port_interface *port, const char *s, size_t l)
@@ -163,7 +216,7 @@
        }
 
        while (gpio_to_release) {
-               release_gpio(gpio_to_release->gpio);
+               release_gpio(gpio_to_release->gpio, gpio_to_release->input, 
gpio_to_release->exported);
                to_free = gpio_to_release;
                gpio_to_release = gpio_to_release->next;
                free(to_free);
@@ -210,7 +263,7 @@
 
 int init_bl_exit(stm32_t *stm, struct port_interface *port, const char *seq)
 {
-       if (seq)
+       if (seq && strchr(seq, ':'))
                return gpio_bl_exit(port, seq);
 
        if (stm32_reset_device(stm) != STM32_ERR_OK)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/stm32flash/main.c new/stm32flash/main.c
--- old/stm32flash/main.c       2014-10-04 12:21:10.000000000 +0200
+++ new/stm32flash/main.c       2016-02-10 20:55:37.000000000 +0100
@@ -2,8 +2,8 @@
   stm32flash - Open Source ST STM32 flash program for *nix
   Copyright 2010 Geoffrey McRae <ge...@spacevs.com>
   Copyright 2011 Steve Markgraf <st...@steve-m.de>
-  Copyright 2012 Tormod Volden <debian.tor...@gmail.com>
-  Copyright 2013 Antonio Borneo <borneo.anto...@gmail.com>
+  Copyright 2012-2016 Tormod Volden <debian.tor...@gmail.com>
+  Copyright 2013-2016 Antonio Borneo <borneo.anto...@gmail.com>
 
   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License
@@ -38,7 +38,7 @@
 #include "parsers/binary.h"
 #include "parsers/hex.h"
 
-#define VERSION "0.4"
+#define VERSION "0.5"
 
 /* device globals */
 stm32_t                *stm            = NULL;
@@ -55,13 +55,19 @@
        .rx_frame_max           = STM32_MAX_RX_FRAME,
        .tx_frame_max           = STM32_MAX_TX_FRAME,
 };
-int            rd              = 0;
-int            wr              = 0;
-int            wu              = 0;
-int            rp              = 0;
-int            ur              = 0;
-int            eraseOnly       = 0;
-int            crc             = 0;
+
+enum actions {
+       ACT_NONE,
+       ACT_READ,
+       ACT_WRITE,
+       ACT_WRITE_UNPROTECT,
+       ACT_READ_PROTECT,
+       ACT_READ_UNPROTECT,
+       ACT_ERASE_ONLY,
+       ACT_CRC
+};
+
+enum actions   action          = ACT_NONE;
 int            npages          = 0;
 int             spage           = 0;
 int             no_erase        = 0;
@@ -81,6 +87,36 @@
 int  parse_options(int argc, char *argv[]);
 void show_help(char *name);
 
+static const char *action2str(enum actions act)
+{
+       switch (act) {
+               case ACT_READ:
+                       return "memory read";
+               case ACT_WRITE:
+                       return "memory write";
+               case ACT_WRITE_UNPROTECT:
+                       return "write unprotect";
+               case ACT_READ_PROTECT:
+                       return "read protect";
+               case ACT_READ_UNPROTECT:
+                       return "read unprotect";
+               case ACT_ERASE_ONLY:
+                       return "flash erase";
+               case ACT_CRC:
+                       return "memory crc";
+               default:
+                       return "";
+       };
+}
+
+static void err_multi_action(enum actions new)
+{
+       fprintf(stderr,
+               "ERROR: Invalid options !\n"
+               "\tCan't execute \"%s\" and \"%s\" at the same time.\n",
+               action2str(action), action2str(new));
+}
+
 static int is_addr_in_ram(uint32_t addr)
 {
        return addr >= stm->dev->ram_start && addr < stm->dev->ram_end;
@@ -91,26 +127,68 @@
        return addr >= stm->dev->fl_start && addr < stm->dev->fl_end;
 }
 
+/* returns the page that contains address "addr" */
 static int flash_addr_to_page_floor(uint32_t addr)
 {
+       int page;
+       uint32_t *psize;
+
        if (!is_addr_in_flash(addr))
                return 0;
 
-       return (addr - stm->dev->fl_start) / stm->dev->fl_ps;
+       page = 0;
+       addr -= stm->dev->fl_start;
+       psize = stm->dev->fl_ps;
+
+       while (addr >= psize[0]) {
+               addr -= psize[0];
+               page++;
+               if (psize[1])
+                       psize++;
+       }
+
+       return page;
 }
 
-static int flash_addr_to_page_ceil(uint32_t addr)
+/* returns the first page whose start addr is >= "addr" */
+int flash_addr_to_page_ceil(uint32_t addr)
 {
+       int page;
+       uint32_t *psize;
+
        if (!(addr >= stm->dev->fl_start && addr <= stm->dev->fl_end))
                return 0;
 
-       return (addr + stm->dev->fl_ps - 1 - stm->dev->fl_start)
-              / stm->dev->fl_ps;
+       page = 0;
+       addr -= stm->dev->fl_start;
+       psize = stm->dev->fl_ps;
+
+       while (addr >= psize[0]) {
+               addr -= psize[0];
+               page++;
+               if (psize[1])
+                       psize++;
+       }
+
+       return addr ? page + 1 : page;
 }
 
+/* returns the lower address of flash page "page" */
 static uint32_t flash_page_to_addr(int page)
 {
-       return stm->dev->fl_start + page * stm->dev->fl_ps;
+       int i;
+       uint32_t addr, *psize;
+
+       addr = stm->dev->fl_start;
+       psize = stm->dev->fl_ps;
+
+       for (i = 0; i < page; i++) {
+               addr += psize[0];
+               if (psize[1])
+                       psize++;
+       }
+
+       return addr;
 }
 
 int main(int argc, char* argv[]) {
@@ -121,15 +199,15 @@
        FILE *diag = stdout;
 
        fprintf(diag, "stm32flash " VERSION "\n\n");
-       fprintf(diag, "http://stm32flash.googlecode.com/\n\n";);
+       fprintf(diag, "http://stm32flash.sourceforge.net/\n\n";);
        if (parse_options(argc, argv) != 0)
                goto close;
 
-       if (rd && filename[0] == '-') {
+       if ((action == ACT_READ) && filename[0] == '-') {
                diag = stderr;
        }
 
-       if (wr) {
+       if (action == ACT_WRITE) {
                /* first try hex */
                if (!force_binary) {
                        parser = &PARSER_HEX;
@@ -194,7 +272,7 @@
        }
        fprintf(diag, "Device ID    : 0x%04x (%s)\n", stm->pid, stm->dev->name);
        fprintf(diag, "- RAM        : %dKiB  (%db reserved by bootloader)\n", 
(stm->dev->ram_end - 0x20000000) / 1024, stm->dev->ram_start - 0x20000000);
-       fprintf(diag, "- Flash      : %dKiB (sector size: %dx%d)\n", 
(stm->dev->fl_end - stm->dev->fl_start ) / 1024, stm->dev->fl_pps, 
stm->dev->fl_ps);
+       fprintf(diag, "- Flash      : %dKiB (size first sector: %dx%d)\n", 
(stm->dev->fl_end - stm->dev->fl_start ) / 1024, stm->dev->fl_pps, 
stm->dev->fl_ps[0]);
        fprintf(diag, "- Option RAM : %db\n", stm->dev->opt_end - 
stm->dev->opt_start + 1);
        fprintf(diag, "- System RAM : %dKiB\n", (stm->dev->mem_end - 
stm->dev->mem_start) / 1024);
 
@@ -230,14 +308,14 @@
 
                first_page = flash_addr_to_page_floor(start);
                if (!first_page && end == stm->dev->fl_end)
-                       num_pages = 0xff; /* mass erase */
+                       num_pages = STM32_MASS_ERASE;
                else
                        num_pages = flash_addr_to_page_ceil(end) - first_page;
        } else if (!spage && !npages) {
                start = stm->dev->fl_start;
                end = stm->dev->fl_end;
                first_page = 0;
-               num_pages = 0xff; /* mass erase */
+               num_pages = STM32_MASS_ERASE;
        } else {
                first_page = spage;
                start = flash_page_to_addr(first_page);
@@ -257,10 +335,10 @@
                }
 
                if (!first_page && end == stm->dev->fl_end)
-                       num_pages = 0xff; /* mass erase */
+                       num_pages = STM32_MASS_ERASE;
        }
 
-       if (rd) {
+       if (action == ACT_READ) {
                unsigned int max_len = port_opts.rx_frame_max;
 
                fprintf(diag, "Memory read\n");
@@ -300,23 +378,23 @@
                fprintf(diag,   "Done.\n");
                ret = 0;
                goto close;
-       } else if (rp) {
+       } else if (action == ACT_READ_PROTECT) {
                fprintf(stdout, "Read-Protecting flash\n");
                /* the device automatically performs a reset after the sending 
the ACK */
                reset_flag = 0;
                stm32_readprot_memory(stm);
                fprintf(stdout, "Done.\n");
-       } else if (ur) {
+       } else if (action == ACT_READ_UNPROTECT) {
                fprintf(stdout, "Read-UnProtecting flash\n");
                /* the device automatically performs a reset after the sending 
the ACK */
                reset_flag = 0;
                stm32_runprot_memory(stm);
                fprintf(stdout, "Done.\n");
-       } else if (eraseOnly) {
+       } else if (action == ACT_ERASE_ONLY) {
                ret = 0;
                fprintf(stdout, "Erasing flash\n");
 
-               if (num_pages != 0xff &&
+               if (num_pages != STM32_MASS_ERASE &&
                    (start != flash_page_to_addr(first_page)
                     || end != flash_page_to_addr(first_page + num_pages))) {
                        fprintf(stderr, "Specified start & length are invalid 
(must be page aligned)\n");
@@ -330,14 +408,14 @@
                        ret = 1;
                        goto close;
                }
-       } else if (wu) {
+       } else if (action == ACT_WRITE_UNPROTECT) {
                fprintf(diag, "Write-unprotecting flash\n");
                /* the device automatically performs a reset after the sending 
the ACK */
                reset_flag = 0;
                stm32_wunprot_memory(stm);
                fprintf(diag,   "Done.\n");
 
-       } else if (wr) {
+       } else if (action == ACT_WRITE) {
                fprintf(diag, "Write to memory\n");
 
                off_t   offset = 0;
@@ -359,7 +437,7 @@
 
                // TODO: It is possible to write to non-page boundaries, by 
reading out flash
                //       from partial pages and combining with the input data
-               // if ((start % stm->dev->fl_ps) != 0 || (end % 
stm->dev->fl_ps) != 0) {
+               // if ((start % stm->dev->fl_ps[i]) != 0 || (end % 
stm->dev->fl_ps[i]) != 0) {
                //      fprintf(stderr, "Specified start & length are invalid 
(must be page aligned)\n");
                //      goto close;
                // } 
@@ -450,7 +528,7 @@
                fprintf(diag,   "Done.\n");
                ret = 0;
                goto close;
-       } else if (crc) {
+       } else if (action == ACT_CRC) {
                uint32_t crc_val = 0;
 
                fprintf(diag, "CRC computation\n");
@@ -533,12 +611,11 @@
 
                        case 'r':
                        case 'w':
-                               rd = rd || c == 'r';
-                               wr = wr || c == 'w';
-                               if (rd && wr) {
-                                       fprintf(stderr, "ERROR: Invalid 
options, can't read & write at the same time\n");
+                               if (action != ACT_NONE) {
+                                       err_multi_action((c == 'r') ? ACT_READ 
: ACT_WRITE);
                                        return 1;
                                }
+                               action = (c == 'r') ? ACT_READ : ACT_WRITE;
                                filename = optarg;
                                if (filename[0] == '-') {
                                        force_binary = 1;
@@ -558,37 +635,37 @@
                                        no_erase = 1;
                                break;
                        case 'u':
-                               wu = 1;
-                               if (rd || wr) {
-                                       fprintf(stderr, "ERROR: Invalid 
options, can't write unprotect and read/write at the same time\n");
+                               if (action != ACT_NONE) {
+                                       err_multi_action(ACT_WRITE_UNPROTECT);
                                        return 1;
                                }
+                               action = ACT_WRITE_UNPROTECT;
                                break;
 
                        case 'j':
-                               rp = 1;
-                               if (rd || wr) {
-                                       fprintf(stderr, "ERROR: Invalid 
options, can't read protect and read/write at the same time\n");
+                               if (action != ACT_NONE) {
+                                       err_multi_action(ACT_READ_PROTECT);
                                        return 1;
                                }
+                               action = ACT_READ_PROTECT;
                                break;
 
                        case 'k':
-                               ur = 1;
-                               if (rd || wr) {
-                                       fprintf(stderr, "ERROR: Invalid 
options, can't read unprotect and read/write at the same time\n");
+                               if (action != ACT_NONE) {
+                                       err_multi_action(ACT_READ_UNPROTECT);
                                        return 1;
                                }
+                               action = ACT_READ_UNPROTECT;
                                break;
 
                        case 'o':
-                               eraseOnly = 1;
-                               if (rd || wr) {
-                                       fprintf(stderr, "ERROR: Invalid 
options, can't erase-only and read/write at the same time\n");
+                               if (action != ACT_NONE) {
+                                       err_multi_action(ACT_ERASE_ONLY);
                                        return 1;
                                }
-                               break;                          
-                       
+                               action = ACT_ERASE_ONLY;
+                               break;
+
                        case 'v':
                                verify = 1;
                                break;
@@ -644,9 +721,9 @@
                                if (port_opts.tx_frame_max == 0)
                                        port_opts.tx_frame_max = 
STM32_MAX_TX_FRAME;
                                if (port_opts.rx_frame_max < 20
-                                   || port_opts.tx_frame_max < 5) {
+                                   || port_opts.tx_frame_max < 6) {
                                        fprintf(stderr, "ERROR: current code 
cannot work with small frames.\n");
-                                       fprintf(stderr, "min(RX) = 20, min(TX) 
= 5\n");
+                                       fprintf(stderr, "min(RX) = 20, min(TX) 
= 6\n");
                                        return 1;
                                }
                                if (port_opts.rx_frame_max > 
STM32_MAX_RX_FRAME) {
@@ -679,7 +756,11 @@
                                break;
 
                        case 'C':
-                               crc = 1;
+                               if (action != ACT_NONE) {
+                                       err_multi_action(ACT_CRC);
+                                       return 1;
+                               }
+                               action = ACT_CRC;
                                break;
                }
        }
@@ -699,7 +780,7 @@
                return 1;
        }
 
-       if (!wr && verify) {
+       if ((action != ACT_WRITE) && verify) {
                fprintf(stderr, "ERROR: Invalid usage, -v is only valid when 
writing\n");
                show_help(argv[0]);
                return 1;
@@ -760,7 +841,7 @@
                "       GPIO sequence:\n"
                "       - entry sequence: GPIO_3=low, GPIO_2=low, GPIO_2=high\n"
                "       - exit sequence: GPIO_3=high, GPIO_2=low, GPIO_2=high\n"
-               "               %s -i -3,-2,2:3,-2,2 /dev/ttyS0\n",
+               "               %s -R -i -3,-2,2:3,-2,2 /dev/ttyS0\n",
                name,
                name,
                name,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/stm32flash/parsers/hex.c new/stm32flash/parsers/hex.c
--- old/stm32flash/parsers/hex.c        2014-10-03 23:35:08.000000000 +0200
+++ new/stm32flash/parsers/hex.c        2016-02-08 18:12:43.000000000 +0100
@@ -32,7 +32,7 @@
 typedef struct {
        size_t          data_len, offset;
        uint8_t         *data;
-       uint8_t         base;
+       uint32_t        base;
 } hex_t;
 
 void* hex_init() {
@@ -105,7 +105,7 @@
 
                                /* extended linear address record */
                                case 4:
-                                       base = address;
+                                       base = 0;
                                        break;
                        }
 
@@ -152,12 +152,17 @@
                                        return PARSER_ERR_OK;
 
                                /* address record */
+                               case 4: base = base << 12;
                                case 2: base = base << 4;
-                               case 4: base = be_u32(base);
                                        /* Reset last_address since our base 
changed */
                                        last_address = 0;
 
-                                       if (st->base == 0) {
+                                       /* Only assign the program's base 
address once, and only
+                                        * do so if we haven't seen any data 
records yet.
+                                        * If there are any data records before 
address records,
+                                        * the program's base address must be 
zero.
+                                        */
+                                       if (st->base == 0 && st->data_len == 0) 
{
                                                st->base = base;
                                                break;
                                        }
@@ -168,11 +173,11 @@
                                                return PARSER_ERR_INVALID_FILE;
                                        }
 
-                                       /* if there is a gap, enlarge and fill 
with zeros */
+                                       /* if there is a gap, enlarge and fill 
with 0xff */
                                        unsigned int len = base - st->base;
                                        if (len > st->data_len) {
                                                st->data = realloc(st->data, 
len);
-                                               memset(&st->data[st->data_len], 
0, len - st->data_len);
+                                               memset(&st->data[st->data_len], 
0xff, len - st->data_len);
                                                st->data_len = len;
                                        }
                                        break;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/stm32flash/serial_posix.c 
new/stm32flash/serial_posix.c
--- old/stm32flash/serial_posix.c       2014-09-19 00:16:02.000000000 +0200
+++ new/stm32flash/serial_posix.c       2016-01-26 23:45:05.000000000 +0100
@@ -18,6 +18,7 @@
 */
 
 #include <fcntl.h>
+#include <limits.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -25,6 +26,7 @@
 #include <termios.h>
 #include <unistd.h>
 #include <sys/ioctl.h>
+#include <stdio.h>
 
 #include "serial.h"
 #include "port.h"
@@ -202,11 +204,7 @@
 {
        serial_t *h;
 
-       /* 1. check device name match */
-       if (strncmp(ops->device, "/dev/tty", strlen("/dev/tty")))
-               return PORT_ERR_NODEV;
-
-       /* 2. check options */
+       /* 1. check options */
        if (ops->baudRate == SERIAL_BAUD_INVALID)
                return PORT_ERR_UNKNOWN;
        if (serial_get_bits(ops->serial_mode) == SERIAL_BITS_INVALID)
@@ -216,11 +214,15 @@
        if (serial_get_stopbit(ops->serial_mode) == SERIAL_STOPBIT_INVALID)
                return PORT_ERR_UNKNOWN;
 
-       /* 3. open it */
+       /* 2. open it */
        h = serial_open(ops->device);
        if (h == NULL)
                return PORT_ERR_UNKNOWN;
 
+       /* 3. check for tty (but only warn) */
+       if (!isatty(h->fd))
+               fprintf(stderr, "Warning: Not a tty: %s\n", ops->device);
+
        /* 4. set options */
        if (serial_setup(h, ops->baudRate,
                         serial_get_bits(ops->serial_mode),
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/stm32flash/serial_w32.c new/stm32flash/serial_w32.c
--- old/stm32flash/serial_w32.c 2014-10-03 23:36:32.000000000 +0200
+++ new/stm32flash/serial_w32.c 2016-02-08 18:38:49.000000000 +0100
@@ -67,6 +67,7 @@
        if (h->fd == INVALID_HANDLE_VALUE) {
                if (GetLastError() == ERROR_FILE_NOT_FOUND)
                        fprintf(stderr, "File not found: %s\n", device);
+               free(h);
                return NULL;
        }
 
@@ -76,6 +77,9 @@
 
        SetCommMask(h->fd, EV_ERR); /* Notify us of error events */
 
+       /* DCBlength should be initialized before calling GetCommState */
+       h->oldtio.DCBlength = sizeof(DCB);
+       h->newtio.DCBlength = sizeof(DCB);
        GetCommState(h->fd, &h->oldtio); /* Retrieve port parameters */
        GetCommState(h->fd, &h->newtio); /* Retrieve port parameters */
 
@@ -161,10 +165,15 @@
        /* reset the settings */
        h->newtio.fOutxCtsFlow = FALSE;
        h->newtio.fOutxDsrFlow = FALSE;
+       h->newtio.fDtrControl = DTR_CONTROL_DISABLE;
+       h->newtio.fDsrSensitivity = FALSE;
+       h->newtio.fTXContinueOnXoff = FALSE;
        h->newtio.fOutX = FALSE;
        h->newtio.fInX = FALSE;
-       h->newtio.fNull = 0;
-       h->newtio.fAbortOnError = 0;
+       h->newtio.fErrorChar = FALSE;
+       h->newtio.fNull = FALSE;
+       h->newtio.fRtsControl = RTS_CONTROL_DISABLE;
+       h->newtio.fAbortOnError = FALSE;
 
        /* set the settings */
        serial_flush(h);
@@ -186,8 +195,7 @@
        serial_t *h;
 
        /* 1. check device name match */
-       if (!(strlen(ops->device) == 4
-             && !strncmp(ops->device, "COM", 3) && isdigit(ops->device[3]))
+       if (!(!strncmp(ops->device, "COM", 3) && isdigit(ops->device[3]))
            && !(!strncmp(ops->device, "\\\\.\\COM", strlen("\\\\.\\COM"))
                 && isdigit(ops->device[strlen("\\\\.\\COM")])))
                return PORT_ERR_NODEV;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/stm32flash/stm32.c new/stm32flash/stm32.c
--- old/stm32flash/stm32.c      2014-10-02 09:20:26.000000000 +0200
+++ new/stm32flash/stm32.c      2016-02-10 10:43:06.000000000 +0100
@@ -57,7 +57,7 @@
 
 #define STM32_RESYNC_TIMEOUT   35      /* seconds */
 #define STM32_MASSERASE_TIMEOUT        35      /* seconds */
-#define STM32_SECTERASE_TIMEOUT        5       /* seconds */
+#define STM32_PAGEERASE_TIMEOUT        5       /* seconds */
 #define STM32_BLKWRITE_TIMEOUT 1       /* seconds */
 #define STM32_WUNPROT_TIMEOUT  1       /* seconds */
 #define STM32_WPROT_TIMEOUT    1       /* seconds */
@@ -95,8 +95,32 @@
 
 static const uint32_t stm_reset_code_length = sizeof(stm_reset_code);
 
+/* RM0360, Empty check
+ * On STM32F070x6 and STM32F030xC devices only, internal empty check flag is
+ * implemented to allow easy programming of the virgin devices by the boot 
loader. This flag is
+ * used when BOOT0 pin is defining Main Flash memory as the target boot space. 
When the
+ * flag is set, the device is considered as empty and System memory (boot 
loader) is selected
+ * instead of the Main Flash as a boot space to allow user to program the 
Flash memory.
+ * This flag is updated only during Option bytes loading: it is set when the 
content of the
+ * address 0x08000 0000 is read as 0xFFFF FFFF, otherwise it is cleared. It 
means a power
+ * on or setting of OBL_LAUNCH bit in FLASH_CR register is needed to clear 
this flag after
+ * programming of a virgin device to execute user code after System reset.
+ */
+static const uint8_t stm_obl_launch_code[] = {
+       0x01, 0x49,             // ldr     r1, [pc, #4] ; (<FLASH_CR>)
+       0x02, 0x4A,             // ldr     r2, [pc, #8] ; (<OBL_LAUNCH>)
+       0x0A, 0x60,             // str     r2, [r1, #0]
+       0xfe, 0xe7,             // endless: b endless
+       0x10, 0x20, 0x02, 0x40, // address: FLASH_CR = 40022010
+       0x00, 0x20, 0x00, 0x00  // value: OBL_LAUNCH = 00002000
+};
+
+static const uint32_t stm_obl_launch_code_length = sizeof(stm_obl_launch_code);
+
 extern const stm32_dev_t devices[];
 
+int flash_addr_to_page_ceil(uint32_t addr);
+
 static void stm32_warn_stretching(const char *f)
 {
        fprintf(stderr, "Attention !!!\n");
@@ -540,8 +564,8 @@
        }
 
        /* must be 32bit aligned */
-       if (address & 0x3 || len & 0x3) {
-               fprintf(stderr, "Error: WRITE address and length must be 4 byte 
aligned\n");
+       if (address & 0x3) {
+               fprintf(stderr, "Error: WRITE address must be 4 byte 
aligned\n");
                return STM32_ERR_UNKNOWN;
        }
 
@@ -604,7 +628,7 @@
                return STM32_ERR_UNKNOWN;
 
        s_err = stm32_get_ack_timeout(stm, STM32_WUNPROT_TIMEOUT);
-       if (s_err == STM32_NACK) {
+       if (s_err == STM32_ERR_NACK) {
                fprintf(stderr, "Error: Failed to WRITE UNPROTECT\n");
                return STM32_ERR_UNKNOWN;
        }
@@ -631,7 +655,7 @@
                return STM32_ERR_UNKNOWN;
 
        s_err = stm32_get_ack_timeout(stm, STM32_WPROT_TIMEOUT);
-       if (s_err == STM32_NACK) {
+       if (s_err == STM32_ERR_NACK) {
                fprintf(stderr, "Error: Failed to WRITE PROTECT\n");
                return STM32_ERR_UNKNOWN;
        }
@@ -658,7 +682,7 @@
                return STM32_ERR_UNKNOWN;
 
        s_err = stm32_get_ack_timeout(stm, STM32_MASSERASE_TIMEOUT);
-       if (s_err == STM32_NACK) {
+       if (s_err == STM32_ERR_NACK) {
                fprintf(stderr, "Error: Failed to READOUT UNPROTECT\n");
                return STM32_ERR_UNKNOWN;
        }
@@ -685,7 +709,7 @@
                return STM32_ERR_UNKNOWN;
 
        s_err = stm32_get_ack_timeout(stm, STM32_RPROT_TIMEOUT);
-       if (s_err == STM32_NACK) {
+       if (s_err == STM32_ERR_NACK) {
                fprintf(stderr, "Error: Failed to READOUT PROTECT\n");
                return STM32_ERR_UNKNOWN;
        }
@@ -698,119 +722,68 @@
        return STM32_ERR_OK;
 }
 
-stm32_err_t stm32_erase_memory(const stm32_t *stm, uint8_t spage, uint8_t 
pages)
+static stm32_err_t stm32_mass_erase(const stm32_t *stm)
 {
        struct port_interface *port = stm->port;
        stm32_err_t s_err;
-       port_err_t p_err;
-
-       if (!pages)
-               return STM32_ERR_OK;
-
-       if (stm->cmd->er == STM32_CMD_ERR) {
-               fprintf(stderr, "Error: ERASE command not implemented in 
bootloader.\n");
-               return STM32_ERR_NO_CMD;
-       }
+       uint8_t buf[3];
 
        if (stm32_send_command(stm, stm->cmd->er) != STM32_ERR_OK) {
-               fprintf(stderr, "Can't initiate chip erase!\n");
+               fprintf(stderr, "Can't initiate chip mass erase!\n");
                return STM32_ERR_UNKNOWN;
        }
 
-       /* The erase command reported by the bootloader is either 0x43, 0x44 or 
0x45 */
-       /* 0x44 is Extended Erase, a 2 byte based protocol and needs to be 
handled differently. */
-       /* 0x45 is clock no-stretching version of Extended Erase for I2C port. 
*/
-       if (stm->cmd->er != STM32_CMD_ER) {
-               /* Not all chips using Extended Erase support mass erase */
-               /* Currently known as not supporting mass erase is the Ultra 
Low Power STM32L15xx range */
-               /* So if someone has not overridden the default, but uses one 
of these chips, take it out of */
-               /* mass erase mode, so it will be done page by page. This 
maximum might not be correct either! */
-               if (stm->pid == 0x416 && pages == 0xFF)
-                       pages = 0xF8; /* works for the STM32L152RB with 128Kb 
flash */
-
-               if (pages == 0xFF) {
-                       uint8_t buf[3];
-
-                       /* 0xFFFF the magic number for mass erase */
-                       buf[0] = 0xFF;
-                       buf[1] = 0xFF;
-                       buf[2] = 0x00;  /* checksum */
-                       if (port->write(port, buf, 3) != PORT_ERR_OK) {
-                               fprintf(stderr, "Mass erase error.\n");
-                               return STM32_ERR_UNKNOWN;
-                       }
-                       s_err = stm32_get_ack_timeout(stm, 
STM32_MASSERASE_TIMEOUT);
-                       if (s_err != STM32_ERR_OK) {
-                               fprintf(stderr, "Mass erase failed. Try 
specifying the number of pages to be erased.\n");
-                               if (port->flags & PORT_STRETCH_W
-                                   && stm->cmd->er != STM32_CMD_EE_NS)
-                                       stm32_warn_stretching("erase");
-                               return STM32_ERR_UNKNOWN;
-                       }
-                       return STM32_ERR_OK;
-               }
-
-               uint16_t pg_num;
-               uint8_t pg_byte;
-               uint8_t cs = 0;
-               uint8_t *buf;
-               int i = 0;
-
-               buf = malloc(2 + 2 * pages + 1);
-               if (!buf)
-                       return STM32_ERR_UNKNOWN;
-
-               /* Number of pages to be erased - 1, two bytes, MSB first */
-               pg_byte = (pages - 1) >> 8;
-               buf[i++] = pg_byte;
-               cs ^= pg_byte;
-               pg_byte = (pages - 1) & 0xFF;
-               buf[i++] = pg_byte;
-               cs ^= pg_byte;
-
-               for (pg_num = spage; pg_num < spage + pages; pg_num++) {
-                       pg_byte = pg_num >> 8;
-                       cs ^= pg_byte;
-                       buf[i++] = pg_byte;
-                       pg_byte = pg_num & 0xFF;
-                       cs ^= pg_byte;
-                       buf[i++] = pg_byte;
-               }
-               buf[i++] = cs;
-               p_err = port->write(port, buf, i);
-               free(buf);
-               if (p_err != PORT_ERR_OK) {
-                       fprintf(stderr, "Page-by-page erase error.\n");
-                       return STM32_ERR_UNKNOWN;
-               }
-
-               s_err = stm32_get_ack_timeout(stm, STM32_SECTERASE_TIMEOUT);
-               if (s_err != STM32_ERR_OK) {
-                       fprintf(stderr, "Page-by-page erase failed. Check the 
maximum pages your device supports.\n");
-                       if (port->flags & PORT_STRETCH_W
-                           && stm->cmd->er != STM32_CMD_EE_NS)
-                               stm32_warn_stretching("erase");
-                       return STM32_ERR_UNKNOWN;
-               }
-
-               return STM32_ERR_OK;
-       }
-
-       /* And now the regular erase (0x43) for all other chips */
-       if (pages == 0xFF) {
+       /* regular erase (0x43) */
+       if (stm->cmd->er == STM32_CMD_ER) {
                s_err = stm32_send_command_timeout(stm, 0xFF, 
STM32_MASSERASE_TIMEOUT);
                if (s_err != STM32_ERR_OK) {
                        if (port->flags & PORT_STRETCH_W)
-                               stm32_warn_stretching("erase");
+                               stm32_warn_stretching("mass erase");
                        return STM32_ERR_UNKNOWN;
                }
                return STM32_ERR_OK;
-       } else {
-               uint8_t cs = 0;
-               uint8_t pg_num;
-               uint8_t *buf;
-               int i = 0;
+       }
+
+       /* extended erase */
+       buf[0] = 0xFF;  /* 0xFFFF the magic number for mass erase */
+       buf[1] = 0xFF;
+       buf[2] = 0x00;  /* checksum */
+       if (port->write(port, buf, 3) != PORT_ERR_OK) {
+               fprintf(stderr, "Mass erase error.\n");
+               return STM32_ERR_UNKNOWN;
+       }
+       s_err = stm32_get_ack_timeout(stm, STM32_MASSERASE_TIMEOUT);
+       if (s_err != STM32_ERR_OK) {
+               fprintf(stderr, "Mass erase failed. Try specifying the number 
of pages to be erased.\n");
+       if (port->flags & PORT_STRETCH_W
+           && stm->cmd->er != STM32_CMD_EE_NS)
+               stm32_warn_stretching("mass erase");
+               return STM32_ERR_UNKNOWN;
+       }
+       return STM32_ERR_OK;
+}
+
+static stm32_err_t stm32_pages_erase(const stm32_t *stm, uint32_t spage, 
uint32_t pages)
+{
+       struct port_interface *port = stm->port;
+       stm32_err_t s_err;
+       port_err_t p_err;
+       uint32_t pg_num;
+       uint8_t pg_byte;
+       uint8_t cs = 0;
+       uint8_t *buf;
+       int i = 0;
+
+       /* The erase command reported by the bootloader is either 0x43, 0x44 or 
0x45 */
+       /* 0x44 is Extended Erase, a 2 byte based protocol and needs to be 
handled differently. */
+       /* 0x45 is clock no-stretching version of Extended Erase for I2C port. 
*/
+       if (stm32_send_command(stm, stm->cmd->er) != STM32_ERR_OK) {
+               fprintf(stderr, "Can't initiate chip mass erase!\n");
+               return STM32_ERR_UNKNOWN;
+       }
 
+       /* regular erase (0x43) */
+       if (stm->cmd->er == STM32_CMD_ER) {
                buf = malloc(1 + pages + 1);
                if (!buf)
                        return STM32_ERR_UNKNOWN;
@@ -828,7 +801,7 @@
                        fprintf(stderr, "Erase failed.\n");
                        return STM32_ERR_UNKNOWN;
                }
-               s_err = stm32_get_ack_timeout(stm, STM32_MASSERASE_TIMEOUT);
+               s_err = stm32_get_ack_timeout(stm, pages * 
STM32_PAGEERASE_TIMEOUT);
                if (s_err != STM32_ERR_OK) {
                        if (port->flags & PORT_STRETCH_W)
                                stm32_warn_stretching("erase");
@@ -836,6 +809,92 @@
                }
                return STM32_ERR_OK;
        }
+
+       /* extended erase */
+       buf = malloc(2 + 2 * pages + 1);
+       if (!buf)
+               return STM32_ERR_UNKNOWN;
+
+       /* Number of pages to be erased - 1, two bytes, MSB first */
+       pg_byte = (pages - 1) >> 8;
+       buf[i++] = pg_byte;
+       cs ^= pg_byte;
+       pg_byte = (pages - 1) & 0xFF;
+       buf[i++] = pg_byte;
+       cs ^= pg_byte;
+
+       for (pg_num = spage; pg_num < spage + pages; pg_num++) {
+               pg_byte = pg_num >> 8;
+               cs ^= pg_byte;
+               buf[i++] = pg_byte;
+               pg_byte = pg_num & 0xFF;
+               cs ^= pg_byte;
+               buf[i++] = pg_byte;
+       }
+       buf[i++] = cs;
+       p_err = port->write(port, buf, i);
+       free(buf);
+       if (p_err != PORT_ERR_OK) {
+               fprintf(stderr, "Page-by-page erase error.\n");
+               return STM32_ERR_UNKNOWN;
+       }
+
+       s_err = stm32_get_ack_timeout(stm, pages * STM32_PAGEERASE_TIMEOUT);
+       if (s_err != STM32_ERR_OK) {
+               fprintf(stderr, "Page-by-page erase failed. Check the maximum 
pages your device supports.\n");
+               if (port->flags & PORT_STRETCH_W
+                   && stm->cmd->er != STM32_CMD_EE_NS)
+                       stm32_warn_stretching("erase");
+               return STM32_ERR_UNKNOWN;
+       }
+
+       return STM32_ERR_OK;
+}
+
+stm32_err_t stm32_erase_memory(const stm32_t *stm, uint32_t spage, uint32_t 
pages)
+{
+       uint32_t n;
+       stm32_err_t s_err;
+
+       if (!pages || spage > STM32_MAX_PAGES ||
+           ((pages != STM32_MASS_ERASE) && ((spage + pages) > 
STM32_MAX_PAGES)))
+               return STM32_ERR_OK;
+
+       if (stm->cmd->er == STM32_CMD_ERR) {
+               fprintf(stderr, "Error: ERASE command not implemented in 
bootloader.\n");
+               return STM32_ERR_NO_CMD;
+       }
+
+       if (pages == STM32_MASS_ERASE) {
+               /*
+                * Not all chips support mass erase.
+                * Mass erase can be obtained executing a "readout protect"
+                * followed by "readout un-protect". This method is not
+                * suggested because can hang the target if a debug SWD/JTAG
+                * is connected. When the target enters in "readout
+                * protection" mode it will consider the debug connection as
+                * a tentative of intrusion and will hang.
+                * Erasing the flash page-by-page is the safer way to go.
+                */
+               if (!(stm->dev->flags & F_NO_ME))
+                       return stm32_mass_erase(stm);
+
+               pages = flash_addr_to_page_ceil(stm->dev->fl_end);
+       }
+
+       /*
+        * Some device, like STM32L152, cannot erase more than 512 pages in
+        * one command. Split the call.
+        */
+       while (pages) {
+               n = (pages <= 512) ? pages : 512;
+               s_err = stm32_pages_erase(stm, spage, n);
+               if (s_err != STM32_ERR_OK)
+                       return s_err;
+               spage += n;
+               pages -= n;
+       }
+       return STM32_ERR_OK;
 }
 
 static stm32_err_t stm32_run_raw_code(const stm32_t *stm,
@@ -843,7 +902,7 @@
                                      const uint8_t *code, uint32_t code_size)
 {
        uint32_t stack_le = le_u32(0x20002000);
-       uint32_t code_address_le = le_u32(target_address + 8);
+       uint32_t code_address_le = le_u32(target_address + 8 + 1); // thumb 
mode address (!)
        uint32_t length = code_size + 8;
        uint8_t *mem, *pos;
        uint32_t address, w;
@@ -910,7 +969,12 @@
 {
        uint32_t target_address = stm->dev->ram_start;
 
-       return stm32_run_raw_code(stm, target_address, stm_reset_code, 
stm_reset_code_length);
+       if (stm->dev->flags & F_OBLL) {
+               /* set the OBL_LAUNCH bit to reset device (see RM0360, 2.5) */
+               return stm32_run_raw_code(stm, target_address, 
stm_obl_launch_code, stm_obl_launch_code_length);
+       } else {
+               return stm32_run_raw_code(stm, target_address, stm_reset_code, 
stm_reset_code_length);
+       }
 }
 
 stm32_err_t stm32_crc_memory(const stm32_t *stm, uint32_t address,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/stm32flash/stm32.h new/stm32flash/stm32.h
--- old/stm32flash/stm32.h      2014-10-02 09:20:26.000000000 +0200
+++ new/stm32flash/stm32.h      2016-02-08 18:28:56.000000000 +0100
@@ -27,6 +27,9 @@
 #define STM32_MAX_RX_FRAME     256     /* cmd read memory */
 #define STM32_MAX_TX_FRAME     (1 + 256 + 1)   /* cmd write memory */
 
+#define STM32_MAX_PAGES                0x0000ffff
+#define STM32_MASS_ERASE       0x00100000 /* > 2 x max_pages */
+
 typedef enum {
        STM32_ERR_OK = 0,
        STM32_ERR_UNKNOWN,      /* Generic error */
@@ -34,6 +37,11 @@
        STM32_ERR_NO_CMD,       /* Command not available in bootloader */
 } stm32_err_t;
 
+typedef enum {
+       F_NO_ME = 1 << 0,       /* Mass-Erase not supported */
+       F_OBLL  = 1 << 1,       /* OBL_LAUNCH required */
+} flags_t;
+
 typedef struct stm32           stm32_t;
 typedef struct stm32_cmd       stm32_cmd_t;
 typedef struct stm32_dev       stm32_dev_t;
@@ -55,9 +63,10 @@
        uint32_t        ram_start, ram_end;
        uint32_t        fl_start, fl_end;
        uint16_t        fl_pps; // pages per sector
-       uint16_t        fl_ps;  // page size
+       uint32_t        *fl_ps;  // page size
        uint32_t        opt_start, opt_end;
        uint32_t        mem_start, mem_end;
+       uint32_t        flags;
 };
 
 stm32_t *stm32_init(struct port_interface *port, const char init);
@@ -68,8 +77,8 @@
                               const uint8_t data[], unsigned int len);
 stm32_err_t stm32_wunprot_memory(const stm32_t *stm);
 stm32_err_t stm32_wprot_memory(const stm32_t *stm);
-stm32_err_t stm32_erase_memory(const stm32_t *stm, uint8_t spage,
-                              uint8_t pages);
+stm32_err_t stm32_erase_memory(const stm32_t *stm, uint32_t spage,
+                              uint32_t pages);
 stm32_err_t stm32_go(const stm32_t *stm, uint32_t address);
 stm32_err_t stm32_reset_device(const stm32_t *stm);
 stm32_err_t stm32_readprot_memory(const stm32_t *stm);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/stm32flash/stm32flash.1 new/stm32flash/stm32flash.1
--- old/stm32flash/stm32flash.1 2014-10-03 23:35:08.000000000 +0200
+++ new/stm32flash/stm32flash.1 2016-02-10 17:57:32.000000000 +0100
@@ -1,6 +1,6 @@
-.TH STM32FLASH 1 "2013\-11\-03" STM32FLASH "User command"
+.TH STM32FLASH 1 "2015\-11\-25" STM32FLASH "User command"
 .SH NAME
-stm32flash \- flashing utility for STM32 and STM32W through UART or I2C
+stm32flash \- flashing utility for STM32 through UART or I2C
 .SH SYNOPSIS
 .B stm32flash
 .RB [ \-cfhjkouvCR ]
@@ -29,19 +29,21 @@
 .RB [ \-i
 .IR GPIO_string ]
 .RI [ tty_device
-.R |
+|
 .IR i2c_device ]
 
 .SH DESCRIPTION
 .B stm32flash
-reads or writes the flash memory of STM32 and STM32W.
+reads or writes the flash memory of STM32.
 
-It requires the STM32[W] to embed a bootloader compliant with ST
-application note AN3155.
+It requires the STM32 to embed a bootloader compliant with ST
+application note AN3155 or AN4221.
 .B stm32flash
 uses the serial port
 .I tty_device
-to interact with the bootloader of STM32[W].
+or the i2c port
+.I i2c_device
+to interact with the bootloader of STM32.
 
 .SH OPTIONS
 .TP
@@ -55,7 +57,7 @@
 Specify baud rate speed of
 .IR tty_device .
 Please notice that the ST bootloader can automatically detect the baud rate,
-as explaned in chapter 2 of AN3155.
+as explained in chapter 2 of AN3155.
 This option could be required together with option
 .B "\-c"
 or if following interaction with bootloader is expected.
@@ -68,7 +70,7 @@
 .I mode
 is a three characters long string where each character specifies, in
 this strict order, character size, parity and stop bits.
-The only values currenly used are
+The only values currently used are
 .I 8e1
 for standard STM32 bootloader and
 .I 8n1
@@ -78,27 +80,27 @@
 
 .TP
 .BI "\-r" " filename"
-Specify to read the STM32[W] flash and write its content in
+Specify to read the STM32 flash and write its content in
 .I filename
 in raw binary format (see below
 .BR "FORMAT CONVERSION" ).
 
 .TP
 .BI "\-w" " filename"
-Specify to write the STM32[W] flash with the content of
+Specify to write the STM32 flash with the content of
 .IR filename .
 File format can be either raw binary or intel hex (see below
 .BR "FORMAT CONVERSION" ).
 The file format is automatically detected.
 To by\-pass format detection and force binary mode (e.g. to
-write an intel hex content in STM32[W] flash), use
+write an intel hex content in STM32 flash), use
 .B \-f
 option.
 
 .TP
 .B \-u
-Specify to disable write\-protection from STM32[W] flash.
-The STM32[W] will be reset after this operation.
+Specify to disable write\-protection from STM32 flash.
+The STM32 will be reset after this operation.
 
 .TP
 .B \-j
@@ -167,9 +169,9 @@
 
 .TP
 .BI "\-i" " GPIO_string"
-Specify the GPIO sequences on the host to force STM32[W] to enter and
+Specify the GPIO sequences on the host to force STM32 to enter and
 exit bootloader mode. GPIO can either be real GPIO connected from host to
-STM32[W] beside the UART connection, or UART's modem signals used as
+STM32 beside the UART connection, or UART's modem signals used as
 GPIO. (See below
 .B BOOTLOADER GPIO SEQUENCE
 for the format of
@@ -226,6 +228,7 @@
 .P
 sequence = [\-]n[,sequence]
 .RE
+.PD
 .P
 In the above sequences, negative numbers correspond to GPIO at "low" level;
 numbers without sign correspond to GPIO at "high" level.
@@ -237,6 +240,9 @@
 Note: the string "\-brk" has no effect and is ignored.
 .PD
 
+.P
+Note that the exit sequence is only executed if -R is specified. If -R is 
specified, but no exit sequence, a software-triggered reset will be performed.
+
 .PD 0
 As example, let's suppose the following connection between host and STM32:
 .IP \(bu 2
@@ -255,13 +261,13 @@
 .I GPIO_string
 is "4,\-5,\-3,3".
 
-To exit from bootloade and run the application program, the sequence is:
+To exit from bootloader and run the application program, the sequence is:
 put GPIO_4="low"; then send reset pulse.
 The corresponding string for
 .I GPIO_string
 is "\-4,\-3,3".
 
-The complete command line flag is "\-i 4,\-5,\-3,3:\-4,\-3,3".
+The complete command line flag is "\-R \-i 4,\-5,\-3,3:\-4,\-3,3".
 
 STM32W uses pad PA5 to select boot mode; if during reset PA5 is "low" then
 STM32W will enter in bootloader mode; if PA5 is "high" it will execute the
@@ -271,7 +277,7 @@
 The command:
 .PD 0
 .RS
-stm32flash \-i \-3,\-2,2:3,\-2,2 /dev/ttyS0
+stm32flash \-R \-i \-3,\-2,2:3,\-2,2 /dev/ttyS0
 .RE
 provides:
 .IP \(bu 2
@@ -321,7 +327,7 @@
 exit sequence: RTS=high, DTR=low, DTR=high
 .P
 .RS
-stm32flash \-i \-rts,\-dtr,dtr:rts,\-dtr,dtr /dev/ttyS0
+stm32flash \-R \-i \-rts,\-dtr,dtr:rts,\-dtr,dtr /dev/ttyS0
 .PD
 .RE
 
@@ -343,7 +349,7 @@
 .IR "Antonio Borneo <borneo.anto...@gmail.com>" .
 
 Please report any bugs at the project homepage
-http://stm32flash.googlecode.com .
+http://stm32flash.sourceforge.net .
 
 .SH SEE ALSO
 .BR "srec_cat" "(1)," " srec_intel" "(5)," " srec_motorola" "(5)."


Reply via email to