summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrej Shadura <andrewsh@debian.org>2020-10-30 17:43:02 +0100
committerAndrej Shadura <andrewsh@debian.org>2020-10-30 17:43:02 +0100
commita06205fb5515908827dff6f6714e7ecc9776d81f (patch)
tree0fa4cbccf21c16db631f4944b25e2a1a2d6951eb
parentf2e31af0dd5cad0b5c17d970be17f7e44814cce0 (diff)
parentaa4fe601399f34a787731133ff31e7154a8f3f8c (diff)
Update upstream source from tag 'upstream/0.5+git20200914+2b0f078'
Update to upstream version '0.5+git20200914+2b0f078' with Debian dir 7967e499074a7740119e2bd266cdcf686e982b18
-rw-r--r--.gitignore3
-rw-r--r--Makefile8
-rw-r--r--Makefile.am39
-rw-r--r--compiler.h38
-rw-r--r--configure.ac33
-rw-r--r--[-rwxr-xr-x]dev_table.c46
-rw-r--r--i2c.c21
-rw-r--r--init.c122
-rw-r--r--init.h1
-rw-r--r--main.c176
-rw-r--r--parsers/Makefile.am11
-rw-r--r--parsers/binary.c16
-rw-r--r--parsers/hex.c8
-rw-r--r--port.h1
-rw-r--r--serial_posix.c36
-rw-r--r--serial_w32.c18
-rw-r--r--stm32.c78
-rw-r--r--stm32.h5
-rw-r--r--stm32flash.142
-rw-r--r--utils.c7
-rw-r--r--utils.h3
21 files changed, 583 insertions, 129 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..1a79f87
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+stm32flash
+*.o
+parsers/parsers.a
diff --git a/Makefile b/Makefile
index e3a019e..81a5344 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,14 @@
PREFIX = /usr/local
CFLAGS += -Wall -g
+ifndef CC
+ $(error CC is not defined)
+endif
+
+ifndef AR
+ $(error AR is not defined)
+endif
+
INSTALL = install
OBJS = dev_table.o \
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..c877c7b
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,39 @@
+
+SUBDIRS = parsers
+
+bin_PROGRAMS = stm32flash
+
+AUTOMAKE_OPTIONS = subdir-objects
+
+
+stm32flash_SOURCES = \
+ dev_table.c \
+ i2c.c \
+ init.c \
+ main.c \
+ port.c \
+ serial_common.c \
+ serial_platform.c\
+ stm32.c \
+ utils.c
+
+stm32flash_LDADD = ${top_builddir}/parsers/parsers.la
+
+stm32flash_CFLAGS = \
+ -g3 \
+ -Os \
+ -Wall \
+ -Wextra \
+ -I$(srcdir)/parsers
+
+
+stm32flash_LDFLAGS = \
+ -Wall \
+ -g3 \
+ -Wextra
+
+all:
+
+
+.PHONY: all
+.SILENT: all
diff --git a/compiler.h b/compiler.h
new file mode 100644
index 0000000..57e83ff
--- /dev/null
+++ b/compiler.h
@@ -0,0 +1,38 @@
+/*
+ stm32flash - Open Source ST STM32 flash program for *nix
+ Copyright (C) 2017 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
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+#ifndef _H_COMPILER
+#define _H_COMPILER
+
+#if defined(__GNUC__)
+#undef __unused
+#undef __maybe_unused
+#define __unused __attribute__ ((unused))
+#define __maybe_unused __attribute__ ((unused))
+#endif
+
+#ifndef __unused
+#define __unused
+#endif
+
+#ifndef __maybe_unused
+#define __maybe_unused
+#endif
+
+#endif /* _H_COMPILER */
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..c05a9e0
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,33 @@
+# -*- Autoconf -*-
+# Process this file with autoconf to produce a configure script.
+
+AC_PREREQ([2.68])
+AC_INIT([stm32flash], [0.5], [])
+
+# Checks for programs.
+AM_INIT_AUTOMAKE([foreign -Wall])
+AC_PROG_CC
+AM_PROG_CC_C_O
+AM_PROG_AR
+AM_PROG_AS
+LT_INIT
+AC_CONFIG_MACRO_DIR([m4])
+
+# Checks for programs.
+
+# Checks for libraries.
+
+# Checks for header files.
+
+# Checks for typedefs, structures, and compiler characteristics.
+
+# Checks for library functions.
+
+
+AC_CONFIG_FILES(
+ [
+ Makefile
+ parsers/Makefile
+ ])
+
+AC_OUTPUT
diff --git a/dev_table.c b/dev_table.c
index f4ada72..ec6d599 100755..100644
--- a/dev_table.c
+++ b/dev_table.c
@@ -36,10 +36,11 @@
*/
/* 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 };
+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 };
+static uint32_t p_128k[] = { SZ_128K, 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 */
@@ -51,16 +52,21 @@ static uint32_t f4db[] = {
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"
+ * Device table, corresponds to the "Bootloader device-dependent parameters"
* table in ST document AN2606.
* Note that the option bytes upper range is inclusive!
+ *
+ * When adding new devices, please double-check agaist the chip-specific
+ * sections and reference manuals, where also flash address and option
+ * byte ranges can be found. In the commit message, please reference the
+ * source documents including their revision.
*/
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},
{0x444, "STM32F03xx4/6" , 0x20000800, 0x20001000, 0x08000000, 0x08008000, 4, p_1k , 0x1FFFF800, 0x1FFFF80F, 0x1FFFEC00, 0x1FFFF800, 0},
+ {0x442, "STM32F030xC/F09xxx" , 0x20001800, 0x20008000, 0x08000000, 0x08040000, 2, p_2k , 0x1FFFF800, 0x1FFFF80F, 0x1FFFD800, 0x1FFFF800, F_OBLL},
{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 */
@@ -86,25 +92,41 @@ const stm32_dev_t devices[] = {
{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},
+ {0x441, "STM32F412xx" , 0x20003000, 0x20040000, 0x08000000, 0x08100000, 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},
+ {0x434, "STM32F469xx/479xx" , 0x20003000, 0x20060000, 0x08000000, 0x08200000, 1, f4db , 0x1FFEC000, 0x1FFFC00F, 0x1FFF0000, 0x1FFF7800, 0},
+ {0x463, "STM32F413xx/423xx" , 0x20003000, 0x20050000, 0x08000000, 0x08180000, 1, f2f4 , 0x1FFFC000, 0x1FFFC00F, 0x1FFF0000, 0x1FFF7800, 0},
+ /* G0 */
+ /* The chips with ID 0x466 have a mismatch in AN2606 Rev 44, where table 141 claims 0x2000000 - 0x20000fff to be readable
+ * as opposed to the correct table 85, where this range is correctly marked as reserved by the bootloader
+ */
+ {0x466, "STM32G03xxx/04xxx" , 0x20001000, 0x20002000, 0x08000000, 0x08010000, 1, p_2k , 0x1FFF7800, 0x1FFF787F, 0x1FFF0000, 0x1FFF7000, 0},
+ {0x460, "STM32G07xxx/08xxx" , 0x20003000, 0x20009000, 0x08000000, 0x08020000, 1, p_2k , 0x1FFF7800, 0x1FFF787F, 0x1FFF0000, 0x1FFF7000, 0},
/* F7 */
+ {0x452, "STM32F72xxx/73xxx" , 0x20004000, 0x20040000, 0x08000000, 0x08080000, 1, f2f4 , 0x1FFF0000, 0x1FFF001F, 0x1FF00000, 0x1FF0EDC0, 0},
{0x449, "STM32F74xxx/75xxx" , 0x20004000, 0x20050000, 0x08000000, 0x08100000, 1, f7 , 0x1FFF0000, 0x1FFF001F, 0x1FF00000, 0x1FF0EDC0, 0},
+ {0x451, "STM32F76xxx/77xxx" , 0x20004000, 0x20080000, 0x08000000, 0x08200000, 1, f7 , 0x1FFF0000, 0x1FFF001F, 0x1FF00000, 0x1FF0EDC0, 0},
+ /* H7 */
+ {0x450, "STM32H74xxx/75xxx" , 0x20004100, 0x20020000, 0x08000000, 0x08200000, 1, p_128k, 0 , 0 , 0x1FF00000, 0x1FF1E800, 0},
/* L0 */
+ {0x457, "STM32L01xxx/02xxx" , 0x20000800, 0x20000800, 0x08000000, 0x08004000, 32, p_128 , 0x1FF80000, 0x1FF8001F, 0x1FF00000, 0x1FF01000, 0},
{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 */
- {0x415, "STM32L476xx/486xx" , 0x20003100, 0x20018000, 0x08000000, 0x08100000, 1, p_2k , 0x1FFF7800, 0x1FFFF80F, 0x1FFF0000, 0x1FFF7000, 0},
+ {0x435, "STM32L43xxx/44xxx" , 0x20003100, 0x2000C000, 0x08000000, 0x08040000, 1, p_2k , 0x1FFF7800, 0x1FFF780F, 0x1FFF0000, 0x1FFF7000, 0},
+ {0x462, "STM32L45xxx/46xxx" , 0x20003100, 0x20020000, 0x08000000, 0x08080000, 1, p_2k , 0x1FFF7800, 0x1FFF780F, 0x1FFF0000, 0x1FFF7000, F_PEMPTY},
+ {0x415, "STM32L47xxx/48xxx" , 0x20003100, 0x20018000, 0x08000000, 0x08100000, 1, p_2k , 0x1FFF7800, 0x1FFFF80F, 0x1FFF0000, 0x1FFF7000, 0},
+ {0x461, "STM32L496xx/4A6xx" , 0x20003100, 0x20040000, 0x08000000, 0x08100000, 1, p_2k , 0x1FFF7800, 0x1FFFF80F, 0x1FFF0000, 0x1FFF7000, 0},
/* These are not (yet) in AN2606: */
{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}
+ { /* sentinel */ }
};
diff --git a/i2c.c b/i2c.c
index 10e6bb1..bb99545 100644
--- a/i2c.c
+++ b/i2c.c
@@ -28,14 +28,15 @@
#include <sys/types.h>
#include <sys/stat.h>
+#include "compiler.h"
#include "serial.h"
#include "port.h"
#if !defined(__linux__)
-static port_err_t i2c_open(struct port_interface *port,
- struct port_options *ops)
+static port_err_t i2c_open(struct port_interface __unused *port,
+ struct port_options __unused *ops)
{
return PORT_ERR_NODEV;
}
@@ -149,7 +150,7 @@ static port_err_t i2c_read(struct port_interface *port, void *buf,
if (h == NULL)
return PORT_ERR_UNKNOWN;
ret = read(h->fd, buf, nbyte);
- if (ret != nbyte)
+ if (ret != (int)nbyte)
return PORT_ERR_UNKNOWN;
return PORT_ERR_OK;
}
@@ -164,13 +165,14 @@ static port_err_t i2c_write(struct port_interface *port, void *buf,
if (h == NULL)
return PORT_ERR_UNKNOWN;
ret = write(h->fd, buf, nbyte);
- if (ret != nbyte)
+ if (ret != (int)nbyte)
return PORT_ERR_UNKNOWN;
return PORT_ERR_OK;
}
-static port_err_t i2c_gpio(struct port_interface *port, serial_gpio_t n,
- int level)
+static port_err_t i2c_gpio(struct port_interface __unused *port,
+ serial_gpio_t __unused n,
+ int __unused level)
{
return PORT_ERR_OK;
}
@@ -194,11 +196,18 @@ static struct varlen_cmd i2c_cmd_get_reply[] = {
{ /* sentinel */ }
};
+static port_err_t i2c_flush(struct port_interface __unused *port)
+{
+ /* We shouldn't need to flush I2C */
+ return PORT_ERR_OK;
+}
+
struct port_interface port_i2c = {
.name = "i2c",
.flags = PORT_STRETCH_W,
.open = i2c_open,
.close = i2c_close,
+ .flush = i2c_flush,
.read = i2c_read,
.write = i2c_write,
.gpio = i2c_gpio,
diff --git a/init.c b/init.c
index 2e72385..3177607 100644
--- a/init.c
+++ b/init.c
@@ -28,10 +28,15 @@
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
+
+#include "compiler.h"
#include "init.h"
#include "serial.h"
#include "stm32.h"
#include "port.h"
+#include "utils.h"
+
+extern FILE *diag;
struct gpio_list {
struct gpio_list *next;
@@ -40,6 +45,7 @@ struct gpio_list {
int exported; /* 0 if gpio should be unexported. */
};
+#if defined(__linux__)
static int write_to(const char *filename, const char *value)
{
int fd, ret;
@@ -59,17 +65,10 @@ static int write_to(const char *filename, const char *value)
return 1;
}
-#if !defined(__linux__)
-static int drive_gpio(int n, int level, struct gpio_list **gpio_to_release)
-{
- fprintf(stderr, "GPIO control only available in Linux\n");
- return 0;
-}
-#else
static int read_from(const char *filename, char *buf, size_t len)
{
int fd, ret;
- ssize_t n = 0;
+ size_t n = 0;
fd = open(filename, O_RDONLY);
if (fd < 0) {
@@ -142,7 +141,6 @@ static int drive_gpio(int n, int level, struct gpio_list **gpio_to_release)
return write_to(file, level ? "high" : "low");
}
-#endif
static int release_gpio(int n, int input, int exported)
{
@@ -159,14 +157,34 @@ static int release_gpio(int n, int input, int exported)
return 1;
}
+#else
+static int drive_gpio(int __unused n, int __unused level,
+ struct gpio_list __unused **gpio_to_release)
+{
+ fprintf(stderr, "GPIO control only available in Linux\n");
+ return 0;
+}
+#endif
-static int gpio_sequence(struct port_interface *port, const char *s, size_t l)
+static int gpio_sequence(struct port_interface *port, const char *seq, size_t len_seq)
{
- struct gpio_list *gpio_to_release = NULL, *to_free;
- int ret, level, gpio;
+ struct gpio_list *gpio_to_release = NULL;
+#if defined(__linux__)
+ struct gpio_list *to_free;
+#endif
+ int ret = 0, level, gpio;
+ int sleep_time = 0;
+ int delimiter = 0;
+ const char *sig_str = NULL;
+ const char *s = seq;
+ size_t l = len_seq;
+
+ fprintf(diag, "\nGPIO sequence start\n");
+ while (ret == 0 && *s && l > 0) {
+ sig_str = NULL;
+ sleep_time = 0;
+ delimiter = 0;
- ret = 1;
- while (ret == 1 && *s && l > 0) {
if (*s == '-') {
level = 0;
s++;
@@ -180,48 +198,78 @@ static int gpio_sequence(struct port_interface *port, const char *s, size_t l)
s++;
l--;
}
- } else if (!strncmp(s, "rts", 3)) {
+ } else if (l >= 3 && !strncmp(s, "rts", 3)) {
+ sig_str = s;
gpio = -GPIO_RTS;
s += 3;
l -= 3;
- } else if (!strncmp(s, "dtr", 3)) {
+ } else if (l >= 3 && !strncmp(s, "dtr", 3)) {
+ sig_str = s;
gpio = -GPIO_DTR;
s += 3;
l -= 3;
- } else if (!strncmp(s, "brk", 3)) {
+ } else if (l >= 3 && !strncmp(s, "brk", 3)) {
+ sig_str = s;
gpio = -GPIO_BRK;
s += 3;
l -= 3;
- } else {
- fprintf(stderr, "Character \'%c\' is not a digit\n", *s);
- ret = 0;
- break;
- }
-
- if (*s && (l > 0)) {
+ } else if (*s && (l > 0)) {
+ delimiter = 1;
+ /* The ',' delimiter adds a 100 ms delay between signal toggles.
+ * i.e -rts,dtr will reset rts, wait 100 ms, set dtr.
+ *
+ * The '&' delimiter adds no delay between signal toggles.
+ * i.e -rts&dtr will reset rts and immediately set dtr.
+ *
+ * Example: -rts&dtr,,,rts,-dtr will reset rts and set dtr
+ * without delay, then wait 300 ms, set rts, wait 100 ms, reset dtr.
+ */
if (*s == ',') {
s++;
l--;
+ sleep_time = 100000;
+ } else if (*s == '&') {
+ s++;
+ l--;
} else {
- fprintf(stderr, "Character \'%c\' is not a separator\n", *s);
- ret = 0;
+ fprintf(stderr, "Character \'%c\' is not a valid signal or separator\n", *s);
+ ret = 1;
break;
}
+ } else {
+ /* E.g. modifier without signal */
+ fprintf(stderr, "Invalid sequence %.*s\n", (int) len_seq, seq);
+ ret = 1;
+ break;
+ }
+
+ if (!delimiter) { /* actual gpio/port signal driving */
+ if (gpio < 0) {
+ gpio = -gpio;
+ fprintf(diag, " setting port signal %.3s to %i... ", sig_str, level);
+ ret = (port->gpio(port, gpio, level) != PORT_ERR_OK);
+ printStatus(diag, ret);
+ } else {
+ fprintf(diag, " setting gpio %i to %i... ", gpio, level);
+ ret = (drive_gpio(gpio, level, &gpio_to_release) != 1);
+ printStatus(diag, ret);
+ }
}
- if (gpio < 0)
- ret = (port->gpio(port, -gpio, level) == PORT_ERR_OK);
- else
- ret = drive_gpio(gpio, level, &gpio_to_release);
- usleep(100000);
- }
+ if (sleep_time) {
+ fprintf(diag, " delay %i us\n", sleep_time);
+ usleep(sleep_time);
+ }
+ }
+#if defined(__linux__)
while (gpio_to_release) {
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);
}
- usleep(500000);
+#endif
+ fprintf(diag, "GPIO sequence end\n\n");
return ret;
}
@@ -239,7 +287,7 @@ static int gpio_bl_entry(struct port_interface *port, const char *seq)
return gpio_sequence(port, seq, s - seq);
}
-static int gpio_bl_exit(struct port_interface *port, const char *seq)
+int gpio_bl_exit(struct port_interface *port, const char *seq)
{
char *s;
@@ -258,7 +306,7 @@ int init_bl_entry(struct port_interface *port, const char *seq)
if (seq)
return gpio_bl_entry(port, seq);
- return 1;
+ return 0;
}
int init_bl_exit(stm32_t *stm, struct port_interface *port, const char *seq)
@@ -266,7 +314,5 @@ int init_bl_exit(stm32_t *stm, struct port_interface *port, const char *seq)
if (seq && strchr(seq, ':'))
return gpio_bl_exit(port, seq);
- if (stm32_reset_device(stm) != STM32_ERR_OK)
- return 0;
- return 1;
+ return stm32_reset_device(stm);
}
diff --git a/init.h b/init.h
index 6075b51..26992ac 100644
--- a/init.h
+++ b/init.h
@@ -27,5 +27,6 @@
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);
+int gpio_bl_exit(struct port_interface *port, const char *seq);
#endif
diff --git a/main.c b/main.c
index dd11b7f..a45521c 100644
--- a/main.c
+++ b/main.c
@@ -27,6 +27,7 @@
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
+#include <signal.h>
#include "init.h"
#include "utils.h"
@@ -38,13 +39,17 @@
#include "parsers/binary.h"
#include "parsers/hex.h"
+#if defined(__WIN32__) || defined(__CYGWIN__)
+#include <windows.h>
+#endif
+
#define VERSION "0.5"
/* device globals */
stm32_t *stm = NULL;
-
void *p_st = NULL;
parser_t *parser = NULL;
+struct port_interface *port = NULL;
/* settings */
struct port_options port_opts = {
@@ -76,7 +81,9 @@ int retry = 10;
char exec_flag = 0;
uint32_t execute = 0;
char init_flag = 1;
+int use_stdinout = 0;
char force_binary = 0;
+FILE *diag;
char reset_flag = 0;
char *filename;
char *gpio_seq = NULL;
@@ -127,6 +134,17 @@ static int is_addr_in_flash(uint32_t addr)
return addr >= stm->dev->fl_start && addr < stm->dev->fl_end;
}
+static int is_addr_in_opt_bytes(uint32_t addr)
+{
+ /* option bytes upper range is inclusive in our device table */
+ return addr >= stm->dev->opt_start && addr <= stm->dev->opt_end;
+}
+
+static int is_addr_in_sysmem(uint32_t addr)
+{
+ return addr >= stm->dev->mem_start && addr < stm->dev->mem_end;
+}
+
/* returns the page that contains address "addr" */
static int flash_addr_to_page_floor(uint32_t addr)
{
@@ -191,22 +209,54 @@ static uint32_t flash_page_to_addr(int page)
return addr;
}
+
+#if defined(__WIN32__) || defined(__CYGWIN__)
+BOOL CtrlHandler( DWORD fdwCtrlType )
+{
+ fprintf(stderr, "\nCaught signal %lu\n",fdwCtrlType);
+ if (p_st && parser ) parser->close(p_st);
+ if (stm ) stm32_close (stm);
+ if (port) port->close(port);
+ exit(1);
+}
+#else
+void sighandler(int s){
+ fprintf(stderr, "\nCaught signal %d\n",s);
+ if (p_st && parser ) parser->close(p_st);
+ if (stm ) stm32_close (stm);
+ if (port) port->close(port);
+ exit(1);
+}
+#endif
+
int main(int argc, char* argv[]) {
- struct port_interface *port = NULL;
int ret = 1;
stm32_err_t s_err;
parser_err_t perr;
- FILE *diag = stdout;
+ diag = stdout;
- fprintf(diag, "stm32flash " VERSION "\n\n");
- fprintf(diag, "http://stm32flash.sourceforge.net/\n\n");
if (parse_options(argc, argv) != 0)
goto close;
- if ((action == ACT_READ) && filename[0] == '-') {
+ if (action == ACT_READ && use_stdinout) {
diag = stderr;
}
+ fprintf(diag, "stm32flash " VERSION "\n\n");
+ fprintf(diag, "http://stm32flash.sourceforge.net/\n\n");
+
+#if defined(__WIN32__) || defined(__CYGWIN__)
+ SetConsoleCtrlHandler( (PHANDLER_ROUTINE) CtrlHandler, TRUE );
+#else
+ struct sigaction sigIntHandler;
+
+ sigIntHandler.sa_handler = sighandler;
+ sigemptyset(&sigIntHandler.sa_mask);
+ sigIntHandler.sa_flags = 0;
+
+ sigaction(SIGINT, &sigIntHandler, NULL);
+#endif
+
if (action == ACT_WRITE) {
/* first try hex */
if (!force_binary) {
@@ -259,8 +309,14 @@ int main(int argc, char* argv[]) {
}
fprintf(diag, "Interface %s: %s\n", port->name, port->get_cfg_str(port));
- if (init_flag && init_bl_entry(port, gpio_seq) == 0)
+ if (init_flag && init_bl_entry(port, gpio_seq)){
+ ret = 1;
+ fprintf(stderr, "Failed to send boot enter sequence\n");
goto close;
+ }
+
+ port->flush(port);
+
stm = stm32_init(port, init_flag);
if (!stm)
goto close;
@@ -271,8 +327,8 @@ int main(int argc, char* argv[]) {
fprintf(diag, "Option 2 : 0x%02x\n", stm->option2);
}
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 (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, "- RAM : Up to %dKiB (%db reserved by bootloader)\n", (stm->dev->ram_end - 0x20000000) / 1024, stm->dev->ram_start - 0x20000000);
+ fprintf(diag, "- Flash : Up to %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);
@@ -299,8 +355,17 @@ int main(int argc, char* argv[]) {
no_erase = 1;
if (is_addr_in_ram(start))
end = stm->dev->ram_end;
- else
- end = start + sizeof(uint32_t);
+ else if (is_addr_in_opt_bytes(start))
+ end = stm->dev->opt_end + 1;
+ else if (is_addr_in_sysmem(start))
+ end = stm->dev->mem_end;
+ else {
+ /* Unknown territory */
+ if (readwrite_len)
+ end = start + readwrite_len;
+ else
+ end = start + sizeof(uint32_t);
+ }
}
if (readwrite_len && (end > start + readwrite_len))
@@ -379,20 +444,30 @@ int main(int argc, char* argv[]) {
ret = 0;
goto close;
} else if (action == ACT_READ_PROTECT) {
- fprintf(stdout, "Read-Protecting flash\n");
+ fprintf(diag, "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");
+ s_err = stm32_readprot_memory(stm);
+ if (s_err != STM32_ERR_OK) {
+ fprintf(stderr, "Failed to read-protect flash\n");
+ goto close;
+ }
+ fprintf(diag, "Done.\n");
+ ret = 0;
} else if (action == ACT_READ_UNPROTECT) {
- fprintf(stdout, "Read-UnProtecting flash\n");
+ fprintf(diag, "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");
+ s_err = stm32_runprot_memory(stm);
+ if (s_err != STM32_ERR_OK) {
+ fprintf(stderr, "Failed to read-unprotect flash\n");
+ goto close;
+ }
+ fprintf(diag, "Done.\n");
+ ret = 0;
} else if (action == ACT_ERASE_ONLY) {
ret = 0;
- fprintf(stdout, "Erasing flash\n");
+ fprintf(diag, "Erasing flash\n");
if (num_pages != STM32_MASS_ERASE &&
(start != flash_page_to_addr(first_page)
@@ -408,18 +483,23 @@ int main(int argc, char* argv[]) {
ret = 1;
goto close;
}
+ ret = 0;
} 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);
+ s_err = stm32_wunprot_memory(stm);
+ if (s_err != STM32_ERR_OK) {
+ fprintf(stderr, "Failed to write-unprotect flash\n");
+ goto close;
+ }
fprintf(diag, "Done.\n");
-
+ ret = 0;
} else if (action == ACT_WRITE) {
fprintf(diag, "Write to memory\n");
- off_t offset = 0;
- ssize_t r;
+ unsigned int offset = 0;
+ unsigned int r;
unsigned int size;
unsigned int max_wlen, max_rlen;
@@ -430,7 +510,7 @@ int main(int argc, char* argv[]) {
max_rlen = max_rlen < max_wlen ? max_rlen : max_wlen;
/* Assume data from stdin is whole device */
- if (filename[0] == '-' && filename[1] == '\0')
+ if (use_stdinout)
size = end - start;
else
size = parser->size(p_st);
@@ -440,7 +520,7 @@ int main(int argc, char* argv[]) {
// 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;
- // }
+ // }
// TODO: If writes are not page aligned, we should probably read out existing flash
// contents first, so it can be preserved and combined with new data
@@ -464,14 +544,14 @@ int main(int argc, char* argv[]) {
goto close;
if (len == 0) {
- if (filename[0] == '-') {
+ if (use_stdinout) {
break;
} else {
fprintf(stderr, "Failed to read input file\n");
goto close;
}
}
-
+
again:
s_err = stm32_write_memory(stm, addr, buffer, len);
if (s_err != STM32_ERR_OK) {
@@ -560,11 +640,17 @@ close:
}
if (stm && reset_flag) {
- fprintf(diag, "\nResetting device... ");
+ fprintf(diag, "\nResetting device... \n");
fflush(diag);
- if (init_bl_exit(stm, port, gpio_seq))
- fprintf(diag, "done.\n");
- else fprintf(diag, "failed.\n");
+ if (init_bl_exit(stm, port, gpio_seq)) {
+ ret = 1;
+ fprintf(diag, "Reset failed.\n");
+ } else
+ fprintf(diag, "Reset done.\n");
+ } else if (port) {
+ /* Always run exit sequence if present */
+ if (gpio_seq && strchr(gpio_seq, ':'))
+ ret = gpio_bl_exit(port, gpio_seq) || ret;
}
if (p_st ) parser->close(p_st);
@@ -617,7 +703,8 @@ int parse_options(int argc, char *argv[])
}
action = (c == 'r') ? ACT_READ : ACT_WRITE;
filename = optarg;
- if (filename[0] == '-') {
+ if (filename[0] == '-' && filename[1] == '\0') {
+ use_stdinout = 1;
force_binary = 1;
}
break;
@@ -627,7 +714,7 @@ int parse_options(int argc, char *argv[])
return 1;
}
npages = strtoul(optarg, NULL, 0);
- if (npages > 0xFF || npages < 0) {
+ if (npages > STM32_MAX_PAGES || npages < 0) {
fprintf(stderr, "ERROR: You need to specify a page count between 0 and 255");
return 1;
}
@@ -815,10 +902,20 @@ void show_help(char *name) {
" -c Resume the connection (don't send initial INIT)\n"
" *Baud rate must be kept the same as the first init*\n"
" This is useful if the reset fails\n"
+ " -R Reset device at exit.\n"
" -i GPIO_string GPIO sequence to enter/exit bootloader mode\n"
" GPIO_string=[entry_seq][:[exit_seq]]\n"
- " sequence=[-]n[,sequence]\n"
- " -R Reset device at exit.\n"
+ " sequence=[[-]signal]&|,[sequence]\n"
+ "\n"
+ "GPIO sequence:\n"
+ " The following signals can appear in a sequence:\n"
+ " Integer number representing GPIO pin\n"
+ " 'dtr', 'rts' or 'brk' representing serial port signal\n"
+ " The sequence can use the following delimiters:\n"
+ " ',' adds 100 ms delay between signals\n"
+ " '&' adds no delay between signals\n"
+ " The following modifiers can be prepended to a signal:\n"
+ " '-' reset signal (low) instead of setting it (high)\n"
"\n"
"Examples:\n"
" Get device information:\n"
@@ -839,9 +936,14 @@ void show_help(char *name) {
" %s -g 0x0 /dev/ttyS0\n"
"\n"
" 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 -R -i -3,-2,2:3,-2,2 /dev/ttyS0\n",
+ " - entry sequence: GPIO_3=low, GPIO_2=low, 100ms delay, GPIO_2=high\n"
+ " - exit sequence: GPIO_3=high, GPIO_2=low, 300ms delay, GPIO_2=high\n"
+ " %s -i '-3&-2,2:3&-2,,,2' /dev/ttyS0\n"
+ " GPIO sequence adding delay after port opening:\n"
+ " - entry sequence: delay 500ms\n"
+ " - exit sequence: rts=high, dtr=low, 300ms delay, GPIO_2=high\n"
+ " %s -R -i ',,,,,:rts&-dtr,,,2' /dev/ttyS0\n",
+ name,
name,
name,
name,
diff --git a/parsers/Makefile.am b/parsers/Makefile.am
new file mode 100644
index 0000000..033d49b
--- /dev/null
+++ b/parsers/Makefile.am
@@ -0,0 +1,11 @@
+noinst_LTLIBRARIES = parsers.la
+
+
+parsers_la_SOURCES = binary.c hex.c
+
+parsers_la_CXXFLAGS = -Wall -g
+
+
+parsers_la_LDFLAGS = -module -avoid-version
+
+
diff --git a/parsers/binary.c b/parsers/binary.c
index f491952..a1a30b4 100644
--- a/parsers/binary.c
+++ b/parsers/binary.c
@@ -39,7 +39,7 @@ void* binary_init() {
parser_err_t binary_open(void *storage, const char *filename, const char write) {
binary_t *st = storage;
if (write) {
- if (filename[0] == '-')
+ if (filename[0] == '-' && filename[1] == '\0')
st->fd = 1;
else
st->fd = open(
@@ -57,7 +57,7 @@ parser_err_t binary_open(void *storage, const char *filename, const char write)
);
st->stat.st_size = 0;
} else {
- if (filename[0] == '-') {
+ if (filename[0] == '-' && filename[1] == '\0') {
st->fd = 0;
} else {
if (stat(filename, &st->stat) != 0)
@@ -92,11 +92,13 @@ unsigned int binary_size(void *storage) {
parser_err_t binary_read(void *storage, void *data, unsigned int *len) {
binary_t *st = storage;
unsigned int left = *len;
+ unsigned char *d = data;
+
if (st->write) return PARSER_ERR_WRONLY;
ssize_t r;
while(left > 0) {
- r = read(st->fd, data, left);
+ r = read(st->fd, d, left);
/* If there is no data to read at all, return OK, but with zero read */
if (r == 0 && left == *len) {
*len = 0;
@@ -104,7 +106,7 @@ parser_err_t binary_read(void *storage, void *data, unsigned int *len) {
}
if (r <= 0) return PARSER_ERR_SYSTEM;
left -= r;
- data += r;
+ d += r;
}
*len = *len - left;
@@ -113,16 +115,18 @@ parser_err_t binary_read(void *storage, void *data, unsigned int *len) {
parser_err_t binary_write(void *storage, void *data, unsigned int len) {
binary_t *st = storage;
+ unsigned char *d = data;
+
if (!st->write) return PARSER_ERR_RDONLY;
ssize_t r;
while(len > 0) {
- r = write(st->fd, data, len);
+ r = write(st->fd, d, len);
if (r < 1) return PARSER_ERR_SYSTEM;
st->stat.st_size += r;
len -= r;
- data += r;
+ d += r;
}
return PARSER_ERR_OK;
diff --git a/parsers/hex.c b/parsers/hex.c
index 1c92ea4..b3eaddf 100644
--- a/parsers/hex.c
+++ b/parsers/hex.c
@@ -27,6 +27,7 @@
#include <string.h>
#include "hex.h"
+#include "../compiler.h"
#include "../utils.h"
typedef struct {
@@ -45,9 +46,9 @@ parser_err_t hex_open(void *storage, const char *filename, const char write) {
return PARSER_ERR_RDONLY;
} else {
char mark;
- int i, fd;
+ int fd;
uint8_t checksum;
- unsigned int c;
+ unsigned int c, i;
uint32_t base = 0;
unsigned int last_address = 0x0;
@@ -153,6 +154,7 @@ parser_err_t hex_open(void *storage, const char *filename, const char write) {
/* address record */
case 4: base = base << 12;
+ /* fall-through */
case 2: base = base << 4;
/* Reset last_address since our base changed */
last_address = 0;
@@ -213,7 +215,7 @@ parser_err_t hex_read(void *storage, void *data, unsigned int *len) {
return PARSER_ERR_OK;
}
-parser_err_t hex_write(void *storage, void *data, unsigned int len) {
+parser_err_t hex_write(void __unused *storage, void __unused *data, unsigned int __unused len) {
return PARSER_ERR_RDONLY;
}
diff --git a/port.h b/port.h
index 290f034..4e728d7 100644
--- a/port.h
+++ b/port.h
@@ -62,6 +62,7 @@ struct port_interface {
unsigned flags;
port_err_t (*open)(struct port_interface *port, struct port_options *ops);
port_err_t (*close)(struct port_interface *port);
+ port_err_t (*flush)(struct port_interface *port);
port_err_t (*read)(struct port_interface *port, void *buf, size_t nbyte);
port_err_t (*write)(struct port_interface *port, void *buf, size_t nbyte);
port_err_t (*gpio)(struct port_interface *port, serial_gpio_t n, int level);
diff --git a/serial_posix.c b/serial_posix.c
index ec6694f..00625b8 100644
--- a/serial_posix.c
+++ b/serial_posix.c
@@ -27,10 +27,17 @@
#include <unistd.h>
#include <sys/ioctl.h>
#include <stdio.h>
+#include <sys/file.h>
#include "serial.h"
#include "port.h"
+#ifndef TERMIOS_TIMEOUT_MS
+#define TERMIOS_TIMEOUT_MS 500
+#endif
+
+#define TERMIOS_TIMEOUT ((TERMIOS_TIMEOUT_MS)/100)
+
struct serial {
int fd;
struct termios oldtio;
@@ -47,6 +54,13 @@ static serial_t *serial_open(const char *device)
free(h);
return NULL;
}
+
+ if(lockf(h->fd,F_TLOCK,0) != 0)
+ {
+ fprintf(stderr, "Error: %s is already open\n", device);
+ free(h);
+ return NULL;
+ }
fcntl(h->fd, F_SETFL, 0);
tcgetattr(h->fd, &h->oldtio);
@@ -64,6 +78,7 @@ static void serial_close(serial_t *h)
{
serial_flush(h);
tcsetattr(h->fd, TCSANOW, &h->oldtio);
+ lockf(h->fd, F_ULOCK, 0);
close(h->fd);
free(h);
}
@@ -129,8 +144,8 @@ static port_err_t serial_setup(serial_t *h, const serial_baud_t baud,
switch (parity) {
case SERIAL_PARITY_NONE: port_parity = 0; break;
- case SERIAL_PARITY_EVEN: port_parity = INPCK | PARENB; break;
- case SERIAL_PARITY_ODD: port_parity = INPCK | PARENB | PARODD; break;
+ case SERIAL_PARITY_EVEN: port_parity = PARENB; break;
+ case SERIAL_PARITY_ODD: port_parity = PARENB | PARODD; break;
default:
return PORT_ERR_UNKNOWN;
@@ -174,9 +189,11 @@ static port_err_t serial_setup(serial_t *h, const serial_baud_t baud,
port_stop |
CLOCAL |
CREAD;
+ if ( port_parity != 0 )
+ h->newtio.c_iflag |= INPCK;
h->newtio.c_cc[VMIN] = 0;
- h->newtio.c_cc[VTIME] = 5; /* in units of 0.1 s */
+ h->newtio.c_cc[VTIME] = TERMIOS_TIMEOUT; /* in units of 0.1 s */
/* set the settings */
serial_flush(h);
@@ -344,11 +361,24 @@ static const char *serial_posix_get_cfg_str(struct port_interface *port)
return h ? h->setup_str : "INVALID";
}
+static port_err_t serial_posix_flush(struct port_interface *port)
+{
+ serial_t *h;
+ h = (serial_t *)port->private;
+ if (h == NULL)
+ return PORT_ERR_UNKNOWN;
+
+ serial_flush(h);
+
+ return PORT_ERR_OK;
+}
+
struct port_interface port_serial = {
.name = "serial_posix",
.flags = PORT_BYTE | PORT_GVR_ETX | PORT_CMD_INIT | PORT_RETRY,
.open = serial_posix_open,
.close = serial_posix_close,
+ .flush = serial_posix_flush,
.read = serial_posix_read,
.write = serial_posix_write,
.gpio = serial_posix_gpio,
diff --git a/serial_w32.c b/serial_w32.c
index 0bcce93..97f7f24 100644
--- a/serial_w32.c
+++ b/serial_w32.c
@@ -27,6 +27,7 @@
#include <windows.h>
#include <ctype.h>
+#include "compiler.h"
#include "serial.h"
#include "port.h"
@@ -88,7 +89,7 @@ static serial_t *serial_open(const char *device)
return h;
}
-static void serial_flush(const serial_t *h)
+static void serial_flush(const serial_t __unused *h)
{
/* We shouldn't need to flush in non-overlapping (blocking) mode */
/* tcflush(h->fd, TCIFLUSH); */
@@ -257,8 +258,6 @@ static port_err_t serial_w32_read(struct port_interface *port, void *buf,
ReadFile(h->fd, pos, nbyte, &r, NULL);
if (r == 0)
return PORT_ERR_TIMEDOUT;
- if (r < 0)
- return PORT_ERR_UNKNOWN;
nbyte -= r;
pos += r;
@@ -337,11 +336,24 @@ static const char *serial_w32_get_cfg_str(struct port_interface *port)
return h ? h->setup_str : "INVALID";
}
+static port_err_t serial_w32_flush(struct port_interface *port)
+{
+ serial_t *h;
+ h = (serial_t *)port->private;
+ if (h == NULL)
+ return PORT_ERR_UNKNOWN;
+
+ serial_flush(h);
+
+ return PORT_ERR_OK;
+}
+
struct port_interface port_serial = {
.name = "serial_w32",
.flags = PORT_BYTE | PORT_GVR_ETX | PORT_CMD_INIT | PORT_RETRY,
.open = serial_w32_open,
.close = serial_w32_close,
+ .flush = serial_w32_flush,
.read = serial_w32_read,
.write = serial_w32_write,
.gpio = serial_w32_gpio,
diff --git a/stm32.c b/stm32.c
index 1b0362d..96c0e81 100644
--- a/stm32.c
+++ b/stm32.c
@@ -117,6 +117,59 @@ static const uint8_t stm_obl_launch_code[] = {
static const uint32_t stm_obl_launch_code_length = sizeof(stm_obl_launch_code);
+/* RM0394, Empty check
+ * On STM32L452 (and possibly all STM32L45xxx/46xxx) 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 or a toggle of PEMPTY bit in FLASH_SR
+ * register is needed to clear this flag after after programming of a virgin device to execute
+ * user code after System reset.
+ * In STM32L45xxx/46xxx the register FLASH_CR could be locked and a special SW sequence is
+ * required for unlocking it. If a previous unsuccessful unlock has happened, a reset is
+ * required before the unlock. Due to such complications, toggling the PEMPTY bit in FLASH_SR
+ * seams the most reasonable choice.
+ * The code below check first word in flash and flag PEMPTY. If they do not match, then it
+ * toggles PEMPTY. At last, it resets.
+ */
+
+static const uint8_t stm_pempty_launch_code[] = {
+ 0x08, 0x48, // ldr r0, [pc, #32] ; (<BASE_FLASH>)
+ 0x00, 0x68, // ldr r0, [r0, #0]
+ 0x01, 0x30, // adds r0, #1
+ 0x41, 0x1e, // subs r1, r0, #1
+ 0x88, 0x41, // sbcs r0, r1
+
+ 0x07, 0x49, // ldr r1, [pc, #28] ; (<FLASH_SR>)
+ 0x07, 0x4a, // ldr r2, [pc, #28] ; (<PEMPTY_MASK>)
+ 0x0b, 0x68, // ldr r3, [r1, #0]
+ 0x13, 0x40, // ands r3, r2
+ 0x5c, 0x1e, // subs r4, r3, #1
+ 0xa3, 0x41, // sbcs r3, r4
+
+ 0x98, 0x42, // cmp r0, r3
+ 0x00, 0xd1, // bne.n skip1
+
+ 0x0a, 0x60, // str r2, [r1, #0]
+
+ 0x04, 0x48, // skip1: ldr r0, [pc, #16] ; (<AIRCR_OFFSET>)
+ 0x05, 0x49, // ldr r1, [pc, #16] ; (<AIRCR_RESET_VALUE>)
+ 0x01, 0x60, // str r1, [r0, #0]
+
+ 0xfe, 0xe7, // endless: b.n endless
+
+ 0x00, 0x00, 0x00, 0x08, // .word 0x08000000 <BASE_FLASH>
+ 0x10, 0x20, 0x02, 0x40, // .word 0x40022010 <FLASH_SR>
+ 0x00, 0x00, 0x02, 0x00, // .word 0x00020000 <PEMPTY_MASK>
+ 0x0c, 0xed, 0x00, 0xe0, // .word 0xe000ed0c <AIRCR_OFFSET> = NVIC AIRCR register address
+ 0x04, 0x00, 0xfa, 0x05 // .word 0x05fa0004 <AIRCR_RESET_VALUE> = VECTKEY | SYSRESETREQ
+};
+
+static const uint32_t stm_pempty_launch_code_length = sizeof(stm_pempty_launch_code);
+
extern const stm32_dev_t devices[];
int flash_addr_to_page_ceil(uint32_t addr);
@@ -606,7 +659,7 @@ stm32_err_t stm32_write_memory(const stm32_t *stm, uint32_t address,
s_err = stm32_get_ack_timeout(stm, STM32_BLKWRITE_TIMEOUT);
if (s_err != STM32_ERR_OK) {
- if (port->flags & PORT_STRETCH_W
+ if ((port->flags & PORT_STRETCH_W)
&& stm->cmd->wm != STM32_CMD_WM_NS)
stm32_warn_stretching("write");
return STM32_ERR_UNKNOWN;
@@ -633,7 +686,7 @@ stm32_err_t stm32_wunprot_memory(const stm32_t *stm)
return STM32_ERR_UNKNOWN;
}
if (s_err != STM32_ERR_OK) {
- if (port->flags & PORT_STRETCH_W
+ if ((port->flags & PORT_STRETCH_W)
&& stm->cmd->uw != STM32_CMD_UW_NS)
stm32_warn_stretching("WRITE UNPROTECT");
return STM32_ERR_UNKNOWN;
@@ -660,7 +713,7 @@ stm32_err_t stm32_wprot_memory(const stm32_t *stm)
return STM32_ERR_UNKNOWN;
}
if (s_err != STM32_ERR_OK) {
- if (port->flags & PORT_STRETCH_W
+ if ((port->flags & PORT_STRETCH_W)
&& stm->cmd->wp != STM32_CMD_WP_NS)
stm32_warn_stretching("WRITE PROTECT");
return STM32_ERR_UNKNOWN;
@@ -687,7 +740,7 @@ stm32_err_t stm32_runprot_memory(const stm32_t *stm)
return STM32_ERR_UNKNOWN;
}
if (s_err != STM32_ERR_OK) {
- if (port->flags & PORT_STRETCH_W
+ if ((port->flags & PORT_STRETCH_W)
&& stm->cmd->ur != STM32_CMD_UR_NS)
stm32_warn_stretching("READOUT UNPROTECT");
return STM32_ERR_UNKNOWN;
@@ -714,7 +767,7 @@ stm32_err_t stm32_readprot_memory(const stm32_t *stm)
return STM32_ERR_UNKNOWN;
}
if (s_err != STM32_ERR_OK) {
- if (port->flags & PORT_STRETCH_W
+ if ((port->flags & PORT_STRETCH_W)
&& stm->cmd->rp != STM32_CMD_RP_NS)
stm32_warn_stretching("READOUT PROTECT");
return STM32_ERR_UNKNOWN;
@@ -755,9 +808,9 @@ static stm32_err_t stm32_mass_erase(const stm32_t *stm)
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");
+ 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;
@@ -842,7 +895,7 @@ static stm32_err_t stm32_pages_erase(const stm32_t *stm, uint32_t spage, uint32_
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
+ if ((port->flags & PORT_STRETCH_W)
&& stm->cmd->er != STM32_CMD_EE_NS)
stm32_warn_stretching("erase");
return STM32_ERR_UNKNOWN;
@@ -972,6 +1025,9 @@ stm32_err_t stm32_reset_device(const stm32_t *stm)
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 if (stm->dev->flags & F_PEMPTY) {
+ /* clear the PEMPTY bit to reset the device (see RM0394) */
+ return stm32_run_raw_code(stm, target_address, stm_pempty_launch_code, stm_pempty_launch_code_length);
} else {
return stm32_run_raw_code(stm, target_address, stm_reset_code, stm_reset_code_length);
}
@@ -983,7 +1039,7 @@ stm32_err_t stm32_crc_memory(const stm32_t *stm, uint32_t address,
struct port_interface *port = stm->port;
uint8_t buf[5];
- if (address & 0x3 || length & 0x3) {
+ if ((address & 0x3) || (length & 0x3)) {
fprintf(stderr, "Start and end addresses must be 4 byte aligned\n");
return STM32_ERR_UNKNOWN;
}
@@ -1076,7 +1132,7 @@ stm32_err_t stm32_crc_wrapper(const stm32_t *stm, uint32_t address,
uint8_t buf[256];
uint32_t start, total_len, len, current_crc;
- if (address & 0x3 || length & 0x3) {
+ if ((address & 0x3) || (length & 0x3)) {
fprintf(stderr, "Start and end addresses must be 4 byte aligned\n");
return STM32_ERR_UNKNOWN;
}
diff --git a/stm32.h b/stm32.h
index 0e0035b..eb9e79e 100644
--- a/stm32.h
+++ b/stm32.h
@@ -38,8 +38,9 @@ typedef enum {
} stm32_err_t;
typedef enum {
- F_NO_ME = 1 << 0, /* Mass-Erase not supported */
- F_OBLL = 1 << 1, /* OBL_LAUNCH required */
+ F_NO_ME = 1 << 0, /* Mass-Erase not supported */
+ F_OBLL = 1 << 1, /* OBL_LAUNCH required */
+ F_PEMPTY = 1 << 2, /* clear PEMPTY bit required */
} flags_t;
typedef struct stm32 stm32_t;
diff --git a/stm32flash.1 b/stm32flash.1
index ca7acb7..6870ae0 100644
--- a/stm32flash.1
+++ b/stm32flash.1
@@ -226,7 +226,7 @@ The format of
.RS
GPIO_string = [entry sequence][:[exit sequence]]
.P
-sequence = [\-]n[,sequence]
+sequence = [[\-]signal]&|,[sequence]
.RE
.PD
.P
@@ -239,9 +239,20 @@ The string "brk" forces the UART to send a BREAK sequence on TX line;
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.
+The ',' delimiter adds 100 ms of delay between signal toggles, whereas
+the '&' delimiter adds no delay.
+An empty signal, thus repeated ',' delimiters, can be used to insert larger
+delays in multiples of 100 ms.
+E.g. "rts,,,,\-dtr" will set RTS, then wait 400 ms, then reset DTR.
+"rts&\-dtr" will set RTS and reset DTR without delay. You can use ',' delimiters
+alone to simply add a delay between opening port and starting to flash.
+.DP
+.P
+Note that since version 0.6, an exit sequence will always be executed if
+specified, regardless of the -R option, to ensure the signals are reset.
+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:
@@ -267,7 +278,7 @@ The corresponding string for
.I GPIO_string
is "\-4,\-3,3".
-The complete command line flag is "\-R \-i 4,\-5,\-3,3:\-4,\-3,3".
+The complete command line flag is "\-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
@@ -277,15 +288,30 @@ As example, supposing GPIO_3 connected to PA5 and GPIO_2 to STM32W's reset.
The command:
.PD 0
.RS
-stm32flash \-R \-i \-3,\-2,2:3,\-2,2 /dev/ttyS0
+stm32flash \-i '\-3&\-2,2:3&\-2,,,2' /dev/ttyS0
.RE
provides:
.IP \(bu 2
-entry sequence: GPIO_3=low, GPIO_2=low, GPIO_2=high
+entry sequence: GPIO_3=low, GPIO_2=low, 100 ms delay, GPIO_2=high
.IP \(bu 2
-exit sequence: GPIO_3=high, GPIO_2=low, GPIO_2=high
+exit sequence: GPIO_3=high, GPIO_2=low, 300 ms delay, GPIO_2=high
.PD
+
+GPIO sequence to bring delays on start after port opening.
+The command:
+.PD 0
+.RS
+stm32flash \-i ',,,,,:rts&\-dtr,,,2' /dev/ttyS0\n",
+.RE
+provides:
+.IP \(bu 2
+entry sequence: delay 500 ms
+.IP \(bu 2
+exit sequence: RTS=high, DTR=low, 300 ms delay, GPIO_2=high
+.PD
+
+
.SH EXAMPLES
Get device information:
.RS
@@ -327,7 +353,7 @@ entry sequence: RTS=low, DTR=low, DTR=high
exit sequence: RTS=high, DTR=low, DTR=high
.P
.RS
-stm32flash \-R \-i \-rts,\-dtr,dtr:rts,\-dtr,dtr /dev/ttyS0
+stm32flash \-i \-rts,\-dtr,dtr:rts,\-dtr,dtr /dev/ttyS0
.PD
.RE
diff --git a/utils.c b/utils.c
index 271bb3e..4bfba17 100644
--- a/utils.c
+++ b/utils.c
@@ -43,3 +43,10 @@ uint32_t le_u32(const uint32_t v) {
((v & 0x000000FF) << 24);
return v;
}
+
+void printStatus(FILE *fd, int condition){
+ if(condition)
+ fprintf(fd, "Error!\n");
+ else
+ fprintf(fd, "OK\n");
+}
diff --git a/utils.h b/utils.h
index a8d37d2..07395d3 100644
--- a/utils.h
+++ b/utils.h
@@ -22,9 +22,12 @@
#define _H_UTILS
#include <stdint.h>
+#include <stdio.h>
char cpu_le();
uint32_t be_u32(const uint32_t v);
uint32_t le_u32(const uint32_t v);
+void printStatus(FILE *fd, int condition);
+
#endif