From bcce066a1c893723dbddb5f9c0f001787814682a Mon Sep 17 00:00:00 2001 From: Michal Ludvig Date: Thu, 8 Oct 2009 02:05:03 +0000 Subject: [PATCH] Added support for the BusPirate programmer. git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk/avrdude@842 81a1dc3b-b13d-400b-aceb-764788c761c2 --- ChangeLog | 6 + Makefile.am | 2 + avrdude.conf.in | 6 + buspirate.c | 371 ++++++++++++++++++++++++++++++++++++++++++++++++ buspirate.h | 28 ++++ config_gram.y | 8 ++ lexer.l | 1 + main.c | 1 + 8 files changed, 423 insertions(+) create mode 100644 buspirate.c create mode 100644 buspirate.h diff --git a/ChangeLog b/ChangeLog index ce131ac9..79b18758 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2009-10-08 Michal Ludvig + + * buspirate.c, buspirate.h: Support for the BusPirate programmer + * config_gram.y, avrdude.conf.in, main.c, lexer.l, Makefile.am: + Glue for BusPirate. + 2009-08-17 Joerg Wunsch * usb_libusb.c (usbdev_close): Repair the logic around the diff --git a/Makefile.am b/Makefile.am index a7d07111..9a68852d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -88,6 +88,8 @@ libavrdude_a_SOURCES = \ avrpart.h \ bitbang.c \ bitbang.h \ + buspirate.c \ + buspirate.h \ butterfly.c \ butterfly.h \ config.c \ diff --git a/avrdude.conf.in b/avrdude.conf.in index 10a89f6f..3f415a70 100644 --- a/avrdude.conf.in +++ b/avrdude.conf.in @@ -340,6 +340,12 @@ programmer type = stk500v2; ; +programmer + id = "buspirate"; + desc = "The Bus Pirate"; + type = buspirate; +; + # This is supposed to be the "default" STK500 entry. # Attempts to select the correct firmware version # by probing for it. Better use one of the entries diff --git a/buspirate.c b/buspirate.c new file mode 100644 index 00000000..ad7e385a --- /dev/null +++ b/buspirate.c @@ -0,0 +1,371 @@ +/* + * avrdude - A Downloader/Uploader for AVR device programmers + * + * avrdude support for The Bus Pirate - universal serial interface + * + * Copyright (C) 2009 Michal Ludvig + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * BusPirate AVR Chip + * --------- -------- + * GND <-> GND + * +5V <-> Vcc + * CS <-> RESET + * MOSI <-> MOSI + * MISO <-> MISO + * SCL/CLK <-> SCK + * + * Tested with BusPirate PTH, firmware version 2.1 programming ATmega328P + */ + +#include "ac_cfg.h" + +#include +#include +#include +#include + +#include "avrdude.h" +#include "avr.h" +#include "pgm.h" +#include "serial.h" + +/* ====== Serial talker functions ====== */ + +static int buspirate_getc(struct programmer_t *pgm) +{ + int rc; + unsigned char ch = 0; + + rc = serial_recv(&pgm->fd, &ch, 1); + if (rc < 0) + return EOF; + return ch; +} + +static char *buspirate_readline(struct programmer_t *pgm, char *buf, size_t len) +{ + char *buf_p; + long orig_serial_recv_timeout = serial_recv_timeout; + + /* Static local buffer - this may come handy at times */ + static char buf_local[100]; + + if (buf == NULL) { + buf = buf_local; + len = sizeof(buf_local); + } + buf_p = buf; + memset(buf, 0, len); + while (buf_p < (buf + len - 1)) { /* keep the very last byte == 0 */ + *buf_p = buspirate_getc(pgm); + if (*buf_p == '\r') + continue; + if (*buf_p == '\n') + break; + if (*buf_p == EOF) { + *buf_p = '\0'; + break; + } + buf_p++; + serial_recv_timeout = 100; + } + serial_recv_timeout = orig_serial_recv_timeout; + if (verbose) + fprintf(stderr, "%s: buspirate_readline(): %s%s", + progname, buf, + buf[strlen(buf) - 1] == '\n' ? "" : "\n"); + if (! buf[0]) { + fprintf(stderr, + "%s: buspirate_readline(): programmer is not responding\n", + progname); + exit(1); + } + return buf; +} + +static int buspirate_send(struct programmer_t *pgm, char *str) +{ + int rc; + + if (verbose) + fprintf(stderr, "%s: buspirate_send(): %s", progname, str); + + rc = serial_send(&pgm->fd, (unsigned char *)str, strlen(str)); + if (rc) + return rc; + while (strcmp(buspirate_readline(pgm, NULL, 0), str) != 0) + /* keep reading until we get what we sent there */ + ; + /* by now we should be in sync */ + return 0; +} + +static int buspirate_is_prompt(char *str) +{ + /* Prompt ends with '>' all other input probably ends with '\n' */ + return (str[strlen(str) - 1] == '>'); +} + +static int buspirate_expect(struct programmer_t *pgm, char *send, + char *expect, int wait_for_prompt) +{ + int got_it = 0; + size_t expect_len = strlen(expect); + char *rcvd; + + buspirate_send(pgm, send); + while (1) { + rcvd = buspirate_readline(pgm, NULL, 0); + + if (strncmp(rcvd, expect, expect_len) == 0) + got_it = 1; + + if (buspirate_is_prompt(rcvd)) + break; + } + return got_it; +} + +/* ====== Do-nothing functions ====== */ +static void buspirate_dummy_6(struct programmer_t *pgm, + const char *p) +{ +} + +/* ====== Programmer methods ======= */ +static int buspirate_open(struct programmer_t *pgm, char * port) +{ + /* BusPirate runs at 115200 by default */ + if(pgm->baudrate == 0) + pgm->baudrate = 115200; + + strcpy(pgm->port, port); + serial_open(port, pgm->baudrate, &pgm->fd); + + /* drain any extraneous input */ + serial_drain(&pgm->fd, 0); + + return 0; +} + +static void buspirate_close(struct programmer_t *pgm) +{ + serial_close(&pgm->fd); + pgm->fd.ifd = -1; +} + +static int buspirate_start_spi_mode(struct programmer_t *pgm) +{ + int spi_cmd = -1; + int cmd; + char *rcvd, *mode, buf[5]; + + buspirate_send(pgm, "M\n"); + while(1) { + rcvd = buspirate_readline(pgm, NULL, 0); + if (spi_cmd == -1 && sscanf(rcvd, "%d. %as", &cmd, &mode)) { + if (strcmp(mode, "SPI") == 0) + spi_cmd = cmd; + } + if (buspirate_is_prompt(rcvd)) + break; + } + if (spi_cmd == -1) { + fprintf(stderr, + "%s: SPI mode number not found. Does your BusPirate support SPI?\n", + progname); + fprintf(stderr, "%s: Try powercycling your BusPirate and try again.\n", + progname); + return -1; + } + snprintf(buf, sizeof(buf), "%d\n", spi_cmd); + buspirate_send(pgm, buf); + buf[0] = '\0'; + while (1) { + rcvd = buspirate_readline(pgm, NULL, 0); + if (strstr(rcvd, "Normal (H=3.3V, L=GND)")) { + /* BP firmware 2.1 defaults to Open-drain output. + * That doesn't work on my board, even with pull-up + * resistors. Select 3.3V output mode instead. */ + sscanf(rcvd, " %d.", &cmd); + snprintf(buf, sizeof(buf), "%d\n", cmd); + } + if (buspirate_is_prompt(rcvd)) { + if (strncmp(rcvd, "SPI>", 4) == 0) { + printf("BusPirate is now configured for SPI\n"); + break; + } + /* Not yet 'SPI>' prompt */ + if (buf[0]) { + buspirate_send(pgm, buf); + buf[0] = '\0'; + } else + buspirate_send(pgm, "\n"); + } + } + return 0; +} + +static void buspirate_enable(struct programmer_t *pgm) +{ + char *rcvd; + + printf("Detecting BusPirate...\n"); + buspirate_send(pgm, "#\n"); + while(1) { + rcvd = buspirate_readline(pgm, NULL, 0); + if (strncmp(rcvd, "RESET", 5) == 0) + continue; + if (buspirate_is_prompt(rcvd)) { + puts("**"); + break; + } + printf("** %s", rcvd); + } + + if (buspirate_start_spi_mode(pgm) < 0) + fprintf(stderr, "%s: Failed to start SPI mode\n", progname); +} + +static void buspirate_disable(struct programmer_t *pgm) +{ + buspirate_expect(pgm, "#\n", "RESET", 1); +} + +static int buspirate_initialize(struct programmer_t *pgm, AVRPART * p) +{ + pgm->powerup(pgm); + + return pgm->program_enable(pgm, p); +} + +static void buspirate_powerup(struct programmer_t *pgm) +{ + if (!buspirate_expect(pgm, "W\n", "POWER SUPPLIES ON", 1)) { + fprintf(stderr, "%s: warning: did not get a response to PowerUp command.\n", progname); + fprintf(stderr, "%s: warning: Trying to continue anyway...\n", progname); + } +} + +static void buspirate_powerdown(struct programmer_t *pgm) +{ + if (!buspirate_expect(pgm, "w\n", "POWER SUPPLIES OFF", 1)) + fprintf(stderr, "%s: warning: did not get a response to PowerDown command.\n", progname); +} + +static int buspirate_cmd(struct programmer_t *pgm, + unsigned char cmd[4], + unsigned char res[4]) +{ + char buf[25]; + char *rcvd; + int spi_write, spi_read, i = 0; + + snprintf(buf, sizeof(buf), "0x%02x 0x%02x 0x%02x 0x%02x\n", + cmd[0], cmd[1], cmd[2], cmd[3]); + buspirate_send(pgm, buf); + while (1) { + rcvd = buspirate_readline(pgm, NULL, 0); + /* WRITE: 0xAC READ: 0x04 */ + if (sscanf(rcvd, "WRITE: 0x%x READ: 0x%x", &spi_write, &spi_read) == 2) { + res[i++] = spi_read; + } + if (buspirate_is_prompt(rcvd)) + break; + } + if (i != 4) { + fprintf(stderr, "%s: error: SPI has not read 4 bytes back\n", progname); + return -1; + } + return 0; +} + +static int buspirate_program_enable(struct programmer_t *pgm, AVRPART * p) +{ + unsigned char cmd[4]; + unsigned char res[4]; + + buspirate_expect(pgm, "{\n", "CS ENABLED", 1); + + if (p->op[AVR_OP_PGM_ENABLE] == NULL) { + fprintf(stderr, + "program enable instruction not defined for part \"%s\"\n", + p->desc); + return -1; + } + + memset(cmd, 0, sizeof(cmd)); + avr_set_bits(p->op[AVR_OP_PGM_ENABLE], cmd); + pgm->cmd(pgm, cmd, res); + + if (res[2] != cmd[1]) + return -2; + + return 0; +} + +static int buspirate_chip_erase(struct programmer_t *pgm, AVRPART * p) +{ + unsigned char cmd[4]; + unsigned char res[4]; + + if (p->op[AVR_OP_CHIP_ERASE] == NULL) { + fprintf(stderr, + "chip erase instruction not defined for part \"%s\"\n", + p->desc); + return -1; + } + + pgm->pgm_led(pgm, ON); + + memset(cmd, 0, sizeof(cmd)); + + avr_set_bits(p->op[AVR_OP_CHIP_ERASE], cmd); + pgm->cmd(pgm, cmd, res); + usleep(p->chip_erase_delay); + pgm->initialize(pgm, p); + + pgm->pgm_led(pgm, OFF); + + return 0; +} + +void buspirate_initpgm(struct programmer_t *pgm) +{ + strcpy(pgm->type, "BusPirate"); + + pgm->display = buspirate_dummy_6; + + /* BusPirate itself related methods */ + pgm->open = buspirate_open; + pgm->close = buspirate_close; + pgm->enable = buspirate_enable; + pgm->disable = buspirate_disable; + pgm->initialize = buspirate_initialize; + + /* Chip related methods */ + pgm->powerup = buspirate_powerup; + pgm->powerdown = buspirate_powerdown; + pgm->program_enable = buspirate_program_enable; + pgm->chip_erase = buspirate_chip_erase; + pgm->cmd = buspirate_cmd; + pgm->read_byte = avr_read_byte_default; + pgm->write_byte = avr_write_byte_default; +} + diff --git a/buspirate.h b/buspirate.h new file mode 100644 index 00000000..afbff55c --- /dev/null +++ b/buspirate.h @@ -0,0 +1,28 @@ +/* + * avrdude - A Downloader/Uploader for AVR device programmers + * + * avrdude support for The Bus Pirate - universal serial interface + * + * Copyright (C) 2009 Michal Ludvig + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef buspirate_h +#define buspirate_h + +void buspirate_initpgm (struct programmer_t *pgm); + +#endif diff --git a/config_gram.y b/config_gram.y index 2351009f..a5b75d13 100644 --- a/config_gram.y +++ b/config_gram.y @@ -38,6 +38,7 @@ #include "pgm.h" #include "stk500.h" #include "arduino.h" +#include "buspirate.h" #include "stk500v2.h" #include "stk500generic.h" #include "avr910.h" @@ -84,6 +85,7 @@ static int parse_cmdbits(OPCODE * op); %token K_BAUDRATE %token K_BS2 %token K_BUFF +%token K_BUSPIRATE %token K_CHIP_ERASE_DELAY %token K_DEDICATED %token K_DEFAULT_PARALLEL @@ -425,6 +427,12 @@ prog_parm : } } | + K_TYPE TKN_EQUAL K_BUSPIRATE { + { + buspirate_initpgm(current_prog); + } + } | + K_TYPE TKN_EQUAL K_STK600 { { stk600_initpgm(current_prog); diff --git a/lexer.l b/lexer.l index d7c1dcd3..689ec5c5 100644 --- a/lexer.l +++ b/lexer.l @@ -127,6 +127,7 @@ banked { yylval=NULL; return K_PAGED; } baudrate { yylval=NULL; return K_BAUDRATE; } bs2 { yylval=NULL; return K_BS2; } buff { yylval=NULL; return K_BUFF; } +buspirate { yylval=NULL; return K_BUSPIRATE; } butterfly { yylval=NULL; return K_BUTTERFLY; } chip_erase_delay { yylval=NULL; return K_CHIP_ERASE_DELAY; } desc { yylval=NULL; return K_DESC; } diff --git a/main.c b/main.c index 15b0dc2c..ee24b238 100644 --- a/main.c +++ b/main.c @@ -679,6 +679,7 @@ int main(int argc, char * argv []) if ((strcmp(pgm->type, "STK500") == 0) || (strcmp(pgm->type, "avr910") == 0) || + (strcmp(pgm->type, "buspirate") == 0) || (strcmp(pgm->type, "STK500V2") == 0) || (strcmp(pgm->type, "JTAGMKII") == 0)) { if (port == default_parallel) {