From 88e2614ee2fc8f99aace0bc2403073330c834342 Mon Sep 17 00:00:00 2001 From: Joerg Wunsch Date: Thu, 17 Aug 2006 15:06:20 +0000 Subject: [PATCH] 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 --- ChangeLog | 15 ++++++++ NEWS | 3 ++ avrdude.1 | 21 ++++++++++- bitbang.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++-- bitbang.h | 1 + doc/avrdude.texi | 17 +++++++++ main.c | 21 ++++++++++- par.c | 31 +++++++---------- pgm.h | 1 + serbb_posix.c | 12 +++---- serbb_win32.c | 12 +++---- 11 files changed, 188 insertions(+), 37 deletions(-) diff --git a/ChangeLog b/ChangeLog index fc412090..eddb33ed 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,18 @@ +2006-08-17 Joerg Wunsch + + 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 Submitted by : diff --git a/NEWS b/NEWS index c7aee8b3..8e43b640 100644 --- a/NEWS +++ b/NEWS @@ -22,6 +22,9 @@ Current: * Add high-voltage mode programming for the STK500 (both, parallel, and high-voltage serial programming). + * Allow for specifying the ISP clock delay as an option for + bit-bang programming adapters. + Version 5.1: * New devices supported: diff --git a/avrdude.1 b/avrdude.1 index 94fa5977..3e86ed4a 100644 --- a/avrdude.1 +++ b/avrdude.1 @@ -19,7 +19,7 @@ .\" .\" $Id$ .\" -.Dd DATE July 19, 2006 +.Dd DATE August 16, 2006 .Os .Dt AVRDUDE 1 .Sh NAME @@ -38,6 +38,7 @@ .Op \&, Ns Ar exitspec .Oc .Op Fl F +.Op Fl i Ar delay .Op Fl n .Op Fl P Ar port .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 but is otherwise operating normally, this options is provided to 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 No-write - disables actually writing data to the MCU (useful for debugging .Nm avrdude diff --git a/bitbang.c b/bitbang.c index 6cbb1689..e6102c7f 100644 --- a/bitbang.c +++ b/bitbang.c @@ -28,18 +28,103 @@ #include #include +#if !defined(WIN32NATIVE) +# include +# include +#endif + #include "avr.h" #include "pindefs.h" #include "pgm.h" #include "par.h" #include "serbb.h" -#define SLOW_TOGGLE 0 - extern char * progname; extern int do_cycles; 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 */ @@ -204,6 +289,8 @@ int bitbang_initialize(PROGRAMMER * pgm, AVRPART * p) int rc; int tries; + bitbang_calibrate_delay(); + pgm->powerup(pgm); usleep(20000); diff --git a/bitbang.h b/bitbang.h index b428e604..90f0d481 100644 --- a/bitbang.h +++ b/bitbang.h @@ -25,6 +25,7 @@ int bitbang_setpin(int fd, int pin, int value); int bitbang_getpin(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_err_led (PROGRAMMER * pgm, int value); diff --git a/doc/avrdude.texi b/doc/avrdude.texi index 5f304a47..1babea75 100644 --- a/doc/avrdude.texi +++ b/doc/avrdude.texi @@ -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 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 No-write - disables actually writing data to the MCU (useful for debugging AVRDUDE). diff --git a/main.c b/main.c index b0a2bee3..64a11e7a 100644 --- a/main.c +++ b/main.c @@ -105,6 +105,7 @@ void usage(void) " -C Specify location of configuration file.\n" " -c Specify programmer type.\n" " -D Disable auto erase for flash memory\n" + " -i ISP Clock Delay [in microseconds]\n" " -P Specify connection port.\n" " -F Override invalid signature check.\n" " -e Perform a chip erase.\n" @@ -695,6 +696,7 @@ int main(int argc, char * argv []) char * e; /* for strtol() error checking */ int baudrate; /* override default programmer baud rate */ 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 silentsafe; /* Don't ask about fuses, 1=silent, 0=normal */ unsigned char safemode_lfuse = 0xff; @@ -752,6 +754,7 @@ int main(int argc, char * argv []) set_cycles = -1; baudrate = 0; bitclock = 0.0; + ispdelay = 0; safemode = 1; /* Safemode on by default */ silentsafe = 0; /* Ask by default */ @@ -802,7 +805,7 @@ int main(int argc, char * argv []) /* * 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) { case 'b': /* override default programmer baud rate */ @@ -823,6 +826,15 @@ int main(int argc, char * argv []) } 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 */ programmer = optarg; break; @@ -1133,6 +1145,13 @@ int main(int argc, char * argv []) 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); if (rc < 0) { exitrc = 1; diff --git a/par.c b/par.c index 7b7766d5..7cc30ff4 100644 --- a/par.c +++ b/par.c @@ -48,8 +48,6 @@ extern int verbose; #if HAVE_PARPORT -#define SLOW_TOGGLE 0 - struct ppipins_t { int pin; int reg; @@ -102,9 +100,8 @@ static int par_setpin(PROGRAMMER * pgm, int pin, int value) else ppi_clr(pgm->fd, ppipins[pin].reg, ppipins[pin].bit); -#if SLOW_TOGGLE - usleep(1000); -#endif + if (pgm->ispdelay > 1) + bitbang_delay(pgm->ispdelay); return 0; } @@ -155,24 +152,20 @@ static int par_highpulsepin(PROGRAMMER * pgm, int pin) if (inverted) { ppi_clr(pgm->fd, ppipins[pin].reg, ppipins[pin].bit); -#if SLOW_TOGGLE - usleep(1000); -#endif - ppi_set(pgm->fd, ppipins[pin].reg, ppipins[pin].bit); + if (pgm->ispdelay > 1) + bitbang_delay(pgm->ispdelay); -#if SLOW_TOGGLE - usleep(1000); -#endif + ppi_set(pgm->fd, ppipins[pin].reg, ppipins[pin].bit); + if (pgm->ispdelay > 1) + bitbang_delay(pgm->ispdelay); } else { ppi_set(pgm->fd, ppipins[pin].reg, ppipins[pin].bit); -#if SLOW_TOGGLE - usleep(1000); -#endif - ppi_clr(pgm->fd, ppipins[pin].reg, ppipins[pin].bit); + if (pgm->ispdelay > 1) + bitbang_delay(pgm->ispdelay); -#if SLOW_TOGGLE - usleep(1000); -#endif + ppi_clr(pgm->fd, ppipins[pin].reg, ppipins[pin].bit); + if (pgm->ispdelay > 1) + bitbang_delay(pgm->ispdelay); } return 0; diff --git a/pgm.h b/pgm.h index f03fdbb2..be4bd105 100644 --- a/pgm.h +++ b/pgm.h @@ -48,6 +48,7 @@ typedef struct programmer_t { int ppictrl; int baudrate; double bitclock; /* JTAG ICE clock period in microseconds */ + int ispdelay; /* ISP clock delay */ int fd; int page_size; /* page size if the programmer supports paged write/load */ int (*rdy_led) (struct programmer_t * pgm, int value); diff --git a/serbb_posix.c b/serbb_posix.c index b023df59..b78cddae 100644 --- a/serbb_posix.c +++ b/serbb_posix.c @@ -158,14 +158,12 @@ static int serbb_highpulsepin(PROGRAMMER * pgm, int pin) return -1; serbb_setpin(pgm, pin, 1); - #if SLOW_TOGGLE - usleep(1000); - #endif - serbb_setpin(pgm, pin, 0); + if (pgm->ispdelay > 1) + bitbang_delay(pgm->ispdelay); - #if SLOW_TOGGLE - usleep(1000); - #endif + serbb_setpin(pgm, pin, 0); + if (pgm->ispdelay > 1) + bitbang_delay(pgm->ispdelay); return 0; } diff --git a/serbb_win32.c b/serbb_win32.c index 9829a7e9..e4cd95d5 100644 --- a/serbb_win32.c +++ b/serbb_win32.c @@ -230,14 +230,12 @@ static int serbb_highpulsepin(PROGRAMMER * pgm, int pin) return -1; serbb_setpin(pgm, pin, 1); -#if SLOW_TOGGLE - usleep(1000); -#endif - serbb_setpin(pgm, pin, 0); + if (pgm->ispdelay > 1) + bitbang_delay(pgm->ispdelay); -#if SLOW_TOGGLE - usleep(1000); -#endif + serbb_setpin(pgm, pin, 0); + if (pgm->ispdelay > 1) + bitbang_delay(pgm->ispdelay); return 0; }