summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Shadura <andrewsh@debian.org>2016-02-15 13:00:35 +0300
committerAndrew Shadura <andrewsh@debian.org>2016-02-15 13:00:35 +0300
commit0e095dab4957364e87f564aed6eb189c24c372df (patch)
tree931139b0a633597a45e10f13990068aed66c95d4
parentfbbebf2cfecf4c184a5076c07ba87e4224f008fc (diff)
Imported Upstream version 0.5
-rw-r--r--AUTHORS8
-rw-r--r--INSTALL16
-rw-r--r--Makefile6
-rw-r--r--TODO3
-rwxr-xr-x[-rw-r--r--]dev_table.c106
-rw-r--r--i2c.c2
-rw-r--r--init.c65
-rw-r--r--main.c189
-rw-r--r--parsers/hex.c17
-rw-r--r--serial_posix.c14
-rw-r--r--serial_w32.c16
-rw-r--r--stm32.c280
-rw-r--r--stm32.h15
-rw-r--r--stm32flash.148
14 files changed, 538 insertions, 247 deletions
diff --git a/AUTHORS b/AUTHORS
index d096f22..7894bb9 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -17,3 +17,11 @@ Armin van der Togt
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 --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..16dcc41
--- /dev/null
+++ b/INSTALL
@@ -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 --git a/Makefile b/Makefile
index 0328d55..e3a019e 100644
--- a/Makefile
+++ b/Makefile
@@ -19,7 +19,7 @@ all: stm32flash
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: all
$(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 --git a/TODO b/TODO
index 41df614..09a1776 100644
--- a/TODO
+++ b/TODO
@@ -1,7 +1,4 @@
-stm32:
-- Add support for variable page size
-
AUTHORS:
- Add contributors from Geoffrey's commits
diff --git a/dev_table.c b/dev_table.c
index 399cd9d..f4ada72 100644..100755
--- a/dev_table.c
+++ b/dev_table.c
@@ -1,7 +1,7 @@
/*
stm32flash - Open Source ST STM32 flash program for *nix
Copyright (C) 2010 Geoffrey McRae <geoff@spacevs.com>
- Copyright (C) 2014 Antonio Borneo <borneo.antonio@gmail.com>
+ Copyright (C) 2014-2015 Antonio Borneo <borneo.antonio@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 --git a/i2c.c b/i2c.c
index 9079e01..10e6bb1 100644
--- a/i2c.c
+++ b/i2c.c
@@ -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 --git a/init.c b/init.c
index 77a571b..2e72385 100644
--- a/init.c
+++ b/init.c
@@ -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 @@ static int drive_gpio(int n, int level, struct gpio_list **gpio_to_release)
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 @@ static int drive_gpio(int n, int level, struct gpio_list **gpio_to_release)
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 @@ static int drive_gpio(int n, int level, struct gpio_list **gpio_to_release)
}
#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 @@ static int gpio_sequence(struct port_interface *port, const char *s, size_t l)
}
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_entry(struct port_interface *port, const char *seq)
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 --git a/main.c b/main.c
index 5105d21..dd11b7f 100644
--- a/main.c
+++ b/main.c
@@ -2,8 +2,8 @@
stm32flash - Open Source ST STM32 flash program for *nix
Copyright 2010 Geoffrey McRae <geoff@spacevs.com>
Copyright 2011 Steve Markgraf <steve@steve-m.de>
- Copyright 2012 Tormod Volden <debian.tormod@gmail.com>
- Copyright 2013 Antonio Borneo <borneo.antonio@gmail.com>
+ Copyright 2012-2016 Tormod Volden <debian.tormod@gmail.com>
+ Copyright 2013-2016 Antonio Borneo <borneo.antonio@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 @@ struct port_options port_opts = {
.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 @@ uint32_t readwrite_len = 0;
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 @@ static int is_addr_in_flash(uint32_t addr)
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 @@ int main(int argc, char* argv[]) {
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 @@ int main(int argc, char* argv[]) {
}
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 @@ int main(int argc, char* argv[]) {
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 @@ int main(int argc, char* argv[]) {
}
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 @@ int main(int argc, char* argv[]) {
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 @@ int main(int argc, char* argv[]) {
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 @@ int main(int argc, char* argv[]) {
// 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 @@ int main(int argc, char* argv[]) {
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 @@ int parse_options(int argc, char *argv[])
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 @@ int parse_options(int argc, char *argv[])
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 @@ int parse_options(int argc, char *argv[])
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 @@ int parse_options(int argc, char *argv[])
break;
case 'C':
- crc = 1;
+ if (action != ACT_NONE) {
+ err_multi_action(ACT_CRC);
+ return 1;
+ }
+ action = ACT_CRC;
break;
}
}
@@ -699,7 +780,7 @@ int parse_options(int argc, char *argv[])
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 @@ void show_help(char *name) {
" 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 --git a/parsers/hex.c b/parsers/hex.c
index 3baf856..1c92ea4 100644
--- a/parsers/hex.c
+++ b/parsers/hex.c
@@ -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 @@ parser_err_t hex_open(void *storage, const char *filename, const char write) {
/* extended linear address record */
case 4:
- base = address;
+ base = 0;
break;
}
@@ -152,12 +152,17 @@ parser_err_t hex_open(void *storage, const char *filename, const char write) {
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 @@ parser_err_t hex_open(void *storage, const char *filename, const char write) {
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 --git a/serial_posix.c b/serial_posix.c
index 46b8a94..ec6694f 100644
--- a/serial_posix.c
+++ b/serial_posix.c
@@ -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 @@ static port_err_t serial_posix_open(struct port_interface *port,
{
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 @@ static port_err_t serial_posix_open(struct port_interface *port,
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 --git a/serial_w32.c b/serial_w32.c
index ceac3a3..0bcce93 100644
--- a/serial_w32.c
+++ b/serial_w32.c
@@ -67,6 +67,7 @@ static serial_t *serial_open(const char *device)
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 @@ static serial_t *serial_open(const char *device)
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 @@ static port_err_t serial_setup(serial_t *h,
/* 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 @@ static port_err_t serial_w32_open(struct port_interface *port,
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 --git a/stm32.c b/stm32.c
index ca95b3e..1b0362d 100644
--- a/stm32.c
+++ b/stm32.c
@@ -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 uint8_t stm_reset_code[] = {
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 @@ stm32_err_t stm32_write_memory(const stm32_t *stm, uint32_t address,
}
/* 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 @@ stm32_err_t stm32_wunprot_memory(const stm32_t *stm)
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 @@ stm32_err_t stm32_wprot_memory(const stm32_t *stm)
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 @@ stm32_err_t stm32_runprot_memory(const stm32_t *stm)
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 @@ stm32_err_t stm32_readprot_memory(const stm32_t *stm)
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 @@ stm32_err_t stm32_readprot_memory(const stm32_t *stm)
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 @@ stm32_err_t stm32_erase_memory(const stm32_t *stm, uint8_t spage, uint8_t pages)
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 @@ stm32_err_t stm32_erase_memory(const stm32_t *stm, uint8_t spage, uint8_t pages)
}
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 @@ static stm32_err_t stm32_run_raw_code(const stm32_t *stm,
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 @@ stm32_err_t stm32_reset_device(const stm32_t *stm)
{
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 --git a/stm32.h b/stm32.h
index 1688fcb..0e0035b 100644
--- a/stm32.h
+++ b/stm32.h
@@ -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 @@ typedef enum {
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 @@ struct stm32_dev {
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 @@ stm32_err_t stm32_write_memory(const stm32_t *stm, uint32_t address,
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 --git a/stm32flash.1 b/stm32flash.1
index d37292f..ca7acb7 100644
--- a/stm32flash.1
+++ b/stm32flash.1
@@ -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 @@ stm32flash \- flashing utility for STM32 and STM32W through UART or I2C
.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 @@ This option is mandatory for I2C interface.
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 @@ Specify the format of UART data.
.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 @@ Default is
.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 @@ existing connection. This is useful if the reset fails.
.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 @@ GPIO_string = [entry sequence][:[exit sequence]]
.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 @@ after BREAK the UART is returned in normal "non\-break" mode.
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 @@ The corresponding string for
.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 @@ As example, supposing GPIO_3 connected to PA5 and GPIO_2 to STM32W's reset.
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 @@ entry sequence: RTS=low, DTR=low, DTR=high
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 @@ Man page and extension to STM32W and I2C are written by
.IR "Antonio Borneo <borneo.antonio@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)."