diff --git a/ChangeLog b/ChangeLog index c3dbe603..14122db3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,34 @@ +2008-03-14 Joerg Wunsch + + Add initial support for the Atmel STK600, for + "classic" AVRs (AT90, ATtiny, ATmega) in both, + ISP and high-voltage programming modes. + * Makefile.am: Add -lm. + * avrdude.conf.in: Add stk600, stk600pp, and stk600hvsp. + * config_gram.y: Add support for the stk600* keywords. + * lexer.l: (Ditto.) + * pgm.h: Add the "chan" parameter to set_varef(). + * stk500.c: (Ditto.) + * serial.h: Add USB endpoint support to struct filedescriptor. + * stk500v2.c: Implement the meat of the STK600 support. + * stk500v2.h: Add new prototypes for stk600*() programmers. + * stk500v2_private.h: Add new constants used in the STK600. + * term.c: Add AREF channel support. + * usb_libusb.c: Automatically determine the correct write + endpoint ID, the STK600 uses 0x83 while all other tools use + 0x82. Propagate the EP to use through struct filedescriptor. + * usbdevs.h: Add the STK600 USB product ID. + * tools/get-stk600-cards.xsl: XSL transformation for + targetboards.xml to obtain the list of socket and routing + card IDs, to be used in stk500v2.c (for displaying the + names). + * tools/get-stk600-devices.xsl: XSL transformation for + targetboards.xml to obtain the table of socket/routing cards + and their respective AVR device support for doc/avrdude.texi. + * avrdude.1: Document all the STK600 stuff. + * doc/avrdude.texi: Ditto. Added a new chapter for + Programmer Specific Information. + 2008-01-26 Joerg Wunsch * stk500v2.c (stk500v2_recv): Make length computation unsigned so diff --git a/Makefile.am b/Makefile.am index 094c177d..93e1c0e7 100644 --- a/Makefile.am +++ b/Makefile.am @@ -52,7 +52,7 @@ avrdude_CFLAGS = @ENABLE_WARNINGS@ libavrdude_a_CFLAGS = @ENABLE_WARNINGS@ -avrdude_LDADD = $(top_builddir)/$(noinst_LIBRARIES) @LIBUSB@ @LIBHID@ +avrdude_LDADD = $(top_builddir)/$(noinst_LIBRARIES) @LIBUSB@ @LIBHID@ -lm bin_PROGRAMS = avrdude diff --git a/NEWS b/NEWS index 2d241cc7..7367baee 100644 --- a/NEWS +++ b/NEWS @@ -13,6 +13,9 @@ Current: * Add support for JTAG daisy-chains, using the -x daisychain= option. + * Add support for the Atmel STK600 for "classic" AVRs (AT90, ATtiny, + ATmega), using either ISP or high-voltage programming modes. + Version 5.5: * Add support for the USBtinyISP programmer (patch #6233) diff --git a/avrdude.1 b/avrdude.1 index 707cd33a..0ecad037 100644 --- a/avrdude.1 +++ b/avrdude.1 @@ -19,7 +19,7 @@ .\" .\" $Id$ .\" -.Dd DATE November 6, 2007 +.Dd DATE March 14, 2008 .Os .Dt AVRDUDE 1 .Sh NAME @@ -59,6 +59,7 @@ microcontrollers. .Nm Avrdude supports Atmel's STK500 programmer, Atmel's AVRISP and AVRISP mkII devices, +Atmel's STK600, Atmel's JTAG ICE (both mkI and mkII, the latter also in ISP mode), programmers complying to AppNote AVR910 and AVR109 (including the Butterfly), as well as a simple hard-wired @@ -106,6 +107,9 @@ Using firmware version 2, high-voltage programming is also supported, both parallel and serial (programmer types stk500pp and stk500hvsp). .Pp +Atmel's STK600 programmer is supported in ISP and high-voltage +programming modes, and connects through the USB. +.Pp The simple serial programmer described in Atmel's application note AVR910, and the bootloader described in Atmel's application note AVR109 (which is also used by the AVR Butterfly evaluation board), are @@ -161,7 +165,7 @@ been code-protected previously, of course) and store the data in a file. Finally, a ``terminal'' mode is available that allows one to interactively communicate with the MCU, and to display or program individual memory cells. -On the STK500 programmer, several operational parameters (target supply +On the STK500 and STK600 programmer, several operational parameters (target supply voltage, target Aref voltage, master clock) can be examined and changed from within terminal mode as well. .Ss Options @@ -661,15 +665,19 @@ device, read/write timing, etc. Set the target's supply voltage to .Ar voltage Volts. -.Em Only supported on the STK500 programmer. -.It Ar varef voltage +.Em Only supported on the STK500 and STK600 programmer. +.It Ar varef Op channel Ar voltage Set the adjustable voltage source to .Ar voltage Volts. This voltage is normally used to drive the target's .Em Aref input on the STK500. -.Em Only supported on the STK500 programmer. +On the Atmel STK600, two reference voltages are available, which +can be selected by the optional +.Ar channel +argument (either 0 or 1). +.Em Only supported on the STK500 and STK600 programmer. .It Ar fosc freq Ns Op M Ns \&| Ns k Set the master oscillator to .Ar freq @@ -679,12 +687,12 @@ An optional trailing letter multiplies by 1E6, a trailing letter .Ar \&k by 1E3. -.Em Only supported on the STK500 programmer. +.Em Only supported on the STK500 and STK600 programmer. .It Ar fosc off Turn the master oscillator off. -.Em Only supported on the STK500 programmer. +.Em Only supported on the STK500 and STK600 programmer. .It Ar sck period -.Em STK500 programmer only: +.Em STK500 and STK600 programmer only: Set the SCK clock period to .Ar period microseconds. @@ -699,7 +707,7 @@ software signs off from the JTAG ICE. This parameter can also be used on the JTAG ICE mkII to specify the ISP clock period when operating the ICE in ISP mode. .It Ar parms -.Em STK500 programmer only: +.Em STK500 and STK600 programmer only: Display the current voltage and master oscillator parameters. .Pp .Em JTAG ICE only: @@ -844,7 +852,7 @@ Page-mode programming the EEPROM through JTAG (i.e. through an .Fl U option) requires a prior chip erase. This is an inherent feature of the way JTAG EEPROM programming works. -This also applies to the STK500 in parallel programming mode. +This also applies to the STK500 and STK600 in parallel programming mode. .Pp The USBasp and USBtinyISP drivers do not offer any option to distinguish multiple devices connected simultaneously, so effectively only a single device diff --git a/avrdude.conf.in b/avrdude.conf.in index 25a9c059..8e3dad3d 100644 --- a/avrdude.conf.in +++ b/avrdude.conf.in @@ -16,6 +16,7 @@ # id = [, [, ] ...] ; # are quoted strings # desc = ; # quoted string # type = par | stk500 | stk500v2 | stk500pp | stk500hvsp | stk500generic | +# stk600 | stk600pp | stk600hvsp | # avr910 | butterfly | usbasp | # jtagmki | jtagmkii | jtagmkii_isp | jtagmkii_dw | # dragon_dw | dragon_jtag | dragon_isp | dragon_pp | @@ -367,6 +368,24 @@ programmer type = stk500hvsp; ; +programmer + id = "stk600"; + desc = "Atmel STK600"; + type = stk600; +; + +programmer + id = "stk600pp"; + desc = "Atmel STK600 in parallel programming mode"; + type = stk600pp; +; + +programmer + id = "stk600hvsp"; + desc = "Atmel STK600 in high-voltage serial programming mode"; + type = stk600hvsp; +; + programmer id = "avr910"; desc = "Atmel Low Cost Serial Programmer"; diff --git a/config_gram.y b/config_gram.y index d75cfd72..c4e8c6e1 100644 --- a/config_gram.y +++ b/config_gram.y @@ -135,6 +135,9 @@ static int parse_cmdbits(OPCODE * op); %token K_STK500PP %token K_STK500V2 %token K_STK500GENERIC +%token K_STK600 +%token K_STK600HVSP +%token K_STK600PP %token K_AVR910 %token K_USBASP %token K_USBTINY @@ -411,6 +414,24 @@ prog_parm : } } | + K_TYPE TKN_EQUAL K_STK600 { + { + stk600_initpgm(current_prog); + } + } | + + K_TYPE TKN_EQUAL K_STK600HVSP { + { + stk600hvsp_initpgm(current_prog); + } + } | + + K_TYPE TKN_EQUAL K_STK600PP { + { + stk600pp_initpgm(current_prog); + } + } | + K_TYPE TKN_EQUAL K_AVR910 { { avr910_initpgm(current_prog); diff --git a/doc/avrdude.texi b/doc/avrdude.texi index 5d66ee86..2b8de588 100644 --- a/doc/avrdude.texi +++ b/doc/avrdude.texi @@ -30,7 +30,7 @@ For avrdude version @value{VERSION}, @value{UPDATED}. Copyright @copyright{} 2003, 2005 Brian Dean -Copyright @copyright{} 2006, 2007 J@"org Wunsch +Copyright @copyright{} 2006 - 2008 J@"org Wunsch Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice @@ -67,7 +67,7 @@ Use @uref{http://savannah.nongnu.org/bugs/?group=avrdude} to report bugs. Copyright @copyright{} 2003,2005 Brian S. Dean -Copyright @copyright{} 2006 J@"org Wunsch +Copyright @copyright{} 2006 - 2008 J@"org Wunsch @sp 2 Permission is granted to make and distribute verbatim copies of @@ -113,6 +113,7 @@ Copyright @copyright{} 2006 J@"org Wunsch * Command Line Options:: * Terminal Mode Operation:: * Configuration File:: +* Programmer Specific Information:: * Platform Dependent Information:: * Troubleshooting:: @end menu @@ -143,6 +144,7 @@ programming fuse/lock bits, etc. AVRDUDE supports the following basic programmer types: Atmel's STK500, Atmel's AVRISP and AVRISP mkII devices, +Atmel's STK600, Atmel's JTAG ICE (both mkI and mkII, the latter also in ISP mode), appnote avr910, appnote avr109 (including the AVR Butterfly), serial bit-bang adapters, @@ -164,7 +166,10 @@ emulated on top of USB is likely to not work at all, or to work abysmally slow. The STK500, JTAG ICE, avr910, and avr109/butterfly use the serial port to communicate with the PC. -The STK500, JTAG ICE, and avr910 contain on-board logic to control the programming of the target +The STK600, JTAG ICE mkII, AVRISP mkII, USBasp, and USBtinyISP +programmers communicate through the USB, using @code{libusb} as a +platform abstraction layer. +The STK500, STK600, JTAG ICE, and avr910 contain on-board logic to control the programming of the target device. The avr109 bootloader implements a protocol similar to avr910, but is actually implemented in the boot area of the target's flash ROM, as @@ -186,7 +191,6 @@ For the JTAG ICE mkII, JTAG, debugWire and ISP mode are supported. See below for the limitations of debugWire. The AVR Dragon is supported in all modes (ISP, JTAG, HVSP, PP, debugWire). -(High-voltage programming is not yet supported.) When used in JTAG and debugWire mode, the AVR Dragon behaves similar to a JTAG ICE mkII, so all device-specific comments for that device will apply as well. @@ -463,6 +467,12 @@ Atmel STK500 in parallel programming mode (version 2.xfirmware only) Atmel STK500, running a version 1.x firmware @item @code{stk500v2} @tab Atmel STK500, running a version 2.x firmware +@item @code{stk600} @tab +Atmel STK600 in ISP mode +@item @code{stk600hvsp} @tab +Atmel STK600 in high-voltage serial programming mode +@item @code{stk600pp} @tab +Atmel STK600 in parallel programming mode @item @code{usbasp} @tab USBasp,@* @url{http://www.fischl.de/usbasp/} @@ -1043,17 +1053,20 @@ Leave terminal mode and thus AVRDUDE. @noindent In addition, the following commands are supported on the STK500 -programmer: +and STK600 programmer: @table @code @item vtarg @var{voltage} Set the target's supply voltage to @var{voltage} Volts. -@item varef @var{voltage} +@item varef @var{[channel]} @var{voltage} Set the adjustable voltage source to @var{voltage} Volts. This voltage is normally used to drive the target's -@emph{Aref} input on the STK500. +@emph{Aref} input on the STK500 and STK600. +The STK600 offers two reference voltages, which can be +selected by the optional parameter @var{channel} (either +0 or 1). @item fosc @var{freq}[@var{M}|@var{k}] Set the master oscillator to @var{freq} Hz. @@ -1064,7 +1077,7 @@ multiplies by 1E6, a trailing letter @var{k} by 1E3. Turn the master oscillator off. @item sck @var{period} -@emph{STK500 only:} +@emph{STK500 and STK600 only:} Set the SCK clock period to @var{period} microseconds. @emph{JTAG ICE only:} @@ -1076,7 +1089,7 @@ This parameter can also be used on the JTAG ICE mkII to specify the ISP clock period when operating the ICE in ISP mode. @item parms -@emph{STK500 only:} +@emph{STK500 and STK600 only:} Display the current voltage and master oscillator parameters. @emph{JTAG ICE only:} @@ -1191,7 +1204,7 @@ avrdude> @c @c Node @c -@node Configuration File, Platform Dependent Information, Terminal Mode Operation, Top +@node Configuration File, Programmer Specific Information, Terminal Mode Operation, Top @chapter Configuration File @noindent @@ -1432,11 +1445,87 @@ functionality does not make sense for these boot loaders. @end itemize +@c +@c Node +@c +@node Programmer Specific Information, Platform Dependent Information, Configuration File, Top +@chapter Programmer Specific Information + +@menu +* Atmel STK600:: +@end menu @c @c Node @c -@node Platform Dependent Information, Troubleshooting, Configuration File, Top +@node Atmel STK600, , Programmer Specific Information, Programmer Specific Information +@section Atmel STK600 + +@c +@c Update the table below by running the tools/get-stk600-devices.xsl +@c XSLT transformation on targetboard.xml as shipped by the latest +@c release of AVR Studio. +@c +The following devices are supported by the respective STK600 routing +and socket card: + +@multitable @columnfractions .25 .25 .5 +@headitem Routing card @tab Socket card @tab Devices +@item @code{STK600-RC008T-2} @tab @code{STK600-DIP} @tab ATtiny11 ATtiny12 ATtiny13 ATtiny25 ATtiny45 ATtiny85 +@item @code{STK600-RC008T-7} @tab @code{STK600-DIP} @tab ATtiny15 +@item @code{STK600-RC020T-1} @tab @code{STK600-DIP} @tab ATtiny2313 +@item @code{} @tab @code{STK600-TinyX3U} @tab ATtiny43U +@item @code{STK600-RC014T-12} @tab @code{STK600-DIP} @tab ATtiny24 ATtiny44 ATtiny84 +@item @code{STK600-RC020T-8} @tab @code{STK600-DIP} @tab ATtiny26 ATtiny261 ATtiny461 ATtiny861 +@item @code{STK600-RC020T-23} @tab @code{STK600-SOIC} @tab ATtiny167 +@item @code{STK600-RC028T-3} @tab @code{STK600-DIP} @tab ATtiny28 +@item @code{STK600-RC028M-6} @tab @code{STK600-DIP} @tab ATtiny48 ATtiny88 ATmega8 ATmega48 ATmega88 ATmega168 ATmega48P ATmega88P ATmega168P ATmega328P +@item @code{STK600-RC040M-4} @tab @code{STK600-DIP} @tab ATmega8515 ATmega162 +@item @code{STK600-RC040M-5} @tab @code{STK600-DIP} @tab ATmega8535 ATmega16 ATmega32 ATmega164P ATmega324P ATmega644 ATmega644P ATmega1284P +@item @code{STK600-RC064M-9} @tab @code{STK600-TQFP64} @tab ATmega64 ATmega128 ATmega1281 ATmega2561 AT90CAN32 AT90CAN64 AT90CAN128 +@item @code{STK600-RC064M-10} @tab @code{STK600-TQFP64} @tab ATmega165 ATmega165P ATmega169 ATmega169P ATmega325 ATmega325P ATmega329 ATmega329P ATmega645 ATmega649 +@item @code{STK600-RC100M-11} @tab @code{STK600-TQFP100} @tab ATmega640 ATmega1280 ATmega2560 +@item @code{} @tab @code{STK600-ATMEGA2560} @tab ATmega2560 +@item @code{STK600-RC100M-18} @tab @code{STK600-TQFP100} @tab ATmega3250 ATmega3250P ATmega3290 ATmega3290P ATmega6450 ATmega6490 +@item @code{STK600-RC32U-20} @tab @code{STK600-TQFP32} @tab AT90USB82 AT90USB162 +@item @code{STK600-RC044U-25} @tab @code{STK600-TQFP44} @tab ATmega32U4 +@item @code{STK600-RC064U-17} @tab @code{STK600-TQFP64} @tab AT90USB646 AT90USB1286 AT90USB647 AT90USB1287 +@item @code{STK600-RCPWM-22} @tab @code{STK600-TQFP32} @tab ATmega32C1 ATmega32M1 +@item @code{STK600-RCPWM-19} @tab @code{STK600-SOIC} @tab AT90PWM2 AT90PWM3 AT90PWM2B AT90PWM3B AT90PWM216 AT90PWM316 +@item @code{STK600-RC044M-24} @tab @code{STK600-TSSOP44} @tab ATmega32HVB +@item @code{STK600-RC100X-13} @tab @code{STK600-TQFP100} @tab ATxmega128A1 ATxmega128A1_revD ATxmega64A1 +@item @code{} @tab @code{STK600-uC3-144} @tab AT32UC3A0512 AT32UC3A0256 AT32UC3A0128 +@item @code{STK600-RCuC3B0-21} @tab @code{STK600-TQFP64-2} @tab AT32UC3B0256 AT32UC3B0128 AT32UC3B064 +@end multitable + +Ensure the correct socket and routing card are mounted @emph{before} +powering on the STK600. While the STK600 firmware ensures the socket +and routing card mounted match each other (using a table stored +internally in nonvolatile memory), it cannot handle the case where a +wrong routing card is used, e. g. the routing card +@code{STK600-RC040M-5} (which is meant for 40-pin DIP AVRs that have +an ADC, with the power supply pins in the center of the package) was +used but an ATmega8515 inserted (which uses the ``industry standard'' +pinout with Vcc and GND at opposite corners). + +Note that for devices that use the routing card @code{STK600-RC008T-2}, +in order to use ISP mode, the jumper for @code{AREF0} must be removed +as it would otherwise block one of the ISP signals. High-voltage +serial programming can be used even with that jumper installed. + +The ISP system of the STK600 contains a detection against shortcuts +and other wiring errors. AVRDUDE initiates a connection check before +trying to enter ISP programming mode, and display the result if the +target is not found ready to be ISP programmed. + +High-voltage programming requires the target voltage to be set to at +least 4.5 V in order to work. This can be done using +@emph{Terminal Mode}, see @ref{Terminal Mode Operation}. + +@c +@c Node +@c +@node Platform Dependent Information, Troubleshooting, Programmer Specific Information, Top @appendix Platform Dependent Information @menu @@ -1951,7 +2040,7 @@ programming works, and is documented that way in the Atmel AVR datasheets. In order to successfully program the EEPROM that way, a prior chip erase (with the EESAVE fuse unprogrammed) is required. -This also applies to the STK500 in high-voltage programming mode. +This also applies to the STK500 and STK600 in high-voltage programming mode. @item Problem: How do I turn off the @var{DWEN} fuse? diff --git a/lexer.l b/lexer.l index c23a0856..e5f7bc75 100644 --- a/lexer.l +++ b/lexer.l @@ -183,6 +183,9 @@ stk500pp { yylval=NULL; return K_STK500PP; } stk500v2 { yylval=NULL; return K_STK500V2; } stk500generic { yylval=NULL; return K_STK500GENERIC; } stk500_devcode { yylval=NULL; return K_STK500_DEVCODE; } +stk600 { yylval=NULL; return K_STK600; } +stk600hvsp { yylval=NULL; return K_STK600HVSP; } +stk600pp { yylval=NULL; return K_STK600PP; } type { yylval=NULL; return K_TYPE; } vcc { yylval=NULL; return K_VCC; } vfyled { yylval=NULL; return K_VFYLED; } diff --git a/pgm.h b/pgm.h index f22767cc..8ec81afe 100644 --- a/pgm.h +++ b/pgm.h @@ -92,7 +92,7 @@ typedef struct programmer_t { int (*read_sig_bytes) (struct programmer_t * pgm, AVRPART * p, AVRMEM * m); void (*print_parms) (struct programmer_t * pgm); int (*set_vtarget) (struct programmer_t * pgm, double v); - int (*set_varef) (struct programmer_t * pgm, double v); + int (*set_varef) (struct programmer_t * pgm, unsigned int chan, double v); int (*set_fosc) (struct programmer_t * pgm, double v); int (*set_sck_period) (struct programmer_t * pgm, double v); int (*setpin) (struct programmer_t * pgm, int pin, int value); diff --git a/serial.h b/serial.h index 0b4662e6..db9c1237 100644 --- a/serial.h +++ b/serial.h @@ -35,6 +35,11 @@ union filedescriptor { int ifd; void *pfd; + struct + { + void *handle; + int ep; + } usb; }; struct serial_device diff --git a/stk500.c b/stk500.c index ce2ccd34..dfe04d7a 100644 --- a/stk500.c +++ b/stk500.c @@ -913,7 +913,8 @@ static int stk500_set_vtarget(PROGRAMMER * pgm, double v) } -static int stk500_set_varef(PROGRAMMER * pgm, double v) +static int stk500_set_varef(PROGRAMMER * pgm, unsigned int chan /* unused */, + double v) { unsigned uaref, utarg; diff --git a/stk500v2.c b/stk500v2.c index a140cace..76c6bad1 100644 --- a/stk500v2.c +++ b/stk500v2.c @@ -38,6 +38,7 @@ #include "ac_cfg.h" +#include #include #include #include @@ -109,6 +110,16 @@ struct pdata #define PDATA(pgm) ((struct pdata *)(pgm->cookie)) +/* + * Data structure for displaying STK600 routing and socket cards. + */ +struct carddata +{ + int id; + const char *name; +}; + +/* XXX That should become part of the private pgm-> data. */ static enum { PGMTYPE_UNKNOWN, @@ -116,6 +127,7 @@ static enum PGMTYPE_AVRISP, PGMTYPE_AVRISP_MKII, PGMTYPE_JTAGICE_MKII, + PGMTYPE_STK600, } pgmtype; @@ -126,8 +138,12 @@ static const char *pgmname[] = "AVRISP", "AVRISP mkII", "JTAG ICE mkII", + "STK600", }; +/* XXX That should become part of the private pgm-> data. */ +static AVRPART *lastpart; + struct jtagispentry { unsigned char cmd; @@ -191,6 +207,9 @@ static struct jtagispentry jtagispcmds[] = { static int stk500v2_getparm(PROGRAMMER * pgm, unsigned char parm, unsigned char * value); static int stk500v2_setparm(PROGRAMMER * pgm, unsigned char parm, unsigned char value); +static int stk500v2_getparm2(PROGRAMMER * pgm, unsigned char parm, unsigned int * value); +static int stk500v2_setparm2(PROGRAMMER * pgm, unsigned char parm, unsigned int value); +static int stk500v2_setparm_real(PROGRAMMER * pgm, unsigned char parm, unsigned char value); static void stk500v2_print_parms1(PROGRAMMER * pgm, const char * p); static int stk500v2_is_page_empty(unsigned int address, int page_size, const unsigned char *buf); @@ -199,6 +218,8 @@ static unsigned int stk500v2_mode_for_pagesize(unsigned int pagesize); static int stk500v2_set_sck_period_mk2(PROGRAMMER * pgm, double v); +static int stk600_set_sck_period(PROGRAMMER * pgm, double v); + static void stk500v2_setup(PROGRAMMER * pgm) { if ((pgm->cookie = malloc(sizeof(struct pdata))) == 0) { @@ -301,7 +322,7 @@ 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 (pgmtype == PGMTYPE_AVRISP_MKII) + if (pgmtype == PGMTYPE_AVRISP_MKII || pgmtype == PGMTYPE_STK600) return stk500v2_send_mk2(pgm, data, len); else if (pgmtype == PGMTYPE_JTAGICE_MKII) return stk500v2_jtagmkII_send(pgm, data, len); @@ -399,7 +420,7 @@ static int stk500v2_recv(PROGRAMMER * pgm, unsigned char msg[], size_t maxsize) struct timeval tv; double tstart, tnow; - if (pgmtype == PGMTYPE_AVRISP_MKII) + if (pgmtype == PGMTYPE_AVRISP_MKII || pgmtype == PGMTYPE_STK600) return stk500v2_recv_mk2(pgm, msg, maxsize); else if (pgmtype == PGMTYPE_JTAGICE_MKII) return stk500v2_jtagmkII_recv(pgm, msg, maxsize); @@ -535,6 +556,9 @@ retry: } else if (siglen >= strlen("AVRISP_MK2") && memcmp(resp + 3, "AVRISP_MK2", strlen("AVRISP_MK2")) == 0) { pgmtype = PGMTYPE_AVRISP_MKII; + } else if (siglen >= strlen("STK600") && + memcmp(resp + 3, "STK600", strlen("STK600")) == 0) { + pgmtype = PGMTYPE_STK600; } else { resp[siglen + 3] = 0; if (verbose) @@ -740,12 +764,38 @@ static int stk500hvsp_chip_erase(PROGRAMMER * pgm, AVRPART * p) return stk500hv_chip_erase(pgm, p, HVSPMODE); } +static struct +{ + unsigned int state; + const char *description; +} connection_status[] = +{ + { STATUS_CONN_FAIL_MOSI, "MOSI fail" }, + { STATUS_CONN_FAIL_RST, "RST fail" }, + { STATUS_CONN_FAIL_SCK, "SCK fail" }, + { STATUS_TGT_NOT_DETECTED, "Target not detected" }, + { STATUS_TGT_REVERSE_INSERTED, "Target reverse inserted" }, + { STATUS_CONN_FAIL_MOSI | STATUS_CONN_FAIL_RST, + "MOSI and RST fail" }, + { STATUS_CONN_FAIL_MOSI | STATUS_CONN_FAIL_RST | STATUS_CONN_FAIL_SCK, + "MOSI, RST, and SCK fail" }, + { STATUS_CONN_FAIL_RST | STATUS_CONN_FAIL_SCK, + "RST and SCK fail" }, + { STATUS_CONN_FAIL_MOSI | STATUS_CONN_FAIL_SCK, + "MOSI and SCK fail" }, +}; + /* * issue the 'program enable' command to the AVR device */ static int stk500v2_program_enable(PROGRAMMER * pgm, AVRPART * p) { unsigned char buf[16]; + size_t i; + const char *msg; + int rv; + + lastpart = p; if (p->op[AVR_OP_PGM_ENABLE] == NULL) { fprintf(stderr, "%s: stk500v2_program_enable(): program enable instruction not defined for part \"%s\"\n", @@ -753,6 +803,35 @@ static int stk500v2_program_enable(PROGRAMMER * pgm, AVRPART * p) return -1; } + if (pgmtype == PGMTYPE_STK500 || pgmtype == PGMTYPE_STK600) + /* Activate AVR-style (low active) RESET */ + stk500v2_setparm_real(pgm, PARAM_RESET_POLARITY, 0x01); + + if (pgmtype == PGMTYPE_STK600) { + buf[0] = CMD_CHECK_TARGET_CONNECTION; + if (stk500v2_command(pgm, buf, 1, sizeof(buf)) < 0) { + fprintf(stderr, "%s: stk500v2_program_enable(): cannot get connection status\n", + progname); + return -1; + } + if (buf[2] != STATUS_ISP_READY) { + msg = "Unknown"; + + for (i = 0; + i < sizeof connection_status / sizeof connection_status[0]; + i++) + if (connection_status[i].state == (unsigned)buf[2]) { + msg = connection_status[i].description; + break; + } + + fprintf(stderr, "%s: stk500v2_program_enable():" + " bad STK600 connection status: %s (0x%02x)\n", + progname, msg, buf[2]); + return -1; + } + } + buf[0] = CMD_ENTER_PROGMODE_ISP; buf[1] = p->timeout; buf[2] = p->stabdelay; @@ -762,8 +841,34 @@ static int stk500v2_program_enable(PROGRAMMER * pgm, AVRPART * p) buf[6] = p->pollvalue; buf[7] = p->pollindex; avr_set_bits(p->op[AVR_OP_PGM_ENABLE], buf+8); + buf[10] = buf[11] = 0; - return stk500v2_command(pgm, buf, 12, sizeof(buf)); + rv = stk500v2_command(pgm, buf, 12, sizeof(buf)); + + if (rv < 0) { + buf[0] = CMD_CHECK_TARGET_CONNECTION; + if (stk500v2_command(pgm, buf, 1, sizeof(buf)) < 0) { + fprintf(stderr, "%s: stk500v2_program_enable(): cannot get connection status\n", + progname); + return -1; + } + + msg = "Unknown"; + + for (i = 0; + i < sizeof connection_status / sizeof connection_status[0]; + i++) + if (connection_status[i].state == (unsigned)buf[2]) { + msg = connection_status[i].description; + break; + } + + fprintf(stderr, "%s: stk500v2_program_enable():" + " bad STK600 connection status: %s (0x%02x)\n", + progname, msg, buf[2]); + } + + return rv; } /* @@ -773,6 +878,8 @@ static int stk500pp_program_enable(PROGRAMMER * pgm, AVRPART * p) { unsigned char buf[16]; + lastpart = p; + buf[0] = CMD_ENTER_PROGMODE_PP; buf[1] = p->hventerstabdelay; buf[2] = p->progmodedelay; @@ -792,7 +899,11 @@ static int stk500hvsp_program_enable(PROGRAMMER * pgm, AVRPART * p) { unsigned char buf[16]; - buf[0] = CMD_ENTER_PROGMODE_HVSP; + lastpart = p; + + buf[0] = pgmtype == PGMTYPE_STK600? + CMD_ENTER_PROGMODE_HVSP_STK600: + CMD_ENTER_PROGMODE_HVSP; buf[1] = p->hventerstabdelay; buf[2] = p->hvspcmdexedelay; buf[3] = p->synchcycles; @@ -934,7 +1045,10 @@ static void stk500hv_disable(PROGRAMMER * pgm, enum hvmode mode) free(PDATA(pgm)->eeprom_pagecache); PDATA(pgm)->eeprom_pagecache = NULL; - buf[0] = mode == PPMODE? CMD_LEAVE_PROGMODE_PP: CMD_LEAVE_PROGMODE_HVSP; + buf[0] = mode == PPMODE? CMD_LEAVE_PROGMODE_PP: + (pgmtype == PGMTYPE_STK600? + CMD_LEAVE_PROGMODE_HVSP_STK600: + CMD_LEAVE_PROGMODE_HVSP); buf[1] = 15; // p->hvleavestabdelay; buf[2] = 15; // p->resetdelay; @@ -1033,6 +1147,56 @@ static int stk500v2_open(PROGRAMMER * pgm, char * port) } +static int stk600_open(PROGRAMMER * pgm, char * port) +{ + long baud = 115200; + + DEBUG("STK500V2: stk600_open()\n"); + + if (pgm->baudrate) + baud = pgm->baudrate; + + pgmtype = PGMTYPE_UNKNOWN; + + /* + * 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) { +#if defined(HAVE_LIBUSB) + serdev = &usb_serdev_frame; + baud = USB_DEVICE_STK600; + pgmtype = PGMTYPE_STK600; + pgm->set_sck_period = stk600_set_sck_period; +#else + fprintf(stderr, "avrdude was compiled without usb support.\n"); + return -1; +#endif + } + + strcpy(pgm->port, port); + serial_open(port, baud, &pgm->fd); + + /* + * drain any extraneous input + */ + stk500v2_drain(pgm, 0); + + stk500v2_getsync(pgm); + + stk500v2_drain(pgm, 0); + + if (pgm->bitclock != 0.0) { + if (pgm->set_sck_period(pgm, pgm->bitclock) != 0) + return -1; + } + + return 0; +} + + static void stk500v2_close(PROGRAMMER * pgm) { DEBUG("STK500V2: stk500v2_close()\n"); @@ -1837,7 +2001,8 @@ static int stk500v2_set_vtarget(PROGRAMMER * pgm, double v) } -static int stk500v2_set_varef(PROGRAMMER * pgm, double v) +static int stk500v2_set_varef(PROGRAMMER * pgm, unsigned int chan /* unused */, + double v) { unsigned char uaref, utarg; @@ -2006,6 +2171,122 @@ static int stk500v2_set_sck_period(PROGRAMMER * pgm, double v) } +static int stk600_set_vtarget(PROGRAMMER * pgm, double v) +{ + unsigned char utarg; + unsigned int uaref; + int rv; + + utarg = (unsigned)((v + 0.049) * 10); + + if (stk500v2_getparm2(pgm, PARAM2_AREF0, &uaref) != 0) { + fprintf(stderr, + "%s: stk500v2_set_vtarget(): cannot obtain V[aref][0]\n", + progname); + return -1; + } + + if (uaref > (unsigned)utarg * 10) { + fprintf(stderr, + "%s: stk500v2_set_vtarget(): reducing V[aref][0] from %.2f to %.1f\n", + progname, uaref / 100.0, v); + uaref = 10 * (unsigned)utarg; + if (stk500v2_setparm2(pgm, PARAM2_AREF0, uaref) + != 0) + return -1; + } + + if (stk500v2_getparm2(pgm, PARAM2_AREF1, &uaref) != 0) { + fprintf(stderr, + "%s: stk500v2_set_vtarget(): cannot obtain V[aref][1]\n", + progname); + return -1; + } + + if (uaref > (unsigned)utarg * 10) { + fprintf(stderr, + "%s: stk500v2_set_vtarget(): reducing V[aref][1] from %.2f to %.1f\n", + progname, uaref / 100.0, v); + uaref = 10 * (unsigned)utarg; + if (stk500v2_setparm2(pgm, PARAM2_AREF1, uaref) + != 0) + return -1; + } + + /* + * Vtarget on the STK600 can only be adjusted while not being in + * programming mode. + */ + pgm->disable(pgm); + rv = stk500v2_setparm(pgm, PARAM_VTARGET, utarg); + pgm->program_enable(pgm, lastpart); + + return rv; +} + + +static int stk600_set_varef(PROGRAMMER * pgm, unsigned int chan, double v) +{ + unsigned char utarg; + unsigned int uaref; + + uaref = (unsigned)((v + 0.0049) * 100); + + if (stk500v2_getparm(pgm, PARAM_VTARGET, &utarg) != 0) { + fprintf(stderr, + "%s: stk500v2_set_varef(): cannot obtain V[target]\n", + progname); + return -1; + } + + if (uaref > (unsigned)utarg * 10) { + fprintf(stderr, + "%s: stk500v2_set_varef(): V[aref] must not be greater than " + "V[target] = %.1f\n", + progname, utarg / 10.0); + return -1; + } + + switch (chan) + { + case 0: + return stk500v2_setparm2(pgm, PARAM2_AREF0, uaref); + + case 1: + return stk500v2_setparm2(pgm, PARAM2_AREF1, uaref); + + default: + fprintf(stderr, + "%s: stk500v2_set_varef(): invalid channel %d\n", + progname, chan); + return -1; + } +} + + +static int stk600_set_fosc(PROGRAMMER * pgm, double v) +{ + unsigned int oct, dac; + + oct = 1.443 * log(v / 1039.0); + dac = 2048 - (2078.0 * pow(2, (double)(10 + oct))) / v; + + return stk500v2_setparm2(pgm, PARAM2_CLOCK_CONF, (oct << 12) | (dac << 2)); +} + +static int stk600_set_sck_period(PROGRAMMER * pgm, double v) +{ + unsigned int sck; + + sck = ceil((16e6 / (2 * 1.0 / v)) - 1); + + if (sck >= 4096) + sck = 4095; + + return stk500v2_setparm2(pgm, PARAM2_SCK_DURATION, sck); +} + + static int stk500v2_getparm(PROGRAMMER * pgm, unsigned char parm, unsigned char * value) { unsigned char buf[32]; @@ -2059,9 +2340,108 @@ static int stk500v2_setparm(PROGRAMMER * pgm, unsigned char parm, unsigned char return stk500v2_setparm_real(pgm, parm, value); } +static int stk500v2_getparm2(PROGRAMMER * pgm, unsigned char parm, unsigned int * value) +{ + unsigned char buf[32]; + + buf[0] = CMD_GET_PARAMETER; + buf[1] = parm; + + if (stk500v2_command(pgm, buf, 2, sizeof(buf)) < 0) { + fprintf(stderr,"%s: stk500v2_getparm2(): failed to get parameter 0x%02x\n", + progname, parm); + return -1; + } + + *value = ((unsigned)buf[2] << 8) | buf[3]; + + return 0; +} + +static int stk500v2_setparm2(PROGRAMMER * pgm, unsigned char parm, unsigned int value) +{ + unsigned char buf[32]; + + buf[0] = CMD_SET_PARAMETER; + buf[1] = parm; + buf[2] = value >> 8; + buf[3] = value; + + if (stk500v2_command(pgm, buf, 4, sizeof(buf)) < 0) { + fprintf(stderr, "\n%s: stk500v2_setparm2(): failed to set parameter 0x%02x\n", + progname, parm); + return -1; + } + + return 0; +} + +/* + * These two tables can be semi-automatically updated from + * targetboards.xml using tools/get-stk600-cards.xsl. + */ +static struct carddata routing_cards[] = +{ + { 0x01, "STK600-RC020T-1" }, + { 0x03, "STK600-RC028T-3" }, + { 0x05, "STK600-RC040M-5" }, + { 0x08, "STK600-RC020T-8" }, + { 0x0A, "STK600-RC040M-4" }, + { 0x0C, "STK600-RC008T-2" }, + { 0x0D, "STK600-RC028M-6" }, + { 0x10, "STK600-RC064M-10" }, + { 0x11, "STK600-RC100M-11" }, + { 0x13, "STK600-RC100X-13" }, + { 0x18, "STK600-RC100M-18" }, + { 0x19, "STK600-RCPWM-19" }, + { 0x1B, "STK600-RC32U-20" }, + { 0x1C, "STK600-RC014T-12" }, + { 0x1E, "STK600-RC064U-17" }, + { 0x1F, "STK600-RCuC3B0-21" }, + { 0x20, "STK600-RCPWM-22" }, + { 0x21, "STK600-RC020T-23" }, + { 0x22, "STK600-RC044M-24" }, + { 0x23, "STK600-RC044U-25" }, + { 0x55, "STK600-RC064M-9" }, + { 0xA0, "STK600-RC008T-7" }, +}; + +static struct carddata socket_cards[] = +{ + { 0x02, "STK600-TQFP32" }, + { 0x03, "STK600-TQFP100" }, + { 0x04, "STK600-SOIC" }, + { 0x09, "STK600-TinyX3U" }, + { 0x0C, "STK600-TSSOP44" }, + { 0x0D, "STK600-TQFP44" }, + { 0x0E, "STK600-TQFP64-2" }, + { 0x0F, "STK600-ATMEGA2560" }, + { 0x55, "STK600-TQFP64" }, + { 0x69, "STK600-uC3-144" }, + { 0xF1, "STK600-DIP" }, +}; + +static const char *stk600_get_cardname(const struct carddata *table, + size_t nele, int id) +{ + const struct carddata *cdp; + + if (id == 0xFF) + /* 0xFF means this card is not present at all. */ + return "Not present"; + + for (cdp = table; nele > 0; cdp++, nele--) + if (cdp->id == id) + return cdp->name; + + return "Unknown"; +} + + static void stk500v2_display(PROGRAMMER * pgm, const char * p) { - unsigned char maj, min, hdw, topcard; + unsigned char maj, min, hdw, topcard, maj_s1, min_s1, maj_s2, min_s2; + unsigned int rev; const char *topcard_name, *pgmname; switch (pgmtype) { @@ -2069,6 +2449,7 @@ static void stk500v2_display(PROGRAMMER * pgm, const char * p) case PGMTYPE_STK500: pgmname = "STK500"; break; case PGMTYPE_AVRISP: pgmname = "AVRISP"; break; case PGMTYPE_AVRISP_MKII: pgmname = "AVRISP mkII"; break; + case PGMTYPE_STK600: pgmname = "STK600"; break; default: pgmname = "None"; } if (pgmtype != PGMTYPE_JTAGICE_MKII) { @@ -2077,7 +2458,15 @@ static void stk500v2_display(PROGRAMMER * pgm, const char * p) stk500v2_getparm(pgm, PARAM_SW_MAJOR, &maj); stk500v2_getparm(pgm, PARAM_SW_MINOR, &min); fprintf(stderr, "%sHardware Version: %d\n", p, hdw); - fprintf(stderr, "%sFirmware Version: %d.%02d\n", p, maj, min); + fprintf(stderr, "%sFirmware Version Master : %d.%02d\n", p, maj, min); + if (pgmtype == PGMTYPE_STK600) { + stk500v2_getparm(pgm, PARAM_SW_MAJOR_SLAVE1, &maj_s1); + stk500v2_getparm(pgm, PARAM_SW_MINOR_SLAVE1, &min_s1); + stk500v2_getparm(pgm, PARAM_SW_MAJOR_SLAVE2, &maj_s2); + stk500v2_getparm(pgm, PARAM_SW_MINOR_SLAVE2, &min_s2); + fprintf(stderr, "%sFirmware Version Slave 1: %d.%02d\n", p, maj_s1, min_s1); + fprintf(stderr, "%sFirmware Version Slave 2: %d.%02d\n", p, maj_s2, min_s2); + } } if (pgmtype == PGMTYPE_STK500) { @@ -2092,17 +2481,50 @@ static void stk500v2_display(PROGRAMMER * pgm, const char * p) default: topcard_name = "Unknown"; break; } fprintf(stderr, "%sTopcard : %s\n", p, topcard_name); + } else if (pgmtype == PGMTYPE_STK600) { + stk500v2_getparm(pgm, PARAM_ROUTINGCARD_ID, &topcard); + fprintf(stderr, "%sRouting card : %s\n", p, + stk600_get_cardname(routing_cards, + sizeof routing_cards / sizeof routing_cards[0], + topcard)); + stk500v2_getparm(pgm, PARAM_SOCKETCARD_ID, &topcard); + fprintf(stderr, "%sSocket card : %s\n", p, + stk600_get_cardname(socket_cards, + sizeof socket_cards / sizeof socket_cards[0], + topcard)); + stk500v2_getparm2(pgm, PARAM2_RC_ID_TABLE_REV, &rev); + fprintf(stderr, "%sRC_ID table rev : %d\n", p, rev); + stk500v2_getparm2(pgm, PARAM2_EC_ID_TABLE_REV, &rev); + fprintf(stderr, "%sEC_ID table rev : %d\n", p, rev); } stk500v2_print_parms1(pgm, p); return; } +static double +f_to_kHz_MHz(double f, const char **unit) +{ + if (f > 1e6) { + f /= 1e6; + *unit = "MHz"; + } else if (f > 1e3) { + f /= 1000; + *unit = "kHz"; + } else + *unit = "Hz"; + + return f; +} static void stk500v2_print_parms1(PROGRAMMER * pgm, const char * p) { unsigned char vtarget, vadjust, osc_pscale, osc_cmatch, sck_duration; + unsigned int sck_stk600, clock_conf, dac, oct, varef; unsigned char vtarget_jtag[4]; + int prescale; + double f; + const char *unit; if (pgmtype == PGMTYPE_JTAGICE_MKII) { jtagmkII_getparm(pgm, PAR_OCD_VTARGET, vtarget_jtag); @@ -2112,20 +2534,22 @@ static void stk500v2_print_parms1(PROGRAMMER * pgm, const char * p) stk500v2_getparm(pgm, PARAM_VTARGET, &vtarget); fprintf(stderr, "%sVtarget : %.1f V\n", p, vtarget / 10.0); } - stk500v2_getparm(pgm, PARAM_SCK_DURATION, &sck_duration); - if (pgmtype == PGMTYPE_STK500) { + switch (pgmtype) { + case PGMTYPE_STK500: + stk500v2_getparm(pgm, PARAM_SCK_DURATION, &sck_duration); stk500v2_getparm(pgm, PARAM_VADJUST, &vadjust); stk500v2_getparm(pgm, PARAM_OSC_PSCALE, &osc_pscale); stk500v2_getparm(pgm, PARAM_OSC_CMATCH, &osc_cmatch); + fprintf(stderr, "%sSCK period : %.1f us\n", p, + sck_duration * 8.0e6 / STK500V2_XTAL + 0.05); fprintf(stderr, "%sVaref : %.1f V\n", p, vadjust / 10.0); fprintf(stderr, "%sOscillator : ", p); if (osc_pscale == 0) fprintf(stderr, "Off\n"); else { - int prescale = 1; - double f = STK500V2_XTAL / 2; - const char *unit; + prescale = 1; + f = STK500V2_XTAL / 2; switch (osc_pscale) { case 2: prescale = 8; break; @@ -2137,23 +2561,40 @@ static void stk500v2_print_parms1(PROGRAMMER * pgm, const char * p) } f /= prescale; f /= (osc_cmatch + 1); - if (f > 1e6) { - f /= 1e6; - unit = "MHz"; - } else if (f > 1e3) { - f /= 1000; - unit = "kHz"; - } else - unit = "Hz"; + f = f_to_kHz_MHz(f, &unit); fprintf(stderr, "%.3f %s\n", f, unit); } - } - if (pgmtype == PGMTYPE_AVRISP_MKII || pgmtype == PGMTYPE_JTAGICE_MKII) + break; + + case PGMTYPE_AVRISP_MKII: + case PGMTYPE_JTAGICE_MKII: + stk500v2_getparm(pgm, PARAM_SCK_DURATION, &sck_duration); fprintf(stderr, "%sSCK period : %.2f us\n", p, - (float) 1000000 / avrispmkIIfreqs[sck_duration]); - else + (float) 1000000 / avrispmkIIfreqs[sck_duration]); + break; + + case PGMTYPE_STK600: + stk500v2_getparm2(pgm, PARAM2_AREF0, &varef); + fprintf(stderr, "%sVaref 0 : %.2f V\n", p, varef / 100.0); + stk500v2_getparm2(pgm, PARAM2_AREF1, &varef); + fprintf(stderr, "%sVaref 1 : %.2f V\n", p, varef / 100.0); + stk500v2_getparm2(pgm, PARAM2_SCK_DURATION, &sck_stk600); + fprintf(stderr, "%sSCK period : %.2f us\n", p, + (float) (sck_stk600 + 1) / 8.0); + stk500v2_getparm2(pgm, PARAM2_CLOCK_CONF, &clock_conf); + oct = (clock_conf & 0xf000) >> 12u; + dac = (clock_conf & 0x0ffc) >> 2u; + f = pow(2, (double)oct) * 2078.0 / (2 - (double)dac / 1024.0); + f = f_to_kHz_MHz(f, &unit); + fprintf(stderr, "%sOscillator : %.3f %s\n", + p, f, unit); + break; + + default: fprintf(stderr, "%sSCK period : %.1f us\n", p, sck_duration * 8.0e6 / STK500V2_XTAL + 0.05); + break; + } return; } @@ -2181,7 +2622,6 @@ static int stk500v2_perform_osccal(PROGRAMMER * pgm) return 0; } - /* * Wrapper functions for the JTAG ICE mkII in ISP mode. This mode * uses the normal JTAG ICE mkII packet stream to communicate with the @@ -2612,3 +3052,105 @@ void stk500v2_dragon_hvsp_initpgm(PROGRAMMER * pgm) pgm->teardown = stk500v2_teardown; pgm->page_size = 256; } + +void stk600_initpgm(PROGRAMMER * pgm) +{ + strcpy(pgm->type, "STK600"); + + /* + * mandatory functions + */ + pgm->initialize = stk500v2_initialize; + pgm->display = stk500v2_display; + pgm->enable = stk500v2_enable; + pgm->disable = stk500v2_disable; + pgm->program_enable = stk500v2_program_enable; + pgm->chip_erase = stk500v2_chip_erase; + pgm->cmd = stk500v2_cmd; + pgm->open = stk600_open; + pgm->close = stk500v2_close; + pgm->read_byte = avr_read_byte_default; + pgm->write_byte = avr_write_byte_default; + + /* + * optional functions + */ + pgm->paged_write = stk500v2_paged_write; + pgm->paged_load = stk500v2_paged_load; + pgm->print_parms = stk500v2_print_parms; + pgm->set_vtarget = stk600_set_vtarget; + pgm->set_varef = stk600_set_varef; + pgm->set_fosc = stk600_set_fosc; + pgm->set_sck_period = stk600_set_sck_period; + pgm->perform_osccal = stk500v2_perform_osccal; + pgm->setup = stk500v2_setup; + pgm->teardown = stk500v2_teardown; + pgm->page_size = 256; +} + +void stk600pp_initpgm(PROGRAMMER * pgm) +{ + strcpy(pgm->type, "STK600PP"); + + /* + * mandatory functions + */ + pgm->initialize = stk500pp_initialize; + pgm->display = stk500v2_display; + pgm->enable = stk500v2_enable; + pgm->disable = stk500pp_disable; + pgm->program_enable = stk500pp_program_enable; + pgm->chip_erase = stk500pp_chip_erase; + pgm->open = stk600_open; + pgm->close = stk500v2_close; + pgm->read_byte = stk500pp_read_byte; + pgm->write_byte = stk500pp_write_byte; + + /* + * optional functions + */ + pgm->paged_write = stk500pp_paged_write; + pgm->paged_load = stk500pp_paged_load; + pgm->print_parms = stk500v2_print_parms; + pgm->set_vtarget = stk600_set_vtarget; + pgm->set_varef = stk600_set_varef; + pgm->set_fosc = stk600_set_fosc; + pgm->set_sck_period = stk600_set_sck_period; + pgm->setup = stk500v2_setup; + pgm->teardown = stk500v2_teardown; + pgm->page_size = 256; +} + +void stk600hvsp_initpgm(PROGRAMMER * pgm) +{ + strcpy(pgm->type, "STK600HVSP"); + + /* + * mandatory functions + */ + pgm->initialize = stk500hvsp_initialize; + pgm->display = stk500v2_display; + pgm->enable = stk500v2_enable; + pgm->disable = stk500hvsp_disable; + pgm->program_enable = stk500hvsp_program_enable; + pgm->chip_erase = stk500hvsp_chip_erase; + pgm->open = stk600_open; + pgm->close = stk500v2_close; + pgm->read_byte = stk500hvsp_read_byte; + pgm->write_byte = stk500hvsp_write_byte; + + /* + * optional functions + */ + pgm->paged_write = stk500hvsp_paged_write; + pgm->paged_load = stk500hvsp_paged_load; + pgm->print_parms = stk500v2_print_parms; + pgm->set_vtarget = stk600_set_vtarget; + pgm->set_varef = stk600_set_varef; + pgm->set_fosc = stk600_set_fosc; + pgm->set_sck_period = stk600_set_sck_period; + pgm->setup = stk500v2_setup; + pgm->teardown = stk500v2_teardown; + pgm->page_size = 256; +} + diff --git a/stk500v2.h b/stk500v2.h index 56b64fef..70e41cc2 100644 --- a/stk500v2.h +++ b/stk500v2.h @@ -34,6 +34,9 @@ void stk500v2_jtagmkII_initpgm(PROGRAMMER * pgm); void stk500v2_dragon_hvsp_initpgm(PROGRAMMER * pgm); void stk500v2_dragon_isp_initpgm(PROGRAMMER * pgm); void stk500v2_dragon_pp_initpgm(PROGRAMMER * pgm); +void stk600_initpgm (PROGRAMMER * pgm); +void stk600hvsp_initpgm (PROGRAMMER * pgm); +void stk600pp_initpgm (PROGRAMMER * pgm); #ifdef __cplusplus } diff --git a/stk500v2_private.h b/stk500v2_private.h index 69eb7edf..4f319b9b 100644 --- a/stk500v2_private.h +++ b/stk500v2_private.h @@ -23,6 +23,9 @@ #define CMD_OSCCAL 0x05 #define CMD_LOAD_ADDRESS 0x06 #define CMD_FIRMWARE_UPGRADE 0x07 +#define CMD_CHECK_TARGET_CONNECTION 0x0D +#define CMD_LOAD_RC_ID_TABLE 0x0E +#define CMD_LOAD_EC_ID_TABLE 0x0F // *****************[ STK ISP command constants ]****************************** @@ -75,6 +78,27 @@ #define CMD_READ_LOCK_HVSP 0x3A #define CMD_READ_SIGNATURE_HVSP 0x3B #define CMD_READ_OSCCAL_HVSP 0x3C +// These two are redefined since 0x30/0x31 collide +// with the STK600 bootloader. +#define CMD_ENTER_PROGMODE_HVSP_STK600 0x3D +#define CMD_LEAVE_PROGMODE_HVSP_STK600 0x3E + +// *** XPROG command constants *** + +#define CMD_XPROG 0x50 +#define CMD_XPROG_SETMODE 0x51 + + +// *** AVR32 JTAG Programming command *** + +#define CMD_JTAG_AVR32 0x80 +#define CMD_ENTER_PROGMODE_JTAG_AVR32 0x81 +#define CMD_LEAVE_PROGMODE_JTAG_AVR32 0x82 + + +// *** AVR JTAG Programming command *** + +#define CMD_JTAG_AVR 0x90 // *****************[ STK test command constants ]*************************** @@ -110,24 +134,136 @@ #define STATUS_CMD_FAILED 0xC0 #define STATUS_CKSUM_ERROR 0xC1 #define STATUS_CMD_UNKNOWN 0xC9 +#define STATUS_CMD_ILLEGAL_PARAMETER 0xCA + +// Status +#define STATUS_CONN_FAIL_MOSI 0x01 +#define STATUS_CONN_FAIL_RST 0x02 +#define STATUS_CONN_FAIL_SCK 0x04 +#define STATUS_TGT_NOT_DETECTED 0x00 +#define STATUS_ISP_READY 0x10 +#define STATUS_TGT_REVERSE_INSERTED 0x20 + +// hw_status +// Bits in status variable +// Bit 0-3: Slave MCU +// Bit 4-7: Master MCU + +#define STATUS_AREF_ERROR 0 +// Set to '1' if AREF is short circuited + +#define STATUS_VTG_ERROR 4 +// Set to '1' if VTG is short circuited + +#define STATUS_RC_CARD_ERROR 5 +// Set to '1' if board id changes when board is powered + +#define STATUS_PROGMODE 6 +// Set to '1' if board is in programming mode + +#define STATUS_POWER_SURGE 7 +// Set to '1' if board draws excessive current // *****************[ STK parameter constants ]*************************** -#define PARAM_BUILD_NUMBER_LOW 0x80 -#define PARAM_BUILD_NUMBER_HIGH 0x81 +#define PARAM_BUILD_NUMBER_LOW 0x80 /* ??? */ +#define PARAM_BUILD_NUMBER_HIGH 0x81 /* ??? */ #define PARAM_HW_VER 0x90 #define PARAM_SW_MAJOR 0x91 #define PARAM_SW_MINOR 0x92 #define PARAM_VTARGET 0x94 -#define PARAM_VADJUST 0x95 -#define PARAM_OSC_PSCALE 0x96 -#define PARAM_OSC_CMATCH 0x97 -#define PARAM_SCK_DURATION 0x98 -#define PARAM_TOPCARD_DETECT 0x9A -#define PARAM_STATUS 0x9C -#define PARAM_DATA 0x9D -#define PARAM_RESET_POLARITY 0x9E +#define PARAM_VADJUST 0x95 /* STK500 only */ +#define PARAM_OSC_PSCALE 0x96 /* STK500 only */ +#define PARAM_OSC_CMATCH 0x97 /* STK500 only */ +#define PARAM_SCK_DURATION 0x98 /* STK500 only */ +#define PARAM_TOPCARD_DETECT 0x9A /* STK500 only */ +#define PARAM_STATUS 0x9C /* STK500 only */ +#define PARAM_DATA 0x9D /* STK500 only */ +#define PARAM_RESET_POLARITY 0x9E /* STK500 only, and STK600 FW + * version <= 2.0.3 */ #define PARAM_CONTROLLER_INIT 0x9F +/* STK600 parameters */ +#define PARAM_STATUS_TGT_CONN 0xA1 +#define PARAM_DISCHARGEDELAY 0xA4 +#define PARAM_SOCKETCARD_ID 0xA5 +#define PARAM_ROUTINGCARD_ID 0xA6 +#define PARAM_EXPCARD_ID 0xA7 +#define PARAM_SW_MAJOR_SLAVE1 0xA8 +#define PARAM_SW_MINOR_SLAVE1 0xA9 +#define PARAM_SW_MAJOR_SLAVE2 0xAA +#define PARAM_SW_MINOR_SLAVE2 0xAB +#define PARAM_BOARD_ID_STATUS 0xAD +#define PARAM_RESET 0xB4 + +#define PARAM_JTAG_ALLOW_FULL_PAGE_STREAM 0x50 +#define PARAM_JTAG_EEPROM_PAGE_SIZE 0x52 +#define PARAM_JTAG_DAISY_BITS_BEFORE 0x53 +#define PARAM_JTAG_DAISY_BITS_AFTER 0x54 +#define PARAM_JTAG_DAISY_UNITS_BEFORE 0x55 +#define PARAM_JTAG_DAISY_UNITS_AFTER 0x56 + +// *** Parameter constants for 2 byte values *** +#define PARAM2_SCK_DURATION 0xC0 +#define PARAM2_CLOCK_CONF 0xC1 +#define PARAM2_AREF0 0xC2 +#define PARAM2_AREF1 0xC3 + +#define PARAM2_JTAG_FLASH_SIZE_H 0xC5 +#define PARAM2_JTAG_FLASH_SIZE_L 0xC6 +#define PARAM2_JTAG_FLASH_PAGE_SIZE 0xC7 +#define PARAM2_RC_ID_TABLE_REV 0xC8 +#define PARAM2_EC_ID_TABLE_REV 0xC9 + +/* STK600 XPROG section */ +// XPROG commands +#define XPRG_CMD_ENTER_PROGMODE 0x01 +#define XPRG_CMD_LEAVE_PROGMODE 0x02 +#define XPRG_CMD_ERASE 0x03 +#define XPRG_CMD_WRITE_MEM 0x04 +#define XPRG_CMD_READ_MEM 0x05 +#define XPRG_CMD_CRC 0x06 +#define XPRG_CMD_SET_PARAM 0x07 + +// Memory types +#define XPRG_MEM_TYPE_APPL 1 +#define XPRG_MEM_TYPE_BOOT 2 +#define XPRG_MEM_TYPE_EEPROM 3 +#define XPRG_MEM_TYPE_FUSE 4 +#define XPRG_MEM_TYPE_LOCKBITS 5 +#define XPRG_MEM_TYPE_USERSIG 6 +#define XPRG_MEM_TYPE_FACTORY_CALIBRATION 7 + +// Erase types +#define XPRG_ERASE_CHIP 1 +#define XPRG_ERASE_APP 2 +#define XPRG_ERASE_BOOT 3 +#define XPRG_ERASE_EEPROM 4 +#define XPRG_ERASE_APP_PAGE 5 +#define XPRG_ERASE_BOOT_PAGE 6 +#define XPRG_ERASE_EEPROM_PAGE 7 +#define XPRG_ERASE_USERSIG 8 + +// Write mode flags +#define XPRG_MEM_WRITE_ERASE 0 +#define XPRG_MEM_WRITE_WRITE 1 + +// CRC types +#define XPRG_CRC_APP 1 +#define XPRG_CRC_BOOT 2 +#define XPRG_CRC_FLASH 3 + +// Error codes +#define XPRG_ERR_OK 0 +#define XPRG_ERR_FAILED 1 +#define XPRG_ERR_COLLISION 2 +#define XPRG_ERR_TIMEOUT 3 + +// XPROG parameters of different sizes +// 4-byte address +#define XPRG_PARAM_NVMBASE 0x01 +// 2-byte page size +#define XPRG_PARAM_EEPPAGESIZE 0x02 + // *****************[ STK answer constants ]*************************** #define ANSWER_CKSUM_ERROR 0xB0 diff --git a/term.c b/term.c index d70564c1..e0e60e0a 100644 --- a/term.c +++ b/term.c @@ -662,25 +662,42 @@ static int cmd_varef(PROGRAMMER * pgm, struct avrpart * p, int argc, char * argv[]) { int rc; + unsigned int chan; double v; char *endp; - if (argc != 2) { - fprintf(stderr, "Usage: varef \n"); + if (argc != 2 && argc != 3) { + fprintf(stderr, "Usage: varef [channel] \n"); return -1; } - v = strtod(argv[1], &endp); - if (endp == argv[1]) { - fprintf(stderr, "%s (varef): can't parse voltage \"%s\"\n", - progname, argv[1]); - return -1; + if (argc == 2) { + chan = 0; + v = strtod(argv[1], &endp); + if (endp == argv[1]) { + fprintf(stderr, "%s (varef): can't parse voltage \"%s\"\n", + progname, argv[1]); + return -1; + } + } else { + chan = strtoul(argv[1], &endp, 10); + if (endp == argv[1]) { + fprintf(stderr, "%s (varef): can't parse channel \"%s\"\n", + progname, argv[1]); + return -1; + } + v = strtod(argv[2], &endp); + if (endp == argv[2]) { + fprintf(stderr, "%s (varef): can't parse voltage \"%s\"\n", + progname, argv[2]); + return -1; + } } if (pgm->set_varef == NULL) { fprintf(stderr, "%s (varef): the %s programmer cannot set V[aref]\n", progname, pgm->type); return -2; } - if ((rc = pgm->set_varef(pgm, v)) != 0) { + if ((rc = pgm->set_varef(pgm, chan, v)) != 0) { fprintf(stderr, "%s (varef): failed to set V[aref] (rc = %d)\n", progname, rc); return -3; diff --git a/tools/get-stk600-cards.xsl b/tools/get-stk600-cards.xsl new file mode 100644 index 00000000..c71d5147 --- /dev/null +++ b/tools/get-stk600-cards.xsl @@ -0,0 +1,63 @@ + + + + + + + + + + { + + , " + + " }, + + + + + + + + { + + , " + + " }, + + + + + + diff --git a/tools/get-stk600-devices.xsl b/tools/get-stk600-devices.xsl new file mode 100644 index 00000000..241994b9 --- /dev/null +++ b/tools/get-stk600-devices.xsl @@ -0,0 +1,52 @@ + + + + + + + @multitable @columnfractions .15 .15 .6 + Routing card @tab Socket card @tab Devices + + @item @code{ + + } @tab @code{ + + } @tab + + + + + + + @end multitable + + + diff --git a/usb_libusb.c b/usb_libusb.c index 1c648a39..ce243ac3 100644 --- a/usb_libusb.c +++ b/usb_libusb.c @@ -59,6 +59,7 @@ static void usbdev_open(char * port, long baud, union filedescriptor *fd) struct usb_device *dev; usb_dev_handle *udev; char *serno, *cp2; + int i; size_t x; /* @@ -187,7 +188,33 @@ static void usbdev_open(char * port, long baud, union filedescriptor *fd) goto trynext; } - fd->pfd = udev; + fd->usb.handle = udev; + fd->usb.ep = -1; + /* Try finding out what our read endpoint is. */ + for (i = 0; i < dev->config[0].interface[0].altsetting[0].bNumEndpoints; i++) + { + int possible_ep = dev->config[0].interface[0].altsetting[0]. + endpoint[i].bEndpointAddress; + + if ((possible_ep & USB_ENDPOINT_DIR_MASK) != 0) + { + if (verbose > 1) + { + fprintf(stderr, + "%s: usbdev_open(): using read endpoint 0x%02x\n", + progname, possible_ep); + } + fd->usb.ep = possible_ep; + break; + } + } + if (fd->usb.ep == -1) + { + fprintf(stderr, + "%s: usbdev_open(): cannot find a read endpoint, using 0x%02x\n", + progname, USBDEV_BULK_EP_READ); + fd->usb.ep = USBDEV_BULK_EP_READ; + } return; } trynext: @@ -203,7 +230,7 @@ static void usbdev_open(char * port, long baud, union filedescriptor *fd) static void usbdev_close(union filedescriptor *fd) { - usb_dev_handle *udev = (usb_dev_handle *)fd->pfd; + usb_dev_handle *udev = (usb_dev_handle *)fd->usb.handle; (void)usb_release_interface(udev, usb_interface); @@ -219,7 +246,7 @@ static void usbdev_close(union filedescriptor *fd) static int usbdev_send(union filedescriptor *fd, unsigned char *bp, size_t mlen) { - usb_dev_handle *udev = (usb_dev_handle *)fd->pfd; + usb_dev_handle *udev = (usb_dev_handle *)fd->usb.handle; int rv; int i = mlen; unsigned char * p = bp; @@ -276,11 +303,11 @@ static int usbdev_send(union filedescriptor *fd, unsigned char *bp, size_t mlen) * empty and more data are requested. */ static int -usb_fill_buf(usb_dev_handle *udev) +usb_fill_buf(usb_dev_handle *udev, int ep) { int rv; - rv = usb_bulk_read(udev, USBDEV_BULK_EP_READ, usbbuf, USBDEV_MAX_XFER, 5000); + rv = usb_bulk_read(udev, ep, usbbuf, USBDEV_MAX_XFER, 5000); if (rv < 0) { if (verbose > 1) @@ -297,7 +324,7 @@ usb_fill_buf(usb_dev_handle *udev) static int usbdev_recv(union filedescriptor *fd, unsigned char *buf, size_t nbytes) { - usb_dev_handle *udev = (usb_dev_handle *)fd->pfd; + usb_dev_handle *udev = (usb_dev_handle *)fd->usb.handle; int i, amnt; unsigned char * p = buf; @@ -305,7 +332,7 @@ static int usbdev_recv(union filedescriptor *fd, unsigned char *buf, size_t nbyt { if (buflen <= bufptr) { - if (usb_fill_buf(udev) < 0) + if (usb_fill_buf(udev, fd->usb.ep) < 0) return -1; } amnt = buflen - bufptr > nbytes? nbytes: buflen - bufptr; @@ -349,7 +376,7 @@ static int usbdev_recv(union filedescriptor *fd, unsigned char *buf, size_t nbyt */ static int usbdev_recv_frame(union filedescriptor *fd, unsigned char *buf, size_t nbytes) { - usb_dev_handle *udev = (usb_dev_handle *)fd->pfd; + usb_dev_handle *udev = (usb_dev_handle *)fd->usb.handle; int rv, n; int i; unsigned char * p = buf; @@ -357,7 +384,7 @@ static int usbdev_recv_frame(union filedescriptor *fd, unsigned char *buf, size_ n = 0; do { - rv = usb_bulk_read(udev, USBDEV_BULK_EP_READ, usbbuf, + rv = usb_bulk_read(udev, fd->usb.ep, usbbuf, USBDEV_MAX_XFER, 10000); if (rv < 0) { @@ -406,11 +433,11 @@ static int usbdev_recv_frame(union filedescriptor *fd, unsigned char *buf, size_ static int usbdev_drain(union filedescriptor *fd, int display) { - usb_dev_handle *udev = (usb_dev_handle *)fd->pfd; + usb_dev_handle *udev = (usb_dev_handle *)fd->usb.handle; int rv; do { - rv = usb_bulk_read(udev, USBDEV_BULK_EP_READ, usbbuf, USBDEV_MAX_XFER, 100); + rv = usb_bulk_read(udev, fd->usb.ep, usbbuf, USBDEV_MAX_XFER, 100); if (rv > 0 && verbose >= 4) fprintf(stderr, "%s: usbdev_drain(): flushed %d characters\n", progname, rv); diff --git a/usbdevs.h b/usbdevs.h index 1b390ffb..0c36f816 100644 --- a/usbdevs.h +++ b/usbdevs.h @@ -29,6 +29,7 @@ #define USB_VENDOR_ATMEL 1003 #define USB_DEVICE_JTAGICEMKII 0x2103 #define USB_DEVICE_AVRISPMKII 0x2104 +#define USB_DEVICE_STK600 0x2106 #define USB_DEVICE_AVRDRAGON 0x2107 /*