diff --git a/src/arduino.c b/src/arduino.c index 3ca836158..7c705da2a 100644 --- a/src/arduino.c +++ b/src/arduino.c @@ -97,10 +97,12 @@ static int arduino_open(PROGRAMMER *pgm, const char *port) { usleep(250 * 1000); // Pull the RTS/DTR line low to reset AVR serial_set_dtr_rts(&pgm->fd, 1); - usleep(50 * 1000); - // Set the RTS/DTR line back to high + // Max 100 us: charging a cap longer creates a high reset spike above Vcc + usleep(100); + // Set the RTS/DTR line back to high, so direct connection to reset works serial_set_dtr_rts(&pgm->fd, 0); - usleep(50 * 1000); + + usleep(100 * 1000); /* * drain any extraneous input diff --git a/src/avrdude.1 b/src/avrdude.1 index c2e41f38f..f1e352913 100644 --- a/src/avrdude.1 +++ b/src/avrdude.1 @@ -1782,15 +1782,20 @@ Show help menu and exit. .El .It Ar Wiring When using the Wiring programmer type, the -following optional extended parameter is accepted: +following optional extended parameters are accepted: .Bl -tag -offset indent -width indent -.It Ar snooze=<0..32767> +.It Ar snooze= After performing the port open phase, AVRDUDE will wait/snooze for .Ar snooze milliseconds before continuing to the protocol sync phase. No toggling of DTR/RTS is performed if .Ar snooze is greater than 0. +.It Ar delay= +Add a milliseconds delay after resetting the part through toggling the +DTR/RTS lines. This can be useful if a board takes a particularly long +time to exit from external reset. can be negative, in which case the +default 100 ms delay after issuing reset will be shortened accordingly. .It Ar help Show help menu and exit. .El diff --git a/src/doc/avrdude.texi b/src/doc/avrdude.texi index 31034e222..f71598ba2 100644 --- a/src/doc/avrdude.texi +++ b/src/doc/avrdude.texi @@ -1438,12 +1438,17 @@ Show help menu and exit. @cindex @code{-x} Wiring @item Wiring -The Wiring programmer type accepts the following extended parameter: +The Wiring programmer type accepts the following extended parameters: @table @code -@item @samp{snooze=@var{0..32767}} +@item @samp{snooze=} After performing the port open phase, AVRDUDE will wait/snooze for @var{snooze} milliseconds before continuing to the protocol sync phase. No toggling of DTR/RTS is performed if @var{snooze} > 0. +@item @samp{delay=} +Add a milliseconds delay after reset. This can be useful if a board +takes a particularly long time to exit from external reset. can be +negative, in which case the default 100 ms delay after issuing reset will +be shortened accordingly. @item @samp{help} Show help menu and exit. @end table diff --git a/src/stk500.c b/src/stk500.c index 2c35ac2fc..46678a8a2 100644 --- a/src/stk500.c +++ b/src/stk500.c @@ -112,9 +112,11 @@ int stk500_getsync(const PROGRAMMER *pgm) { // This code assumes a negative-logic USB to TTL serial adapter // Pull the RTS/DTR line low to reset AVR: it is still high from open()/last attempt serial_set_dtr_rts(&pgm->fd, 1); - usleep(20*1000); - // Set the RTS/DTR line back to high + // Max 100 us: charging a cap longer creates a high reset spike above Vcc + usleep(100); + // Set the RTS/DTR line back to high, so direct connection to reset works serial_set_dtr_rts(&pgm->fd, 0); + usleep(20*1000); stk500_drain(pgm, 0); } diff --git a/src/urclock.c b/src/urclock.c index ed919a07f..c65e01e72 100644 --- a/src/urclock.c +++ b/src/urclock.c @@ -2220,12 +2220,13 @@ static int urclock_open(PROGRAMMER *pgm, const char *port) { usleep(20*1000); // Pull the RTS/DTR line low to reset AVR serial_set_dtr_rts(&pgm->fd, 1); - usleep(20*1000); - // Set the RTS/DTR line back to high + // Max 100 us: charging a cap longer creates a high reset spike above Vcc + usleep(100); + // Set the RTS/DTR line back to high, so direct connection to reset works serial_set_dtr_rts(&pgm->fd, 0); - if((100+ur.delay) > 0) - usleep((100+ur.delay)*1000); // Wait until board comes out of reset + if((120+ur.delay) > 0) + usleep((120+ur.delay)*1000); // Wait until board comes out of reset pmsg_debug("%4ld ms: enter urclock_getsync()\n", avr_mstimestamp()); if(urclock_getsync(pgm) < 0) diff --git a/src/wiring.c b/src/wiring.c index ae99b3046..61cd9f37c 100644 --- a/src/wiring.c +++ b/src/wiring.c @@ -28,14 +28,13 @@ * e.g. chip erase). * DTR and RTS signals are diddled to set the board into programming mode. * - * Also includes an extended parameter to introduce a delay after opening - * to accommodate multi-layered programmers/bootloaders. If the extended - * parameter 'snooze' > 0, then no DTR/RTS toggle takes place, and - * AVRDUDE will wait that amount of time in milliseconds before syncing. + * Also includes an extended parameter to introduce a delay after opening to + * accommodate multi-layered programmers/bootloaders. If the extended + * parameter 'snooze' > 0, then no DTR/RTS toggle takes place, and AVRDUDE + * will wait that amount of time in milliseconds before syncing. If the + * extended parameter 'delay' is set then this number of milliseconds is + * added to the usual delay of 80 ms after toggling DTR/RTS. * - * Unfortunately, there is no way to easily chain private programmer data - * when we "inherit" programmer types as we have (stk500v2). Sooooo, a - * *cringe* global variable is used to store the snooze time. */ #include "ac_cfg.h" @@ -55,84 +54,60 @@ /* * Private data for this programmer. */ -struct wiringpdata -{ - /* - * We just have the single snooze integer to carry around for now. - */ - int snoozetime; +struct wiringpdata { + int snoozetime, delay; }; /* wiringpdata is our private data */ /* pdata is stk500v2's private data (inherited) */ -#define WIRINGPDATA(x) ((struct wiringpdata *)(x)) - -#define STK500V2PDATA(pgm) ((struct pdata *)(pgm->cookie)) - +#define WIRINGPDATA(pgm) ((struct wiringpdata *)(((struct pdata *)(pgm->cookie)) -> chained_pdata)) -static void wiring_setup(PROGRAMMER * pgm) -{ - void *mycookie; - - /* - * First, have STK500v2 backend allocate its own private data. - */ +static void wiring_setup(PROGRAMMER *pgm) { + // First, have STK500v2 backend allocate its own private data stk500v2_setup(pgm); - /* - * Now prepare our data - */ - if ((mycookie = malloc(sizeof(struct wiringpdata))) == 0) { - pmsg_error("out of memory allocating private data\n"); - exit(1); - } - memset(mycookie, 0, sizeof(struct wiringpdata)); - WIRINGPDATA(mycookie)->snoozetime = 0; - - /* - * Store our own cookie in a safe place for the time being. - */ - STK500V2PDATA(pgm)->chained_pdata = mycookie; + // Then prepare our data and store in a safe place for the time being + ((struct pdata *)(pgm->cookie))->chained_pdata = cfg_malloc(__func__, sizeof(struct wiringpdata)); } -static void wiring_teardown(PROGRAMMER * pgm) -{ - void *mycookie; - - mycookie = STK500V2PDATA(pgm)->chained_pdata; - - free(mycookie); - +static void wiring_teardown(PROGRAMMER *pgm) { + free(((struct pdata *)(pgm->cookie))->chained_pdata); stk500v2_teardown(pgm); } static int wiring_parseextparms(const PROGRAMMER *pgm, const LISTID extparms) { LNODEID ln; - const char *extended_param; + const char *extended_param, *errstr; int rv = 0; - void *mycookie = STK500V2PDATA(pgm)->chained_pdata; for (ln = lfirst(extparms); ln; ln = lnext(ln)) { extended_param = ldata(ln); if (str_starts(extended_param, "snooze=")) { - int newsnooze; - if (sscanf(extended_param, "snooze=%i", &newsnooze) != 1 || - newsnooze < 0) { - pmsg_error("invalid snooze time '%s'\n", extended_param); + int val = str_int(extended_param+7, STR_INT32, &errstr); + if(errstr || val < 0) { + pmsg_error("-x%s: %s\n", extended_param, errstr? errstr: "snooze time cannot be negative"); rv = -1; continue; } - pmsg_notice2("wiring_parseextparms(): snooze time set to %d ms\n", newsnooze); - WIRINGPDATA(mycookie)->snoozetime = newsnooze; - + pmsg_notice2("%s(): snooze time set to %d ms\n", __func__, val); + WIRINGPDATA(pgm)->snoozetime = val; continue; - } - if (str_eq(extended_param, "help")) { + } else if (str_starts(extended_param, "delay=")) { + int val = str_int(extended_param+6, STR_INT32, &errstr); + if(errstr) { + pmsg_error("-x%s: %s\n", extended_param, errstr); + return -1; + } + pmsg_notice2("%s(): delay set to %d ms\n", __func__, val); + WIRINGPDATA(pgm)->delay = val; + continue; + } else if (str_eq(extended_param, "help")) { msg_error("%s -c %s extended options:\n", progname, pgmid); - msg_error(" -xsnooze= Wait [ms] before protocol sync after port open\n"); + msg_error(" -xsnooze= Wait snooze [ms] before protocol sync after port open\n"); + msg_error(" -xdelay= Add delay [ms] after reset, can be negative\n"); msg_error(" -xhelp Show this help menu and exit\n"); exit(0); } @@ -146,7 +121,6 @@ static int wiring_parseextparms(const PROGRAMMER *pgm, const LISTID extparms) { static int wiring_open(PROGRAMMER *pgm, const char *port) { int timetosnooze; - void *mycookie = STK500V2PDATA(pgm)->chained_pdata; union pinfo pinfo; strcpy(pgm->port, port); @@ -154,43 +128,42 @@ static int wiring_open(PROGRAMMER *pgm, const char *port) { pinfo.serialinfo.cflags = SERIAL_8N1; serial_open(port, pinfo, &pgm->fd); - /* If we have a snoozetime, then we wait and do NOT toggle DTR/RTS */ - - if (WIRINGPDATA(mycookie)->snoozetime > 0) { - timetosnooze = WIRINGPDATA(mycookie)->snoozetime; + // If we have a snoozetime, then we wait and do NOT toggle DTR/RTS + if (WIRINGPDATA(pgm)->snoozetime > 0) { + timetosnooze = WIRINGPDATA(pgm)->snoozetime; pmsg_notice2("wiring_open(): snoozing for %d ms\n", timetosnooze); while (timetosnooze--) usleep(1000); pmsg_notice2("wiring_open(): done snoozing\n"); } else { - /* Perform Wiring programming mode RESET. */ - /* This effectively *releases* both DTR and RTS. */ - /* i.e. both DTR and RTS rise to a HIGH logic level */ - /* since they are active LOW signals. */ - + // This code assumes a negative-logic USB to TTL serial adapter + // Set RTS/DTR high to discharge the series-capacitor, if present pmsg_notice2("wiring_open(): releasing DTR/RTS\n"); - serial_set_dtr_rts(&pgm->fd, 0); usleep(50*1000); - /* After releasing for 50 milliseconds, DTR and RTS */ - /* are asserted (i.e. logic LOW) again. */ - + // Pull the RTS/DTR line low to reset AVR pmsg_notice2("wiring_open(): asserting DTR/RTS\n"); - serial_set_dtr_rts(&pgm->fd, 1); - usleep(50*1000); - /* Set high, so a direct connection to reset works. */ + // Max 100 us: charging a cap longer creates a high reset spike above Vcc + usleep(100); + // Set the RTS/DTR line back to high, so direct connection to reset works serial_set_dtr_rts(&pgm->fd, 0); + + int delay = WIRINGPDATA(pgm)->delay; + if((100+delay) > 0) + usleep((100+delay)*1000); // Wait until board comes out of reset } - /* drain any extraneous input */ + // Drain any extraneous input stk500v2_drain(pgm, 0); - if (stk500v2_getsync(pgm) < 0) + if (stk500v2_getsync(pgm) < 0) { + pmsg_error("stk500v2_getsync() failed; try -xdelay=n with some n in [-80, 100]\n"); return -1; + } return 0; }