patch #7437 modifications to Bus Pirate module

patch #7686 Updating buspirate ascii mode to current firmware, use AUX
            as clock generator, and setting of serial receive timeout
  * buspirate.c: added paged_write, changed binary mode setup/detection,
                 added clock output on AUX pin
  * avrdude.1: updated documentation
  * doc/avrdude.texi: updated documentation


git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk/avrdude@1052 81a1dc3b-b13d-400b-aceb-764788c761c2
This commit is contained in:
Rene Liebscher 2012-01-31 19:01:00 +00:00
parent c1095de822
commit fa5e2bb849
4 changed files with 320 additions and 83 deletions

View File

@ -1,3 +1,13 @@
2012-01-31 Rene Liebscher <R.Liebscher@gmx.de>
patch #7437 modifications to Bus Pirate module
patch #7686 Updating buspirate ascii mode to current firmware, use AUX
as clock generator, and setting of serial receive timeout
* buspirate.c: added paged_write, changed binary mode setup/detection,
added clock output on AUX pin
* avrdude.1: updated documentation
* doc/avrdude.texi: updated documentation
2012-01-31 Rene Liebscher <R.Liebscher@gmx.de>
Parser does not need to know all programmer types now, new programmers

View File

@ -882,7 +882,7 @@ each other using a 3-state bus buffer. For example 74HC125 or 74HC244 are some
good candidates with the latches driven by the appropriate reset pin (cs,
aux or aux2). Otherwise the SPI traffic in one active circuit may interfere
with programming the AVR in the other design.
.It Ar speed=<0..7>
.It Ar spifreq=<0..7>
BusPirate to AVR SPI speed:
.Bd -literal
0 .. 30 kHz (default)
@ -895,14 +895,36 @@ BusPirate to AVR SPI speed:
7 .. 8 MHz
.Ed
.It Ar ascii
Use ASCII mode even when the firmware supports BinMode (binary mode).
Attempt to ASCII mode even when the firmware supports BinMode (binary mode).
BinMode is supported in firmware 2.7 and newer, older FW's either don't
have BinMode or their BinMode is buggy. ASCII mode is slower and makes
the above
.Ar reset=
and
.Ar speed=
parameters unavailable.
.Ar spifreq=
parameters unavailable. Be aware that ASCII mode is not guaranteed to work
with newer firmware versions, and is retained only to maintain compatability
with older firmware versions.
.It Ar nopagedwrite
Firmware versions 5.10 and newer support a binary mode SPI command that enables
whole pages to be written to AVR flash memory at once, resulting in a
significant write speed increase. If use of this mode is not desirable for some
reason, this option disables it.
.It Ar cpufreq=<125..4000>
This sets the AUX pin to output a frequency of
.Ar n
kHz. Connecting
the AUX pin to the XTAL1 pin of your MCU, you can provide it a clock,
for example when it needs an external clock because of wrong fuses settings.
This setting is only available in ASCII mode. (The lower limit was chosen so
the CPU frequency is at least for four times the SPI frequency which is in
ASCII mode 30kHz.)
.It Ar serial_recv_timeout=<1...>
This sets the serial receive timeout to the given value.
The timeout happens every time avrdude waits for the BusPirate prompt.
Especially in ascii mode this happens very often, so setting a smaller value
can speed up programming a lot.
The default value is 100ms. Using 10ms might work in most cases.
.El
.It Ar Wiring
When using the Wiring programmer type, the

View File

