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:
parent
3f87de3252
commit
5d0bfcaf4c
19
ChangeLog
19
ChangeLog
|
@ -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>
|
||||
|
||||
Fix a bunch of warnings.
|
||||
|
|
3
NEWS
3
NEWS
|
@ -25,6 +25,9 @@ Current:
|
|||
* Add support to bootstrap with GNU autoconf 2.61, and automake 1.10,
|
||||
respectively.
|
||||
|
||||
* Add support for ATxmega128A1 (including the revision D engineering
|
||||
samples) for STK600 tools using PDI
|
||||
|
||||
Version 5.5:
|
||||
|
||||
* Add support for the USBtinyISP programmer (patch #6233)
|
||||
|
|
6
avr.c
6
avr.c
|
@ -171,7 +171,8 @@ int avr_read(PROGRAMMER * pgm, AVRPART * p, char * memtype, int 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) {
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
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) {
|
||||
/*
|
||||
* the programmer supports a paged mode write, perhaps more
|
||||
|
|
14
avrdude.1
14
avrdude.1
|
@ -19,7 +19,7 @@
|
|||
.\"
|
||||
.\" $Id$
|
||||
.\"
|
||||
.Dd DATE March 24, 2008
|
||||
.Dd DATE July 27, 2008
|
||||
.Os
|
||||
.Dt AVRDUDE 1
|
||||
.Sh NAME
|
||||
|
@ -109,6 +109,7 @@ both parallel and serial
|
|||
.Pp
|
||||
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.
|
||||
.Pp
|
||||
The simple serial programmer described in Atmel's application note
|
||||
AVR910, and the bootloader described in Atmel's application note
|
||||
|
@ -232,6 +233,8 @@ t25 ATtiny25
|
|||
t26 ATtiny26
|
||||
t45 ATtiny45
|
||||
t85 ATtiny85
|
||||
x128a1 ATxmega128A1
|
||||
x128a1d ATxmega128A1revD
|
||||
.TE
|
||||
.Bl -tag -width "(**) "
|
||||
.It "(*)"
|
||||
|
@ -286,11 +289,18 @@ option with flash memory is specified,
|
|||
will perform a chip erase before starting any of the programming
|
||||
operations, since it generally is a mistake to program the flash
|
||||
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
|
||||
Causes a chip erase to be executed. This will reset the contents of the
|
||||
flash ROM and EEPROM to the value
|
||||
.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
|
||||
contents would exclusively cause bits to be programmed from the value
|
||||
.Ql 1
|
||||
|
|
148
avrdude.conf.in
148
avrdude.conf.in
|
@ -12512,3 +12512,151 @@ part
|
|||
"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;
|
||||
;
|
||||
|
||||
;
|
||||
|
|
|
@ -88,6 +88,7 @@ typedef struct opcode {
|
|||
#define AVRPART_ALLOWFULLPAGEBITSTREAM 0x0010 /* 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_PDI 0x0080 /* part has PDI i/f rather than ISP (ATxmega) */
|
||||
|
||||
#define AVR_DESCLEN 64
|
||||
#define AVR_IDLEN 32
|
||||
|
@ -147,6 +148,7 @@ typedef struct avrpart {
|
|||
unsigned char rampz; /* 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 int nvm_base; /* Base address of NVM controller in ATxmega devices */
|
||||
|
||||
OPCODE * op[AVR_OP_MAX]; /* opcodes */
|
||||
|
||||
|
@ -162,6 +164,7 @@ typedef struct avrmem {
|
|||
int size; /* total memory size in bytes */
|
||||
int page_size; /* size of memory page (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 max_write_delay; /* microseconds */
|
||||
int pwroff_after_write; /* after this memory type is written to,
|
||||
|
|
|
@ -111,6 +111,8 @@ static int parse_cmdbits(OPCODE * op);
|
|||
%token K_MISO
|
||||
%token K_MOSI
|
||||
%token K_NUM_PAGES
|
||||
%token K_NVM_BASE
|
||||
%token K_OFFSET
|
||||
%token K_PAGEL
|
||||
%token K_PAR
|
||||
%token K_PARALLEL
|
||||
|
@ -201,6 +203,7 @@ static int parse_cmdbits(OPCODE * op);
|
|||
%token K_ENABLEPAGEPROGRAMMING /* ? yes for mega256*, mega406 */
|
||||
%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_IDR /* address of OCD register in IO space */
|
||||
%token K_RAMPZ /* address of RAMPZ reg. in IO space */
|
||||
%token K_SPMCR /* address of SPMC[S]R in memory space */
|
||||
|
@ -1028,6 +1031,16 @@ part_parm :
|
|||
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
|
||||
{
|
||||
if ($3->primary == K_YES)
|
||||
|
@ -1072,6 +1085,12 @@ part_parm :
|
|||
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
|
||||
{
|
||||
if ($3->primary == K_YES)
|
||||
|
@ -1189,6 +1208,12 @@ mem_spec :
|
|||
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
|
||||
{
|
||||
current_mem->min_write_delay = $3->value.number;
|
||||
|
|
|
@ -327,6 +327,8 @@ Currently, the following MCU types are understood:
|
|||
@item @code{t26} @tab ATtiny26
|
||||
@item @code{t45} @tab ATtiny45
|
||||
@item @code{t85} @tab ATtiny85
|
||||
@item @code{x128a1} @tab ATxmega128A1
|
||||
@item @code{x128a1d} @tab ATxmega128A1revD
|
||||
@end multitable
|
||||
|
||||
(*) The AT90S2323 and ATtiny22 use the same algorithm.
|
||||
|
@ -470,7 +472,7 @@ 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
|
||||
Atmel STK600 in ISP mode, or in PDI mode for ATxmega devices
|
||||
@item @code{stk600hvsp} @tab
|
||||
Atmel STK600 in high-voltage serial programming mode
|
||||
@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
|
||||
specified, avrdude will perform a chip erase before starting any of the
|
||||
programming operations, since it generally is a mistake to program the flash
|
||||
without performing an erase first. This option disables that. However, to
|
||||
remain backward compatible, the -i, and -m options automatically disable the
|
||||
auto erase feature.
|
||||
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.
|
||||
|
||||
@item -e
|
||||
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.
|
||||
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
|
||||
|
|
3
lexer.l
3
lexer.l
|
@ -145,6 +145,7 @@ errled { yylval=NULL; return K_ERRLED; }
|
|||
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; }
|
||||
id { yylval=NULL; return K_ID; }
|
||||
idr { yylval=NULL; return K_IDR; }
|
||||
jtagmki { yylval=NULL; return K_JTAG_MKI; }
|
||||
|
@ -158,6 +159,8 @@ miso { yylval=NULL; return K_MISO; }
|
|||
mosi { yylval=NULL; return K_MOSI; }
|
||||
num_banks { 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; }
|
||||
paged { yylval=NULL; return K_PAGED; }
|
||||
pagel { yylval=NULL; return K_PAGEL; }
|
||||
|
|
7
main.c
7
main.c
|
@ -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)) {
|
||||
|
|
543
stk500v2.c
543
stk500v2.c
|
@ -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 void stk600_setup_xprog(PROGRAMMER * pgm);
|
||||
static int stk600_xprog_program_enable(PROGRAMMER * pgm, AVRPART * p);
|
||||
|
||||
static void stk500v2_setup(PROGRAMMER * pgm)
|
||||
{
|
||||
if ((pgm->cookie = malloc(sizeof(struct pdata))) == 0) {
|
||||
|
@ -629,14 +632,47 @@ retry:
|
|||
fprintf(stderr, "%s: stk500v2_command(): short reply\n", progname);
|
||||
return -1;
|
||||
}
|
||||
if (buf[1] == STATUS_CMD_OK)
|
||||
return status;
|
||||
if (buf[1] == STATUS_CMD_FAILED)
|
||||
fprintf(stderr, "%s: stk500v2_command(): command failed\n", progname);
|
||||
else
|
||||
fprintf(stderr, "%s: stk500v2_command(): unknown status 0x%02x\n",
|
||||
progname, buf[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)
|
||||
return status;
|
||||
if (buf[1] == STATUS_CMD_FAILED)
|
||||
fprintf(stderr, "%s: stk500v2_command(): command failed\n", progname);
|
||||
else
|
||||
fprintf(stderr, "%s: stk500v2_command(): unknown status 0x%02x\n",
|
||||
progname, buf[1]);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// otherwise try to sync up again
|
||||
|
@ -799,7 +835,7 @@ static int stk500v2_program_enable(PROGRAMMER * pgm, AVRPART * p)
|
|||
|
||||
if (p->op[AVR_OP_PGM_ENABLE] == NULL) {
|
||||
fprintf(stderr, "%s: stk500v2_program_enable(): program enable instruction not defined for part \"%s\"\n",
|
||||
progname, p->desc);
|
||||
progname, p->desc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -924,6 +960,15 @@ static int stk500hvsp_program_enable(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);
|
||||
}
|
||||
|
||||
|
@ -1240,7 +1285,7 @@ static int stk500hv_read_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
|
|||
enum hvmode mode)
|
||||
{
|
||||
int result, cmdlen = 2;
|
||||
char buf[266];
|
||||
unsigned char buf[266];
|
||||
unsigned long paddr = 0UL, *paddr_ptr = NULL;
|
||||
unsigned int pagesize = 0, use_ext_addr = 0, addrshift = 0;
|
||||
unsigned char *cache_ptr = NULL;
|
||||
|
@ -1371,7 +1416,7 @@ static int stk500hv_write_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
|
|||
enum hvmode mode)
|
||||
{
|
||||
int result, cmdlen, timeout = 0, pulsewidth = 0;
|
||||
char buf[266];
|
||||
unsigned char buf[266];
|
||||
unsigned long paddr = 0UL, *paddr_ptr = NULL;
|
||||
unsigned int pagesize = 0, use_ext_addr = 0, addrshift = 0;
|
||||
unsigned char *cache_ptr = NULL;
|
||||
|
@ -2822,6 +2867,482 @@ static int stk500v2_dragon_hv_open(PROGRAMMER * pgm, char * port)
|
|||
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)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue