diff --git a/Makefile b/Makefile index e3a019e..a102fae 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ PREFIX = /usr/local -CFLAGS += -Wall -g +CFLAGS += -Wall -g -DB460800 -DB921600 -DTERMIOS_TIMEOUT_MS=500 INSTALL = install diff --git a/README.md b/README.md new file mode 100644 index 0000000..3d87274 --- /dev/null +++ b/README.md @@ -0,0 +1,112 @@ +stm32flash +========== + +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. diff --git a/i2c.c b/i2c.c index 10e6bb1..fd15b7a 100644 --- a/i2c.c +++ b/i2c.c @@ -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, diff --git a/init.c b/init.c index 2e72385..47fbeba 100644 --- a/init.c +++ b/init.c @@ -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; @@ -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; @@ -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) { @@ -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++; @@ -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; } @@ -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; @@ -258,7 +297,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 +305,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..0249e72 100644 --- a/main.c +++ b/main.c @@ -259,8 +259,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; @@ -382,13 +388,15 @@ int main(int argc, char* argv[]) { fprintf(stdout, "Read-Protecting flash\n"); /* the device automatically performs a reset after the sending the ACK */ reset_flag = 0; - stm32_readprot_memory(stm); + if(stm32_readprot_memory(stm) == STM32_ERR_OK) + ret = 0; fprintf(stdout, "Done.\n"); } 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); + if(stm32_runprot_memory(stm) == STM32_ERR_OK) + ret = 0; fprintf(stdout, "Done.\n"); } else if (action == ACT_ERASE_ONLY) { ret = 0; @@ -412,7 +420,8 @@ int main(int argc, char* argv[]) { fprintf(diag, "Write-unprotecting flash\n"); /* the device automatically performs a reset after the sending the ACK */ reset_flag = 0; - stm32_wunprot_memory(stm); + if(stm32_wunprot_memory(stm) == STM32_ERR_OK) + ret = 0; fprintf(diag, "Done.\n"); } else if (action == ACT_WRITE) { @@ -560,11 +569,16 @@ int main(int argc, char* argv[]) { } 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); @@ -817,7 +831,16 @@ void show_help(char *name) { " This is useful if the reset fails\n" " -i GPIO_string GPIO sequence to enter/exit bootloader mode\n" " GPIO_string=[entry_seq][:[exit_seq]]\n" - " sequence=[-]n[,sequence]\n" + " sequence=[[-]signal]&|,[&|,][sequence]\n" + + " sequence is evaluated with the following delimiters:\n" + " ',' brings 100ms delay between signals\n" + " '&' brings 0ms delay between signals\n" + " the following signals can appear in sequence:\n" + " integer number represents GPIO pin\n" + " 'dtr' or 'rts' or 'brk' represents COM port signals\n" + " the following modificators can be applied to signals:\n" + " '-' resets signal\n" " -R Reset device at exit.\n" "\n" "Examples:\n" @@ -839,9 +862,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 -R -i -3&-2,2:3&-2,,,2 /dev/ttyS0\n" + " GPIO sequence to bring delays on start 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/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 1683b85..0e999b1 100644 --- a/serial_posix.c +++ b/serial_posix.c @@ -31,6 +31,12 @@ #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; @@ -178,7 +184,7 @@ static port_err_t serial_setup(serial_t *h, const serial_baud_t baud, 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); @@ -346,11 +352,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..b53a055 100644 --- a/serial_w32.c +++ b/serial_w32.c @@ -337,11 +337,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..32b1d1c 100644 --- a/stm32.c +++ b/stm32.c @@ -606,7 +606,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 +633,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 +660,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 +687,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 +714,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,7 +755,7 @@ 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 + if ((port->flags & PORT_STRETCH_W) && stm->cmd->er != STM32_CMD_EE_NS) stm32_warn_stretching("mass erase"); return STM32_ERR_UNKNOWN; @@ -842,7 +842,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; @@ -983,7 +983,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 +1076,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/stm32flash.1 b/stm32flash.1 index ca7acb7..11642c5 100644 --- a/stm32flash.1 +++ b/stm32flash.1 @@ -226,10 +226,18 @@ The format of .RS GPIO_string = [entry sequence][:[exit sequence]] .P -sequence = [\-]n[,sequence] +sequence=[[\-]signal]&|,[&|,][sequence] .RE .PD .P +Version 0.6 introduces delays between signals. You can use '&' delimiter to +bring 0ms delay or ',' delimiter to bring 100ms delay between signal toggle. +"," Delimiters can be used alone to bring n time 100ms delay in sequence. +e.g. "rts,,,,\-dtr" will set rts, then wait 400ms, then reset dtr. +"rts&\-dtr" will set rts, and reset dtr without delay. You can use "," delimiters +alone to bring any delay you want after port open but before flashing start. +.DP +.P In the above sequences, negative numbers correspond to GPIO at "low" level; numbers without sign correspond to GPIO at "high" level. The value "n" can either be the GPIO number on the host system or the @@ -241,7 +249,9 @@ Note: the string "\-brk" has no effect and is ignored. .PD .P -Note that the exit sequence is only executed if -R is specified. If -R is specified, but no exit sequence, a software-triggered reset will be performed. +Note that since 0.6 version the exit sequence is executed ALWAYS if specified. +This can help us to reset signals after failure is happened. 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: @@ -273,19 +283,35 @@ 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 program in flash. + 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 \-R \-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, 100ms 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, 300ms delay, GPIO_2=high .PD + +GPIO sequence to bring delays on start after port opening. +The command: +.PD 0 +.RS +stm32flash \-R \-i ,,,,,:rts&\-dtr,,,2 /dev/ttyS0\n", +.RE +provides: +.IP \(bu 2 +entry sequence: delay 500ms +.IP \(bu 2 +exit sequence: rts=high, dtr=low, 300ms delay, GPIO_2=high +.PD + + .SH EXAMPLES Get device information: .RS 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 +#include 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