@ -29,6 +29,7 @@
* MOSI <-> MOSI
* MISO <-> MISO
* SCL/CLK <-> SCK
* ( AUX <-> XTAL1 )
*
* Tested with BusPirate PTH, firmware version 2.1 programming ATmega328P
*/
@ -61,6 +62,8 @@
#define BP_FLAG_XPARM_FORCE_ASCII (1<<1)
#define BP_FLAG_XPARM_RESET (1<<2)
#define BP_FLAG_XPARM_SPIFREQ (1<<3)
#define BP_FLAG_NOPAGEDWRITE (1<<4)
#define BP_FLAG_XPARM_CPUFREQ (1<<5)
struct pdata
{
@ -70,26 +73,17 @@ struct pdata
int bin_spi_version;
int current_peripherals_config;
int spifreq; /* 0..7 - see buspirate manual for what freq each value means */
int cpufreq; /* (125)..4000 kHz - see buspirate manual */
int serial_recv_timeout; /* timeout in ms, default 100 */
int reset; /* See BP_RESET_* above */
};
#define PDATA(pgm) ((struct pdata *)(pgm->cookie))
/* Binary mode is available from firmware v2.7 on */
#define FW_BINMODE_VER 207
/* ====== Feature checks ====== */
static inline int
buspirate_has_aux2(struct programmer_t *pgm)
{
return ((PDATA(pgm)->fw_version >= 300) &&
strcmp(PDATA(pgm)->hw_version, "v1a") == 0);
}
static inline int
buspirate_uses_ascii(struct programmer_t *pgm)
{
return (pgm->flag & BP_FLAG_XPARM_FORCE_ASCII) ||
(PDATA(pgm)->fw_version < FW_BINMODE_VER);
return (pgm->flag & BP_FLAG_XPARM_FORCE_ASCII);
}
/* ====== Serial talker functions - binmode ====== */
@ -206,7 +200,7 @@ static char *buspirate_readline_noexit(struct programmer_t *pgm, char *buf, size
break;
}
buf_p++;
serial_recv_timeout = 100;
serial_recv_timeout = PDATA(pgm)->serial_recv_timeout;
}
serial_recv_timeout = orig_serial_recv_timeout;
if (verbose)
@ -296,6 +290,8 @@ buspirate_parseextparms(struct programmer_t *pgm, LISTID extparms)
char reset[10];
char *preset = reset; /* for strtok() */
int spifreq;
int cpufreq;
int serial_recv_timeout;
for (ln = lfirst(extparms); ln; ln = lnext(ln)) {
extended_param = ldata(ln);
@ -314,6 +310,18 @@ buspirate_parseextparms(struct programmer_t *pgm, LISTID extparms)
continue;
}
if (sscanf(extended_param, "cpufreq=%d", &cpufreq) == 1) {
/* lower limit comes from 'cpufreq > 4 * spifreq', spifreq in ascii mode is 30kHz. */
if (cpufreq < 125 || cpufreq > 4000) {
fprintf(stderr, "BusPirate: cpufreq must be between 125 and 4000 kHz.\n");
fprintf(stderr, "BusPirate: see BusPirate manual for details.\n");
return -1;
}
PDATA(pgm)->cpufreq = cpufreq;
pgm->flag |= BP_FLAG_XPARM_CPUFREQ;
continue;
}
if (sscanf(extended_param, "reset=%s", reset) == 1) {
char *resetpin;
while ((resetpin = strtok(preset, ","))) {
@ -332,6 +340,20 @@ buspirate_parseextparms(struct programmer_t *pgm, LISTID extparms)
pgm->flag |= BP_FLAG_XPARM_RESET;
continue;
}
if (strcmp(extended_param, "nopagedwrite") == 0) {
pgm->flag |= BP_FLAG_NOPAGEDWRITE;
continue;
}
if (sscanf(extended_param, "serial_recv_timeout=%d", &serial_recv_timeout) == 1) {
if (serial_recv_timeout < 1) {
fprintf(stderr, "BusPirate: serial_recv_timeout must be greater 0.\n");
return -1;
}
PDATA(pgm)->serial_recv_timeout = serial_recv_timeout;
continue;
}
}
return 0;
@ -344,15 +366,6 @@ buspirate_verifyconfig(struct programmer_t *pgm)
if (PDATA(pgm)->reset == 0x00)
PDATA(pgm)->reset |= BP_RESET_CS;
/* reset=AUX2 is only available on HW=v1a and FW>=3.0 */
if ((PDATA(pgm)->reset & BP_RESET_AUX2) && !buspirate_has_aux2(pgm)) {
fprintf(stderr, "BusPirate: Pin AUX2 is only available in binary mode\n");
fprintf(stderr, "BusPirate: with hardware==v1a && firmware>=3.0\n");
fprintf(stderr, "BusPirate: Your hardware==%s and firmware==%d.%d\n",
PDATA(pgm)->hw_version, PDATA(pgm)->fw_version/100, PDATA(pgm)->fw_version%100);
return -1;
}
if ((PDATA(pgm)->reset != BP_RESET_CS) && buspirate_uses_ascii(pgm)) {
fprintf(stderr, "BusPirate: RESET pin other than CS is not supported in ASCII mode\n");
return -1;
@ -363,6 +376,11 @@ buspirate_verifyconfig(struct programmer_t *pgm)
return -1;
}
if ((pgm->flag & BP_FLAG_XPARM_CPUFREQ) && !buspirate_uses_ascii(pgm)) {
fprintf(stderr, "BusPirate: Setting cpufreq is only supported in ASCII mode\n");
return -1;
}
return 0;
}
@ -459,13 +477,37 @@ static int buspirate_start_spi_mode_bin(struct programmer_t *pgm)
fprintf(stderr, "BusPirate SPI version: %d\n",
PDATA(pgm)->bin_spi_version);
if (pgm->flag & BP_FLAG_NOPAGEDWRITE) {
if (verbose)
fprintf(stderr, "%s: Paged flash write disabled.\n", progname);
} else {
/* Check for write-then-read without !CS/CS and disable paged_write if absent: */
strncpy(buf, "\x5\x0\x0\x0\x0", 5);
buspirate_send_bin(pgm, buf, 5);
buspirate_recv_bin(pgm, buf, 1);
if (buf[0] != 0x01) {
/* Disable paged write: */
pgm->flag |= BP_FLAG_NOPAGEDWRITE;
/* Return to SPI mode (0x00s have landed us back in binary bitbang mode): */
buf[0] = 0x1;
buspirate_send_bin(pgm, buf, 1);
if (verbose)
fprintf(stderr, "%s: Disabling paged flash write. (Need BusPirate firmware >=v5.10.)\n", progname);
/* Flush serial buffer: */
serial_drain(&pgm->fd, 0);
} else {
if (verbose)
fprintf(stderr, "%s: Paged flash write enabled.\n", progname);
}
}
/* 0b0100wxyz - Configure peripherals w=power, x=pull-ups/aux2, y=AUX, z=CS
* we want power (0x48) and all reset pins high. */
PDATA(pgm)->current_peripherals_config = 0x48;
PDATA(pgm)->current_peripherals_config |= BP_RESET_CS;
PDATA(pgm)->current_peripherals_config |= BP_RESET_AUX;
if (buspirate_has_aux2(pgm))
PDATA(pgm)->current_peripherals_config |= BP_RESET_AUX2;
PDATA(pgm)->current_peripherals_config = 0x48 | PDATA(pgm)->reset;
buspirate_expect_bin_byte(pgm, PDATA(pgm)->current_peripherals_config, 0x01);
usleep(50000); // sleep for 50ms after power up
@ -490,7 +532,7 @@ static int buspirate_start_spi_mode_ascii(struct programmer_t *pgm)
int cmd;
char *rcvd, mode[11], buf[5];
buspirate_send(pgm, "M\n");
buspirate_send(pgm, "m\n");
while(1) {
rcvd = buspirate_readline(pgm, NULL, 0);
if (spi_cmd == -1 && sscanf(rcvd, "%d. %10s", &cmd, mode)) {
@ -541,10 +583,30 @@ static void buspirate_enable(struct programmer_t *pgm)
unsigned char *reset_str = "#\n";
unsigned char *accept_str = "y\n";
char *rcvd;
int fw_v1 = 0, fw_v2 = 0;
int rc, print_banner = 0;
fprintf(stderr, "Detecting BusPirate...\n");
/* Ensure configuration is self-consistant: */
if (buspirate_verifyconfig(pgm)<0)
exit(1);
/* Attempt to start binary SPI mode unless explicitly told otherwise: */
if (!buspirate_uses_ascii(pgm)) {
fprintf(stderr, "Attempting to initiate BusPirate binary mode...\n");
/* Send two CRs to ensure we're not in a sub-menu of the UI if we're in ASCII mode: */
buspirate_send_bin(pgm, "\n\n", 2);
/* Clear input buffer: */
serial_drain(&pgm->fd, 0);
/* Attempt to enter binary mode: */
if (buspirate_start_spi_mode_bin(pgm) >= 0)
return;
else
fprintf(stderr, "%s: Failed to start binary SPI mode, falling back to ASCII...\n", progname);
}
fprintf(stderr, "Attempting to initiate BusPirate ASCII mode...\n");
/* Call buspirate_send_bin() instead of buspirate_send()
* because we don't know if BP is in text or bin mode */
@ -557,11 +619,8 @@ static void buspirate_enable(struct programmer_t *pgm)
while(1) {
rcvd = buspirate_readline_noexit(pgm, NULL, 0);
if (! rcvd) {
fprintf(stderr, "BusPirate is not responding. Attempting reset.\n");
buspirate_reset_from_binmode(pgm);
/* re-run buspirate_enable() */
buspirate_enable(pgm);
return;
fprintf(stderr, "%s: Fatal: Programmer is not responding.\n", progname);
exit(1);
}
if (strncmp(rcvd, "Are you sure?", 13) == 0) {
buspirate_send_bin(pgm, accept_str, strlen(accept_str));
@ -574,27 +633,11 @@ static void buspirate_enable(struct programmer_t *pgm)
puts("**");
break;
}
sscanf(rcvd, "Bus Pirate %9s", PDATA(pgm)->hw_version);
sscanf(rcvd, "Firmware v%d.%d", &fw_v1, &fw_v2);
if (print_banner)
fprintf(stderr, "** %s", rcvd);
}
PDATA(pgm)->fw_version = 100 * fw_v1 + fw_v2;
if (PDATA(pgm)->hw_version[0] == 0 || PDATA(pgm)->fw_version == 0) {
fprintf(stderr, "BusPirate not detected. Aborting.\n");
exit(1);
}
if (buspirate_verifyconfig(pgm) < 0)
exit(1);
if (PDATA(pgm)->fw_version >= FW_BINMODE_VER && !(pgm->flag & BP_FLAG_XPARM_FORCE_ASCII)) {
fprintf(stderr, "BusPirate: using BINARY mode\n");
if (buspirate_start_spi_mode_bin(pgm) < 0)
fprintf(stderr, "%s: Failed to start binary SPI mode\n", progname);
}
if (!pgm->flag & BP_FLAG_IN_BINMODE) {
if (!(pgm->flag & BP_FLAG_IN_BINMODE)) {
fprintf(stderr, "BusPirate: using ASCII mode\n");
if (buspirate_start_spi_mode_ascii(pgm) < 0) {
fprintf(stderr, "%s: Failed to start ascii SPI mode\n", progname);
@ -624,9 +667,26 @@ static void buspirate_powerup(struct programmer_t *pgm)
if (pgm->flag & BP_FLAG_IN_BINMODE) {
/* Powerup in BinMode is handled in SPI init */
return;
} else
if (buspirate_expect(pgm, "W\n", "POWER SUPPLIES ON", 1))
} else {
if (buspirate_expect(pgm, "W\n", "Power supplies ON", 1)) {
if (pgm->flag & BP_FLAG_XPARM_CPUFREQ) {
char buf[25];
int ok = 0;
snprintf(buf, sizeof(buf), "%d\n", PDATA(pgm)->cpufreq);
if (buspirate_expect(pgm, "g\n", "Frequency in KHz", 1)) {
if (buspirate_expect(pgm, buf, "Duty cycle in %", 1)) {
if (buspirate_expect(pgm, "50\n", "PWM active", 1)) {
ok = 1;
}
}
}
if(!ok) {
fprintf(stderr, "%s: warning: did not get a response to start PWM command.\n", progname);
}
}
return;
}
}
fprintf(stderr, "%s: warning: did not get a response to PowerUp command.\n", progname);
fprintf(stderr, "%s: warning: Trying to continue anyway...\n", progname);
@ -639,9 +699,15 @@ static void buspirate_powerdown(struct programmer_t *pgm)
* we want everything off -- 0b01000000 = 0x40 */
if (buspirate_expect_bin_byte(pgm, 0x40, 0x01))
return;
} else
if (buspirate_expect(pgm, "w\n", "POWER SUPPLIES OFF", 1))
} else {
if (pgm->flag & BP_FLAG_XPARM_CPUFREQ) {
if (!buspirate_expect(pgm, "g\n", "PWM disabled", 1)) {
fprintf(stderr, "%s: warning: did not get a response to stop PWM command.\n", progname);
}
}
if (buspirate_expect(pgm, "w\n", "Power supplies OFF", 1))
return;
}
fprintf(stderr, "%s: warning: did not get a response to PowerDown command.\n", progname);
}
@ -704,6 +770,127 @@ static int buspirate_cmd(struct programmer_t *pgm,
return buspirate_cmd_ascii(pgm, cmd, res);
}
/* Paged write function which utilizes the Bus Pirate's "Write then Read" binary SPI instruction */
static int buspirate_paged_write(struct programmer_t *pgm,
AVRPART *p,
AVRMEM *m,
unsigned int page_size,
unsigned int base_addr,
unsigned int n_data_bytes)
{
int page, i;
int addr = base_addr;
int n_page_writes;
int this_page_size;
char cmd_buf[4096] = {'\0'};
char send_byte, recv_byte;
if (!(pgm->flag & BP_FLAG_IN_BINMODE)) {
/* Return if we are not in binary mode. */
return -1;
}
if (pgm->flag & BP_FLAG_NOPAGEDWRITE) {
/* Return if we've nominated not to use paged writes. */
return -1;
}
if (page_size>1024) {
/* Page sizes greater than 1kB not yet supported. */
return -1;
}
if (strcmp(m->desc,"flash") != 0) {
/* Only flash memory currently supported. */
return -1;
}
/* pre-check opcodes */
if (m->op[AVR_OP_LOADPAGE_LO] == NULL) {
fprintf(stderr,
"%s failure: %s command not defined for %s\n",
progname, "AVR_OP_LOADPAGE_LO", p->desc);
return -1;
}
if (m->op[AVR_OP_LOADPAGE_HI] == NULL) {
fprintf(stderr,
"%s failure: %s command not defined for %s\n",
progname, "AVR_OP_LOADPAGE_HI", p->desc);
return -1;
}
/* Calculate total number of page writes needed: */
n_page_writes = n_data_bytes/page_size;
if (n_data_bytes%page_size >0)
n_page_writes++;
/* Ensure error LED is off: */
pgm->err_led(pgm, OFF);
/* Loop over pages: */
for (page=0; page<n_page_writes; page++) {
/* Determine bytes to write in this page: */
this_page_size = page_size;
if (page == n_page_writes-1)
this_page_size = n_data_bytes - page_size*page;
/* Set up command buffer: */
memset(cmd_buf, 0, 4*this_page_size);
for (i=0; i<this_page_size; i++) {
addr = base_addr + page*page_size + i;
if (i%2 == 0) {
avr_set_bits(m->op[AVR_OP_LOADPAGE_LO], &(cmd_buf[4*i]));
avr_set_addr(m->op[AVR_OP_LOADPAGE_LO], &(cmd_buf[4*i]), addr/2);
avr_set_input(m->op[AVR_OP_LOADPAGE_LO], &(cmd_buf[4*i]), m->buf[addr]);
} else {
avr_set_bits(m->op[AVR_OP_LOADPAGE_HI], &(cmd_buf[4*i]));
avr_set_addr(m->op[AVR_OP_LOADPAGE_HI], &(cmd_buf[4*i]), addr/2);
avr_set_input(m->op[AVR_OP_LOADPAGE_HI], &(cmd_buf[4*i]), m->buf[addr]);
}
}
/* 00000100 - Write then read */
send_byte = 0x05;
buspirate_send_bin(pgm, &send_byte, 1);
/* Number of bytes to write: */
send_byte = (4*this_page_size)/0x100;
buspirate_send_bin(pgm, &send_byte, 1); /* High byte */
send_byte = (4*this_page_size)%0x100;
buspirate_send_bin(pgm, &send_byte, 1); /* Low byte */
/* Number of bytes to read: */
send_byte = 0x0;
buspirate_send_bin(pgm, &send_byte, 1); /* High byte */
buspirate_send_bin(pgm, &send_byte, 1); /* Low byte */
/* Set programming LED: */
pgm->pgm_led(pgm, ON);
/* Send command buffer: */
buspirate_send_bin(pgm, cmd_buf, 4*this_page_size);
/* Check for write failure: */
if ((buspirate_recv_bin(pgm, &recv_byte, 1) == EOF) || (recv_byte != 0x01)) {
fprintf(stderr, "BusPirate: Fatal error: Write Then Read did not succeed.\n");
pgm->pgm_led(pgm, OFF);
pgm->err_led(pgm, ON);
exit(1);
}
/* Unset programming LED: */
pgm->pgm_led(pgm, OFF);
/* Write loaded page to flash: */
avr_write_page(pgm, p, m, addr);
}
return n_data_bytes;
}
static int buspirate_program_enable(struct programmer_t *pgm, AVRPART * p)
{
unsigned char cmd[4];
@ -769,6 +956,7 @@ static void buspirate_setup(struct programmer_t *pgm)
progname);
exit(1);
}
PDATA(pgm)->serial_recv_timeout = 100;
}
static void buspirate_teardown(struct programmer_t *pgm)
@ -799,10 +987,11 @@ void buspirate_initpgm(struct programmer_t *pgm)
pgm->read_byte = avr_read_byte_default;
pgm->write_byte = avr_write_byte_default;
pgm->paged_write = buspirate_paged_write;
/* Support functions */
pgm->parseextparams = buspirate_parseextparms;
pgm->setup = buspirate_setup;
pgm->teardown = buspirate_teardown;
}

