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; pageop[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); } } -