First stab at an implementation of the STK500 parallel programming

feature (v2 firmware only), named "stk500pp".  Still not yet
complete: EEPROM writes not working, documentation missing, only
ATmega16 parameters available in avrdude.conf.in, some parameters
not yet implemented.

* avrdude.conf.in: Add sample parameters for PP mode to ATmega16.
* avrpart.h: Add the parallel programming control parameters.
* avrpart.c: (Ditto.)
* config_gram.y: Add stk500pp configuration grammar.
* lexer.l: Add stk500pp token recognition.
* stk500v2.h: Add declaration for stk500pp_initpgm().
* stk500v2.c: Add stk500pp implementation.


git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk/avrdude@587 81a1dc3b-b13d-400b-aceb-764788c761c2
This commit is contained in:
joerg_wunsch 2006-07-16 21:30:14 +00:00
parent 0970c1295e
commit 39ecfefa7d
8 changed files with 767 additions and 3 deletions

View File

@ -1,3 +1,18 @@
2006-07-16 Joerg Wunsch <j@uriah.heep.sax.de>
First stab at an implementation of the STK500 parallel programming
feature (v2 firmware only), named "stk500pp". Still not yet
complete: EEPROM writes not working, documentation missing, only
ATmega16 parameters available in avrdude.conf.in, some parameters
not yet implemented.
* avrdude.conf.in: Add sample parameters for PP mode to ATmega16.
* avrpart.h: Add the parallel programming control parameters.
* avrpart.c: (Ditto.)
* config_gram.y: Add stk500pp configuration grammar.
* lexer.l: Add stk500pp token recognition.
* stk500v2.h: Add declaration for stk500pp_initpgm().
* stk500v2.c: Add stk500pp implementation.
2006-07-11 Joerg Wunsch <j@uriah.heep.sax.de> 2006-07-11 Joerg Wunsch <j@uriah.heep.sax.de>
* avrdude.conf.in: Fix the signatures for the * avrdude.conf.in: Fix the signatures for the

View File

@ -15,7 +15,7 @@
# programmer # programmer
# id = <id1> [, <id2> [, <id3>] ...] ; # <idN> are quoted strings # id = <id1> [, <id2> [, <id3>] ...] ; # <idN> are quoted strings
# desc = <description> ; # quoted string # desc = <description> ; # quoted string
# type = par | stk500 | stk500v2 | avr910 | jtagmki | jtagmkii; # programmer type # type = par | stk500 | stk500v2 | stk500pp | avr910 | jtagmki | jtagmkii; # programmer type
# baudrate = <num> ; # baudrate for avr910-programmer # baudrate = <num> ; # baudrate for avr910-programmer
# vcc = <num1> [, <num2> ... ] ; # pin number(s) # vcc = <num1> [, <num2> ... ] ; # pin number(s)
# reset = <num> ; # pin number # reset = <num> ; # pin number
@ -258,6 +258,12 @@ programmer
type = stk500v2; type = stk500v2;
; ;
programmer
id = "stk500pp";
desc = "Atmel STK500 V2 in parallel programming mode";
type = stk500pp;
;
programmer programmer
id = "avr910"; id = "avr910";
desc = "Atmel Low Cost Serial Programmer"; desc = "Atmel Low Cost Serial Programmer";
@ -2363,6 +2369,21 @@ part
postdelay = 1; postdelay = 1;
pollmethod = 0; pollmethod = 0;
pp_controlstack =
0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B,
0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00;
ppenterstabdelay = 100;
progmodedelay = 100;
latchcycles = 6;
togglevtg = 0;
poweroffdelay = 0;
resetdelayms = 0;
resetdelayus = 0;
ppleavestabdelay = 15;
resetdelay = 15;
idr = 0x31; idr = 0x31;
spmcr = 0x57; spmcr = 0x57;
allowfullpagebitstream = yes; allowfullpagebitstream = yes;

View File

