avrdude-dev
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[avrdude-dev] Support for BusPirate programmer


From: Michal Ludvig
Subject: [avrdude-dev] Support for BusPirate programmer
Date: Tue, 06 Oct 2009 22:30:27 +1300
User-agent: Thunderbird 2.0.0.23 (X11/20090817)

Hi all,

attached is a patch that adds support for using "The Bus Pirate" as a
programmer in avrdude (based on current SVN r841).

The Bus Pirate is a universal (usb)serial-to-SPI/I2C/JTAG/... interface
with on-board +5V and +3.3V power supply, therefore it is a good
candidate for an AVR programmer.

The patch has been tested with Bus Pirate v1a with firmware 2.1.
Unfortunately I don't have the newer Bus Pirate v2 or v3 hardware but am
pretty confident it should work as well.

For more informations about the Bus Pirate check out Dangerous
Prototypes: http://dangerousprototypes.com/category/bus-pirate/

Here's a sample session:
~/src/avrdude-trunk$ ./avrdude -C ./avrdude.conf -p atmega328p \
                          -P /dev/ttyS0 -c buspirate -b 115200
Detecting BusPirate...
**
**  Bus Pirate v1a
**  http://dangerousprototypes.com
**  Firmware v2.1
**  DEVID:0x0447 REVID:0x3003 (A3)
**
BusPirate is now configured for SPI
avrdude: AVR device initialized and ready to accept instructions
Reading | ########################################## | 100% 0.34s
avrdude: Device signature = 0x1e950f
avrdude: safemode: Fuses OK
avrdude done.  Thank you.

Reading and writing Flash and EEPROM seem to work just fine.

The wiring is easy, the only exception bing that BusPirates's CS (Chip
Select) pin connects to AVR's RESET. Other than that it's obvious.

BusPirate  <->  AVR Chip
------------------------
      GND  <->  GND
      +5V  <->  Vcc
       CS  <->  RESET
     MOSI  <->  MOSI
     MISO  <->  MISO
  SCL/CLK  <->  SCK

I hope to see BusPirate supported in the next AVRdude release :-)

Michal




Index: avrdude-trunk/buspirate.c
===================================================================
--- /dev/null
+++ avrdude-trunk/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 <address@hidden>
+ *
+ * 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 v1a, 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"
+
+/* ====== 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;
+}
+
Index: avrdude-trunk/buspirate.h
===================================================================
--- /dev/null
+++ avrdude-trunk/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 <address@hidden>
+ *
+ * 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
Index: avrdude-trunk/config_gram.y
===================================================================
--- avrdude-trunk.orig/config_gram.y
+++ avrdude-trunk/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);
Index: avrdude-trunk/avrdude.conf.in
===================================================================
--- avrdude-trunk.orig/avrdude.conf.in
+++ avrdude-trunk/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
Index: avrdude-trunk/Makefile.am
===================================================================
--- avrdude-trunk.orig/Makefile.am
+++ avrdude-trunk/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 \
Index: avrdude-trunk/lexer.l
===================================================================
--- avrdude-trunk.orig/lexer.l
+++ avrdude-trunk/lexer.l
@@ -127,6 +127,7 @@ banked           { yylval=NULL; return K
 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; }
Index: avrdude-trunk/main.c
===================================================================
--- avrdude-trunk.orig/main.c
+++ avrdude-trunk/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) {

reply via email to

[Prev in Thread] Current Thread [Next in Thread]