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/avrdude@916 81a1dc3b-b13d-400b-aceb-764788c761c2
This commit is contained in:
joerg_wunsch 2010-01-15 16:36:13 +00:00
parent 24e0a12960
commit 46715b4296
11 changed files with 430 additions and 62 deletions

View File

@ -1,3 +1,15 @@
2010-01-15 Joerg Wunsch <j.gnu@uriah.heep.sax.de>
* 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 <j.gnu@uriah.heep.sax.de>
Submitted by clint fisher:

5
NEWS
View File

@ -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

View File

@ -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

View File

@ -39,6 +39,8 @@
# desc = <description> ; # quoted string
# has_jtag = <yes/no> ; # part has JTAG i/f
# has_debugwire = <yes/no> ; # part has debugWire i/f
# has_pdi = <yes/no> ; # part has PDI i/f
# has_tpi = <yes/no> ; # part has TPI i/f
# devicecode = <num> ; # deprecated, use stk500_devcode
# stk500_devcode = <num> ; # numeric
# avr910_devcode = <num> ; # 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;
;
;

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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; }

2
main.c
View File

@ -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;
}

View File

@ -3,7 +3,7 @@
* Copyright (C) 2005 Erik Walthinsen
* Copyright (C) 2002-2004 Brian S. Dean <bsd@bsdhome.com>
* Copyright (C) 2006 David Moore
* Copyright (C) 2006,2007 Joerg Wunsch <j@uriah.heep.sax.de>
* Copyright (C) 2006,2007,2010 Joerg Wunsch <j@uriah.heep.sax.de>
*
* 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,8 +2409,10 @@ static int stk600_set_vtarget(PROGRAMMER * pgm, double v)
* Vtarget on the STK600 can only be adjusted while not being in
* programming mode.
*/
if (PDATA(pgm)->lastpart)
pgm->disable(pgm);
rv = stk500v2_setparm(pgm, PARAM_VTARGET, utarg);
if (PDATA(pgm)->lastpart)
pgm->program_enable(pgm, PDATA(pgm)->lastpart);
return rv;
@ -3044,30 +3046,35 @@ 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;
use_tpi = (p->flags & AVRPART_HAS_TPI) != 0;
if (!use_tpi) {
if (p->nvm_base == 0) {
fprintf(stderr,
"%s: stk600_xprog_program_enable(): no nvm_base parameter for XPROG device\n",
"%s: stk600_xprog_program_enable(): no nvm_base parameter for PDI device\n",
progname);
return -1;
}
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 XPROG device\n",
"%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;
}
@ -3079,6 +3086,34 @@ static int stk600_xprog_program_enable(PROGRAMMER * pgm, AVRPART * p)
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;
buf[0] = XPRG_CMD_SET_PARAM;
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_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;
@ -3112,6 +3147,7 @@ static int stk600_xprog_program_enable(PROGRAMMER * pgm, AVRPART * p)
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",

View File

@ -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 ]***************************