Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
PREFIX = /usr/local
CFLAGS += -Wall -g
CFLAGS += -Wall -g -DB460800 -DB921600 -DTERMIOS_TIMEOUT_MS=500

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems superfluous since it will be defined in serial_posix.c anyway.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, this was left here after our experiments. I'll remove it.

What about speed opts? Is it needed to have those defines in code and here? Why not enable it by default? Driver won't let you set unsupported speed.

INSTALL = install

Expand Down
112 changes: 112 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
stm32flash
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can need a README file, but pasting in the whole wiki page is maybe not right.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was done for github only, to make a project good looking from repository. Sure, duplicating info from man can be an overhead

==========

stm32flash 0.5 was released 2016-02-11 and is available at
https://sourceforge.net/projects/stm32flash/files/

The 0.5 version adds
- support for multiple bank sizes
- improved serial port support on Windows
- improved erase functionality
- improved hex parser
- many new devices and device info corrections

Thanks to Antonio Borneo and many other contributors (see git log and AUTHORS file)

The 0.4 version is the work of Antonio Borneo and includes support for programming over I2C. See the included I2C.txt for more information. The code has been refactored to make it easier to add other transports.

Features
--------

- UART and I2C transports supported
- device identification
- write to flash/ram
- read from flash/ram
- auto-detect Intel HEX or raw binary input format with option to force binary
- flash from binary file
- save flash to binary file
- verify & retry up to N times on failed writes
- start execution at specified address
- software reset the device when finished if -R is specified
- resume already initialized connection (for when reset fails, UART only)
- GPIO signalling to enter bootloader mode (hardware dependent)

Usage
-----

See the included manual page for up-to-date, complete usage instructions (PDF version)
Usage synopsis:

stm32flash [-bvngfhc] [-[rw] filename] [tty_device | i2c_device]
-a bus_address Bus address (e.g. for I2C port)
-b rate Baud rate (default 57600)
-m mode Serial port mode (default 8e1)
-r filename Read flash to file (or - stdout)
-w filename Write flash from file (or - stdout)
-C Compute CRC of flash content
-u Disable the flash write-protection
-j Enable the flash read-protection
-k Disable the flash read-protection
-o Erase only
-e n Only erase n pages before writing the flash
-v Verify writes
-n count Retry failed writes up to count times (default 10)
-g address Start execution at specified address (0 = flash start)
-S address[:length] Specify start address and optionally length for
read/write/erase operations
-F RX_length[:TX_length] Specify the max length of RX and TX frame
-s start_page Flash at specified page (0 = flash start)
-f Force binary parser
-h Show this help
-c Resume the connection (don't send initial INIT)
*Baud rate must be kept the same as the first init*
This is useful if the reset fails
-i GPIO_string GPIO sequence to enter/exit bootloader mode
GPIO_string=[entry_seq][:[exit_seq]]
sequence=[[\-]signal]&|,[&|,][sequence]
-R Reset device at exit.

Examples:
Get device information:
stm32flash /dev/ttyS0
or:
stm32flash /dev/i2c-0```

Write with verify and then start execution:
stm32flash -w filename -v -g 0x0 /dev/ttyS0

Read flash to file:
stm32flash -r filename /dev/ttyS0

Read 100 bytes of flash from 0x1000 to stdout:
stm32flash -r - -S 0x1000:100 /dev/ttyS0

Start execution:
stm32flash -g 0x0 /dev/ttyS0

GPIO sequence:
- entry sequence: GPIO_3=low, GPIO_2=low, delay 100ms, GPIO_2=high
- exit sequence: GPIO_3=high, GPIO_2=low, delay 300ms, GPIO_2=high
stm32flash -R -i -3&-2,2:3&-2,,,2 /dev/ttyS0

Bug reports and patches
-----------------------

Please file bugs and post patches in the official tracker https://sourceforge.net/p/stm32flash/tickets/

Help and hints
--------------

Find help on our [Hints] page about
- Linux and CH340 USB-serial adapters
- MacOSX and PL2303 USB-serial adapters

Building from source
--------------------

On most platforms just run "make" in the source folder. For building on Windows see also [Build].

Authors
-------

stm32flash was originally written by Geoffrey McRae and is since 2012 maintained by Tormod Volden. See the git log for the many other contributors.
7 changes: 7 additions & 0 deletions i2c.c
Original file line number Diff line number Diff line change
Expand Up @@ -194,11 +194,18 @@ static struct varlen_cmd i2c_cmd_get_reply[] = {
{ /* sentinel */ }
};

static port_err_t i2c_flush(struct port_interface *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,
Expand Down
101 changes: 69 additions & 32 deletions init.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,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;
Expand All @@ -59,13 +60,6 @@ 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;
Expand Down Expand Up @@ -142,7 +136,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)
{
Expand All @@ -159,14 +152,31 @@ static int release_gpio(int n, int input, int exported)

return 1;
}
#else
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;
}
#endif

static int gpio_sequence(struct port_interface *port, const char *s, size_t l)
{
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;

fprintf(stdout, "\nGPIO sequence start\n\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++;
Expand All @@ -181,47 +191,76 @@ static int gpio_sequence(struct port_interface *port, const char *s, size_t l)
l--;
}
} else if (!strncmp(s, "rts", 3)) {
sig_str = s;
gpio = -GPIO_RTS;
s += 3;
l -= 3;
} else if (!strncmp(s, "dtr", 3)) {
sig_str = s;
gpio = -GPIO_DTR;
s += 3;
l -= 3;
} else if (!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;
/* use ',' delimiter to bring 100ms delay between signal toggles.
* i.e -rts,dtr will reset rts, wait 100ms, set dtr
*
* use '&' delimiter to bring 0ms delay between signal toggles.
* i.e -rts&dtr will reset rts, and immediately set dtr
*
* you can also write -rts&dtr,,,rts,-dtr reset rts and set dtr without delay,
* then wait 300ms, set rts , wait 100ms, 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;
ret = 1;
break;
}
} else {
fprintf(stderr, "Character \'%c\' is not a digit\n", *s);
ret = 1;
break;
}

if(!delimiter){ //actual gpio driving, delimiters just bring delays
if (gpio < 0){
gpio = -gpio;
fprintf(stdout, "setting port signal %.3s to %i... ", sig_str, level);
ret = (port->gpio(port, gpio, level) != PORT_ERR_OK);
printStatus(stdout, ret);
}else{
fprintf(stdout, "setting gpio %i to %i... ", gpio, level);
ret = (drive_gpio(gpio, level, &gpio_to_release) != 1);
printStatus(stdout, 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(stdout, "sleep %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(stdout, "\n\nGPIO sequence end\n");
return ret;
}

Expand All @@ -239,7 +278,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;

Expand All @@ -258,15 +297,13 @@ 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)
{
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);
}
1 change: 1 addition & 0 deletions init.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Loading