/* * 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 (i < 4) { 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; } /* wait for prompt */ while (buspirate_getc(pgm) != '>') /* do nothing */; 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; }