Dear AVRDude dudes,
First off, thanks for writing such an awesome tool - if it weren't for
you, I wouldn't be able to tinker with AVRs. (What a sad and
miserable life that would be! :-) )
In case you're interested, I've made a couple of changes/improvements
I've made to the support for dangerousprototypes.com's Bus Pirate.
The first change is structural. During initialization, the previous
buspirate.c (specifically, buspirate_enable() ) sent a reset command
to the BP and parsed the resulting serial output to determine the
versions of the BP hardware and firmware. This was then used to
determine whether the binary SPI mode could be used for communication
with the MCU. Unfortunately, this approach has been a source of
ongoing compatibility issues due to small changes made to the BP user
interface over the last few firmware revisions. Furthermore, the
initial reset command will cause havoc with the next version of the BP
hardware (v4), as it will cause the USB connection to the BP to
disappear and reattach.
Following the suggestion of Ian Lesnet, the lead BP developer, I've
therefore removed the initial reset, as well as any attempt to detect
the BP hardware or firmware versions via the BP user interface.
Instead, I've implemented a try-then-fallback approach that attempts
to enter the binary SPI mode, then falls back to the original ascii
mode in the event that this fails. Entering binary mode implicitly
causes the BP to reset its internal mode settings, which is why the
explicit reset is unnecessary, but a reset is still performed in the
event that ascii mode is used. This change fixes all of the recent
compatibility issues as all but the earliest firmware versions support
the binary mode. (The extended option "ascii" can still be used to
force the use of the legacy ascii SPI mode, if desired. However,
ascii mode is likely to fail on BPs using recent firmware versions due
again to small changes in the ascii user interface.)
The second change is a feature addition. Ian has added a new bulk SPI
write command to the latest BP firmware version. The presence of this
new command is determined during initialization (again by trial and
error, this time in buspirate_start_spi_mode_bin() ) and, if found, a
new buspirate_pagedwrite() function is enabled which makes use of this
command which speeds up writes to AVR flash memory by about a factor
of 4. I've created an additional extended option "nopagedwrite" which
disables detection and use of this function in case it's not wanted,
and added an appropriate entry to the manpage documenting this new
option.
The attached patch includes these changes and is against the current
svn trunk. If you're happy with the modifications, please let me know
if there's anything I can do to make them appropriate for inclusion in
the avrdude code base. I've done my best to keep the
changes/additions in line with the existing style, but no-doubt
there's plenty that could be done better.
Thanks again for all the hard work you guys have put in to opening up
AVR programming to *nix users!
Tim
diff --git avrdude.1 avrdude.1
index 406b540..36be222 100644
--- avrdude.1
+++ avrdude.1
@@ -949,14 +949,21 @@ 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.
+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.
.El
.El
.Sh FILES
diff --git buspirate.c buspirate.c
index 22ce395..f052a55 100644
--- buspirate.c
+++ buspirate.c
@@ -61,6 +61,7 @@
#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)
struct pdata
{
@@ -74,22 +75,11 @@ struct pdata
};
#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 ====== */
@@ -332,6 +322,11 @@ 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;
+ }
}
return 0;
@@ -344,15 +339,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;
@@ -459,13 +445,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
@@ -541,10 +551,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 +587,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,26 +601,10 @@ 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) {
fprintf(stderr, "BusPirate: using ASCII mode\n");
if (buspirate_start_spi_mode_ascii(pgm) < 0) {
@@ -704,6 +715,115 @@ 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,
+ int page_size,
+ int n_data_bytes)
+{
+ int page, i;
+ int addr = 0;
+ int n_page_writes;
+ int this_page_size;
+ char cmd_buf[4096] = {'\0'};
+ char send_byte, recv_byte;
+
+ 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;
+ }
+
+ if (m->op[AVR_OP_LOADPAGE_LO] == NULL) {
+ /* Only word-addressable memory currently supported. */
+ 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++) {
+
+ /* Update progress bar: */
+ report_progress(page*page_size, n_data_bytes, NULL);
+
+ /* 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 = 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];
@@ -782,6 +902,8 @@ 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;
@@ -792,4 +914,3 @@ void buspirate_initpgm(struct programmer_t *pgm)
exit(1);
}
}
-
_______________________________________________
avrdude-dev mailing list
[email protected]
http://lists.nongnu.org/mailman/listinfo/avrdude-dev