@ -2,6 +2,7 @@
/* /*
* avrdude - A Downloader/Uploader for AVR device programmers * avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2000-2004 Brian S. Dean <bsd@bsdhome.com> * Copyright (C) 2000-2004 Brian S. Dean <bsd@bsdhome.com>
* Copyright (C) 2006 Joerg Wunsch <j@uriah.heep.sax.de>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -371,6 +372,7 @@ AVRPART * avr_new_part(void)
p->config_file[0] = 0; p->config_file[0] = 0;
p->lineno = 0; p->lineno = 0;
memset(p->signature, 0xFF, 3); memset(p->signature, 0xFF, 3);
p->ctl_stack_type = CTL_STACK_NONE;
p->mem = lcreat(NULL, 0); p->mem = lcreat(NULL, 0);

View File

@ -1,6 +1,7 @@
/* /*
* avrdude - A Downloader/Uploader for AVR device programmers * avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2003-2004 Brian S. Dean <bsd@bsdhome.com> * Copyright (C) 2003-2004 Brian S. Dean <bsd@bsdhome.com>
* Copyright (C) 2006 Joerg Wunsch <j@uriah.heep.sax.de>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -62,6 +63,12 @@ enum { /* these are assigned to reset_disposition of AVRPART */
RESET_IO /* reset pin might be configured as an I/O pin */ RESET_IO /* reset pin might be configured as an I/O pin */
}; };
enum ctl_stack_t {
CTL_STACK_NONE, /* no control stack defined */
CTL_STACK_PP, /* parallel programming control stack */
CTL_STACK_HVSP /* high voltage serial programming control stack */
};
/* /*
* serial programming instruction bit specifications * serial programming instruction bit specifications
*/ */
@ -85,6 +92,7 @@ typedef struct opcode {
#define AVR_DESCLEN 64 #define AVR_DESCLEN 64
#define AVR_IDLEN 32 #define AVR_IDLEN 32
#define CTL_STACK_SIZE 32
typedef struct avrpart { typedef struct avrpart {
char desc[AVR_DESCLEN]; /* long part name */ char desc[AVR_DESCLEN]; /* long part name */
char id[AVR_IDLEN]; /* short part name */ char id[AVR_IDLEN]; /* short part name */
@ -110,6 +118,19 @@ typedef struct avrpart {
int postdelay; /* stk500 v2 xml file parameter */ int postdelay; /* stk500 v2 xml file parameter */
int pollmethod; /* stk500 v2 xml file parameter */ int pollmethod; /* stk500 v2 xml file parameter */
enum ctl_stack_t ctl_stack_type; /* what to use the ctl stack for */
unsigned char controlstack[CTL_STACK_SIZE]; /* stk500v2 PP/HVSP ctl stack */
int ppenterstabdelay; /* stk500 v2 pp mode parameter */
int progmodedelay; /* stk500 v2 pp mode parameter */
int latchcycles; /* stk500 v2 pp mode parameter */
int togglevtg; /* stk500 v2 pp mode parameter */
int poweroffdelay; /* stk500 v2 pp mode parameter */
int resetdelayms; /* stk500 v2 pp mode parameter */
int resetdelayus; /* stk500 v2 pp mode parameter */
int ppleavestabdelay; /* stk500 v2 pp mode parameter */
int resetdelay; /* stk500 v2 pp mode parameter */
unsigned char idr; /* JTAG ICE mkII XML file parameter */ unsigned char idr; /* JTAG ICE mkII XML file parameter */
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 */

View File

@ -1,6 +1,7 @@
/* /*
* avrdude - A Downloader/Uploader for AVR device programmers * avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2000-2004 Brian S. Dean <bsd@bsdhome.com> * Copyright (C) 2000-2004 Brian S. Dean <bsd@bsdhome.com>
* Copyright (C) 2006 Joerg Wunsch <j@uriah.heep.sax.de>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -120,6 +121,7 @@ static int parse_cmdbits(OPCODE * op);
%token K_SIGNATURE %token K_SIGNATURE
%token K_SIZE %token K_SIZE
%token K_STK500 %token K_STK500
%token K_STK500PP
%token K_STK500V2 %token K_STK500V2
%token K_AVR910 %token K_AVR910
%token K_BUTTERFLY %token K_BUTTERFLY
@ -132,6 +134,7 @@ static int parse_cmdbits(OPCODE * op);
%token K_YES %token K_YES
/* stk500 v2 xml file parameters */ /* stk500 v2 xml file parameters */
/* ISP */
%token K_TIMEOUT %token K_TIMEOUT
%token K_STABDELAY %token K_STABDELAY
%token K_CMDEXEDELAY %token K_CMDEXEDELAY
@ -146,6 +149,18 @@ static int parse_cmdbits(OPCODE * op);
%token K_DELAY %token K_DELAY
%token K_BLOCKSIZE %token K_BLOCKSIZE
%token K_READSIZE %token K_READSIZE
/* PP mode */
%token K_PPENTERSTABDELAY
%token K_PROGMODEDELAY
%token K_LATCHCYCLES
%token K_TOGGLEVTG
%token K_POWEROFFDELAY
%token K_RESETDELAYMS
%token K_RESETDELAYUS
%token K_PPLEAVESTABDELAY
%token K_RESETDELAY
%token K_PP_CONTROLSTACK
/* JTAG ICE mkII specific parameters */ /* JTAG ICE mkII specific parameters */
%token K_ALLOWFULLPAGEBITSTREAM /* %token K_ALLOWFULLPAGEBITSTREAM /*
@ -350,6 +365,12 @@ prog_parm :
} }
} | } |
K_TYPE TKN_EQUAL K_STK500PP {
{
stk500pp_initpgm(current_prog);
}
} |
K_TYPE TKN_EQUAL K_AVR910 { K_TYPE TKN_EQUAL K_AVR910 {
{ {
avr910_initpgm(current_prog); avr910_initpgm(current_prog);
@ -544,6 +565,48 @@ part_parm :
} }
} | } |
K_PP_CONTROLSTACK TKN_EQUAL num_list {
{
TOKEN * t;
unsigned nbytes;
int ok;
if (current_part->ctl_stack_type != CTL_STACK_NONE)
{
fprintf(stderr,
"%s: error at line %d of %s: "
"control stack already defined\n",
progname, lineno, infile);
exit(1);
}
current_part->ctl_stack_type = CTL_STACK_PP;
nbytes = 0;
ok = 1;
while (lsize(number_list)) {
t = lrmv_n(number_list, 1);
if (nbytes < CTL_STACK_SIZE)
{
current_part->controlstack[nbytes] = t->value.number;
nbytes++;
}
else
{
ok = 0;
}
free_token(t);
}
if (!ok)
{
fprintf(stderr,
"%s: Warning: line %d of %s: "
"too many bytes in control stack\n",
progname, lineno, infile);
}
}
} |
K_CHIP_ERASE_DELAY TKN_EQUAL TKN_NUMBER K_CHIP_ERASE_DELAY TKN_EQUAL TKN_NUMBER
{ {
current_part->chip_erase_delay = $3->value.number; current_part->chip_erase_delay = $3->value.number;
@ -632,6 +695,60 @@ part_parm :
free_token($3); free_token($3);
} | } |
K_PPENTERSTABDELAY TKN_EQUAL TKN_NUMBER
{
current_part->ppenterstabdelay = $3->value.number;
free_token($3);
} |
K_PROGMODEDELAY TKN_EQUAL TKN_NUMBER
{
current_part->progmodedelay = $3->value.number;
free_token($3);
} |
K_LATCHCYCLES TKN_EQUAL TKN_NUMBER
{
current_part->latchcycles = $3->value.number;
free_token($3);
} |
K_TOGGLEVTG TKN_EQUAL TKN_NUMBER
{
current_part->togglevtg = $3->value.number;
free_token($3);
} |
K_POWEROFFDELAY TKN_EQUAL TKN_NUMBER
{
current_part->poweroffdelay = $3->value.number;
free_token($3);
} |
K_RESETDELAYMS TKN_EQUAL TKN_NUMBER
{
current_part->resetdelayms = $3->value.number;
free_token($3);
} |
K_RESETDELAYUS TKN_EQUAL TKN_NUMBER
{
current_part->resetdelayus = $3->value.number;
free_token($3);
} |
K_PPLEAVESTABDELAY TKN_EQUAL TKN_NUMBER
{
current_part->ppleavestabdelay = $3->value.number;
free_token($3);
} |
K_RESETDELAY TKN_EQUAL TKN_NUMBER
{
current_part->resetdelay = $3->value.number;
free_token($3);
} |
K_HAS_JTAG TKN_EQUAL yesno K_HAS_JTAG TKN_EQUAL yesno
{ {
if ($3->primary == K_YES) if ($3->primary == K_YES)

13
lexer.l
View File

@ -1,6 +1,7 @@
/* /*
* avrdude - A Downloader/Uploader for AVR device programmers * avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2000-2004 Brian S. Dean <bsd@bsdhome.com> * Copyright (C) 2000-2004 Brian S. Dean <bsd@bsdhome.com>
* Copyright (C) 2006 Joerg Wunsch <j@uriah.heep.sax.de>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -170,6 +171,7 @@ signature { yylval=NULL; return K_SIGNATURE; }
size { yylval=NULL; return K_SIZE; } size { yylval=NULL; return K_SIZE; }
spmcr { yylval=NULL; return K_SPMCR; } spmcr { yylval=NULL; return K_SPMCR; }
stk500 { yylval=NULL; return K_STK500; } stk500 { yylval=NULL; return K_STK500; }
stk500pp { yylval=NULL; return K_STK500PP; }
stk500v2 { yylval=NULL; return K_STK500V2; } stk500v2 { yylval=NULL; return K_STK500V2; }
stk500_devcode { yylval=NULL; return K_STK500_DEVCODE; } stk500_devcode { yylval=NULL; return K_STK500_DEVCODE; }
type { yylval=NULL; return K_TYPE; } type { yylval=NULL; return K_TYPE; }
@ -190,7 +192,16 @@ mode { yylval=NULL; return K_MODE; }
delay { yylval=NULL; return K_DELAY; } delay { yylval=NULL; return K_DELAY; }
blocksize { yylval=NULL; return K_BLOCKSIZE; } blocksize { yylval=NULL; return K_BLOCKSIZE; }
readsize { yylval=NULL; return K_READSIZE; } readsize { yylval=NULL; return K_READSIZE; }
pp_controlstack { yylval=NULL; return K_PP_CONTROLSTACK; }
ppenterstabdelay { yylval=NULL; return K_PPENTERSTABDELAY; }
progmodedelay { yylval=NULL; return K_PROGMODEDELAY; }
latchcycles { yylval=NULL; return K_LATCHCYCLES; }
togglevtg { yylval=NULL; return K_TOGGLEVTG; }
poweroffdelay { yylval=NULL; return K_POWEROFFDELAY; }
resetdelayms { yylval=NULL; return K_RESETDELAYMS; }
resetdelayus { yylval=NULL; return K_RESETDELAYUS; }
ppleavestabdelay { yylval=NULL; return K_PPLEAVESTABDELAY; }
resetdelay { yylval=NULL; return K_RESETDELAY; }
dedicated { yylval=new_token(K_DEDICATED); return K_DEDICATED; } dedicated { yylval=new_token(K_DEDICATED); return K_DEDICATED; }

View File

@ -3,6 +3,7 @@
* Copyright (C) 2005 Erik Walthinsen * Copyright (C) 2005 Erik Walthinsen
* Copyright (C) 2002-2004 Brian S. Dean <bsd@bsdhome.com> * Copyright (C) 2002-2004 Brian S. Dean <bsd@bsdhome.com>
* Copyright (C) 2006 David Moore * Copyright (C) 2006 David Moore
* Copyright (C) 2006 Joerg Wunsch <j@uriah.heep.sax.de>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -72,6 +73,21 @@ extern int verbose;
extern char * progname; extern char * progname;
extern int do_cycles; extern int do_cycles;
/*
* See stk500pp_read_byte() for an explanation of the flash and
* EEPROM page caches.
*/
static unsigned char *flash_pagecache;
static unsigned long flash_pageaddr;
static unsigned int flash_pagesize;
static unsigned char *eeprom_pagecache;
static unsigned long eeprom_pageaddr;
static unsigned int eeprom_pagesize;
/* page buffer for single-byte IO */
static unsigned char *pagebuf;
static unsigned char command_sequence = 1; static unsigned char command_sequence = 1;
static int is_mk2; /* Is the device an AVRISP mkII? */ static int is_mk2; /* Is the device an AVRISP mkII? */
@ -309,7 +325,8 @@ retry:
return 0; return 0;
} }
static int stk500v2_command(PROGRAMMER * pgm, unsigned char * buf, size_t len, size_t maxlen) { static int stk500v2_command
(PROGRAMMER * pgm, unsigned char * buf, size_t len, size_t maxlen) {
int i; int i;
int tries = 0; int tries = 0;
int status; int status;
@ -381,6 +398,16 @@ static int stk500v2_cmd(PROGRAMMER * pgm, unsigned char cmd[4],
} }
static int stk500pp_cmd(PROGRAMMER * pgm, unsigned char cmd[4],
unsigned char res[4])
{
fprintf(stderr, "%s: stk500pp_command(): no direct SPI supported for PP mode\n",
progname);
return -1;
}
/* /*
* issue the 'chip erase' command to the AVR device * issue the 'chip erase' command to the AVR device
*/ */
@ -410,6 +437,28 @@ static int stk500v2_chip_erase(PROGRAMMER * pgm, AVRPART * p)
return result; return result;
} }
/*
* issue the 'chip erase' command to the AVR device, parallel mode
*/
static int stk500pp_chip_erase(PROGRAMMER * pgm, AVRPART * p)
{
int result;
unsigned char buf[3];
pgm->pgm_led(pgm, ON);
buf[0] = CMD_CHIP_ERASE_PP;
buf[1] = 0; /* pulseWidth */
buf[2] = 5; /* pollTimeout */
result = stk500v2_command(pgm, buf, 3, sizeof(buf));
usleep(p->chip_erase_delay);
pgm->initialize(pgm, p);
pgm->pgm_led(pgm, OFF);
return result;
}
/* /*
* issue the 'program enable' command to the AVR device * issue the 'program enable' command to the AVR device
*/ */
@ -436,6 +485,25 @@ static int stk500v2_program_enable(PROGRAMMER * pgm, AVRPART * p)
return stk500v2_command(pgm, buf, 12, sizeof(buf)); return stk500v2_command(pgm, buf, 12, sizeof(buf));
} }
/*
* issue the 'program enable' command to the AVR device, parallel mode
*/
static int stk500pp_program_enable(PROGRAMMER * pgm, AVRPART * p)
{
unsigned char buf[16];
buf[0] = CMD_ENTER_PROGMODE_PP;
buf[1] = p->ppenterstabdelay;
buf[2] = p->progmodedelay;
buf[3] = p->latchcycles;
buf[4] = p->togglevtg;
buf[5] = p->poweroffdelay;
buf[6] = p->resetdelayms;
buf[7] = p->resetdelayus;
return stk500v2_command(pgm, buf, 8, sizeof(buf));
}
/* /*
@ -447,6 +515,79 @@ static int stk500v2_initialize(PROGRAMMER * pgm, AVRPART * p)
} }
/*
* initialize the AVR device and prepare it to accept commands, parallel mode
*/
static int stk500pp_initialize(PROGRAMMER * pgm, AVRPART * p)
{
unsigned char buf[CTL_STACK_SIZE + 1];
int result;
LNODEID ln;
AVRMEM * m;
if (p->ctl_stack_type != CTL_STACK_PP) {
fprintf(stderr,
"%s: stk500pp_initialize(): "
"parallel programming control stack not defined for part \"%s\"\n",
progname, p->desc);
return -1;
}
buf[0] = CMD_SET_CONTROL_STACK;
memcpy(buf + 1, p->controlstack, CTL_STACK_SIZE);
result = stk500v2_command(pgm, buf, CTL_STACK_SIZE + 1, sizeof(buf));
if (result < 0 || buf[1] != STATUS_CMD_OK) {
fprintf(stderr,
"%s: stk500pp_initalize(): "
"failed to set control stack, got 0x%02x\n",
progname, buf[1]);
return -1;
}
/*
* Examine the avrpart's memory definitions, and initialize the page
* caches. For devices/memory that are not page oriented, treat
* them as page size 1 for EEPROM, and 2 for flash.
*/
flash_pagesize = 2;
eeprom_pagesize = 1;
for (ln = lfirst(p->mem); ln; ln = lnext(ln)) {
m = ldata(ln);
if (strcmp(m->desc, "flash") == 0) {
flash_pagesize = m->page_size;
} else if (strcmp(m->desc, "eeprom") == 0) {
eeprom_pagesize = m->page_size;
}
}
free(flash_pagecache);
free(eeprom_pagecache);
free(pagebuf);
if ((pagebuf = malloc(flash_pagesize + 5)) == NULL) {
fprintf(stderr, "%s: stk500pp_initialize(): Out of memory\n",
progname);
return -1;
}
if ((flash_pagecache = malloc(flash_pagesize)) == NULL) {
fprintf(stderr, "%s: stk500pp_initialize(): Out of memory\n",
progname);
free(pagebuf);
return -1;
}
if ((eeprom_pagecache = malloc(eeprom_pagesize)) == NULL) {
fprintf(stderr, "%s: stk500pp_initialize(): Out of memory\n",
progname);
free(flash_pagecache);
free(pagebuf);
return -1;
}
flash_pageaddr = eeprom_pageaddr = (unsigned long)-1L;
return pgm->program_enable(pgm, p);
}
static void stk500v2_disable(PROGRAMMER * pgm) static void stk500v2_disable(PROGRAMMER * pgm)
{ {
unsigned char buf[16]; unsigned char buf[16];
@ -467,6 +608,35 @@ static void stk500v2_disable(PROGRAMMER * pgm)
return; return;
} }
static void stk500pp_disable(PROGRAMMER * pgm)
{
unsigned char buf[16];
int result;
free(pagebuf);
pagebuf = NULL;
free(flash_pagecache);
flash_pagecache = NULL;
free(eeprom_pagecache);
eeprom_pagecache = NULL;
buf[0] = CMD_LEAVE_PROGMODE_PP;
buf[1] = 15; // p->ppleavestabdelay;
buf[2] = 15; // p->resetdelay;
result = stk500v2_command(pgm, buf, 3, sizeof(buf));
if (result < 0 || buf[1] != STATUS_CMD_OK) {
fprintf(stderr,
"%s: stk500pp_disable(): "
"failed to leave programming mode, got 0x%02x\n",
progname,buf[1]);
exit(1);
}
return;
}
static void stk500v2_enable(PROGRAMMER * pgm) static void stk500v2_enable(PROGRAMMER * pgm)
{ {
return; return;
@ -552,6 +722,229 @@ static int stk500v2_loadaddr(PROGRAMMER * pgm, unsigned int addr)
} }
static int stk500pp_read_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
unsigned long addr, unsigned char * value)
{
int result, cmdlen = 2;
unsigned long paddr = 0UL, *paddr_ptr = NULL;
unsigned int pagesize = 0, use_ext_addr = 0, addrshift = 0;
unsigned char *cache_ptr = NULL;
if (verbose >= 2)
fprintf(stderr, "%s: stk500pp_read_byte(.., %s, 0x%lx, ...)\n",
progname, mem->desc, addr);
if (stk500pp_program_enable(pgm, p) < 0)
return -1;
if (strcmp(mem->desc, "flash") == 0) {
pagebuf[0] = CMD_READ_FLASH_PP;
cmdlen = 3;
pagesize = mem->page_size;
if (pagesize == 0)
pagesize = 2;
paddr = addr & ~(pagesize - 1);
paddr_ptr = &flash_pageaddr;
cache_ptr = flash_pagecache;
addrshift = 1;
/*
* If bit 31 is set, this indicates that the following read/write
* operation will be performed on a memory that is larger than
* 64KBytes. This is an indication to STK500 that a load extended
* address must be executed.
*/
if (mem->op[AVR_OP_LOAD_EXT_ADDR] != NULL) {
use_ext_addr = (1U << 31);
}
} else if (strcmp(mem->desc, "eeprom") == 0) {
pagebuf[0] = CMD_READ_EEPROM_PP;
cmdlen = 3;
pagesize = mem->page_size;
if (pagesize == 0)
pagesize = 1;
paddr = addr & ~(pagesize - 1);
paddr_ptr = &eeprom_pageaddr;
cache_ptr = eeprom_pagecache;
} else if (strcmp(mem->desc, "lfuse") == 0) {
pagebuf[0] = CMD_READ_FUSE_PP;
addr = 0;
} else if (strcmp(mem->desc, "hfuse") == 0) {
pagebuf[0] = CMD_READ_FUSE_PP;
addr = 1;
} else if (strcmp(mem->desc, "efuse") == 0) {
pagebuf[0] = CMD_READ_FUSE_PP;
addr = 2;
} else if (strcmp(mem->desc, "lock") == 0) {
pagebuf[0] = CMD_READ_LOCK_PP;
} else if (strcmp(mem->desc, "calibration") == 0) {
pagebuf[0] = CMD_READ_OSCCAL_PP;
} else if (strcmp(mem->desc, "signature") == 0) {
pagebuf[0] = CMD_READ_SIGNATURE_PP;
}
/*
* In parallel mode, we have to use paged reads for flash and
* EEPROM, and cache the results in a page cache.
*
* Page cache validation is based on "{flash,eeprom}_pageaddr"
* (holding the base address of the most recent cache fill
* operation). This variable is set to (unsigned long)-1L when the
* cache needs to be invalidated.
*/
if (pagesize && paddr == *paddr_ptr) {
*value = cache_ptr[addr & (pagesize - 1)];
return 0;
}
if (cmdlen == 3) {
/* long command, fill in # of bytes */
pagebuf[1] = (pagesize >> 8) & 0xff;
pagebuf[2] = pagesize & 0xff;
/* flash and EEPROM reads require the load address command */
stk500v2_loadaddr(pgm, use_ext_addr | (addr >> addrshift));
} else {
pagebuf[1] = addr;
}
if (verbose >= 2)
fprintf(stderr, "%s: stk500pp_read_byte(): Sending read memory command: ",
progname);
result = stk500v2_command(pgm, pagebuf, cmdlen, pagesize == 0? 3: pagesize + 3);
if (result < 0 || pagebuf[1] != STATUS_CMD_OK) {
fprintf(stderr,
"%s: stk500pp_read_byte(): "
"timeout/error communicating with programmer (status %d)\n",
progname, result);
return -1;
}
if (pagesize) {
*paddr_ptr = paddr;
memcpy(cache_ptr, pagebuf + 2, pagesize);
*value = cache_ptr[addr & (pagesize - 1)];
} else {
*value = pagebuf[2];
}
return 0;
}
static int stk500pp_write_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
unsigned long addr, unsigned char data)
{
int result, cmdlen;
unsigned long paddr = 0UL, *paddr_ptr = NULL;
unsigned int pagesize = 0, use_ext_addr = 0, addrshift = 0;
unsigned char *cache_ptr = NULL;
if (verbose >= 2)
fprintf(stderr, "%s: stk500pp_write_byte(.., %s, 0x%lx, ...)\n",
progname, mem->desc, addr);
if (stk500pp_program_enable(pgm, p) < 0)
return -1;
if (strcmp(mem->desc, "flash") == 0) {
pagebuf[0] = CMD_PROGRAM_FLASH_PP;
pagesize = mem->page_size;
if (pagesize == 0)
pagesize = 2;
paddr = addr & ~(pagesize - 1);
paddr_ptr = &flash_pageaddr;
cache_ptr = flash_pagecache;
addrshift = 1;
/*
* If bit 31 is set, this indicates that the following read/write
* operation will be performed on a memory that is larger than
* 64KBytes. This is an indication to STK500 that a load extended
* address must be executed.
*/
if (mem->op[AVR_OP_LOAD_EXT_ADDR] != NULL) {
use_ext_addr = (1U << 31);
}
} else if (strcmp(mem->desc, "eeprom") == 0) {
pagebuf[0] = CMD_PROGRAM_EEPROM_PP;
pagesize = mem->page_size;
if (pagesize == 0)
pagesize = 1;
paddr = addr & ~(pagesize - 1);
paddr_ptr = &eeprom_pageaddr;
cache_ptr = eeprom_pagecache;
} else if (strcmp(mem->desc, "lfuse") == 0) {
pagebuf[0] = CMD_PROGRAM_FUSE_PP;
addr = 0;
} else if (strcmp(mem->desc, "hfuse") == 0) {
pagebuf[0] = CMD_PROGRAM_FUSE_PP;
addr = 1;
} else if (strcmp(mem->desc, "efuse") == 0) {
pagebuf[0] = CMD_PROGRAM_FUSE_PP;
addr = 2;
} else if (strcmp(mem->desc, "lock") == 0) {
pagebuf[0] = CMD_PROGRAM_LOCK_PP;
} else {
fprintf(stderr,
"%s: stk500pp_write_byte(): "
"unsupported memory type: %s\n",
progname, mem->desc);
return -1;
}
cmdlen = 5 + pagesize;
/*
* In parallel mode, we have to use paged writes for flash and
* EEPROM. As both, flash and EEPROM cells can only be programmed
* from `1' to `0' bits (even EEPROM does not support auto-erase in
* parallel mode), we just pre-fill the page cache with 0xff, so all
* those cells that are outside our current address will remain
* unaffected.
*/
if (pagesize) {
memset(cache_ptr, 0xff, pagesize);
cache_ptr[addr & (pagesize - 1)] = data;
/* long command, fill in # of bytes */
pagebuf[1] = (pagesize >> 8) & 0xff;
pagebuf[2] = pagesize & 0xff;
pagebuf[3] = mem->mode | 0x80;
pagebuf[4] = mem->delay;
memcpy(pagebuf + 5, cache_ptr, pagesize);
/* flash and EEPROM reads require the load address command */
stk500v2_loadaddr(pgm, use_ext_addr | (paddr >> addrshift));
} else {
pagebuf[1] = addr;
pagebuf[2] = data;
pagebuf[3] = 0; /* pulseWidth */
pagebuf[4] = 5; /* pollTimeout */
}
if (verbose >= 2)
fprintf(stderr, "%s: stk500pp_write_byte(): Sending write memory command: ",
progname);
result = stk500v2_command(pgm, pagebuf, cmdlen, cmdlen);
if (result < 0 || pagebuf[1] != STATUS_CMD_OK) {
fprintf(stderr,
"%s: stk500pp_write_byte(): "
"timeout/error communicating with programmer (status %d)\n",
progname, result);
return -1;
}
if (pagesize) {
/* Invalidate the page cache. */
*paddr_ptr = (unsigned long)-1L;
}
return 0;
}
static int stk500v2_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, static int stk500v2_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
int page_size, int n_bytes) int page_size, int n_bytes)
{ {
@ -684,6 +1077,82 @@ static int stk500v2_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
return n_bytes; return n_bytes;
} }
static int stk500pp_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
int page_size, int n_bytes)
{
unsigned int addr, block_size, last_addr, hiaddr, addrshift, use_ext_addr;
unsigned char commandbuf[5];
int result;
DEBUG("STK500V2: stk500pp_paged_write(..,%s,%d,%d)\n",m->desc,page_size,n_bytes);
if (page_size == 0) page_size = 256;
hiaddr = UINT_MAX;
addrshift = 0;
use_ext_addr = 0;
// determine which command is to be used
if (strcmp(m->desc, "flash") == 0) {
addrshift = 1;
flash_pageaddr = (unsigned long)-1L;
commandbuf[0] = CMD_PROGRAM_FLASH_PP;
/*
* If bit 31 is set, this indicates that the following read/write
* operation will be performed on a memory that is larger than
* 64KBytes. This is an indication to STK500 that a load extended
* address must be executed.
*/
if (m->op[AVR_OP_LOAD_EXT_ADDR] != NULL) {
use_ext_addr = (1U << 31);
}
} else if (strcmp(m->desc, "eeprom") == 0) {
eeprom_pageaddr = (unsigned long)-1L;
commandbuf[0] = CMD_PROGRAM_EEPROM_PP;
}
commandbuf[3] = m->mode | 0x80; // yes, write the page to flash
commandbuf[4] = m->delay;
last_addr = UINT_MAX; /* impossible address */
for (addr=0; addr < n_bytes; addr += page_size) {
report_progress(addr,n_bytes,NULL);
if ((n_bytes-addr) < page_size)
block_size = n_bytes - addr;
else
block_size = page_size;
DEBUG("block_size at addr %d is %d\n",addr,block_size);
if (commandbuf[0] == CMD_PROGRAM_FLASH_PP){
if (stk500v2_is_page_empty(addr, block_size, m->buf)) {
continue;
}
}
memcpy(pagebuf, commandbuf, sizeof(commandbuf));
pagebuf[1] = block_size >> 8;
pagebuf[2] = block_size & 0xff;
if ((last_addr == UINT_MAX) || (last_addr + block_size != addr)) {
stk500v2_loadaddr(pgm, use_ext_addr | (addr >> addrshift));
}
last_addr=addr;
memcpy(pagebuf + 5, m->buf + addr, block_size);
result = stk500v2_command(pgm, pagebuf, block_size + 5, page_size + 5);
if (pagebuf[1] != STATUS_CMD_OK) {
fprintf(stderr, "%s: stk500pp_paged_write: write command failed with %d\n",
progname, pagebuf[1]);
return -1;
}
}
return n_bytes;
}
static int stk500v2_is_page_empty(unsigned int address, int page_size, static int stk500v2_is_page_empty(unsigned int address, int page_size,
const unsigned char *buf) const unsigned char *buf)
{ {
@ -788,6 +1257,80 @@ static int stk500v2_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
} }
static int stk500pp_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
int page_size, int n_bytes)
{
unsigned int addr, block_size, hiaddr, addrshift, use_ext_addr;
unsigned char commandbuf[3];
int result;
DEBUG("STK500V2: stk500pp_paged_load(..,%s,%d,%d)\n",m->desc,page_size,n_bytes);
page_size = m->readsize;
hiaddr = UINT_MAX;
addrshift = 0;
use_ext_addr = 0;
// determine which command is to be used
if (strcmp(m->desc, "flash") == 0) {
commandbuf[0] = CMD_READ_FLASH_PP;
addrshift = 1;
/*
* If bit 31 is set, this indicates that the following read/write
* operation will be performed on a memory that is larger than
* 64KBytes. This is an indication to STK500 that a load extended
* address must be executed.
*/
if (m->op[AVR_OP_LOAD_EXT_ADDR] != NULL) {
use_ext_addr = (1U << 31);
}
}
else if (strcmp(m->desc, "eeprom") == 0) {
commandbuf[0] = CMD_READ_EEPROM_PP;
}
for (addr = 0; addr < n_bytes; addr += page_size) {
report_progress(addr, n_bytes, NULL);
if ((n_bytes-addr) < page_size)
block_size = n_bytes - addr;
else
block_size = page_size;
DEBUG("block_size at addr %d is %d\n",addr,block_size);
memcpy(pagebuf, commandbuf, sizeof(commandbuf));
pagebuf[1] = block_size >> 8;
pagebuf[2] = block_size & 0xff;
// Ensure a new "load extended address" will be issued
// when crossing a 64 KB boundary in flash.
if (hiaddr != (addr & ~0xFFFF)) {
hiaddr = addr & ~0xFFFF;
stk500v2_loadaddr(pgm, use_ext_addr | (addr >> addrshift));
}
result = stk500v2_command(pgm, pagebuf, 3, block_size + 3);
if (pagebuf[1] != STATUS_CMD_OK) {
fprintf(stderr, "%s: stk500pp_paged_load: read command failed with %d\n",
progname, pagebuf[1]);
return -1;
}
#if 0
for (i = 0; i < page_size; i++) {
fprintf(stderr, "%02X", buf[2 + i]);
if (i % 16 == 15) fprintf(stderr, "\n");
}
#endif
memcpy(&m->buf[addr], &pagebuf[2], block_size);
}
return n_bytes;
}
static int stk500v2_set_vtarget(PROGRAMMER * pgm, double v) static int stk500v2_set_vtarget(PROGRAMMER * pgm, double v)
{ {
unsigned char uaref, utarg; unsigned char uaref, utarg;
@ -1128,3 +1671,35 @@ void stk500v2_initpgm(PROGRAMMER * pgm)
pgm->set_sck_period = stk500v2_set_sck_period; pgm->set_sck_period = stk500v2_set_sck_period;
pgm->page_size = 256; pgm->page_size = 256;
} }
void stk500pp_initpgm(PROGRAMMER * pgm)
{
strcpy(pgm->type, "STK500PP");
/*
* mandatory functions
*/
pgm->initialize = stk500pp_initialize;
pgm->display = stk500v2_display;
pgm->enable = stk500v2_enable;
pgm->disable = stk500pp_disable;
pgm->program_enable = stk500pp_program_enable;
pgm->chip_erase = stk500pp_chip_erase;
pgm->cmd = stk500pp_cmd;
pgm->open = stk500v2_open;
pgm->close = stk500v2_close;
/*
* optional functions
*/
pgm->read_byte = stk500pp_read_byte;
pgm->write_byte = stk500pp_write_byte;
pgm->paged_write = stk500pp_paged_write;
pgm->paged_load = stk500pp_paged_load;
pgm->print_parms = stk500v2_print_parms;
pgm->set_vtarget = stk500v2_set_vtarget;
pgm->set_varef = stk500v2_set_varef;
pgm->set_fosc = stk500v2_set_fosc;
pgm->set_sck_period = stk500v2_set_sck_period;
pgm->page_size = 256;
}

View File

@ -1,6 +1,7 @@
/* /*
* avrdude - A Downloader/Uploader for AVR device programmers * avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2002-2005 Brian S. Dean <bsd@bsdhome.com> * Copyright (C) 2002-2005 Brian S. Dean <bsd@bsdhome.com>
* Copyright (C) 2006 Joerg Wunsch <j@uriah.heep.sax.de>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -23,6 +24,7 @@
#define stk500v2_h__ #define stk500v2_h__
void stk500v2_initpgm (PROGRAMMER * pgm); void stk500v2_initpgm (PROGRAMMER * pgm);
void stk500pp_initpgm (PROGRAMMER * pgm);
#endif #endif