avrdude/buspirate.c

638 lines
16 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* avrdude - A Downloader/Uploader for AVR device programmers
*
* avrdude support for The Bus Pirate - universal serial interface
*
* Copyright (C) 2009 Michal Ludvig <mludvig@logix.net.nz>
*
* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "avrdude.h"
#include "avr.h"
#include "pgm.h"
#include "serial.h"
/* ====== Private data structure ====== */
struct pdata
{
char hw_version[10];
int fw_version; /* = 100*fw_major + fw_minor */
int binmode_version;
int bin_spi_version;
int in_binmode;
int force_ascii;
};
#define PDATA(pgm) ((struct pdata *)(pgm->cookie))
/* Binary mode is available from firmware v2.7 on */
#define FW_BINMODE_VER 207
/* ====== Serial talker functions - binmode ====== */
static void dump_mem(unsigned char *buf, size_t len)
{
size_t i;
for (i = 0; i<len; i++) {
if (i % 8 == 0)
fprintf(stderr, "\t");
fprintf(stderr, "0x%02x ", buf[i] & 0xFF);
if (i % 8 == 3)
fprintf(stderr, " ");
else if (i % 8 == 7)
fprintf(stderr, "\n");
}
if (i % 8 != 7)
fprintf(stderr, "\n");
}
static int buspirate_send_bin(struct programmer_t *pgm, char *data, size_t len)
{
int rc;
if (verbose > 1) {
fprintf(stderr, "%s: buspirate_send_bin():\n", progname);
dump_mem(data, len);
}
rc = serial_send(&pgm->fd, data, len);
return rc;
}
static int buspirate_recv_bin(struct programmer_t *pgm, char *buf, size_t len)
{
int rc;
rc = serial_recv(&pgm->fd, buf, len);
if (rc < 0)
return EOF;
if (verbose > 1) {
fprintf(stderr, "%s: buspirate_recv_bin():\n", progname);
dump_mem(buf, len);
}
return len;
}
static int buspirate_expect_bin(struct programmer_t *pgm,
char *send_data, size_t send_len,
char *expect_data, size_t expect_len)
{
char *recv_buf = alloca(expect_len);
if (!PDATA(pgm)->in_binmode) {
fprintf(stderr, "BusPirate: Internal error: buspirate_send_bin() called from ascii mode");
exit(1);
}
buspirate_send_bin(pgm, send_data, send_len);
buspirate_recv_bin(pgm, recv_buf, expect_len);
if (memcmp(expect_data, recv_buf, expect_len) != 0)
return 0;
return 1;
}
static int buspirate_expect_bin_byte(struct programmer_t *pgm,
char send_byte, char expect_byte)
{
return buspirate_expect_bin(pgm, &send_byte, 1, &expect_byte, 1);
}
/* ====== Serial talker functions - ascii mode ====== */
static int buspirate_getc(struct programmer_t *pgm)
{
int rc;
unsigned char ch = 0;
if (PDATA(pgm)->in_binmode) {
fprintf(stderr, "BusPirate: Internal error: buspirate_getc() called from binmode");
exit(1);
}
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);
if (PDATA(pgm)->in_binmode) {
fprintf(stderr, "BusPirate: Internal error: buspirate_send() called from binmode");
exit(1);
}
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 void buspirate_reset_from_binmode(struct programmer_t *pgm)
{
char buf[10];
buf[0] = 0x00; /* BinMode: revert to HiZ */
buspirate_send_bin(pgm, buf, 1);
buf[0] = 0x0F; /* BinMode: reset */
buspirate_send_bin(pgm, buf, 1);
PDATA(pgm)->in_binmode = 0;
while(1) {
buspirate_readline(pgm, buf, sizeof(buf) - 1);
if (buspirate_is_prompt(buf))
break;
}
if (verbose)
printf("BusPirate is back in the text mode\n");
}
static int buspirate_start_spi_mode_bin(struct programmer_t *pgm)
{
unsigned char buf[20] = { '\0' };
/* == Switch to binmode - send 20x '\0' == */
buspirate_send_bin(pgm, buf, sizeof(buf));
/* Expecting 'BBIOx' reply */
memset(buf, 0, sizeof(buf));
buspirate_recv_bin(pgm, buf, 5);
if (sscanf(buf, "BBIO%d", &PDATA(pgm)->binmode_version) != 1) {
fprintf(stderr, "Binary mode not confirmed: '%s'\n", buf);
buspirate_reset_from_binmode(pgm);
return -1;
}
if (verbose)
printf("BusPirate binmode version: %d\n", PDATA(pgm)->binmode_version);
PDATA(pgm)->in_binmode = 1;
/* == Enter SPI mode == */
buf[0] = 0x01; /* Enter raw SPI mode */
buspirate_send_bin(pgm, buf, 1);
memset(buf, 0, sizeof(buf));
buspirate_recv_bin(pgm, buf, 4);
if (sscanf(buf, "SPI%d", &PDATA(pgm)->bin_spi_version) != 1) {
fprintf(stderr, "SPI mode not confirmed: '%s'\n", buf);
buspirate_reset_from_binmode(pgm);
return -1;
}
if (verbose)
printf("BusPirate SPI version: %d\n", PDATA(pgm)->bin_spi_version);
/* 0b0100wxyz Configure peripherals w=power, x=pull-ups, y=AUX, z=CS
* we want power and CS -- 0b01001001 = 0x49 */
buspirate_expect_bin_byte(pgm, 0x49, 0x01);
usleep(50000); // sleep for 50ms after power up
/* 01100xxx - SPI speed
* xxx = 000=30kHz, 001=125kHz, 010=250kHz, 011=1MHz,
* 100=2MHz, 101=2.6MHz, 110=4MHz, 111=8MHz
* use 30kHz = 0x60 */
buspirate_expect_bin_byte(pgm, 0x60, 0x01);
/* 1000wxyz SPI config, w=HiZ(0)/3.3v(1), x=CLK idle, y=CLK edge, z=SMP sample
* we want: 3.3V(1), idle low(0), data change on trailing edge (1),
* sample in the middle of the pulse (0)
* => 0b10001010 = 0x8a */
buspirate_expect_bin_byte(pgm, 0x8A, 0x01);
return 0;
}
static int buspirate_start_spi_mode_ascii(struct programmer_t *pgm)
{
int spi_cmd = -1;
int cmd;
char *rcvd, mode[11], buf[5];
buspirate_send(pgm, "M\n");
while(1) {
rcvd = buspirate_readline(pgm, NULL, 0);
if (spi_cmd == -1 && sscanf(rcvd, "%d. %10s", &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;
int fw_v1, fw_v2;
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;
}
sscanf(rcvd, "Bus Pirate %9s", PDATA(pgm)->hw_version);
sscanf(rcvd, "Firmware v%d.%d", &fw_v1, &fw_v2);
printf("** %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);
}
printf("BusPirate: firmware %d.%d\n", fw_v1, fw_v2);
if (PDATA(pgm)->fw_version >= FW_BINMODE_VER && !PDATA(pgm)->force_ascii) {
printf("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 (! PDATA(pgm)->in_binmode) {
printf("BusPirate: using ASCII mode\n");
if (buspirate_start_spi_mode_ascii(pgm) < 0) {
fprintf(stderr, "%s: Failed to start ascii SPI mode\n", progname);
exit(1);
}
}
}
static void buspirate_disable(struct programmer_t *pgm)
{
if (PDATA(pgm)->in_binmode)
buspirate_reset_from_binmode(pgm);
else
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 (PDATA(pgm)->in_binmode) {
/* Powerup in BinMode is handled in SPI init */
return;
} else
if (buspirate_expect(pgm, "W\n", "POWER SUPPLIES ON", 1))
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);
}
static void buspirate_powerdown(struct programmer_t *pgm)
{
if (PDATA(pgm)->in_binmode) {
/* 0b0100wxyz Configure peripherals w=power, x=pull-ups, y=AUX, z=CS
* 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))
return;
fprintf(stderr, "%s: warning: did not get a response to PowerDown command.\n", progname);
}
static int buspirate_cmd_bin(struct programmer_t *pgm,
unsigned char cmd[4],
unsigned char res[4])
{
/* 0001xxxx Bulk SPI transfer, send/read 1-16 bytes (0=1byte!)
* we are sending 4 bytes -> 0x13 */
if (!buspirate_expect_bin_byte(pgm, 0x13, 0x01))
return -1;
buspirate_send_bin(pgm, cmd, 4);
buspirate_recv_bin(pgm, res, 4);
return 0;
}
static int buspirate_cmd_ascii(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_cmd(struct programmer_t *pgm,
unsigned char cmd[4],
unsigned char res[4])
{
if (PDATA(pgm)->in_binmode)
return buspirate_cmd_bin(pgm, cmd, res);
else
return buspirate_cmd_ascii(pgm, cmd, res);
}
static int buspirate_program_enable(struct programmer_t *pgm, AVRPART * p)
{
unsigned char cmd[4];
unsigned char res[4];
if (PDATA(pgm)->in_binmode)
/* 0000001x CS high (1) or low (0)
* we want CS low -> 0x02 */
buspirate_expect_bin_byte(pgm, 0x02, 0x01);
else
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;
}
static int buspirate_parseextparms(struct programmer_t *pgm, LISTID extparms)
{
LNODEID ln;
const char *extended_param;
for (ln = lfirst(extparms); ln; ln = lnext(ln)) {
extended_param = ldata(ln);
if (strcmp(extended_param, "ascii") == 0)
PDATA(pgm)->force_ascii = 1;
}
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;
/* Support functions */
pgm->parseextparams = buspirate_parseextparms;
/* Allocate private data */
if ((pgm->cookie = calloc(1, sizeof(struct pdata))) == 0) {
fprintf(stderr, "%s: buspirate_initpgm(): Out of memory allocating private data\n",
progname);
exit(1);
}
}