First implementation of ATxmega support. By now, only the

PDI mode of the STK600 is supported.  Single-byte EEPROM
(and flash) updates do not work yet.
* avr.c: "boot" memory is a candidate memory region for paged
operations, besides "flash" and "eeprom".
* avrdude.conf.in: add ATxmega128A1 and ATxmega128A1revD
* avrpart.h: add the AVRPART_HAS_PDI flag (used to distinguish
ATxmega parts from classic AVRs), the nvm_base part field, and
the offset field for a memory region.
* config_gram.y: add "has_pdi", "nvm_base", and "offset"
* lexer.l: (Ditto.)
* main.c: disable auto_erase for ATxmega parts
* stk500v2.c: implement the XPROG functionality, and divert to
this for ATxmega parts
* avrdude.1: Document the changes.


git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk/avrdude@777 81a1dc3b-b13d-400b-aceb-764788c761c2
This commit is contained in:
Joerg Wunsch 2008-07-26 22:53:40 +00:00
parent 3f87de3252
commit 5d0bfcaf4c
11 changed files with 769 additions and 21 deletions

View File

@ -1,3 +1,22 @@
2008-07-27 Joerg Wunsch <j.gnu@uriah.heep.sax.de>
First implementation of ATxmega support. By now, only the
PDI mode of the STK600 is supported. Single-byte EEPROM
(and flash) updates do not work yet.
* avr.c: "boot" memory is a candidate memory region for paged
operations, besides "flash" and "eeprom".
* avrdude.conf.in: add ATxmega128A1 and ATxmega128A1revD
* avrpart.h: add the AVRPART_HAS_PDI flag (used to distinguish
ATxmega parts from classic AVRs), the nvm_base part field, and
the offset field for a memory region.
* config_gram.y: add "has_pdi", "nvm_base", and "offset"
* lexer.l: (Ditto.)
* main.c: disable auto_erase for ATxmega parts
* stk500v2.c: implement the XPROG functionality, and divert to
this for ATxmega parts
* avrdude.1: Document the changes.
* doc/avrdude.texi: (Ditto.)
2008-07-25 Joerg Wunsch <j.gnu@uriah.heep.sax.de> 2008-07-25 Joerg Wunsch <j.gnu@uriah.heep.sax.de>
Fix a bunch of warnings. Fix a bunch of warnings.

3
NEWS
View File

