Submitted by Neil Davey:

patch #4539: Ability to control the bit clock (usleep) delay
for ppi interface
* bitbang.c: Implement bitbang_delay() and its calibration.
* bitbang.h: Declare bitbang_delay().
* main.c: Add the ispdelay option (-i).
* pgm.h (struct programmer_t): Add the ispdelay parameter.
* par.c: Add calls to bitbang_delay() when requested.
* serbb_posix.c: (Ditto.)
* serbb_win32.c: (Ditto.)
* avrdude.1: Document the new -i option.
* doc/avrdude.texi: (Ditto.)


git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk/avrdude@610 81a1dc3b-b13d-400b-aceb-764788c761c2
This commit is contained in:
Joerg Wunsch 2006-08-17 15:06:20 +00:00
parent 0608a54a5e
commit 88e2614ee2
11 changed files with 188 additions and 37 deletions

View File

@ -1,3 +1,18 @@
2006-08-17 Joerg Wunsch <j@uriah.heep.sax.de>
Submitted by Neil Davey:
patch #4539: Ability to control the bit clock (usleep) delay
for ppi interface
* bitbang.c: Implement bitbang_delay() and its calibration.
* bitbang.h: Declare bitbang_delay().
* main.c: Add the ispdelay option (-i).
* pgm.h (struct programmer_t): Add the ispdelay parameter.
* par.c: Add calls to bitbang_delay() when requested.
* serbb_posix.c: (Ditto.)
* serbb_win32.c: (Ditto.)
* avrdude.1: Document the new -i option.
* doc/avrdude.texi: (Ditto.)
2006-08-14 Joerg Wunsch <j@uriah.heep.sax.de> 2006-08-14 Joerg Wunsch <j@uriah.heep.sax.de>
Submitted by <chris@awaretechs.com>: Submitted by <chris@awaretechs.com>:

3
NEWS
View File

@ -22,6 +22,9 @@ Current:
* Add high-voltage mode programming for the STK500 (both, * Add high-voltage mode programming for the STK500 (both,
parallel, and high-voltage serial programming). parallel, and high-voltage serial programming).
* Allow for specifying the ISP clock delay as an option for
bit-bang programming adapters.
Version 5.1: Version 5.1:
* New devices supported: * New devices supported:

View File

