From 86432b91d9832b1b189716b94e0f3600bb7fff9d Mon Sep 17 00:00:00 2001 From: Joerg Wunsch Date: Fri, 26 Aug 2011 20:22:09 +0000 Subject: [PATCH] Submitted by Brett Hagman: Add support for the "Wiring" board/bootloader * wiring.c: New file. * wiring.h: (Ditto.) * Makefile.am: Add new files. * stk500v2_private.h: Reorganize so some functions and struct pdata are globally known. * stk500v2.c: (Ditto.) * stk500v2.h: (Ditto.) * lexer.l: Add new programmer keywords. * config_gram.y: (Ditto.) * avrdude.conf.in: Add "wiring" programmer entry. * avrdude.1: Document the new programmer. * doc/avrdude.texi: (Ditto.) * AUTHORS: Add Brett Hagman. git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk/avrdude@987 81a1dc3b-b13d-400b-aceb-764788c761c2 --- AUTHORS | 2 + ChangeLog | 18 ++++ Makefile.am | 4 +- NEWS | 1 + avrdude.1 | 16 +++ avrdude.conf.in | 11 ++- config_gram.y | 8 ++ doc/avrdude.texi | 18 ++++ lexer.l | 1 + stk500v2.c | 68 ++++--------- stk500v2.h | 5 + stk500v2_private.h | 42 ++++++++ wiring.c | 235 +++++++++++++++++++++++++++++++++++++++++++++ wiring.h | 29 ++++++ 14 files changed, 405 insertions(+), 53 deletions(-) create mode 100644 wiring.c create mode 100644 wiring.h diff --git a/AUTHORS b/AUTHORS index fa37909e..d3c7a34a 100644 --- a/AUTHORS +++ b/AUTHORS @@ -20,5 +20,7 @@ Contributors: Ville Voipio Hannes Weisbach Doug Springer + Brett Hagman + For minor contributions, please see the ChangeLog files. diff --git a/ChangeLog b/ChangeLog index 2f46e9ed..46d97e17 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,21 @@ +2011-08-26 Joerg Wunsch + + Submitted by Brett Hagman: + Add support for the "Wiring" board/bootloader + * wiring.c: New file. + * wiring.h: (Ditto.) + * Makefile.am: Add new files. + * stk500v2_private.h: Reorganize so some functions and struct + pdata are globally known. + * stk500v2.c: (Ditto.) + * stk500v2.h: (Ditto.) + * lexer.l: Add new programmer keywords. + * config_gram.y: (Ditto.) + * avrdude.conf.in: Add "wiring" programmer entry. + * avrdude.1: Document the new programmer. + * doc/avrdude.texi: (Ditto.) + * AUTHORS: Add Brett Hagman. + 2011-08-26 Joerg Wunsch Submitted by an anonymous contributor on the mailinglist: diff --git a/Makefile.am b/Makefile.am index 8311dea0..49a3182b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -152,7 +152,9 @@ libavrdude_a_SOURCES = \ usbtiny.h \ usbtiny.c \ update.h \ - update.c + update.c \ + wiring.h \ + wiring.c avrdude_SOURCES = \ main.c \ diff --git a/NEWS b/NEWS index 2fa835d0..b9f69c5b 100644 --- a/NEWS +++ b/NEWS @@ -16,6 +16,7 @@ Current: - TPI programming through bitbang programmers (both, serial and parallel ones) - FT2232 (and relatives) based programmers (MPSSE bitbang mode) + - Wiring environment (http://wiring.org.co/) * Bugfixes diff --git a/avrdude.1 b/avrdude.1 index b7ea21f5..44ea4e70 100644 --- a/avrdude.1 +++ b/avrdude.1 @@ -107,6 +107,10 @@ Using firmware version 2, high-voltage programming is also supported, both parallel and serial (programmer types stk500pp and stk500hvsp). .Pp +Wiring boards are supported, utilizing STK500 V2.x protocol, but +a simple DTR/RTS toggle is used to set the boards into programming mode. +The programmer type is ``wiring''. +.Pp The Arduino (which is very similar to the STK500 1.x) is supported via its own programmer type specification ``arduino''. .Pp @@ -975,6 +979,18 @@ and .Ar speed= parameters unavailable. .El +.It Ar Wiring +When using the Wiring programmer type, the +following optional extended parameter is accepted: +.Bl -tag -offset indent -width indent +.It Ar snooze=<0..32767> +After performing the port open phase, AVRDUDE will wait/snooze for +.Ar snooze +milliseconds before continuing to the protocol sync phase. +No toggling of DTR/RTS is performed if +.Ar snooze +is greater than 0. +.El .El .Sh FILES .Bl -tag -offset indent -width /dev/ppi0XXX diff --git a/avrdude.conf.in b/avrdude.conf.in index 03c308da..9f0b0f88 100644 --- a/avrdude.conf.in +++ b/avrdude.conf.in @@ -21,7 +21,7 @@ # jtagmki | jtagmkii | jtagmkii_isp | jtagmkii_dw | # jtagmkII_avr32 | jtagmkii_pdi | # dragon_dw | dragon_jtag | dragon_isp | dragon_pp | -# dragon_hvsp | dragon_pdi | arduino; # programmer type +# dragon_hvsp | dragon_pdi | arduino | wiring; # programmer type # baudrate = ; # baudrate for avr910-programmer # vcc = [, ... ] ; # pin number(s) # reset = ; # pin number @@ -322,6 +322,15 @@ default_serial = "@DEFAULT_SER_PORT@"; # PROGRAMMER DEFINITIONS # +# http://wiring.org.co/ +# Basically STK500v2 protocol, with some glue to trigger the +# bootloader. +programmer + id = "wiring"; + desc = "Wiring"; + type = wiring; +; + programmer id = "arduino"; desc = "Arduino"; diff --git a/config_gram.y b/config_gram.y index 48ecf137..0e1af900 100644 --- a/config_gram.y +++ b/config_gram.y @@ -40,6 +40,7 @@ #include "arduino.h" #include "buspirate.h" #include "stk500v2.h" +#include "wiring.h" #include "stk500generic.h" #include "avr910.h" #include "butterfly.h" @@ -162,6 +163,7 @@ static int parse_cmdbits(OPCODE * op); %token K_TYPE %token K_VCC %token K_VFYLED +%token K_WIRING %token K_NO %token K_YES @@ -416,6 +418,12 @@ prog_parm : } } | + K_TYPE TKN_EQUAL K_WIRING { + { + wiring_initpgm(current_prog); + } + } | + K_TYPE TKN_EQUAL K_STK500HVSP { { stk500hvsp_initpgm(current_prog); diff --git a/doc/avrdude.texi b/doc/avrdude.texi index 7e7cbe7c..18bc4a50 100644 --- a/doc/avrdude.texi +++ b/doc/avrdude.texi @@ -214,6 +214,10 @@ option might be required to achieve a stable ISP communication. For ATxmega devices, the AVR Dragon is supported in PDI mode, provided it has a firmware version of at least 6.11 (decimal). +Wiring boards are supported, utilizing STK500 V2.x protocol, but +a simple DTR/RTS toggle to set the boards into programming mode. +The programmer type is ``wiring''. + The Arduino (which is very similar to the STK500 1.x) is supported via its own programmer type specification ``arduino''. @@ -571,6 +575,9 @@ USBtiny simple USB programmer,@* @url{http://www.ladyada.net/make/usbtinyisp/} @item @code{xil} @tab Xilinx JTAG cable +@item @code{wiring} @tab +Wiring board, utilizing STK500 V2.x protocol,@* +@url{http://wiring.org.co/} @end multitable @@ -1014,6 +1021,17 @@ and parameters unavailable. @end table +@item Wiring + +When using the Wiring programmer type, the +following optional extended parameter is accepted: +@table @code +@item @samp{snooze=@var{0..32767}} +After performing the port open phase, AVRDUDE will wait/snooze for +@var{snooze} milliseconds before continuing to the protocol sync phase. +No toggling of DTR/RTS is performed if @var{snooze} > 0. +@end table + @end table @page diff --git a/lexer.l b/lexer.l index d8790a68..980eb3ba 100644 --- a/lexer.l +++ b/lexer.l @@ -206,6 +206,7 @@ usbvendor { yylval=NULL; return K_USBVENDOR; } usbvid { yylval=NULL; return K_USBVID; } vcc { yylval=NULL; return K_VCC; } vfyled { yylval=NULL; return K_VFYLED; } +wiring { yylval=NULL; return K_WIRING; } timeout { yylval=NULL; return K_TIMEOUT; } stabdelay { yylval=NULL; return K_STABDELAY; } diff --git a/stk500v2.c b/stk500v2.c index 401af733..276d6f58 100644 --- a/stk500v2.c +++ b/stk500v2.c @@ -69,6 +69,12 @@ #define STK500V2_XTAL 7372800U +// Timeout (in seconds) for waiting for serial response +#define SERIAL_TIMEOUT 2 + +// Retry count +#define RETRIES 5 + #if 0 #define DEBUG(...) fprintf(stderr, __VA_ARGS__) #else @@ -87,46 +93,6 @@ enum hvmode }; -/* - * Private data for this programmer. - */ -struct pdata -{ - /* - * See stk500pp_read_byte() for an explanation of the flash and - * EEPROM page caches. - */ - unsigned char *flash_pagecache; - unsigned long flash_pageaddr; - unsigned int flash_pagesize; - - unsigned char *eeprom_pagecache; - unsigned long eeprom_pageaddr; - unsigned int eeprom_pagesize; - - unsigned char command_sequence; - - enum - { - PGMTYPE_UNKNOWN, - PGMTYPE_STK500, - PGMTYPE_AVRISP, - PGMTYPE_AVRISP_MKII, - PGMTYPE_JTAGICE_MKII, - PGMTYPE_STK600, - } - pgmtype; - - AVRPART *lastpart; - - /* - * Chained pdata for the JTAG ICE mkII backend. This is used when - * calling the backend functions for ISP/HVSP/PP programming - * functionality of the JTAG ICE mkII and AVR Dragon. - */ - void *chained_pdata; -}; - #define PDATA(pgm) ((struct pdata *)(pgm->cookie)) @@ -314,7 +280,7 @@ static void stk600_setup_xprog(PROGRAMMER * pgm); static void stk600_setup_isp(PROGRAMMER * pgm); static int stk600_xprog_program_enable(PROGRAMMER * pgm, AVRPART * p); -static void stk500v2_setup(PROGRAMMER * pgm) +void stk500v2_setup(PROGRAMMER * pgm) { if ((pgm->cookie = malloc(sizeof(struct pdata))) == 0) { fprintf(stderr, @@ -350,7 +316,7 @@ static void stk500v2_jtagmkII_setup(PROGRAMMER * pgm) PDATA(pgm)->chained_pdata = theircookie; } -static void stk500v2_teardown(PROGRAMMER * pgm) +void stk500v2_teardown(PROGRAMMER * pgm) { free(pgm->cookie); } @@ -486,7 +452,7 @@ static int stk500v2_send(PROGRAMMER * pgm, unsigned char * data, size_t len) } -static int stk500v2_drain(PROGRAMMER * pgm, int display) +int stk500v2_drain(PROGRAMMER * pgm, int display) { return serial_drain(&pgm->fd, display); } @@ -554,7 +520,7 @@ static int stk500v2_recv(PROGRAMMER * pgm, unsigned char msg[], size_t maxsize) int timeout = 0; unsigned char c, checksum = 0; - long timeoutval = 5; // seconds + long timeoutval = SERIAL_TIMEOUT; // seconds struct timeval tv; double tstart, tnow; @@ -647,7 +613,7 @@ static int stk500v2_recv(PROGRAMMER * pgm, unsigned char msg[], size_t maxsize) tnow = tv.tv_sec; if (tnow-tstart > timeoutval) { // wuff - signed/unsigned/overflow timedout: - fprintf(stderr, "%s: stk500_2_ReceiveMessage(): timeout\n", + fprintf(stderr, "%s: stk500v2_ReceiveMessage(): timeout\n", progname); return -1; } @@ -660,7 +626,7 @@ static int stk500v2_recv(PROGRAMMER * pgm, unsigned char msg[], size_t maxsize) -static int stk500v2_getsync(PROGRAMMER * pgm) { +int stk500v2_getsync(PROGRAMMER * pgm) { int tries = 0; unsigned char buf[1], resp[32]; int status; @@ -713,7 +679,7 @@ retry: progname, pgmname[PDATA(pgm)->pgmtype]); return 0; } else { - if (tries > 33) { + if (tries > RETRIES) { fprintf(stderr, "%s: stk500v2_getsync(): can't communicate with device: resp=0x%02x\n", progname, resp[0]); @@ -724,7 +690,7 @@ retry: // or if we got a timeout } else if (status == -1) { - if (tries > 33) { + if (tries > RETRIES) { fprintf(stderr,"%s: stk500v2_getsync(): timeout communicating with programmer\n", progname); return -1; @@ -733,7 +699,7 @@ retry: // or any other error } else { - if (tries > 33) { + if (tries > RETRIES) { fprintf(stderr,"%s: stk500v2_getsync(): error communicating with programmer: (%d)\n", progname,status); } else @@ -750,7 +716,7 @@ static int stk500v2_command(PROGRAMMER * pgm, unsigned char * buf, int status; DEBUG("STK500V2: stk500v2_command("); - for (i=0;i 33) { + if (tries > RETRIES) { fprintf(stderr,"%s: stk500v2_command(): failed miserably to execute command 0x%02x\n", progname,buf[0]); return -1; diff --git a/stk500v2.h b/stk500v2.h index 70e41cc2..2278270d 100644 --- a/stk500v2.h +++ b/stk500v2.h @@ -38,6 +38,11 @@ void stk600_initpgm (PROGRAMMER * pgm); void stk600hvsp_initpgm (PROGRAMMER * pgm); void stk600pp_initpgm (PROGRAMMER * pgm); +void stk500v2_setup(PROGRAMMER * pgm); +void stk500v2_teardown(PROGRAMMER * pgm); +int stk500v2_drain(PROGRAMMER * pgm, int display); +int stk500v2_getsync(PROGRAMMER * pgm); + #ifdef __cplusplus } #endif diff --git a/stk500v2_private.h b/stk500v2_private.h index 2f3cd2af..66a419b7 100644 --- a/stk500v2_private.h +++ b/stk500v2_private.h @@ -9,6 +9,8 @@ //* //************************************************************************** +#include "pgm.h" + // *****************[ STK message constants ]*************************** #define MESSAGE_START 0x1B //= ESC = 27 decimal @@ -278,3 +280,43 @@ #define ANSWER_CKSUM_ERROR 0xB0 +/* + * Private data for this programmer. + */ +struct pdata +{ + /* + * See stk500pp_read_byte() for an explanation of the flash and + * EEPROM page caches. + */ + unsigned char *flash_pagecache; + unsigned long flash_pageaddr; + unsigned int flash_pagesize; + + unsigned char *eeprom_pagecache; + unsigned long eeprom_pageaddr; + unsigned int eeprom_pagesize; + + unsigned char command_sequence; + + enum + { + PGMTYPE_UNKNOWN, + PGMTYPE_STK500, + PGMTYPE_AVRISP, + PGMTYPE_AVRISP_MKII, + PGMTYPE_JTAGICE_MKII, + PGMTYPE_STK600, + } + pgmtype; + + AVRPART *lastpart; + + /* + * Chained pdata for the JTAG ICE mkII backend. This is used when + * calling the backend functions for ISP/HVSP/PP programming + * functionality of the JTAG ICE mkII and AVR Dragon. + */ + void *chained_pdata; +}; + diff --git a/wiring.c b/wiring.c new file mode 100644 index 00000000..6c71e6e9 --- /dev/null +++ b/wiring.c @@ -0,0 +1,235 @@ +/* + * avrdude - A Downloader/Uploader for AVR device programmers + * Copyright (C) 2011 Brett Hagman + * + * 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$ */ + +/* + * avrdude interface for Wiring bootloaders + * + * http://wiring.org.co/ + * + * The Wiring bootloader uses a near-complete STK500v2 protocol. + * (Only ISP specific programming commands are not implemented + * e.g. chip erase). + * DTR and RTS signals are diddled to set the board into programming mode. + * + * Also includes an extended parameter to introduce a delay after opening + * to accommodate multi-layered programmers/bootloaders. If the extended + * parameter 'snooze' > 0, then no DTR/RTS toggle takes place, and + * AVRDUDE will wait that amount of time in milliseconds before syncing. + * + * Unfortunately, there is no way to easily chain private programmer data + * when we "inherit" programmer types as we have (stk500v2). Sooooo, a + * *cringe* global variable is used to store the snooze time. + */ + +#include "ac_cfg.h" + +#include +#include +#include + +#include "avrdude.h" +#include "pgm.h" +#include "stk500v2_private.h" +#include "stk500v2.h" +#include "serial.h" + +/* + * Private data for this programmer. + */ +struct wiringpdata +{ + /* + * We just have the single snooze integer to carry around for now. + */ + int snoozetime; +}; + + +/* wiringpdata is our private data */ +/* pdata is stk500v2's private data (inherited) */ + +#define WIRINGPDATA(x) ((struct wiringpdata *)(x)) + +#define STK500V2PDATA(pgm) ((struct pdata *)(pgm->cookie)) + + +static void wiring_setup(PROGRAMMER * pgm) +{ + void *mycookie; + + /* + * First, have STK500v2 backend allocate its own private data. + */ + stk500v2_setup(pgm); + + /* + * Now prepare our data + */ + if ((mycookie = malloc(sizeof(struct wiringpdata))) == 0) { + fprintf(stderr, + "%s: wiring_setup(): Out of memory allocating private data\n", + progname); + exit(1); + } + memset(mycookie, 0, sizeof(struct wiringpdata)); + WIRINGPDATA(mycookie)->snoozetime = 0; + + /* + * Store our own cookie in a safe place for the time being. + */ + STK500V2PDATA(pgm)->chained_pdata = mycookie; +} + +static void wiring_teardown(PROGRAMMER * pgm) +{ + void *mycookie; + + mycookie = STK500V2PDATA(pgm)->chained_pdata; + + free(mycookie); + + stk500v2_teardown(pgm); +} + +static int wiring_parseextparms(PROGRAMMER * pgm, LISTID extparms) +{ + LNODEID ln; + const char *extended_param; + int rv = 0; + void *mycookie = STK500V2PDATA(pgm)->chained_pdata; + + for (ln = lfirst(extparms); ln; ln = lnext(ln)) { + extended_param = ldata(ln); + + if (strncmp(extended_param, "snooze=", strlen("snooze=")) == 0) { + int newsnooze; + if (sscanf(extended_param, "snooze=%i", &newsnooze) != 1 || + newsnooze < 0) { + fprintf(stderr, + "%s: wiring_parseextparms(): invalid snooze time '%s'\n", + progname, extended_param); + rv = -1; + continue; + } + if (verbose >= 2) { + fprintf(stderr, + "%s: wiring_parseextparms(): snooze time set to %d ms\n", + progname, newsnooze); + } + WIRINGPDATA(mycookie)->snoozetime = newsnooze; + + continue; + } + + fprintf(stderr, + "%s: wiring_parseextparms(): invalid extended parameter '%s'\n", + progname, extended_param); + rv = -1; + } + + return rv; +} + +static int wiring_open(PROGRAMMER * pgm, char * port) +{ + int timetosnooze; + void *mycookie = STK500V2PDATA(pgm)->chained_pdata; + + strcpy(pgm->port, port); + serial_open(port, pgm->baudrate ? pgm->baudrate: 115200, &pgm->fd); + + /* If we have a snoozetime, then we wait and do NOT toggle DTR/RTS */ + + if (WIRINGPDATA(mycookie)->snoozetime > 0) { + timetosnooze = WIRINGPDATA(mycookie)->snoozetime; + + if (verbose >= 2) { + fprintf(stderr, + "%s: wiring_open(): snoozing for %d ms\n", + progname, timetosnooze); + } + while (timetosnooze--) + usleep(1000); + if (verbose >= 2) { + fprintf(stderr, + "%s: wiring_open(): done snoozing\n", + progname); + } + + } else { + /* Perform Wiring programming mode RESET. */ + /* This effectively *releases* both DTR and RTS. */ + /* i.e. both DTR and RTS rise to a HIGH logic level */ + /* since they are active LOW signals. */ + + if (verbose >= 2) { + fprintf(stderr, + "%s: wiring_open(): releasing DTR/RTS\n", + progname); + } + + serial_set_dtr_rts(&pgm->fd, 0); + usleep(50*1000); + + /* After releasing for 50 milliseconds, DTR and RTS */ + /* are asserted (i.e. logic LOW) again. */ + + if (verbose >= 2) { + fprintf(stderr, + "%s: wiring_open(): asserting DTR/RTS\n", + progname); + } + + serial_set_dtr_rts(&pgm->fd, 1); + usleep(50*1000); + } + + /* drain any extraneous input */ + stk500v2_drain(pgm, 0); + + if (stk500v2_getsync(pgm) < 0) + return -1; + + return 0; +} + +static void wiring_close(PROGRAMMER * pgm) +{ + serial_set_dtr_rts(&pgm->fd, 0); + serial_close(&pgm->fd); + pgm->fd.ifd = -1; +} + +void wiring_initpgm(PROGRAMMER * pgm) +{ + /* The Wiring bootloader uses a near-complete STK500v2 protocol. */ + + stk500v2_initpgm(pgm); + + strcpy(pgm->type, "Wiring"); + pgm->open = wiring_open; + pgm->close = wiring_close; + + pgm->setup = wiring_setup; + pgm->teardown = wiring_teardown; + pgm->parseextparams = wiring_parseextparms; +} + diff --git a/wiring.h b/wiring.h new file mode 100644 index 00000000..57f70a75 --- /dev/null +++ b/wiring.h @@ -0,0 +1,29 @@ +/* + * avrdude - A Downloader/Uploader for AVR device programmers + * Copyright (C) 2011 Brett Hagman + * + * 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$ */ + +#ifndef wiring_h__ +#define wiring_h__ + +void wiring_initpgm(PROGRAMMER * pgm); + +#endif + +