diff --git a/ChangeLog b/ChangeLog index 535de7ae..d3b62171 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,20 @@ +2006-01-13 Joerg Wunsch + + Contributed by dcm@mit.edu: add support for the + AVRISP mkII device. (Savannah patch #4789.) + * serial.h: Declare usb_serdev_frame device descriptor. + * stk500v2.c: Implementation of the AVRISP mkII handling. + * usb_libusb.c: Add USB handling for short-frame delimited + AVRISP mkII USB protocol; add distinction of different + devices in usbdev_open(). + * jtagmkII.c: Tell usbdev_open() to search for the JTAG ICE mkII. + * usbdevs.h: (New file.) + * Makefile.am: Add usbdevs.h, as well as some other forgotten + files "make distcheck" complained about. + * avrdude.conf.in: Add more aliases for the AVRISP mkII. + * avrdude.1: Document how to use the AVRISP mkII. + * doc/avrdude.texi: (Ditto.) + 2006-01-12 Joerg Wunsch * avrdude.conf.in: Add EEPROM page instructions for the diff --git a/Makefile.am b/Makefile.am index 54eb0562..73912bc0 100644 --- a/Makefile.am +++ b/Makefile.am @@ -22,6 +22,7 @@ # EXTRA_DIST = \ + ChangeLog \ ChangeLog-2001 \ ChangeLog-2002 \ ChangeLog-2003 \ @@ -69,6 +70,7 @@ avrdude_SOURCES = \ crc16.h \ fileio.c \ fileio.h \ + freebsd_ppi.h \ jtagmkI.c \ jtagmkI.h \ jtagmkI_private.h \ @@ -95,6 +97,7 @@ avrdude_SOURCES = \ serbb_win32.c \ ser_posix.c \ ser_win32.c \ + solaris_ecpp.h \ stk500.c \ stk500.h \ stk500_private.h \ @@ -103,6 +106,7 @@ avrdude_SOURCES = \ stk500v2_private.h \ term.c \ term.h \ + usbdevs.h \ usb_libusb.c man_MANS = avrdude.1 diff --git a/avrdude.1 b/avrdude.1 index 3d9f0dd0..fb9759f0 100644 --- a/avrdude.1 +++ b/avrdude.1 @@ -55,6 +55,7 @@ is a program for downloading code and data to Atmel AVR microcontrollers. .Nm Avrdude supports Atmel's STK500 programmer, +Atmel's AVRISP and AVRISP mkII devices, Atmel's JTAG ICE (both mkI and mkII), programmers complying to AppNote AVR910 and AVR109 (including the Butterfly), as well as a simple hard-wired @@ -352,6 +353,9 @@ from any JTAG ICE mkII found on USB. The match is done after stripping any existing colons from the given serial number, and right-to-left, so only the least significant bytes from the serial number need to be given. +.Pp +As the AVRISP mkII device can only be talked to over USB, the very +same method of specifying the port is required there. .It Fl q Disable (or quell) output of the progress bar while reading or writing to the device. Specify it a second time for even quieter operation. diff --git a/avrdude.conf.in b/avrdude.conf.in index 5bf61e4f..3aa35dff 100644 --- a/avrdude.conf.in +++ b/avrdude.conf.in @@ -233,6 +233,18 @@ programmer type = stk500v2; ; +programmer + id = "avrispmkII"; + desc = "Atmel AVR ISP mkII"; + type = stk500v2; +; + +programmer + id = "avrisp2"; + desc = "Atmel AVR ISP mkII"; + type = stk500v2; +; + programmer id = "stk500"; desc = "Atmel STK500"; diff --git a/doc/avrdude.texi b/doc/avrdude.texi index cb8362c5..d693de8c 100644 --- a/doc/avrdude.texi +++ b/doc/avrdude.texi @@ -135,7 +135,8 @@ from the contents of a file, while interactive mode is useful for exploring memory contents, modifing individual bytes of eeprom, programming fuse/lock bits, etc. -AVRDUDE supports six basic programmer types: Atmel's STK500, +AVRDUDE supports the following basic programmer types: Atmel's STK500, +Atmel's AVRISP and AVRISP mkII devices, Atmel's JTAG ICE (both mkI and mkII), appnote avr910, appnote avr109 (including the AVR Butterfly), serial bit-bang adapters, @@ -430,7 +431,16 @@ Atmel Low Cost Serial Programmer Atmel AppNote AVR911 AVROSP (an alias for avr109) @itemx avrisp -Atmel AVR ISP +Atmel AVR ISP (an alias for stk500) + +@itemx avrispv2 +Atmel AVR ISP, running a version 2.x firmware (an alias for stk500v2) + +@itemx avrispmkII +Atmel AVR ISP mkII (alias for stk500v2) + +@itemx avrispmk2 +Atmel AVR ISP mkII (alias for stk500v2) @itemx bascom Bascom SAMPLE programming cable @@ -480,7 +490,7 @@ STK200 Atmel STK500 @itemx stk500v2 -Atmel STK500, running a verrsion 2.x firmware +Atmel STK500, running a version 2.x firmware @end table @@ -579,6 +589,9 @@ bytes from the serial number need to be given. For a trick how to find out the serial numbers of all JTAG ICEs attached to USB, see @ref{Example Command Line Invocations}. +As the AVRISP mkII device can only be talked to over USB, the very +same method of specifying the port is required there. + @item -q Disable (or quell) output of the progress bar while reading or writing to the device. Specify it a second time for even quieter operation. diff --git a/jtagmkII.c b/jtagmkII.c index a9796a02..a8605159 100644 --- a/jtagmkII.c +++ b/jtagmkII.c @@ -1,6 +1,6 @@ /* * avrdude - A Downloader/Uploader for AVR device programmers - * Copyright (C) 2005 Joerg Wunsch + * Copyright (C) 2005,2006 Joerg Wunsch * * Derived from stk500 code which is: * Copyright (C) 2002-2004 Brian S. Dean @@ -43,6 +43,7 @@ #include "pgm.h" #include "jtagmkII_private.h" #include "serial.h" +#include "usbdevs.h" extern int verbose; @@ -1044,26 +1045,34 @@ static void jtagmkII_enable(PROGRAMMER * pgm) static int jtagmkII_open(PROGRAMMER * pgm, char * port) { + long baud; + if (verbose >= 2) fprintf(stderr, "%s: jtagmkII_open()\n", progname); -#if defined(HAVE_LIBUSB) - /* - * If the port name starts with "usb", divert the serial routines - * to the USB ones. - */ - if (strncmp(port, "usb", 3) == 0) - serdev = &usb_serdev; -#endif - - strcpy(pgm->port, port); /* * The JTAG ICE mkII always starts with a baud rate of 19200 Bd upon * attaching. If the config file or command-line parameters specify * a higher baud rate, we switch to it later on, after establishing * the connection with the ICE. */ - pgm->fd = serial_open(port, 19200); + baud = 19200; + +#if defined(HAVE_LIBUSB) + /* + * If the port name starts with "usb", divert the serial routines + * to the USB ones. The serial_open() function for USB overrides + * the meaning of the "baud" parameter to be the USB device ID to + * search for. + */ + if (strncmp(port, "usb", 3) == 0) { + serdev = &usb_serdev; + baud = USB_DEVICE_JTAGICEMKII; + } +#endif + + strcpy(pgm->port, port); + pgm->fd = serial_open(port, baud); /* * drain any extraneous input diff --git a/serial.h b/serial.h index 5b557032..ddfc6d9a 100644 --- a/serial.h +++ b/serial.h @@ -44,7 +44,7 @@ struct serial_device }; extern struct serial_device *serdev; -extern struct serial_device serial_serdev, usb_serdev; +extern struct serial_device serial_serdev, usb_serdev, usb_serdev_frame; #define serial_open (serdev->open) #define serial_setspeed (serdev->setspeed) diff --git a/stk500v2.c b/stk500v2.c index c8aa49a9..a49142d3 100644 --- a/stk500v2.c +++ b/stk500v2.c @@ -2,6 +2,7 @@ * avrdude - A Downloader/Uploader for AVR device programmers * Copyright (C) 2005 Erik Walthinsen * Copyright (C) 2002-2004 Brian S. Dean + * Copyright (C) 2006 dcm@mit.edu * * 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 @@ -24,6 +25,10 @@ /* * avrdude interface for Atmel STK500V2 programmer * + * As the AVRISP mkII device is basically an STK500v2 one that can + * only talk across USB, and that misses any kind of framing protocol, + * this is handled here as well. + * * Note: most commands use the "universal command" feature of the * programmer in a "pass through" mode, exceptions are "program * enable", "paged read", and "paged write". @@ -45,6 +50,7 @@ #include "stk500_private.h" // temp until all code converted #include "stk500v2_private.h" #include "serial.h" +#include "usbdevs.h" #define STK500V2_XTAL 7372800U @@ -66,6 +72,7 @@ extern char * progname; extern int do_cycles; static unsigned char command_sequence = 1; +static int is_mk2; /* Is the device an AVRISP mkII? */ static int stk500v2_getparm(PROGRAMMER * pgm, unsigned char parm, unsigned char * value); @@ -74,12 +81,26 @@ static void stk500v2_print_parms1(PROGRAMMER * pgm, char * p); static int stk500v2_is_page_empty(unsigned int address, int page_size, const unsigned char *buf); +static int stk500v2_set_sck_period_mk2(PROGRAMMER * pgm, double v); + +static int stk500v2_send_mk2(PROGRAMMER * pgm, unsigned char * data, size_t len) +{ + if (serial_send(pgm->fd, data, len) != 0) { + fprintf(stderr,"%s: stk500_send_mk2(): failed to send command to serial port\n",progname); + exit(1); + } + + return 0; +} static int stk500v2_send(PROGRAMMER * pgm, unsigned char * data, size_t len) { unsigned char buf[275 + 6]; // max MESSAGE_BODY of 275 bytes, 6 bytes overhead int i; + if (is_mk2) + return stk500v2_send_mk2(pgm, data, len); + buf[0] = MESSAGE_START; buf[1] = command_sequence; buf[2] = len / 256; @@ -110,6 +131,19 @@ static int stk500v2_drain(PROGRAMMER * pgm, int display) return serial_drain(pgm->fd, display); } +static int stk500v2_recv_mk2(PROGRAMMER * pgm, unsigned char msg[], + size_t maxsize) +{ + int rv; + + rv = serial_recv(pgm->fd, msg, maxsize); + if (rv < 0) { + fprintf(stderr, "%s: stk500v2_recv_mk2: error in USB receive\n", progname); + return -1; + } + + return rv; +} static int stk500v2_recv(PROGRAMMER * pgm, unsigned char msg[], size_t maxsize) { enum states { sINIT, sSTART, sSEQNUM, sSIZE1, sSIZE2, sTOKEN, sDATA, sCSUM, sDONE } state = sSTART; @@ -122,6 +156,9 @@ static int stk500v2_recv(PROGRAMMER * pgm, unsigned char msg[], size_t maxsize) struct timeval tv; double tstart, tnow; + if (is_mk2) + return stk500v2_recv_mk2(pgm, msg, maxsize); + DEBUG("STK500V2: stk500v2_recv(): "); gettimeofday(&tv, NULL); @@ -437,13 +474,30 @@ static void stk500v2_enable(PROGRAMMER * pgm) static int stk500v2_open(PROGRAMMER * pgm, char * port) { + long baud = 115200; + DEBUG("STK500V2: stk500v2_open()\n"); - strcpy(pgm->port, port); if (pgm->baudrate) - pgm->fd = serial_open(port, pgm->baudrate); - else - pgm->fd = serial_open(port, 115200); + baud = pgm->baudrate; + +#if defined(HAVE_LIBUSB) + /* + * If the port name starts with "usb", divert the serial routines + * to the USB ones. The serial_open() function for USB overrides + * the meaning of the "baud" parameter to be the USB device ID to + * search for. + */ + if (strncmp(port, "usb", 3) == 0) { + serdev = &usb_serdev_frame; + baud = USB_DEVICE_AVRISPMKII; + is_mk2 = 1; + pgm->set_sck_period = stk500v2_set_sck_period_mk2; + } +#endif + + strcpy(pgm->port, port); + pgm->fd = serial_open(port, baud); /* * drain any extraneous input @@ -797,6 +851,44 @@ static int stk500v2_set_fosc(PROGRAMMER * pgm, double v) return 0; } +/* The list of SCK frequencies supported by the AVRISP mkII, as listed + * in AVR069 */ +double avrispmkIIfreqs[] = { + 8000000, 4000000, 2000000, 1000000, 500000, 250000, 125000, + 96386, 89888, 84211, 79208, 74767, 70797, 67227, 64000, + 61069, 58395, 55945, 51613, 49690, 47905, 46243, 43244, + 41885, 39409, 38278, 36200, 34335, 32654, 31129, 29740, + 28470, 27304, 25724, 24768, 23461, 22285, 21221, 20254, + 19371, 18562, 17583, 16914, 16097, 15356, 14520, 13914, + 13224, 12599, 12031, 11511, 10944, 10431, 9963, 9468, + 9081, 8612, 8239, 7851, 7498, 7137, 6809, 6478, 6178, + 5879, 5607, 5359, 5093, 4870, 4633, 4418, 4209, 4019, + 3823, 3645, 3474, 3310, 3161, 3011, 2869, 2734, 2611, + 2484, 2369, 2257, 2152, 2052, 1956, 1866, 1779, 1695, + 1615, 1539, 1468, 1398, 1333, 1271, 1212, 1155, 1101, + 1049, 1000, 953, 909, 866, 826, 787, 750, 715, 682, + 650, 619, 590, 563, 536, 511, 487, 465, 443, 422, + 402, 384, 366, 349, 332, 317, 302, 288, 274, 261, + 249, 238, 226, 216, 206, 196, 187, 178, 170, 162, + 154, 147, 140, 134, 128, 122, 116, 111, 105, 100, + 95.4, 90.9, 86.6, 82.6, 78.7, 75.0, 71.5, 68.2, + 65.0, 61.9, 59.0, 56.3, 53.6, 51.1 +}; + +static int stk500v2_set_sck_period_mk2(PROGRAMMER * pgm, double v) +{ + int i; + + for (i = 0; i < sizeof(avrispmkIIfreqs); i++) { + if (1 / avrispmkIIfreqs[i] >= v) + break; + } + + fprintf(stderr, "Using p = %.2f us for SCK (param = %d)\n", + 1000000 / avrispmkIIfreqs[i], i); + + return stk500v2_setparm(pgm, PARAM_SCK_DURATION, i); +} /* This code assumes that each count of the SCK duration parameter represents 8/f, where f is the clock frequency of the STK500V2 master @@ -938,7 +1030,11 @@ static void stk500v2_print_parms1(PROGRAMMER * pgm, char * p) unit = "Hz"; fprintf(stderr, "%.3f %s\n", f, unit); } - fprintf(stderr, "%sSCK period : %.1f us\n", p, + if (is_mk2) + fprintf(stderr, "%sSCK period : %.2f us\n", p, + (float) 1000000 / avrispmkIIfreqs[sck_duration]); + else + fprintf(stderr, "%sSCK period : %.1f us\n", p, sck_duration * 8.0e6 / STK500V2_XTAL + 0.05); return; diff --git a/usb_libusb.c b/usb_libusb.c index 901f16ec..bcfdce2c 100644 --- a/usb_libusb.c +++ b/usb_libusb.c @@ -1,6 +1,7 @@ /* * avrdude - A Downloader/Uploader for AVR device programmers - * Copyright (C) 2005 Joerg Wunsch + * Copyright (C) 2005,2006 Joerg Wunsch + * Copyright (C) 2006 dcm@mit.edu * * 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 @@ -38,28 +39,24 @@ #include #include "serial.h" +#include "usbdevs.h" extern char *progname; extern int verbose; -#define USB_VENDOR_ATMEL 1003 -#define USB_DEVICE_JTAGICEMKII 0x2103 -/* - * Should we query the endpoint number and max transfer size from USB? - * After all, the JTAG ICE mkII docs document these values. - */ -#define JTAGICE_BULK_EP_WRITE 0x02 -#define JTAGICE_BULK_EP_READ 0x82 -#define JTAGICE_MAX_XFER 64 - -static char usbbuf[JTAGICE_MAX_XFER]; +static char usbbuf[USBDEV_MAX_XFER]; static int buflen = -1, bufptr; static int usb_interface; +/* + * The "baud" parameter is meaningless for USB devices, so we reuse it + * to pass the desired USB device ID. + */ static int usbdev_open(char * port, long baud) { char string[256]; + char product[256]; struct usb_bus *bus; struct usb_device *dev; usb_dev_handle *udev; @@ -110,7 +107,7 @@ static int usbdev_open(char * port, long baud) if (udev) { if (dev->descriptor.idVendor == USB_VENDOR_ATMEL && - dev->descriptor.idProduct == USB_DEVICE_JTAGICEMKII) + dev->descriptor.idProduct == (unsigned short)baud) { /* yeah, we found something */ if (usb_get_string_simple(udev, @@ -133,10 +130,20 @@ static int usbdev_open(char * port, long baud) strcpy(string, "[unknown]"); } + if (usb_get_string_simple(udev, + dev->descriptor.iProduct, + product, sizeof(product)) < 0) + { + fprintf(stderr, + "%s: usb_open(): cannot read product name \"%s\"\n", + progname, usb_strerror()); + strcpy(product, "[unnamed product]"); + } + if (verbose) fprintf(stderr, - "%s: usbdev_open(): Found JTAG ICE, serno: %s\n", - progname, string); + "%s: usbdev_open(): Found %s, serno: %s\n", + progname, product, string); if (serno != NULL) { /* @@ -205,6 +212,13 @@ static void usbdev_close(int fd) usb_dev_handle *udev = (usb_dev_handle *)fd; (void)usb_release_interface(udev, usb_interface); + + /* + * Without this reset, the AVRISP mkII seems to stall the second + * time we try to connect to it. + */ + usb_reset(udev); + usb_close(udev); } @@ -213,13 +227,48 @@ static int usbdev_send(int fd, unsigned char *bp, size_t mlen) { usb_dev_handle *udev = (usb_dev_handle *)fd; size_t rv; + int i = mlen; + unsigned char * p = bp; + int tx_size; - rv = usb_bulk_write(udev, JTAGICE_BULK_EP_WRITE, (char *)bp, mlen, 5000); - if (rv != mlen) + /* + * Split the frame into multiple packets. It's important to make + * sure we finish with a short packet, or else the device won't know + * the frame is finished. For example, if we need to send 64 bytes, + * we must send a packet of length 64 followed by a packet of length + * 0. + */ + do { + tx_size = (mlen < USBDEV_MAX_XFER)? mlen: USBDEV_MAX_XFER; + rv = usb_bulk_write(udev, USBDEV_BULK_EP_WRITE, (char *)bp, tx_size, 5000); + if (rv != tx_size) + { + fprintf(stderr, "%s: usbdev_send(): wrote %d out of %d bytes, err = %s\n", + progname, rv, tx_size, usb_strerror()); + return -1; + } + bp += tx_size; + mlen -= tx_size; + } while (tx_size == USBDEV_MAX_XFER); + + if (verbose > 3) { - fprintf(stderr, "%s: usbdev_send(): wrote %d out of %d bytes, err = %s\n", - progname, rv, mlen, usb_strerror()); - return -1; + fprintf(stderr, "%s: Sent: ", progname); + + while (i) { + unsigned char c = *p; + if (isprint(c)) { + fprintf(stderr, "%c ", c); + } + else { + fprintf(stderr, ". "); + } + fprintf(stderr, "[%02x] ", c); + + p++; + i--; + } + fprintf(stderr, "\n"); } return 0; } @@ -237,7 +286,7 @@ usb_fill_buf(usb_dev_handle *udev) { int rv; - rv = usb_bulk_read(udev, JTAGICE_BULK_EP_READ, usbbuf, JTAGICE_MAX_XFER, 5000); + rv = usb_bulk_read(udev, USBDEV_BULK_EP_READ, usbbuf, USBDEV_MAX_XFER, 5000); if (rv < 0) { if (verbose > 1) @@ -295,6 +344,71 @@ static int usbdev_recv(int fd, unsigned char *buf, size_t nbytes) return 0; } +/* + * This version of recv keeps reading packets until we receive a short + * packet. Then, the entire frame is assembled and returned to the + * user. The length will be unknown in advance, so we return the + * length as the return value of this function, or -1 in case of an + * error. + * + * This is used for the AVRISP mkII device. + */ +static int usbdev_recv_frame(int fd, unsigned char *buf, size_t nbytes) +{ + usb_dev_handle *udev = (usb_dev_handle *)fd; + int rv, n; + int i; + unsigned char * p = buf; + + n = 0; + do + { + rv = usb_bulk_read(udev, USBDEV_BULK_EP_READ, usbbuf, + USBDEV_MAX_XFER, 10000); + if (rv < 0) + { + if (verbose > 1) + fprintf(stderr, "%s: usbdev_recv_frame(): usb_bulk_read(): %s\n", + progname, usb_strerror()); + return -1; + } + + if (rv <= nbytes) + { + memcpy (buf, usbbuf, rv); + buf += rv; + } + + n += rv; + nbytes -= rv; + } + while (rv == USBDEV_MAX_XFER); + + if (nbytes < 0) + return -1; + + if (verbose > 3) + { + i = n; + fprintf(stderr, "%s: Recv: ", progname); + + while (i) { + unsigned char c = *p; + if (isprint(c)) { + fprintf(stderr, "%c ", c); + } + else { + fprintf(stderr, ". "); + } + fprintf(stderr, "[%02x] ", c); + + p++; + i--; + } + fprintf(stderr, "\n"); + } + return n; +} static int usbdev_drain(int fd, int display) { @@ -302,7 +416,7 @@ static int usbdev_drain(int fd, int display) int rv; do { - rv = usb_bulk_read(udev, JTAGICE_BULK_EP_READ, usbbuf, JTAGICE_MAX_XFER, 100); + rv = usb_bulk_read(udev, USBDEV_BULK_EP_READ, usbbuf, USBDEV_MAX_XFER, 100); if (rv > 0 && verbose >= 4) fprintf(stderr, "%s: usbdev_drain(): flushed %d characters\n", progname, rv); @@ -311,6 +425,9 @@ static int usbdev_drain(int fd, int display) return 0; } +/* + * Device descriptor for the JTAG ICE mkII. + */ struct serial_device usb_serdev = { .open = usbdev_open, @@ -321,4 +438,17 @@ struct serial_device usb_serdev = .drain = usbdev_drain, }; +/* + * Device descriptor for the AVRISP mkII. + */ +struct serial_device usb_serdev_frame = +{ + .open = usbdev_open, + .setspeed = usbdev_setspeed, + .close = usbdev_close, + .send = usbdev_send, + .recv = usbdev_recv_frame, + .drain = usbdev_drain, +}; + #endif /* HAVE_LIBUSB */ diff --git a/usbdevs.h b/usbdevs.h new file mode 100644 index 00000000..608f9d70 --- /dev/null +++ b/usbdevs.h @@ -0,0 +1,40 @@ +/* + * avrdude - A Downloader/Uploader for AVR device programmers + * Copyright (C) 2006 Joerg Wunsch + * + * 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 + */ + +/* $Id$ */ + +/* + * defines for the USB interface + */ + +#ifndef usbdevs_h +#define usbdevs_h + +#define USB_VENDOR_ATMEL 1003 +#define USB_DEVICE_JTAGICEMKII 0x2103 +#define USB_DEVICE_AVRISPMKII 0x2104 +/* + * Should we query the endpoint number and max transfer size from USB? + * After all, the JTAG ICE mkII docs document these values. + */ +#define USBDEV_BULK_EP_WRITE 0x02 +#define USBDEV_BULK_EP_READ 0x82 +#define USBDEV_MAX_XFER 64 + +#endif /* usbdevs_h */