@ -19,7 +19,7 @@
.\" .\"
.\" $Id$ .\" $Id$
.\" .\"
.Dd DATE July 19, 2006 .Dd DATE August 16, 2006
.Os .Os
.Dt AVRDUDE 1 .Dt AVRDUDE 1
.Sh NAME .Sh NAME
@ -38,6 +38,7 @@
.Op \&, Ns Ar exitspec .Op \&, Ns Ar exitspec
.Oc .Oc
.Op Fl F .Op Fl F
.Op Fl i Ar delay
.Op Fl n .Op Fl n
.Op Fl P Ar port .Op Fl P Ar port
.Op Fl q .Op Fl q
@ -330,6 +331,24 @@ reasonable before continuing. Since it can happen from time to time
that a device has a broken (erased or overwritten) device signature that a device has a broken (erased or overwritten) device signature
but is otherwise operating normally, this options is provided to but is otherwise operating normally, this options is provided to
override the check. override the check.
.It Fl i Ar delay
For bitbang-type programmers, delay for approximately
.Ar delay
microseconds between each bit state change.
If the host system is very fast, or the target runs off a slow clock
(like a 32 kHz crystal, or the 128 kHz internal RC oscillator), this
can become necessary to satisfy the requirement that the ISP clock
frequency must not be higher than 1/4 of the CPU clock frequency.
This is implemented as a spin-loop delay to allow even for very
short delays.
On Unix-style operating systems, the spin loop is initially calibrated
against a system timer, so the number of microseconds might be rather
realistic, assuming a constant system load while
.Nm
is running.
On Win32 operating systems, a preconfigured number of cycles per
microsecond is assumed that might be off a bit for very fast or very
slow machines.
.It Fl n .It Fl n
No-write - disables actually writing data to the MCU (useful for debugging No-write - disables actually writing data to the MCU (useful for debugging
.Nm avrdude .Nm avrdude

View File

@ -28,18 +28,103 @@
#include <unistd.h> #include <unistd.h>
#include <errno.h> #include <errno.h>
#if !defined(WIN32NATIVE)
# include <signal.h>
# include <sys/time.h>
#endif
#include "avr.h" #include "avr.h"
#include "pindefs.h" #include "pindefs.h"
#include "pgm.h" #include "pgm.h"
#include "par.h" #include "par.h"
#include "serbb.h" #include "serbb.h"
#define SLOW_TOGGLE 0
extern char * progname; extern char * progname;
extern int do_cycles; extern int do_cycles;
extern int verbose; extern int verbose;
static int delay_decrement;
#if !defined(WIN32NATIVE)
static volatile int done;
typedef void (*mysighandler_t)(int);
static mysighandler_t saved_alarmhandler;
static void alarmhandler(int signo)
{
done = 1;
signal(SIGALRM, saved_alarmhandler);
}
#endif /* !WIN32NATIVE */
/*
* Calibrate the microsecond delay loop below.
*/
static void bitbang_calibrate_delay(void)
{
/*
* Right now, we don't have any Win32 implementation for this, so we
* can only run on a preconfigured delay stepping there. The figure
* below should at least be correct within an order of magnitude,
* judging from the auto-calibration figures seen on various Unix
* systems on comparable hardware.
*/
#if defined(WIN32NATIVE)
delay_decrement = 100;
#else /* !WIN32NATIVE */
struct itimerval itv;
volatile int i;
if (verbose >= 2)
fprintf(stderr,
"%s: Calibrating delay loop...",
progname);
i = 0;
done = 0;
saved_alarmhandler = signal(SIGALRM, alarmhandler);
/*
* Set ITIMER_REAL to 100 ms. All known systems have a timer
* granularity of 10 ms or better, so counting the delay cycles
* accumulating over 100 ms should give us a rather realistic
* picture, without annoying the user by a lengthy startup time (as
* an alarm(1) would do). Of course, if heavy system activity
* happens just during calibration but stops before the remaining
* part of AVRDUDE runs, this will yield wrong values. There's not
* much we can do about this.
*/
itv.it_value.tv_sec = 0;
itv.it_value.tv_usec = 100000;
itv.it_interval.tv_sec = itv.it_interval.tv_usec = 0;
setitimer(ITIMER_REAL, &itv, 0);
while (!done)
i--;
itv.it_value.tv_sec = itv.it_value.tv_usec = 0;
setitimer(ITIMER_REAL, &itv, 0);
/*
* Calculate back from 100 ms to 1 us.
*/
delay_decrement = -i / 100000;
if (verbose >= 2)
fprintf(stderr,
" calibrated to %d cycles per us\n",
delay_decrement);
#endif /* WIN32NATIVE */
}
/*
* Delay for approximately the number of microseconds specified.
* usleep()'s granularity is usually like 1 ms or 10 ms, so it's not
* really suitable for short delays in bit-bang algorithms.
*/
void bitbang_delay(int us)
{
volatile int del = us * delay_decrement;
while (del > 0)
del--;
}
/* /*
* transmit and receive a byte of data to/from the AVR device * transmit and receive a byte of data to/from the AVR device
*/ */
@ -204,6 +289,8 @@ int bitbang_initialize(PROGRAMMER * pgm, AVRPART * p)
int rc; int rc;
int tries; int tries;
bitbang_calibrate_delay();
pgm->powerup(pgm); pgm->powerup(pgm);
usleep(20000); usleep(20000);

View File

@ -25,6 +25,7 @@
int bitbang_setpin(int fd, int pin, int value); int bitbang_setpin(int fd, int pin, int value);
int bitbang_getpin(int fd, int pin); int bitbang_getpin(int fd, int pin);
int bitbang_highpulsepin(int fd, int pin); int bitbang_highpulsepin(int fd, int pin);
void bitbang_delay(unsigned int us);
int bitbang_rdy_led (PROGRAMMER * pgm, int value); int bitbang_rdy_led (PROGRAMMER * pgm, int value);
int bitbang_err_led (PROGRAMMER * pgm, int value); int bitbang_err_led (PROGRAMMER * pgm, int value);

View File

@ -584,6 +584,23 @@ to time that a device has a broken (erased or overwritten) device
signature but is otherwise operating normally, this options is provided signature but is otherwise operating normally, this options is provided
to override the check. to override the check.
@item -i @var{delay}
For bitbang-type programmers, delay for approximately
@var{delay}
microseconds between each bit state change.
If the host system is very fast, or the target runs off a slow clock
(like a 32 kHz crystal, or the 128 kHz internal RC oscillator), this
can become necessary to satisfy the requirement that the ISP clock
frequency must not be higher than 1/4 of the CPU clock frequency.
This is implemented as a spin-loop delay to allow even for very
short delays.
On Unix-style operating systems, the spin loop is initially calibrated
against a system timer, so the number of microseconds might be rather
realistic, assuming a constant system load while AVRDUDE is running.
On Win32 operating systems, a preconfigured number of cycles per
microsecond is assumed that might be off a bit for very fast or very
slow machines.
@item -n @item -n
No-write - disables actually writing data to the MCU (useful for No-write - disables actually writing data to the MCU (useful for
debugging AVRDUDE). debugging AVRDUDE).

21
main.c
View File

@ -105,6 +105,7 @@ void usage(void)
" -C <config-file> Specify location of configuration file.\n" " -C <config-file> Specify location of configuration file.\n"
" -c <programmer> Specify programmer type.\n" " -c <programmer> Specify programmer type.\n"
" -D Disable auto erase for flash memory\n" " -D Disable auto erase for flash memory\n"
" -i <delay> ISP Clock Delay [in microseconds]\n"
" -P <port> Specify connection port.\n" " -P <port> Specify connection port.\n"
" -F Override invalid signature check.\n" " -F Override invalid signature check.\n"
" -e Perform a chip erase.\n" " -e Perform a chip erase.\n"
@ -695,6 +696,7 @@ int main(int argc, char * argv [])
char * e; /* for strtol() error checking */ char * e; /* for strtol() error checking */
int baudrate; /* override default programmer baud rate */ int baudrate; /* override default programmer baud rate */
double bitclock; /* Specify programmer bit clock (JTAG ICE) */ double bitclock; /* Specify programmer bit clock (JTAG ICE) */
int ispdelay; /* Specify the delay for ISP clock */
int safemode; /* Enable safemode, 1=safemode on, 0=normal */ int safemode; /* Enable safemode, 1=safemode on, 0=normal */
int silentsafe; /* Don't ask about fuses, 1=silent, 0=normal */ int silentsafe; /* Don't ask about fuses, 1=silent, 0=normal */
unsigned char safemode_lfuse = 0xff; unsigned char safemode_lfuse = 0xff;
@ -752,6 +754,7 @@ int main(int argc, char * argv [])
set_cycles = -1; set_cycles = -1;
baudrate = 0; baudrate = 0;
bitclock = 0.0; bitclock = 0.0;
ispdelay = 0;
safemode = 1; /* Safemode on by default */ safemode = 1; /* Safemode on by default */
silentsafe = 0; /* Ask by default */ silentsafe = 0; /* Ask by default */
@ -802,7 +805,7 @@ int main(int argc, char * argv [])
/* /*
* process command line arguments * process command line arguments
*/ */
while ((ch = getopt(argc,argv,"?b:B:c:C:DeE:Fnp:P:qstU:uvVyY:")) != -1) { while ((ch = getopt(argc,argv,"?b:B:c:C:DeE:Fi:np:P:qstU:uvVyY:")) != -1) {
switch (ch) { switch (ch) {
case 'b': /* override default programmer baud rate */ case 'b': /* override default programmer baud rate */
@ -823,6 +826,15 @@ int main(int argc, char * argv [])
} }
break; break;
case 'i': /* specify isp clock delay */
ispdelay = strtol(optarg, &e,10);
if ((e == optarg) || (*e != 0) || ispdelay == 0) {
fprintf(stderr, "%s: invalid isp clock delay specified '%s'\n",
progname, optarg);
exit(1);
}
break;
case 'c': /* programmer id */ case 'c': /* programmer id */
programmer = optarg; programmer = optarg;
break; break;
@ -1133,6 +1145,13 @@ int main(int argc, char * argv [])
pgm->bitclock = bitclock * 1e-6; pgm->bitclock = bitclock * 1e-6;
} }
if (ispdelay != 0) {
if (verbose) {
fprintf(stderr, "%sSetting isp clock delay: %3i\n", progbuf, ispdelay);
}
pgm->ispdelay = ispdelay;
}
rc = pgm->open(pgm, port); rc = pgm->open(pgm, port);
if (rc < 0) { if (rc < 0) {
exitrc = 1; exitrc = 1;

31
par.c
View File

@ -48,8 +48,6 @@ extern int verbose;
#if HAVE_PARPORT #if HAVE_PARPORT
#define SLOW_TOGGLE 0
struct ppipins_t { struct ppipins_t {
int pin; int pin;
int reg; int reg;
@ -102,9 +100,8 @@ static int par_setpin(PROGRAMMER * pgm, int pin, int value)
else else
ppi_clr(pgm->fd, ppipins[pin].reg, ppipins[pin].bit); ppi_clr(pgm->fd, ppipins[pin].reg, ppipins[pin].bit);
#if SLOW_TOGGLE if (pgm->ispdelay > 1)
usleep(1000); bitbang_delay(pgm->ispdelay);
#endif
return 0; return 0;
} }
@ -155,24 +152,20 @@ static int par_highpulsepin(PROGRAMMER * pgm, int pin)
if (inverted) { if (inverted) {
ppi_clr(pgm->fd, ppipins[pin].reg, ppipins[pin].bit); ppi_clr(pgm->fd, ppipins[pin].reg, ppipins[pin].bit);
#if SLOW_TOGGLE if (pgm->ispdelay > 1)
usleep(1000); bitbang_delay(pgm->ispdelay);
#endif
ppi_set(pgm->fd, ppipins[pin].reg, ppipins[pin].bit);
#if SLOW_TOGGLE ppi_set(pgm->fd, ppipins[pin].reg, ppipins[pin].bit);
usleep(1000); if (pgm->ispdelay > 1)
#endif bitbang_delay(pgm->ispdelay);
} else { } else {
ppi_set(pgm->fd, ppipins[pin].reg, ppipins[pin].bit); ppi_set(pgm->fd, ppipins[pin].reg, ppipins[pin].bit);
#if SLOW_TOGGLE if (pgm->ispdelay > 1)
usleep(1000); bitbang_delay(pgm->ispdelay);
#endif
ppi_clr(pgm->fd, ppipins[pin].reg, ppipins[pin].bit);
#if SLOW_TOGGLE ppi_clr(pgm->fd, ppipins[pin].reg, ppipins[pin].bit);
usleep(1000); if (pgm->ispdelay > 1)
#endif bitbang_delay(pgm->ispdelay);
} }
return 0; return 0;

1
pgm.h
View File

@ -48,6 +48,7 @@ typedef struct programmer_t {
int ppictrl; int ppictrl;
int baudrate; int baudrate;
double bitclock; /* JTAG ICE clock period in microseconds */ double bitclock; /* JTAG ICE clock period in microseconds */
int ispdelay; /* ISP clock delay */
int fd; int fd;
int page_size; /* page size if the programmer supports paged write/load */ int page_size; /* page size if the programmer supports paged write/load */
int (*rdy_led) (struct programmer_t * pgm, int value); int (*rdy_led) (struct programmer_t * pgm, int value);

View File

@ -158,14 +158,12 @@ static int serbb_highpulsepin(PROGRAMMER * pgm, int pin)
return -1; return -1;
serbb_setpin(pgm, pin, 1); serbb_setpin(pgm, pin, 1);
#if SLOW_TOGGLE if (pgm->ispdelay > 1)
usleep(1000); bitbang_delay(pgm->ispdelay);
#endif
serbb_setpin(pgm, pin, 0);
#if SLOW_TOGGLE serbb_setpin(pgm, pin, 0);
usleep(1000); if (pgm->ispdelay > 1)
#endif bitbang_delay(pgm->ispdelay);
return 0; return 0;
} }

View File

@ -230,14 +230,12 @@ static int serbb_highpulsepin(PROGRAMMER * pgm, int pin)
return -1; return -1;
serbb_setpin(pgm, pin, 1); serbb_setpin(pgm, pin, 1);
#if SLOW_TOGGLE if (pgm->ispdelay > 1)
usleep(1000); bitbang_delay(pgm->ispdelay);
#endif
serbb_setpin(pgm, pin, 0);
#if SLOW_TOGGLE serbb_setpin(pgm, pin, 0);
usleep(1000); if (pgm->ispdelay > 1)
#endif bitbang_delay(pgm->ispdelay);
return 0; return 0;
} }