Add -xdelay=n for -c wiring to modify sleep after dtr/rts reset

This commit is contained in:
Stefan Rueger
2023-09-26 23:19:34 +01:00
parent 8ed9615f86
commit 35dcf686a2
3 changed files with 65 additions and 83 deletions

View File

@@ -1666,7 +1666,7 @@ query on flash prepared with -xnometadata yields useful results.
.It Ar delay=<n>
Add a <n> ms delay after reset. This can be useful if a board takes a
particularly long time to exit from external reset. <n> can be negative,
in which case the default 120 ms delay after issuing reset will be
in which case the default 100 ms delay after issuing reset will be
shortened accordingly.
.It Ar strict
Urclock has a faster, but slightly different strategy than -c arduino to
@@ -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=<n>
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=<n>
Add a <n> 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. <n> can be negative, in which case the
default 80 ms delay after issuing reset will be shortened accordingly.
.It Ar help
Show help menu and exit.
.El

View File

@@ -1304,7 +1304,7 @@ yields useful results.
@item @samp{delay=<n>}
Add a <n> ms delay after reset. This can be useful if a board takes a
particularly long time to exit from external reset. <n> can be negative,
in which case the default 120 ms delay after issuing reset will be
in which case the default 100 ms delay after issuing reset will be
shortened accordingly.
@item @samp{strict}
Urclock has a faster, but slightly different strategy than -c arduino to
@@ -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=<n>}
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=<n>}
Add a <n> milliseconds delay after reset. This can be useful if a board
takes a particularly long time to exit from external reset. <n> can be
negative, in which case the default 80 ms delay after issuing reset will
be shortened accordingly.
@item @samp{help}
Show help menu and exit.
@end table

View File

@@ -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 WIRINGPDATA(pgm) ((struct wiringpdata *)(((struct pdata *)(pgm->cookie)) -> chained_pdata))
#define STK500V2PDATA(pgm) ((struct pdata *)(pgm->cookie))
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=<arg> Wait <arg> [ms] before protocol sync after port open\n");
msg_error(" -xsnooze=<arg> Wait snooze [ms] before protocol sync after port open\n");
msg_error(" -xdelay=<arg> 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,41 @@ 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);
usleep(20*1000);
/* Set high, so a direct connection to reset works. */
// 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((80+delay) > 0)
usleep((80+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;
}