@ -25,6 +25,9 @@ Current:
* Add support to bootstrap with GNU autoconf 2.61, and automake 1.10, * Add support to bootstrap with GNU autoconf 2.61, and automake 1.10,
respectively. respectively.
* Add support for ATxmega128A1 (including the revision D engineering
samples) for STK600 tools using PDI
Version 5.5: Version 5.5:
* Add support for the USBtinyISP programmer (patch #6233) * Add support for the USBtinyISP programmer (patch #6233)

6
avr.c
View File

@ -171,7 +171,8 @@ int avr_read(PROGRAMMER * pgm, AVRPART * p, char * memtype, int size,
*/ */
memset(buf, 0xff, size); memset(buf, 0xff, size);
if ((strcmp(mem->desc, "flash")==0) || (strcmp(mem->desc, "eeprom")==0)) { if ((strcmp(mem->desc, "flash")==0) || (strcmp(mem->desc, "eeprom")==0) ||
(strcmp(mem->desc, "boot")==0)) {
if (pgm->paged_load != NULL && mem->page_size != 0) { if (pgm->paged_load != NULL && mem->page_size != 0) {
/* /*
* the programmer supports a paged mode read, perhaps more * the programmer supports a paged mode read, perhaps more
@ -568,7 +569,8 @@ int avr_write(PROGRAMMER * pgm, AVRPART * p, char * memtype, int size,
progbuf, wsize); progbuf, wsize);
} }
if ((strcmp(m->desc, "flash")==0) || (strcmp(m->desc, "eeprom")==0)) { if ((strcmp(m->desc, "flash")==0) || (strcmp(m->desc, "eeprom")==0) ||
(strcmp(m->desc, "boot")==0)) {
if (pgm->paged_write != NULL && m->page_size != 0) { if (pgm->paged_write != NULL && m->page_size != 0) {
/* /*
* the programmer supports a paged mode write, perhaps more * the programmer supports a paged mode write, perhaps more

View File

@ -19,7 +19,7 @@
.\" .\"
.\" $Id$ .\" $Id$
.\" .\"
.Dd DATE March 24, 2008 .Dd DATE July 27, 2008
.Os .Os
.Dt AVRDUDE 1 .Dt AVRDUDE 1
.Sh NAME .Sh NAME
@ -109,6 +109,7 @@ both parallel and serial
.Pp .Pp
Atmel's STK600 programmer is supported in ISP and high-voltage Atmel's STK600 programmer is supported in ISP and high-voltage
programming modes, and connects through the USB. programming modes, and connects through the USB.
For ATxmega devices, the STK600 is supported in PDI mode.
.Pp .Pp
The simple serial programmer described in Atmel's application note The simple serial programmer described in Atmel's application note
AVR910, and the bootloader described in Atmel's application note AVR910, and the bootloader described in Atmel's application note
@ -232,6 +233,8 @@ t25 ATtiny25
t26 ATtiny26 t26 ATtiny26
t45 ATtiny45 t45 ATtiny45
t85 ATtiny85 t85 ATtiny85
x128a1 ATxmega128A1
x128a1d ATxmega128A1revD
.TE .TE
.Bl -tag -width "(**) " .Bl -tag -width "(**) "
.It "(*)" .It "(*)"
@ -286,11 +289,18 @@ option with flash memory is specified,
will perform a chip erase before starting any of the programming will perform a chip erase before starting any of the programming
operations, since it generally is a mistake to program the flash operations, since it generally is a mistake to program the flash
without performing an erase first. This option disables that. without performing an erase first. This option disables that.
Auto erase is not used for ATxmega devices as these devices can
use page erase before writing each page so no explicit chip erase
is required.
Note however that any page not affected by the current operation
will retain its previous contents.
.It Fl e .It Fl e
Causes a chip erase to be executed. This will reset the contents of the Causes a chip erase to be executed. This will reset the contents of the
flash ROM and EEPROM to the value flash ROM and EEPROM to the value
.Ql 0xff , .Ql 0xff ,
and is basically a prerequisite command before the flash ROM can be and clear all lock bits.
Except for ATxmega devices which can use page erase,
it is basically a prerequisite command before the flash ROM can be
reprogrammed again. The only exception would be if the new reprogrammed again. The only exception would be if the new
contents would exclusively cause bits to be programmed from the value contents would exclusively cause bits to be programmed from the value
.Ql 1 .Ql 1

View File

@ -12512,3 +12512,151 @@ part
"0 0 0 0 0 0 0 0 o o o o o o o o"; "0 0 0 0 0 0 0 0 o o o o o o o o";
; ;
; ;
#------------------------------------------------------------
# ATxmega128A1 rev. D (engineering samples)
#------------------------------------------------------------
part
id = "x128a1d";
desc = "ATXMEGA128A1REVD";
signature = 0x1E 0x97 0x41;
has_jtag = yes;
has_pdi = yes;
nvm_base = 0x01C0;
memory "eeprom"
page_size = 32;
size = 2048;
;
memory "flash"
size = 0x20000;
page_size = 512;
;
memory "boot"
size = 0x2000;
page_size = 512;
;
# signature is actually in IO address space
memory "signature"
size = 3;
offset = 0x90;
;
memory "fuse0"
size = 1;
offset = 0x20;
;
memory "fuse1"
size = 1;
offset = 0x21;
;
memory "fuse2"
size = 1;
offset = 0x22;
;
memory "fuse4"
size = 1;
offset = 0x24;
;
memory "fuse5"
size = 1;
offset = 0x25;
;
memory "lockbits"
size = 1;
offset = 0x27;
;
memory "calibration"
size = 512;
offset = 0x200;
;
memory "usersig"
size = 512;
;
;
#------------------------------------------------------------
# ATxmega128A1
#------------------------------------------------------------
part
id = "x128a1";
desc = "ATXMEGA128A1";
signature = 0x1E 0x97 0x4C;
has_jtag = yes;
has_pdi = yes;
nvm_base = 0x01C0;
memory "eeprom"
page_size = 32;
size = 2048;
;
memory "flash"
size = 0x20000;
page_size = 512;
;
memory "boot"
size = 0x2000;
page_size = 512;
;
# signature is actually in IO address space
memory "signature"
size = 3;
offset = 0x90;
;
memory "fuse0"
size = 1;
offset = 0x20;
;
memory "fuse1"
size = 1;
offset = 0x21;
;
memory "fuse2"
size = 1;
offset = 0x22;
;
memory "fuse4"
size = 1;
offset = 0x24;
;
memory "fuse5"
size = 1;
offset = 0x25;
;
memory "lockbits"
size = 1;
offset = 0x27;
;
memory "calibration"
size = 512;
;
memory "usersig"
size = 512;
offset = 0x200;
;
;

View File

@ -88,6 +88,7 @@ typedef struct opcode {
#define AVRPART_ALLOWFULLPAGEBITSTREAM 0x0010 /* JTAG ICE mkII param. */ #define AVRPART_ALLOWFULLPAGEBITSTREAM 0x0010 /* JTAG ICE mkII param. */
#define AVRPART_ENABLEPAGEPROGRAMMING 0x0020 /* JTAG ICE mkII param. */ #define AVRPART_ENABLEPAGEPROGRAMMING 0x0020 /* JTAG ICE mkII param. */
#define AVRPART_HAS_DW 0x0040 /* part has a debugWire i/f */ #define AVRPART_HAS_DW 0x0040 /* part has a debugWire i/f */
#define AVRPART_HAS_PDI 0x0080 /* part has PDI i/f rather than ISP (ATxmega) */
#define AVR_DESCLEN 64 #define AVR_DESCLEN 64
#define AVR_IDLEN 32 #define AVR_IDLEN 32
@ -147,6 +148,7 @@ typedef struct avrpart {
unsigned char rampz; /* JTAG ICE mkII XML file parameter */ unsigned char rampz; /* JTAG ICE mkII XML file parameter */
unsigned char spmcr; /* JTAG ICE mkII XML file parameter */ unsigned char spmcr; /* JTAG ICE mkII XML file parameter */
unsigned short eecr; /* JTAC ICE mkII XML file parameter */ unsigned short eecr; /* JTAC ICE mkII XML file parameter */
unsigned int nvm_base; /* Base address of NVM controller in ATxmega devices */
OPCODE * op[AVR_OP_MAX]; /* opcodes */ OPCODE * op[AVR_OP_MAX]; /* opcodes */
@ -162,6 +164,7 @@ typedef struct avrmem {
int size; /* total memory size in bytes */ int size; /* total memory size in bytes */
int page_size; /* size of memory page (if page addressed) */ int page_size; /* size of memory page (if page addressed) */
int num_pages; /* number of pages (if page addressed) */ int num_pages; /* number of pages (if page addressed) */
unsigned int offset; /* offset in IO memory (ATxmega) */
int min_write_delay; /* microseconds */ int min_write_delay; /* microseconds */
int max_write_delay; /* microseconds */ int max_write_delay; /* microseconds */
int pwroff_after_write; /* after this memory type is written to, int pwroff_after_write; /* after this memory type is written to,

View File

@ -111,6 +111,8 @@ static int parse_cmdbits(OPCODE * op);
%token K_MISO %token K_MISO
%token K_MOSI %token K_MOSI
%token K_NUM_PAGES %token K_NUM_PAGES
%token K_NVM_BASE
%token K_OFFSET
%token K_PAGEL %token K_PAGEL
%token K_PAR %token K_PAR
%token K_PARALLEL %token K_PARALLEL
@ -201,6 +203,7 @@ static int parse_cmdbits(OPCODE * op);
%token K_ENABLEPAGEPROGRAMMING /* ? yes for mega256*, mega406 */ %token K_ENABLEPAGEPROGRAMMING /* ? yes for mega256*, mega406 */
%token K_HAS_JTAG /* MCU has JTAG i/f. */ %token K_HAS_JTAG /* MCU has JTAG i/f. */
%token K_HAS_DW /* MCU has debugWire 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_IDR /* address of OCD register in IO space */ %token K_IDR /* address of OCD register in IO space */
%token K_RAMPZ /* address of RAMPZ reg. in IO space */ %token K_RAMPZ /* address of RAMPZ reg. in IO space */
%token K_SPMCR /* address of SPMC[S]R in memory space */ %token K_SPMCR /* address of SPMC[S]R in memory space */
@ -1028,6 +1031,16 @@ part_parm :
free_token($3); free_token($3);
} | } |
K_HAS_PDI TKN_EQUAL yesno
{
if ($3->primary == K_YES)
current_part->flags |= AVRPART_HAS_PDI;
else if ($3->primary == K_NO)
current_part->flags &= ~AVRPART_HAS_PDI;
free_token($3);
} |
K_ALLOWFULLPAGEBITSTREAM TKN_EQUAL yesno K_ALLOWFULLPAGEBITSTREAM TKN_EQUAL yesno
{ {
if ($3->primary == K_YES) if ($3->primary == K_YES)
@ -1072,6 +1085,12 @@ part_parm :
free_token($3); free_token($3);
} | } |
K_NVM_BASE TKN_EQUAL TKN_NUMBER
{
current_part->nvm_base = $3->value.number;
free_token($3);
} |
K_SERIAL TKN_EQUAL yesno K_SERIAL TKN_EQUAL yesno
{ {
if ($3->primary == K_YES) if ($3->primary == K_YES)
@ -1189,6 +1208,12 @@ mem_spec :
free_token($3); free_token($3);
} | } |
K_OFFSET TKN_EQUAL TKN_NUMBER
{
current_mem->offset = $3->value.number;
free_token($3);
} |
K_MIN_WRITE_DELAY TKN_EQUAL TKN_NUMBER K_MIN_WRITE_DELAY TKN_EQUAL TKN_NUMBER
{ {
current_mem->min_write_delay = $3->value.number; current_mem->min_write_delay = $3->value.number;

View File

@ -327,6 +327,8 @@ Currently, the following MCU types are understood:
@item @code{t26} @tab ATtiny26 @item @code{t26} @tab ATtiny26
@item @code{t45} @tab ATtiny45 @item @code{t45} @tab ATtiny45
@item @code{t85} @tab ATtiny85 @item @code{t85} @tab ATtiny85
@item @code{x128a1} @tab ATxmega128A1
@item @code{x128a1d} @tab ATxmega128A1revD
@end multitable @end multitable
(*) The AT90S2323 and ATtiny22 use the same algorithm. (*) The AT90S2323 and ATtiny22 use the same algorithm.
@ -470,7 +472,7 @@ Atmel STK500, running a version 1.x firmware
@item @code{stk500v2} @tab @item @code{stk500v2} @tab
Atmel STK500, running a version 2.x firmware Atmel STK500, running a version 2.x firmware
@item @code{stk600} @tab @item @code{stk600} @tab
Atmel STK600 in ISP mode Atmel STK600 in ISP mode, or in PDI mode for ATxmega devices
@item @code{stk600hvsp} @tab @item @code{stk600hvsp} @tab
Atmel STK600 in high-voltage serial programming mode Atmel STK600 in high-voltage serial programming mode
@item @code{stk600pp} @tab @item @code{stk600pp} @tab
@ -501,13 +503,18 @@ the method of searching for the configuration file for Windows.
Disable auto erase for flash. When the -U option with flash memory is Disable auto erase for flash. When the -U option with flash memory is
specified, avrdude will perform a chip erase before starting any of the specified, avrdude will perform a chip erase before starting any of the
programming operations, since it generally is a mistake to program the flash programming operations, since it generally is a mistake to program the flash
without performing an erase first. This option disables that. However, to without performing an erase first. This option disables that.
remain backward compatible, the -i, and -m options automatically disable the Auto erase is not used for ATxmega devices as these devices can
auto erase feature. use page erase before writing each page so no explicit chip erase
is required.
Note however that any page not affected by the current operation
will retain its previous contents.
@item -e @item -e
Causes a chip erase to be executed. This will reset the contents of the Causes a chip erase to be executed. This will reset the contents of the
flash ROM and EEPROM to the value `0xff', and is basically a flash ROM and EEPROM to the value `0xff', and clear all lock bits.
Except for ATxmega devices which can use page erase,
it is basically a
prerequisite command before the flash ROM can be reprogrammed again. prerequisite command before the flash ROM can be reprogrammed again.
The only exception would be if the new contents would exclusively cause The only exception would be if the new contents would exclusively cause
bits to be programmed from the value `1' to `0'. Note that in order bits to be programmed from the value `1' to `0'. Note that in order

View File

@ -145,6 +145,7 @@ errled { yylval=NULL; return K_ERRLED; }
flash { yylval=NULL; return K_FLASH; } flash { yylval=NULL; return K_FLASH; }
has_jtag { yylval=NULL; return K_HAS_JTAG; } has_jtag { yylval=NULL; return K_HAS_JTAG; }
has_debugwire { yylval=NULL; return K_HAS_DW; } has_debugwire { yylval=NULL; return K_HAS_DW; }
has_pdi { yylval=NULL; return K_HAS_PDI; }
id { yylval=NULL; return K_ID; } id { yylval=NULL; return K_ID; }
idr { yylval=NULL; return K_IDR; } idr { yylval=NULL; return K_IDR; }
jtagmki { yylval=NULL; return K_JTAG_MKI; } jtagmki { yylval=NULL; return K_JTAG_MKI; }
@ -158,6 +159,8 @@ miso { yylval=NULL; return K_MISO; }
mosi { yylval=NULL; return K_MOSI; } mosi { yylval=NULL; return K_MOSI; }
num_banks { yylval=NULL; return K_NUM_PAGES; } num_banks { yylval=NULL; return K_NUM_PAGES; }
num_pages { yylval=NULL; return K_NUM_PAGES; } num_pages { yylval=NULL; return K_NUM_PAGES; }
nvm_base { yylval=NULL; return K_NVM_BASE; }
offset { yylval=NULL; return K_OFFSET; }
page_size { yylval=NULL; return K_PAGE_SIZE; } page_size { yylval=NULL; return K_PAGE_SIZE; }
paged { yylval=NULL; return K_PAGED; } paged { yylval=NULL; return K_PAGED; }
pagel { yylval=NULL; return K_PAGEL; } pagel { yylval=NULL; return K_PAGEL; }

7
main.c
View File

@ -953,6 +953,13 @@ int main(int argc, char * argv [])
} }
if ((p->flags & AVRPART_HAS_PDI) != 0) {
/*
* This is an ATxmega which can page erase, so no auto erase is
* needed.
*/
auto_erase = 0;
}
if ((erase == 0) && (auto_erase == 1)) { if ((erase == 0) && (auto_erase == 1)) {

View File

@ -220,6 +220,9 @@ static int stk500v2_set_sck_period_mk2(PROGRAMMER * pgm, double v);
static int stk600_set_sck_period(PROGRAMMER * pgm, double v); static int stk600_set_sck_period(PROGRAMMER * pgm, double v);
static void stk600_setup_xprog(PROGRAMMER * pgm);
static int stk600_xprog_program_enable(PROGRAMMER * pgm, AVRPART * p);
static void stk500v2_setup(PROGRAMMER * pgm) static void stk500v2_setup(PROGRAMMER * pgm)
{ {
if ((pgm->cookie = malloc(sizeof(struct pdata))) == 0) { if ((pgm->cookie = malloc(sizeof(struct pdata))) == 0) {
@ -629,6 +632,38 @@ retry:
fprintf(stderr, "%s: stk500v2_command(): short reply\n", progname); fprintf(stderr, "%s: stk500v2_command(): short reply\n", progname);
return -1; return -1;
} }
if (buf[0] == CMD_XPROG_SETMODE || buf[0] == CMD_XPROG) {
/*
* Decode XPROG wrapper errors.
*/
const char *msg;
int i;
/*
* For CMD_XPROG_SETMODE, the status is returned in buf[1].
* For CMD_XPROG, buf[1] contains the XPRG_CMD_* command, and
* buf[2] contains the status.
*/
i = buf[0] == CMD_XPROG_SETMODE? 1: 2;
if (buf[i] != XPRG_ERR_OK) {
switch (buf[i]) {
case XPRG_ERR_FAILED: msg = "Failed"; break;
case XPRG_ERR_COLLISION: msg = "Collision"; break;
case XPRG_ERR_TIMEOUT: msg = "Timeout"; break;
default: msg = "Unknown"; break;
}
fprintf(stderr, "%s: stk500v2_command(): error in %s: %s\n",
progname,
(buf[0] == CMD_XPROG_SETMODE? "CMD_XPROG_SETMODE": "CMD_XPROG"),
msg);
return -1;
}
return 0;
} else {
/*
* Decode STK500v2 errors.
*/
if (buf[1] == STATUS_CMD_OK) if (buf[1] == STATUS_CMD_OK)
return status; return status;
if (buf[1] == STATUS_CMD_FAILED) if (buf[1] == STATUS_CMD_FAILED)
@ -638,6 +673,7 @@ retry:
progname, buf[1]); progname, buf[1]);
return -1; return -1;
} }
}
// otherwise try to sync up again // otherwise try to sync up again
status = stk500v2_getsync(pgm); status = stk500v2_getsync(pgm);
@ -924,6 +960,15 @@ static int stk500hvsp_program_enable(PROGRAMMER * pgm, AVRPART * p)
static int stk500v2_initialize(PROGRAMMER * pgm, AVRPART * p) static int stk500v2_initialize(PROGRAMMER * pgm, AVRPART * p)
{ {
if (pgmtype == PGMTYPE_STK600 &&
(p->flags & AVRPART_HAS_PDI) != 0) {
/*
* This is an ATxmega device, must use XPROG protocol for the
* remaining actions.
*/
stk600_setup_xprog(pgm);
}
return pgm->program_enable(pgm, p); return pgm->program_enable(pgm, p);
} }
@ -1240,7 +1285,7 @@ static int stk500hv_read_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
enum hvmode mode) enum hvmode mode)
{ {
int result, cmdlen = 2; int result, cmdlen = 2;
char buf[266]; unsigned char buf[266];
unsigned long paddr = 0UL, *paddr_ptr = NULL; unsigned long paddr = 0UL, *paddr_ptr = NULL;
unsigned int pagesize = 0, use_ext_addr = 0, addrshift = 0; unsigned int pagesize = 0, use_ext_addr = 0, addrshift = 0;
unsigned char *cache_ptr = NULL; unsigned char *cache_ptr = NULL;
@ -1371,7 +1416,7 @@ static int stk500hv_write_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
enum hvmode mode) enum hvmode mode)
{ {
int result, cmdlen, timeout = 0, pulsewidth = 0; int result, cmdlen, timeout = 0, pulsewidth = 0;
char buf[266]; unsigned char buf[266];
unsigned long paddr = 0UL, *paddr_ptr = NULL; unsigned long paddr = 0UL, *paddr_ptr = NULL;
unsigned int pagesize = 0, use_ext_addr = 0, addrshift = 0; unsigned int pagesize = 0, use_ext_addr = 0, addrshift = 0;
unsigned char *cache_ptr = NULL; unsigned char *cache_ptr = NULL;
@ -2822,6 +2867,482 @@ static int stk500v2_dragon_hv_open(PROGRAMMER * pgm, char * port)
return 0; return 0;
} }
/*
* XPROG wrapper
*/
static int stk600_xprog_command(PROGRAMMER * pgm, unsigned char *b,
unsigned int cmdsize, unsigned int responsesize)
{
unsigned char *newb;
unsigned int s;
int rv;
if (cmdsize < responsesize)
s = responsesize;
else
s = cmdsize;
if ((newb = malloc(s + 1)) == 0) {
fprintf(stderr, "%s: stk600_xprog_cmd(): out of memory\n",
progname);
return -1;
}
newb[0] = CMD_XPROG;
memcpy(newb + 1, b, cmdsize);
rv = stk500v2_command(pgm, newb, cmdsize + 1, responsesize + 1);
if (rv == 0) {
memcpy(b, newb + 1, responsesize);
}
free(newb);
return rv;
}
/*
* issue the 'program enable' command to the AVR device, XPROG version
*/
static int stk600_xprog_program_enable(PROGRAMMER * pgm, AVRPART * p)
{
unsigned char buf[16];
unsigned int eepagesize = 42;
unsigned int nvm_base;
AVRMEM *mem;
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) {
fprintf(stderr,
"%s: stk600_xprog_program_enable(): no EEPROM page_size parameter for XPROG device\n",
progname);
return -1;
}
eepagesize = mem->page_size;
}
buf[0] = CMD_XPROG_SETMODE;
buf[1] = 0; /* PDI mode */
if (stk500v2_command(pgm, buf, 2, sizeof(buf)) < 0) {
fprintf(stderr,
"%s: stk600_xprog_program_enable(): CMD_XPROG_SETMODE failed\n",
progname);
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",
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 (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;
}
static void stk600_xprog_disable(PROGRAMMER * pgm)
{
unsigned char buf[2];
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",
progname);
}
}
static int stk600_xprog_write_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
unsigned long addr, unsigned char data)
{
unsigned char b[10];
/*
* Fancy offsets everywhere.
* This is probably what AVR079 means when writing about the
* "TIF address space".
*/
if (strcmp(mem->desc, "flash") == 0) {
b[1] = XPRG_MEM_TYPE_APPL;
addr += 0x00800000;
} else if (strcmp(mem->desc, "boot") == 0) {
b[1] = XPRG_MEM_TYPE_BOOT;
addr += 0x00800000;
} else if (strcmp(mem->desc, "eeprom") == 0) {
b[1] = XPRG_MEM_TYPE_EEPROM;
addr += 0x008c0000;
} else if (strcmp(mem->desc, "lockbits") == 0) {
b[1] = XPRG_MEM_TYPE_LOCKBITS;
addr += 0x008f0000;
} else if (strcmp(mem->desc, "usersig") == 0) {
b[1] = XPRG_MEM_TYPE_USERSIG;
addr += 0x008e0000;
} else {
fprintf(stderr,
"%s: stk600_xprog_write_byte(): unknown memory \"%s\"\n",
progname, mem->desc);
return -1;
}
addr += mem->offset;
b[0] = XPRG_CMD_WRITE_MEM;
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[9] = data;
if (stk600_xprog_command(pgm, b, 10, 2) < 0) {
fprintf(stderr,
"%s: stk600_xprog_write_byte(): XPRG_CMD_WRITE_MEM failed\n",
progname);
return -1;
}
return 0;
}
static int stk600_xprog_read_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
unsigned long addr, unsigned char * value)
{
unsigned char b[8];
/*
* Fancy offsets everywhere.
* This is probably what AVR079 means when writing about the
* "TIF address space".
*/
if (strcmp(mem->desc, "flash") == 0) {
b[1] = XPRG_MEM_TYPE_APPL;
addr += 0x00800000;
} else if (strcmp(mem->desc, "boot") == 0) {
b[1] = XPRG_MEM_TYPE_BOOT;
addr += 0x00800000;
} else if (strcmp(mem->desc, "eeprom") == 0) {
b[1] = XPRG_MEM_TYPE_EEPROM;
addr += 0x008c0000;
} else if (strcmp(mem->desc, "signature") == 0) {
b[1] = XPRG_MEM_TYPE_APPL;
addr += 0x01000000;
} else if (strncmp(mem->desc, "fuse", strlen("fuse")) == 0) {
b[1] = XPRG_MEM_TYPE_FUSE;
addr += 0x008f0000;
} else if (strcmp(mem->desc, "lockbits") == 0) {
b[1] = XPRG_MEM_TYPE_LOCKBITS;
addr += 0x008f0000;
} else if (strcmp(mem->desc, "calibration") == 0) {
b[1] = XPRG_MEM_TYPE_FACTORY_CALIBRATION;
addr += 0x008e0000;
} else if (strcmp(mem->desc, "usersig") == 0) {
b[1] = XPRG_MEM_TYPE_USERSIG;
addr += 0x008e0000;
} else {
fprintf(stderr,
"%s: stk600_xprog_read_byte(): unknown memory \"%s\"\n",
progname, mem->desc);
return -1;
}
addr += mem->offset;
b[0] = XPRG_CMD_READ_MEM;
b[2] = addr >> 24;
b[3] = addr >> 16;
b[4] = addr >> 8;
b[5] = addr;
b[6] = 0;
b[7] = 1;
if (stk600_xprog_command(pgm, b, 8, 3) < 0) {
fprintf(stderr,
"%s: stk600_xprog_read_byte(): XPRG_CMD_READ_MEM failed\n",
progname);
return -1;
}
*value = b[2];
return 0;
}
static int stk600_xprog_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
int page_size, int n_bytes)
{
unsigned char *b;
unsigned int addr;
unsigned int offset;
unsigned char memtype;
int n_bytes_orig = n_bytes;
/*
* The XPROG read command supports at most 256 bytes in one
* transfer.
*/
if (page_size > 256)
page_size = 256; /* not really a page size anymore */
/*
* Fancy offsets everywhere.
* This is probably what AVR079 means when writing about the
* "TIF address space".
*/
if (strcmp(mem->desc, "flash") == 0) {
memtype = XPRG_MEM_TYPE_APPL;
addr = 0x00800000;
} else if (strcmp(mem->desc, "boot") == 0) {
memtype = XPRG_MEM_TYPE_BOOT;
addr = 0x00800000;
} else if (strcmp(mem->desc, "eeprom") == 0) {
memtype = XPRG_MEM_TYPE_EEPROM;
addr = 0x008c0000;
} else {
fprintf(stderr,
"%s: stk600_xprog_paged_load(): unknown paged memory \"%s\"\n",
progname, mem->desc);
return -1;
}
if ((b = malloc(page_size + 2)) == NULL) {
fprintf(stderr,
"%s: stk600_xprog_paged_load(): out of memory\n",
progname);
return -1;
}
offset = 0;
while (n_bytes != 0) {
report_progress(offset, n_bytes_orig, NULL);
b[0] = XPRG_CMD_READ_MEM;
b[1] = memtype;
b[2] = addr >> 24;
b[3] = addr >> 16;
b[4] = addr >> 8;
b[5] = addr;
b[6] = page_size >> 8;
b[7] = page_size;
if (stk600_xprog_command(pgm, b, 8, page_size + 2) < 0) {
fprintf(stderr,
"%s: stk600_xprog_paged_load(): XPRG_CMD_READ_MEM failed\n",
progname);
return -1;
}
memcpy(mem->buf + offset, b + 2, page_size);
if (n_bytes < page_size) {
n_bytes = page_size;
}
offset += page_size;
addr += page_size;
n_bytes -= page_size;
}
free(b);
return n_bytes_orig;
}
static int stk600_xprog_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
int page_size, int n_bytes)
{
unsigned char *b;
unsigned int addr;
unsigned int offset;
unsigned char memtype;
int n_bytes_orig = n_bytes;
/*
* The XPROG read command supports at most 256 bytes in one
* transfer.
*/
if (page_size > 512) {
fprintf(stderr,
"%s: stk600_xprog_paged_write(): cannot handle page size > 512\n",
progname);
return -1;
}
/*
* Fancy offsets everywhere.
* This is probably what AVR079 means when writing about the
* "TIF address space".
*/
if (strcmp(mem->desc, "flash") == 0) {
memtype = XPRG_MEM_TYPE_APPL;
addr = 0x00800000;
} else if (strcmp(mem->desc, "boot") == 0) {
memtype = XPRG_MEM_TYPE_BOOT;
addr = 0x00800000;
} else if (strcmp(mem->desc, "eeprom") == 0) {
memtype = XPRG_MEM_TYPE_EEPROM;
addr = 0x008c0000;
} else {
fprintf(stderr,
"%s: stk600_xprog_paged_write(): unknown paged memory \"%s\"\n",
progname, mem->desc);
return -1;
}
if ((b = malloc(page_size + 9)) == NULL) {
fprintf(stderr,
"%s: stk600_xprog_paged_write(): out of memory\n",
progname);
return -1;
}
offset = 0;
while (n_bytes != 0) {
report_progress(offset, n_bytes_orig, NULL);
if (page_size > 256) {
/*
* AVR079 is not quite clear. While it suggests that
* downloading up to 512 bytes (256 words) were OK, it
* obviously isn't -- 512-byte pages on the ATxmega128A1
* are getting corrupted when written as a single piece.
* It writes random junk somewhere beyond byte 256.
* Splitting it into 256 byte chunks, and only setting the
* erase page / write page bits in the final chunk helps.
*/
if (page_size % 256 != 0) {
fprintf(stderr,
"%s: stk600_xprog_paged_write(): page size not multiple of 256\n",
progname);
return -1;
}
unsigned int chunk;
for (chunk = 0; chunk < page_size; chunk += 256) {
memset(b + 9, 0xff, 256);
b[0] = XPRG_CMD_WRITE_MEM;
b[1] = memtype;
if (chunk + 256 == page_size) {
b[2] = 3; /* last chunk: erase page | write page */
} else {
b[2] = 0; /* initial/intermediate chunk: just download */
}
b[3] = addr >> 24;
b[4] = addr >> 16;
b[5] = addr >> 8;
b[6] = addr;
b[7] = 1;
b[8] = 0;
memcpy(b + 9, mem->buf + offset, n_bytes);
if (stk600_xprog_command(pgm, b, 256 + 9, 2) < 0) {
fprintf(stderr,
"%s: stk600_xprog_paged_write(): XPRG_CMD_WRITE_MEM failed\n",
progname);
return -1;
}
if (n_bytes < 256)
n_bytes = 256;
offset += 256;
addr += 256;
n_bytes -= 256;
}
} else {
if (n_bytes < page_size)
/*
* This can easily happen if the input file was not a
* multiple of the page size.
*/
memset(b + 9 + n_bytes, 0xff, page_size - n_bytes);
b[0] = XPRG_CMD_WRITE_MEM;
b[1] = memtype;
b[2] = 3; /* erase page | write page */
b[3] = addr >> 24;
b[4] = addr >> 16;
b[5] = addr >> 8;
b[6] = addr;
b[7] = page_size >> 8;
b[8] = page_size;
memcpy(b + 9, mem->buf + offset, n_bytes);
if (stk600_xprog_command(pgm, b, page_size + 9, 2) < 0) {
fprintf(stderr,
"%s: stk600_xprog_paged_write(): XPRG_CMD_WRITE_MEM failed\n",
progname);
return -1;
}
if (n_bytes < page_size)
n_bytes = page_size;
offset += page_size;
addr += page_size;
n_bytes -= page_size;
}
}
free(b);
return n_bytes_orig;
}
static int stk600_xprog_chip_erase(PROGRAMMER * pgm, AVRPART * p)
{
unsigned char b[6];
b[0] = XPRG_CMD_ERASE;
b[1] = XPRG_ERASE_CHIP;
b[2] = b[3] = b[4] = b[5] = 0;
if (stk600_xprog_command(pgm, b, 6, 2) < 0) {
fprintf(stderr,
"%s: stk600_xprog_chip_erase(): XPRG_CMD_ERASE(XPRG_ERASE_CHIP) failed\n",
progname);
return -1;
}
return 0;
}
/*
* Modify pgm's methods for XPROG operation.
*/
static void stk600_setup_xprog(PROGRAMMER * pgm)
{
pgm->program_enable = stk600_xprog_program_enable;
pgm->disable = stk600_xprog_disable;
pgm->read_byte = stk600_xprog_read_byte;
pgm->write_byte = stk600_xprog_write_byte;
pgm->paged_load = stk600_xprog_paged_load;
pgm->paged_write = stk600_xprog_paged_write;
pgm->chip_erase = stk600_xprog_chip_erase;
}
void stk500v2_initpgm(PROGRAMMER * pgm) void stk500v2_initpgm(PROGRAMMER * pgm)
{ {