View File

@ -919,35 +919,51 @@ good candidates with the latches driven by the appropriate reset pin (cs,
aux or aux2). Otherwise the SPI traffic in one active circuit may interfere
with programming the AVR in the other design.
@item @samp{speed=@var{0..7}}
@table @code
@item 0
30 kHz (default)
@item 1
125 kHz
@item 2
250 kHz
@item 3
1 MHz
@item 4
2 MHz
@item 5
2.6 MHz
@item 6
4 MHz
@item 7
8 MHz
@end table
@item @samp{spifreq=@var{0..7}}
@multitable @columnfractions .05 .3
@item @code{0} @tab 30 kHz (default)
@item @code{1} @tab 125 kHz
@item @code{2} @tab 250 kHz
@item @code{3} @tab 1 MHz
@item @code{4} @tab 2 MHz
@item @code{5} @tab 2.6 MHz
@item @code{6} @tab 4 MHz
@item @code{7} @tab 8 MHz
@end multitable
@item @samp{ascii}
Use ASCII mode even when the firmware supports BinMode (binary mode).
Attempt to ASCII mode even when the firmware supports BinMode (binary mode).
BinMode is supported in firmware 2.7 and newer, older FW's either don't
have BinMode or their BinMode is buggy. ASCII mode is slower and makes
the above
@samp{reset=}
and
@samp{speed=}
parameters unavailable.
@samp{spifreq=}
parameters unavailable. Be aware that ASCII mode is not guaranteed to work
with newer firmware versions, and is retained only to maintain compatability
with older firmware versions.
@item @samp{nopagedwrite}
Firmware versions 5.10 and newer support a binary mode SPI command that enables
whole pages to be written to AVR flash memory at once, resulting in a
significant write speed increase. If use of this mode is not desirable for some
reason, this option disables it.
@item @samp{cpufreq=@var{125..4000}}
This sets the @emph{AUX} pin to output a frequency of @var{n} kHz. Connecting
the @emph{AUX} pin to the XTAL1 pin of your MCU, you can provide it a clock,
for example when it needs an external clock because of wrong fuses settings.
This setting is only available in ASCII mode. (The lower limit was chosen so
the CPU frequency is at least for four times the SPI frequency which is in
ASCII mode 30kHz.)
@item @samp{serial_recv_timeout=@var{1...}}
This sets the serial receive timeout to the given value.
The timeout happens every time avrdude waits for the BusPirate prompt.
Especially in ascii mode this happens very often, so setting a smaller value
can speed up programming a lot.
The default value is 100ms. Using 10ms might work in most cases.
@end table
@item Wiring