From 485ac8ed6e23c0734d59eae08bef38fee317562e Mon Sep 17 00:00:00 2001 From: Joerg Wunsch Date: Fri, 15 Jan 2010 16:36:13 +0000 Subject: [PATCH] Implement TPI mode for AVRISPmkII/STK600. Add ATtiny4/5/9/10 to avrdude.conf.in. Document TPI and new device support. git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk@916 81a1dc3b-b13d-400b-aceb-764788c761c2 --- avrdude/ChangeLog | 12 +++ avrdude/NEWS | 5 + avrdude/avrdude.1 | 10 +- avrdude/avrdude.conf.in | 164 +++++++++++++++++++++++++++++- avrdude/avrpart.h | 1 + avrdude/config_gram.y | 11 ++ avrdude/doc/avrdude.texi | 76 +++++++++++++- avrdude/lexer.l | 1 + avrdude/main.c | 2 +- avrdude/stk500v2.c | 200 ++++++++++++++++++++++++++----------- avrdude/stk500v2_private.h | 10 ++ 11 files changed, 430 insertions(+), 62 deletions(-) diff --git a/avrdude/ChangeLog b/avrdude/ChangeLog index 59b74bac..830f4aa6 100644 --- a/avrdude/ChangeLog +++ b/avrdude/ChangeLog @@ -1,3 +1,15 @@ +2010-01-15 Joerg Wunsch + + * stk500v2_private.h: Implement TPI mode for AVRISPmkII/STK600 + * config_gram.y: (Dito.) + * avrpart.h: (Dito.) + * stk500v2.c: (Dito.) + * main.c: (Dito.) + * lexer.l: (Dito.) + * avrdude.conf.in: Add ATtiny4/5/9/10 + * avrdude.1: Document TPI and new device support. + * doc/avrdude.texi: (Dito.) + 2010-01-14 Joerg Wunsch Submitted by clint fisher: diff --git a/avrdude/NEWS b/avrdude/NEWS index 848b52c4..3ef307a5 100644 --- a/avrdude/NEWS +++ b/avrdude/NEWS @@ -11,12 +11,17 @@ Current: - AVR32A0512 (JTAGMKII only) - ATmega32U4 + - ATtiny4 + - ATtiny5 + - ATtiny9 + - ATtiny10 * New programmers supported: - BusPirate - Arduino - JTAGICEmkII and AVR Dragon in PDI mode (ATxmega devices) + - STK600 and AVRISP mkII in TPI mode (ATtiny4/5/9/10) * Bugfixes diff --git a/avrdude/avrdude.1 b/avrdude/avrdude.1 index 23b4b620..3da8b556 100644 --- a/avrdude/avrdude.1 +++ b/avrdude/avrdude.1 @@ -119,6 +119,7 @@ below for details. Atmel's STK600 programmer is supported in ISP and high-voltage programming modes, and connects through the USB. For ATxmega devices, the STK600 is supported in PDI mode. +For ATtiny4/5/9/10 devices, the STK600 and AVRISP mkII are supported in TPI mode. .Pp The simple serial programmer described in Atmel's application note AVR910, and the bootloader described in Atmel's application note @@ -256,20 +257,24 @@ pwm2 AT90PWM2 pwm2b AT90PWM2B pwm3 AT90PWM3 pwm3b AT90PWM3B -t12 ATtiny12 +t10 ATtiny10 +t12 ATtiny12 (***) t13 ATtiny13 t15 ATtiny15 t2313 ATtiny2313 t25 ATtiny25 t26 ATtiny26 t261 ATtiny261 +t4 ATtiny4 t44 ATtiny44 t45 ATtiny45 t461 ATtiny461 +t5 ATtiny5 t84 ATtiny84 t85 ATtiny85 t861 ATtiny861 t88 ATtiny88 +t9 ATtiny9 ucr2 AT32uca0512 usb1286 ATmega1286 usb1287 ATmega1287 @@ -299,6 +304,9 @@ The AT90S2323 and ATtiny22 use the same algorithm. Flash addressing above 128 KB is not supported by all programming hardware. Known to work are jtag2, stk500v2, and bit-bang programmers. +.It "(***)" +The ATtiny11 uses the same algorithm, but can only be +programmed in high-voltage serial mode. .El .It Fl b Ar baudrate Override the RS-232 connection baud rate specified in the respective diff --git a/avrdude/avrdude.conf.in b/avrdude/avrdude.conf.in index 61a7e16c..24f30320 100644 --- a/avrdude/avrdude.conf.in +++ b/avrdude/avrdude.conf.in @@ -39,6 +39,8 @@ # desc = ; # quoted string # has_jtag = ; # part has JTAG i/f # has_debugwire = ; # part has debugWire i/f +# has_pdi = ; # part has PDI i/f +# has_tpi = ; # part has TPI i/f # devicecode = ; # deprecated, use stk500_devcode # stk500_devcode = ; # numeric # avr910_devcode = ; # numeric @@ -185,7 +187,7 @@ # http://www.atmel.com/atmel/acrobat/doc2525.pdf # -#define ATTINY10 0x10 +#define ATTINY10 0x10 /* the _old_ one that never existed! */ #define ATTINY11 0x11 #define ATTINY12 0x12 #define ATTINY15 0x13 @@ -15316,3 +15318,163 @@ part ; ; +#------------------------------------------------------------ +# ATtiny4 +#------------------------------------------------------------ + +part + id = "t4"; + desc = "ATtiny4"; + signature = 0x1e 0x8f 0x0a; + has_tpi = yes; + + memory "flash" + size = 512; + offset = 0x4000; + page_size = 16; + blocksize = 128; + ; + + memory "signature" + size = 3; + offset = 0x3fc0; + ; + + memory "fuse" + size = 1; + offset = 0x3f40; + blocksize = 4; + ; + + memory "calibration" + size = 1; + offset = 0x3f80; + ; + + memory "lockbits" + size = 1; + offset = 0x3f00; + ; +; + + +#------------------------------------------------------------ +# ATtiny5 +#------------------------------------------------------------ + +part + id = "t5"; + desc = "ATtiny5"; + signature = 0x1e 0x8f 0x09; + has_tpi = yes; + + memory "flash" + size = 512; + offset = 0x4000; + page_size = 16; + blocksize = 128; + ; + + memory "signature" + size = 3; + offset = 0x3fc0; + ; + + memory "fuse" + size = 1; + offset = 0x3f40; + blocksize = 4; + ; + + memory "calibration" + size = 1; + offset = 0x3f80; + ; + + memory "lockbits" + size = 1; + offset = 0x3f00; + ; +; + + +#------------------------------------------------------------ +# ATtiny9 +#------------------------------------------------------------ + +part + id = "t8"; + desc = "ATtiny9"; + signature = 0x1e 0x90 0x08; + has_tpi = yes; + + memory "flash" + size = 1024; + offset = 0x4000; + page_size = 16; + blocksize = 128; + ; + + memory "signature" + size = 3; + offset = 0x3fc0; + ; + + memory "fuse" + size = 1; + offset = 0x3f40; + blocksize = 4; + ; + + memory "calibration" + size = 1; + offset = 0x3f80; + ; + + memory "lockbits" + size = 1; + offset = 0x3f00; + ; +; + + +#------------------------------------------------------------ +# ATtiny10 +#------------------------------------------------------------ + +part + id = "t10"; + desc = "ATtiny10"; + signature = 0x1e 0x90 0x03; + has_tpi = yes; + + memory "flash" + size = 1024; + offset = 0x4000; + page_size = 16; + blocksize = 128; + ; + + memory "signature" + size = 3; + offset = 0x3fc0; + ; + + memory "fuse" + size = 1; + offset = 0x3f40; + blocksize = 4; + ; + + memory "calibration" + size = 1; + offset = 0x3f80; + ; + + memory "lockbits" + size = 1; + offset = 0x3f00; + ; +; + + diff --git a/avrdude/avrpart.h b/avrdude/avrpart.h index dc6250d1..04334609 100644 --- a/avrdude/avrpart.h +++ b/avrdude/avrpart.h @@ -92,6 +92,7 @@ typedef struct opcode { #define AVRPART_AVR32 0x0100 /* part is in AVR32 family */ #define AVRPART_INIT_SMC 0x0200 /* part will undergo chip erase */ #define AVRPART_WRITE 0x0400 /* at least one write operation specified */ +#define AVRPART_HAS_TPI 0x0800 /* part has TPI i/f rather than ISP (ATtiny4/5/9/10) */ #define AVR_DESCLEN 64 #define AVR_IDLEN 32 diff --git a/avrdude/config_gram.y b/avrdude/config_gram.y index 32dedc92..2ff8452a 100644 --- a/avrdude/config_gram.y +++ b/avrdude/config_gram.y @@ -211,6 +211,7 @@ static int parse_cmdbits(OPCODE * op); %token K_HAS_JTAG /* MCU has JTAG i/f. */ %token K_HAS_DW /* MCU has debugWire i/f. */ %token K_HAS_PDI /* MCU has PDI i/f rather than ISP (ATxmega). */ +%token K_HAS_TPI /* MCU has TPI i/f rather than ISP (ATtiny4/5/9/10). */ %token K_IDR /* address of OCD register in IO space */ %token K_IS_AVR32 /* chip is in the avr32 family */ %token K_RAMPZ /* address of RAMPZ reg. in IO space */ @@ -1078,6 +1079,16 @@ part_parm : free_token($3); } | + K_HAS_TPI TKN_EQUAL yesno + { + if ($3->primary == K_YES) + current_part->flags |= AVRPART_HAS_TPI; + else if ($3->primary == K_NO) + current_part->flags &= ~AVRPART_HAS_TPI; + + free_token($3); + } | + K_IS_AVR32 TKN_EQUAL yesno { if ($3->primary == K_YES) diff --git a/avrdude/doc/avrdude.texi b/avrdude/doc/avrdude.texi index 694ab9ff..f187845a 100644 --- a/avrdude/doc/avrdude.texi +++ b/avrdude/doc/avrdude.texi @@ -350,20 +350,24 @@ Currently, the following MCU types are understood: @item @code{pwm2b} @tab AT90PWM2B @item @code{pwm3} @tab AT90PWM3 @item @code{pwm3b} @tab AT90PWM3B -@item @code{t12} @tab ATtiny12 +@item @code{t10} @tab ATtiny10 +@item @code{t12} @tab ATtiny12 (***) @item @code{t13} @tab ATtiny13 @item @code{t15} @tab ATtiny15 @item @code{t2313} @tab ATtiny2313 @item @code{t25} @tab ATtiny25 @item @code{t26} @tab ATtiny26 @item @code{t261} @tab ATtiny261 +@item @code{t4} @tab ATtiny4 @item @code{t44} @tab ATtiny44 @item @code{t45} @tab ATtiny45 @item @code{t461} @tab ATtiny461 +@item @code{t5} @tab ATtiny5 @item @code{t84} @tab ATtiny84 @item @code{t85} @tab ATtiny85 @item @code{t861} @tab ATtiny861 @item @code{t88} @tab ATtiny88 +@item @code{t9} @tab ATtiny9 @item @code{ucr2} @tab AT32uca0512 @item @code{usb1286} @tab ATmega1286 @item @code{usb1287} @tab ATmega1287 @@ -393,6 +397,10 @@ Currently, the following MCU types are understood: programming hardware. Known to work are jtag2, stk500v2, and bit-bang programmers. +(***) +The ATtiny11 uses the same algorithm, but can only be +programmed in high-voltage serial mode. + @item -b @var{baudrate} Override the RS-232 connection baud rate specified in the respective programmer's entry of the configuration file. @@ -440,7 +448,8 @@ Atmel AppNote AVR911 AVROSP (an alias for avr109) @item @code{avrisp} @tab Atmel AVR ISP (an alias for stk500) @item @code{avrisp2} @tab -Atmel AVR ISP mkII (alias for stk500v2) +Atmel AVR ISP mkII in ISP mode, in PDI mode for ATxmega devices, or +in TPI mode for ATtiny4/5/9/10 @item @code{avrispmkII} @tab Atmel AVR ISP mkII (alias for stk500v2) @item @code{avrispv2} @tab @@ -540,7 +549,8 @@ 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, or in PDI mode for ATxmega devices +Atmel STK600 in ISP mode, in PDI mode for ATxmega devices, or +in TPI mode for ATtiny4/5/9/10 @item @code{stk600hvsp} @tab Atmel STK600 in high-voltage serial programming mode @item @code{stk600pp} @tab @@ -2335,6 +2345,66 @@ This sequence is automatically initiated by using the JTAG ICE mkII or AVR Dragon in ISP mode, when they detect that ISP mode cannot be entered. +@item +Problem: I want to use my JTAG ICE mkII or AVR Dragon to program an +Xmega device through PDI. The documentation tells me to use the +@emph{XMEGA PDI adapter for JTAGICE mkII} that is supposed to ship +with the kit, yet I don't have it. + +Solution: Use the following pin mapping: + +@multitable @columnfractions .2 .2 .2 .2 +@item @strong{JTAGICE} @tab @strong{Target} @tab @strong{Squid cab-} @tab @strong{PDI} +@item @strong{mkII probe} @tab @strong{pins} @tab @strong{le colors} @tab @strong{header} +@item 1 (TCK) @tab @tab Black @tab +@item 2 (GND) @tab GND @tab White @tab 6 +@item 3 (TDO) @tab @tab Grey @tab +@item 4 (VTref) @tab VTref @tab Purple @tab 2 +@item 5 (TMS) @tab @tab Blue @tab +@item 6 (nSRST) @tab PDI_CLK @tab Green @tab 5 +@item 7 (N.C.) @tab @tab Yellow @tab +@item 8 (nTRST) @tab @tab Orange @tab +@item 9 (TDI) @tab PDI_DATA @tab Red @tab 1 +@item 10 (GND) @tab @tab Brown @tab +@end multitable + + +@item +Problem: I want to use my AVRISP mkII to program an +ATtiny4/5/9/10 device through TPI. How to connect the pins? + +Solution: Use the following pin mapping: + +@multitable @columnfractions .2 .2 .2 +@item @strong{AVRISP} @tab @strong{Target} @tab @strong{ATtiny} +@item @strong{connector} @tab @strong{pins} @tab @strong{pin #} +@item 1 (MISO) @tab TPIDATA @tab 1 +@item 2 (VTref) @tab Vcc @tab 5 +@item 3 (SCK) @tab TPICLK @tab 3 +@item 4 (MOSI) @tab @tab +@item 5 (RESET) @tab /RESET @tab 6 +@item 6 (GND) @tab GND @tab 2 +@end multitable + +@item +Problem: My ATtiny4/5/9/10 reads out fine, but any attempt to program +it (through TPI) fails. Instead, the memory retains the old contents. + +Solution: Mind the limited programming supply voltage range of these +devices. + +In-circuit programming through TPI is only guaranteed by the datasheet +at Vcc = 5 V. + +@item +Problem: My ATxmega@dots{}A1/A2/A3 cannot be programmed through PDI with +my AVR Dragon. Programming through a JTAG ICE mkII works though, as does +programming through JTAG. + +Solution: None by this time (2010 Q1). + +It is said that the AVR Dragon can only program devices from the A4 +Xmega sub-family. @end itemize diff --git a/avrdude/lexer.l b/avrdude/lexer.l index faf4596f..926aca1c 100644 --- a/avrdude/lexer.l +++ b/avrdude/lexer.l @@ -149,6 +149,7 @@ flash { yylval=NULL; return K_FLASH; } has_jtag { yylval=NULL; return K_HAS_JTAG; } has_debugwire { yylval=NULL; return K_HAS_DW; } has_pdi { yylval=NULL; return K_HAS_PDI; } +has_tpi { yylval=NULL; return K_HAS_TPI; } id { yylval=NULL; return K_ID; } idr { yylval=NULL; return K_IDR; } is_avr32 { yylval=NULL; return K_IS_AVR32; } diff --git a/avrdude/main.c b/avrdude/main.c index ea68791c..98af95c5 100644 --- a/avrdude/main.c +++ b/avrdude/main.c @@ -730,7 +730,7 @@ int main(int argc, char * argv []) auto_erase = 0; } - if(p->flags & AVRPART_HAS_PDI) { + if(p->flags & (AVRPART_HAS_PDI | AVRPART_HAS_TPI)) { safemode = 0; } diff --git a/avrdude/stk500v2.c b/avrdude/stk500v2.c index a78e9a53..3956223e 100644 --- a/avrdude/stk500v2.c +++ b/avrdude/stk500v2.c @@ -3,7 +3,7 @@ * Copyright (C) 2005 Erik Walthinsen * Copyright (C) 2002-2004 Brian S. Dean * Copyright (C) 2006 David Moore - * Copyright (C) 2006,2007 Joerg Wunsch + * Copyright (C) 2006,2007,2010 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 @@ -1100,7 +1100,7 @@ static int stk500v2_initialize(PROGRAMMER * pgm, AVRPART * p) if ((PDATA(pgm)->pgmtype == PGMTYPE_STK600 || PDATA(pgm)->pgmtype == PGMTYPE_AVRISP_MKII || PDATA(pgm)->pgmtype == PGMTYPE_JTAGICE_MKII) != 0 - && (p->flags & AVRPART_HAS_PDI) != 0) { + && (p->flags & (AVRPART_HAS_PDI | AVRPART_HAS_TPI)) != 0) { /* * This is an ATxmega device, must use XPROG protocol for the * remaining actions. @@ -2409,9 +2409,11 @@ static int stk600_set_vtarget(PROGRAMMER * pgm, double v) * Vtarget on the STK600 can only be adjusted while not being in * programming mode. */ - pgm->disable(pgm); + if (PDATA(pgm)->lastpart) + pgm->disable(pgm); rv = stk500v2_setparm(pgm, PARAM_VTARGET, utarg); - pgm->program_enable(pgm, PDATA(pgm)->lastpart); + if (PDATA(pgm)->lastpart) + pgm->program_enable(pgm, PDATA(pgm)->lastpart); return rv; } @@ -3044,73 +3046,107 @@ static int stk600_xprog_program_enable(PROGRAMMER * pgm, AVRPART * p) unsigned char buf[16]; unsigned int eepagesize = 42; unsigned int nvm_base; - AVRMEM *mem; + AVRMEM *mem = NULL; + int use_tpi; - if (p->nvm_base == 0) { - fprintf(stderr, - "%s: stk600_xprog_program_enable(): no nvm_base parameter for XPROG device\n", - progname); - return -1; - } - if ((mem = avr_locate_mem(p, "eeprom")) != NULL) { - if (mem->page_size == 0) { + use_tpi = (p->flags & AVRPART_HAS_TPI) != 0; + + if (!use_tpi) { + if (p->nvm_base == 0) { fprintf(stderr, - "%s: stk600_xprog_program_enable(): no EEPROM page_size parameter for XPROG device\n", + "%s: stk600_xprog_program_enable(): no nvm_base parameter for PDI device\n", progname); return -1; } - eepagesize = mem->page_size; + if ((mem = avr_locate_mem(p, "eeprom")) != NULL) { + if (mem->page_size == 0) { + fprintf(stderr, + "%s: stk600_xprog_program_enable(): no EEPROM page_size parameter for PDI device\n", + progname); + return -1; + } + eepagesize = mem->page_size; + } } buf[0] = CMD_XPROG_SETMODE; - buf[1] = 0; /* PDI mode */ + buf[1] = use_tpi? XPRG_MODE_TPI: XPRG_MODE_PDI; if (stk500v2_command(pgm, buf, 2, sizeof(buf)) < 0) { fprintf(stderr, - "%s: stk600_xprog_program_enable(): CMD_XPROG_SETMODE failed\n", - progname); + "%s: stk600_xprog_program_enable(): CMD_XPROG_SETMODE(XPRG_MODE_%s) failed\n", + progname, use_tpi? "TPI": "PDI"); return -1; } buf[0] = XPRG_CMD_ENTER_PROGMODE; if (stk600_xprog_command(pgm, buf, 1, 2) < 0) { fprintf(stderr, - "%s: stk600_xprog_program_enable(): XPRG_CMD_ENTER_PROGMODE failed\n", + "%s: stk600_xprog_program_enable(): XPRG_CMD_ENTER_PROGMODE failed\n", progname); return -1; } - buf[0] = XPRG_CMD_SET_PARAM; - buf[1] = XPRG_PARAM_NVMBASE; - nvm_base = p->nvm_base; - /* - * The 0x01000000 appears to be an indication to the programmer - * that the respective address is located in IO (i.e., SRAM) - * memory address space rather than flash. This is not documented - * anywhere in AVR079 but matches what AVR Studio does. - */ - nvm_base |= 0x01000000; - buf[2] = nvm_base >> 24; - buf[3] = nvm_base >> 16; - buf[4] = nvm_base >> 8; - buf[5] = nvm_base; - if (stk600_xprog_command(pgm, buf, 6, 2) < 0) { - fprintf(stderr, - "%s: stk600_xprog_program_enable(): XPRG_CMD_SET_PARAM(XPRG_PARAM_NVMBASE) failed\n", - progname); - return -1; - } + if (use_tpi) { + /* + * Whatever all that might mean, it matches what AVR Studio + * does. + */ + if (stk500v2_setparm_real(pgm, PARAM_DISCHARGEDELAY, 232) < 0) + return -1; - if (mem != NULL) { buf[0] = XPRG_CMD_SET_PARAM; - buf[1] = XPRG_PARAM_EEPPAGESIZE; - buf[2] = eepagesize >> 8; - buf[3] = eepagesize; - if (stk600_xprog_command(pgm, buf, 4, 2) < 0) { + buf[1] = XPRG_PARAM_TPI_3; + buf[2] = 51; + if (stk600_xprog_command(pgm, buf, 3, 2) < 0) { fprintf(stderr, - "%s: stk600_xprog_program_enable(): XPRG_CMD_SET_PARAM(XPRG_PARAM_EEPPAGESIZE) failed\n", + "%s: stk600_xprog_program_enable(): XPRG_CMD_SET_PARAM(XPRG_PARAM_TPI_3) failed\n", progname); return -1; } + + buf[0] = XPRG_CMD_SET_PARAM; + buf[1] = XPRG_PARAM_TPI_4; + buf[2] = 50; + if (stk600_xprog_command(pgm, buf, 3, 2) < 0) { + fprintf(stderr, + "%s: stk600_xprog_program_enable(): XPRG_CMD_SET_PARAM(XPRG_PARAM_TPI_4) failed\n", + progname); + return -1; + } + } else { + buf[0] = XPRG_CMD_SET_PARAM; + buf[1] = XPRG_PARAM_NVMBASE; + nvm_base = p->nvm_base; + /* + * The 0x01000000 appears to be an indication to the programmer + * that the respective address is located in IO (i.e., SRAM) + * memory address space rather than flash. This is not documented + * anywhere in AVR079 but matches what AVR Studio does. + */ + nvm_base |= 0x01000000; + buf[2] = nvm_base >> 24; + buf[3] = nvm_base >> 16; + buf[4] = nvm_base >> 8; + buf[5] = nvm_base; + if (stk600_xprog_command(pgm, buf, 6, 2) < 0) { + fprintf(stderr, + "%s: stk600_xprog_program_enable(): XPRG_CMD_SET_PARAM(XPRG_PARAM_NVMBASE) failed\n", + progname); + return -1; + } + + if (mem != NULL) { + buf[0] = XPRG_CMD_SET_PARAM; + buf[1] = XPRG_PARAM_EEPPAGESIZE; + buf[2] = eepagesize >> 8; + buf[3] = eepagesize; + if (stk600_xprog_command(pgm, buf, 4, 2) < 0) { + fprintf(stderr, + "%s: stk600_xprog_program_enable(): XPRG_CMD_SET_PARAM(XPRG_PARAM_EEPPAGESIZE) failed\n", + progname); + return -1; + } + } } return 0; @@ -3123,7 +3159,7 @@ static void stk600_xprog_disable(PROGRAMMER * pgm) buf[0] = XPRG_CMD_LEAVE_PROGMODE; if (stk600_xprog_command(pgm, buf, 1, 2) < 0) { fprintf(stderr, - "%s: stk600_xprog_program_enable(): XPRG_CMD_LEAVE_PROGMODE failed\n", + "%s: stk600_xprog_program_disable(): XPRG_CMD_LEAVE_PROGMODE failed\n", progname); } } @@ -3131,20 +3167,31 @@ static void stk600_xprog_disable(PROGRAMMER * pgm) static int stk600_xprog_write_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem, unsigned long addr, unsigned char data) { - unsigned char b[10]; + unsigned char b[9 + 256]; + int need_erase = 0; + unsigned char write_size = 1; + unsigned char memcode; + + memset(b, 0, sizeof(b)); if (strcmp(mem->desc, "flash") == 0) { - b[1] = XPRG_MEM_TYPE_APPL; + memcode = XPRG_MEM_TYPE_APPL; } else if (strcmp(mem->desc, "boot") == 0) { - b[1] = XPRG_MEM_TYPE_BOOT; + memcode = XPRG_MEM_TYPE_BOOT; } else if (strcmp(mem->desc, "eeprom") == 0) { - b[1] = XPRG_MEM_TYPE_EEPROM; + memcode = XPRG_MEM_TYPE_EEPROM; } else if (strcmp(mem->desc, "lockbits") == 0) { - b[1] = XPRG_MEM_TYPE_LOCKBITS; + memcode = XPRG_MEM_TYPE_LOCKBITS; } else if (strncmp(mem->desc, "fuse", strlen("fuse")) == 0) { - b[1] = XPRG_MEM_TYPE_FUSE; + memcode = XPRG_MEM_TYPE_FUSE; + if (p->flags & AVRPART_HAS_TPI) + /* + * TPI devices need a mystic erase prior to writing their + * fuses. + */ + need_erase = 1; } else if (strcmp(mem->desc, "usersig") == 0) { - b[1] = XPRG_MEM_TYPE_USERSIG; + memcode = XPRG_MEM_TYPE_USERSIG; } else { fprintf(stderr, "%s: stk600_xprog_write_byte(): unknown memory \"%s\"\n", @@ -3153,16 +3200,42 @@ static int stk600_xprog_write_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem, } addr += mem->offset; + if (need_erase) { + b[0] = XPRG_CMD_ERASE; + b[1] = XPRG_ERASE_CONFIG; + b[2] = mem->offset >> 24; + b[3] = mem->offset >> 16; + b[4] = mem->offset >> 8; + b[5] = mem->offset + 1; + if (stk600_xprog_command(pgm, b, 6, 2) < 0) { + fprintf(stderr, + "%s: stk600_xprog_chip_erase(): XPRG_CMD_ERASE(XPRG_ERASE_CONFIG) failed\n", + progname); + return -1; + } + } + + if (p->flags & AVRPART_HAS_TPI) { + /* + * Some TPI memories (configuration aka. fuse) require a + * larger write block size. We record that as a blocksize in + * avrdude.conf. + */ + if (mem->blocksize != 0) + write_size = mem->blocksize; + } + b[0] = XPRG_CMD_WRITE_MEM; + b[1] = memcode; b[2] = 0; /* pagemode: non-paged write */ b[3] = addr >> 24; b[4] = addr >> 16; b[5] = addr >> 8; b[6] = addr; b[7] = 0; - b[8] = 1; + b[8] = write_size; b[9] = data; - if (stk600_xprog_command(pgm, b, 10, 2) < 0) { + if (stk600_xprog_command(pgm, b, 9 + write_size, 2) < 0) { fprintf(stderr, "%s: stk600_xprog_write_byte(): XPRG_CMD_WRITE_MEM failed\n", progname); @@ -3460,10 +3533,25 @@ static int stk600_xprog_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem, static int stk600_xprog_chip_erase(PROGRAMMER * pgm, AVRPART * p) { unsigned char b[6]; + AVRMEM *mem; + unsigned int addr = 0; + + if (p->flags & AVRPART_HAS_TPI) { + if ((mem = avr_locate_mem(p, "flash")) == NULL) { + fprintf(stderr, + "%s: stk600_xprog_chip_erase(): no FLASH definition found for TPI device\n", + progname); + return -1; + } + addr = mem->offset + 1; + } b[0] = XPRG_CMD_ERASE; b[1] = XPRG_ERASE_CHIP; - b[2] = b[3] = b[4] = b[5] = 0; + b[2] = addr >> 24; + b[3] = addr >> 16; + b[4] = addr >> 8; + b[5] = addr; if (stk600_xprog_command(pgm, b, 6, 2) < 0) { fprintf(stderr, "%s: stk600_xprog_chip_erase(): XPRG_CMD_ERASE(XPRG_ERASE_CHIP) failed\n", diff --git a/avrdude/stk500v2_private.h b/avrdude/stk500v2_private.h index 4f319b9b..d0079801 100644 --- a/avrdude/stk500v2_private.h +++ b/avrdude/stk500v2_private.h @@ -215,6 +215,11 @@ #define PARAM2_EC_ID_TABLE_REV 0xC9 /* STK600 XPROG section */ +// XPROG modes +#define XPRG_MODE_PDI 0 +#define XPRG_MODE_JTAG 1 +#define XPRG_MODE_TPI 2 + // XPROG commands #define XPRG_CMD_ENTER_PROGMODE 0x01 #define XPRG_CMD_LEAVE_PROGMODE 0x02 @@ -242,6 +247,7 @@ #define XPRG_ERASE_BOOT_PAGE 6 #define XPRG_ERASE_EEPROM_PAGE 7 #define XPRG_ERASE_USERSIG 8 +#define XPRG_ERASE_CONFIG 9 // TPI only, prepare fuse write // Write mode flags #define XPRG_MEM_WRITE_ERASE 0 @@ -263,6 +269,10 @@ #define XPRG_PARAM_NVMBASE 0x01 // 2-byte page size #define XPRG_PARAM_EEPPAGESIZE 0x02 +// 1-byte, undocumented TPI param +#define XPRG_PARAM_TPI_3 0x03 +// 1-byte, undocumented TPI param +#define XPRG_PARAM_TPI_4 0x04 // *****************[ STK answer constants ]***************************