From 8368f8317bc46d698febfe576fe942e10087ef24 Mon Sep 17 00:00:00 2001 From: "Brian S. Dean" Date: Sun, 1 Dec 2002 06:35:18 +0000 Subject: [PATCH] Optimize reading and writing for the STK500 programmer if the part supports paged reads and writes. This greatly decreases the program/verify time from about 4.5 minutes down to about 10 seconds in a 12K program size test case. Print out the hardware and firmware version for the STK500 if verbose is enabled. git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk@161 81a1dc3b-b13d-400b-aceb-764788c761c2 --- avrdude/avr.c | 17 +++ avrdude/avr.h | 18 --- avrdude/avrpart.h | 18 +++ avrdude/main.c | 16 +-- avrdude/pgm.c | 11 ++ avrdude/pgm.h | 4 + avrdude/stk500.c | 314 +++++++++++++++++++++++++++++++++++++++++++++- 7 files changed, 370 insertions(+), 28 deletions(-) diff --git a/avrdude/avr.c b/avrdude/avr.c index 8555ec8d..b1013533 100644 --- a/avrdude/avr.c +++ b/avrdude/avr.c @@ -374,6 +374,15 @@ int avr_read(PROGRAMMER * pgm, AVRPART * p, char * memtype, int size, size = mem->size; } + if (mem->paged && pgm->paged_load != NULL) { + /* + * the programmer directly supports writing this memory, perhaps + * more efficiently than we can from here + */ + return pgm->paged_load(pgm, p, mem, size); + } + + printed = 0; for (i=0; ierr_led(pgm, OFF); + if (m->paged && pgm->paged_write != NULL) { + /* + * the programmer directly supports writing this memory, perhaps + * more efficiently than we can from here + */ + return pgm->paged_write(pgm, p, m, size); + } + printed = 0; werror = 0; diff --git a/avrdude/avr.h b/avrdude/avr.h index c48f1cfa..7e7ac16d 100644 --- a/avrdude/avr.h +++ b/avrdude/avr.h @@ -39,24 +39,6 @@ #include "pgm.h" -#define AVR_MEMDESCLEN 64 -typedef struct avrmem { - char desc[AVR_MEMDESCLEN]; /* memory description ("flash", "eeprom", etc) */ - int paged; /* page addressed (e.g. ATmega flash) */ - 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) */ - int min_write_delay; /* microseconds */ - int max_write_delay; /* microseconds */ - int pwroff_after_write; /* after this memory type is written to, - the device must be powered off and - back on, see errata - http://www.atmel.com/atmel/acrobat/doc1280.pdf */ - unsigned char readback[2]; /* polled read-back values */ - unsigned char * buf; /* pointer to memory buffer */ - OPCODE * op[AVR_OP_MAX]; /* opcodes */ -} AVRMEM; - extern struct avrpart parts[]; diff --git a/avrdude/avrpart.h b/avrdude/avrpart.h index 3072ca3b..96db5c5a 100644 --- a/avrdude/avrpart.h +++ b/avrdude/avrpart.h @@ -56,4 +56,22 @@ typedef struct avrpart { LISTID mem; /* avr memory definitions */ } AVRPART; +#define AVR_MEMDESCLEN 64 +typedef struct avrmem { + char desc[AVR_MEMDESCLEN]; /* memory description ("flash", "eeprom", etc) */ + int paged; /* page addressed (e.g. ATmega flash) */ + 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) */ + int min_write_delay; /* microseconds */ + int max_write_delay; /* microseconds */ + int pwroff_after_write; /* after this memory type is written to, + the device must be powered off and + back on, see errata + http://www.atmel.com/atmel/acrobat/doc1280.pdf */ + unsigned char readback[2]; /* polled read-back values */ + unsigned char * buf; /* pointer to memory buffer */ + OPCODE * op[AVR_OP_MAX]; /* opcodes */ +} AVRMEM; + #endif diff --git a/avrdude/main.c b/avrdude/main.c index 23c83b39..8e0dd9a8 100644 --- a/avrdude/main.c +++ b/avrdude/main.c @@ -735,14 +735,6 @@ int main(int argc, char * argv []) p = avr_dup_part(p); v = avr_dup_part(p); - if (verbose) { - avr_display(stderr, p, progbuf, verbose); - fprintf(stderr, "\n"); - pinconfig_display(progbuf); - } - - fprintf(stderr, "\n"); - if (strcmp(pgm->type, "PPI") == 0) { verify_pin_assigned(PIN_AVR_RESET, "AVR RESET"); verify_pin_assigned(PIN_AVR_SCK, "AVR SCK"); @@ -755,6 +747,14 @@ int main(int argc, char * argv []) */ pgm->open(pgm, port); + if (verbose) { + avr_display(stderr, p, progbuf, verbose); + fprintf(stderr, "\n"); + pinconfig_display(progbuf); + } + + fprintf(stderr, "\n"); + exitrc = 0; rc = pgm->save(pgm); diff --git a/avrdude/pgm.c b/avrdude/pgm.c index 5d466338..47acf982 100644 --- a/avrdude/pgm.c +++ b/avrdude/pgm.c @@ -69,6 +69,10 @@ PROGRAMMER * pgm_new(void) for (i=0; ipinno[i] = 0; + /* + * mandatory functions - these are called without checking to see + * whether they are assigned or not + */ pgm->rdy_led = pgm_default_1; pgm->err_led = pgm_default_1; pgm->pgm_led = pgm_default_1; @@ -87,6 +91,13 @@ PROGRAMMER * pgm_new(void) pgm->open = pgm_default_6; pgm->close = pgm_default_4; + /* + * optional functions - these are checked to make sure they are + * assigned before they are called + */ + pgm->paged_write = NULL; + pgm->paged_load = NULL; + return pgm; } diff --git a/avrdude/pgm.h b/avrdude/pgm.h index 3d5f1738..83e8db55 100644 --- a/avrdude/pgm.h +++ b/avrdude/pgm.h @@ -71,6 +71,10 @@ typedef struct programmer_t { unsigned char res[4]); void (*open) (struct programmer_t * pgm, char * port); void (*close) (struct programmer_t * pgm); + int (*paged_write) (struct programmer_t * pgm, AVRPART * p, AVRMEM * m, + int n_bytes); + int (*paged_load) (struct programmer_t * pgm, AVRPART * p, AVRMEM * m, + int n_bytes); } PROGRAMMER; diff --git a/avrdude/stk500.c b/avrdude/stk500.c index 24c7ac6f..bd9bd379 100644 --- a/avrdude/stk500.c +++ b/avrdude/stk500.c @@ -29,6 +29,15 @@ /* $Id$ */ +/* + * avrprog interface for Atmel STK500 programmer + * + * Note: most commands use the "universal command" feature of the + * programmer in a "pass through" mode, exceptions are "program + * enable", "paged read", and "paged write". + * + */ + #include #include #include @@ -201,8 +210,7 @@ static int getsync(PROGRAMMER * pgm) unsigned char buf[32], resp[32]; /* - * get in sync - */ + * get in sync */ buf[0] = Cmnd_STK_GET_SYNC; buf[1] = Sync_CRC_EOP; send(pgm, buf, 2); @@ -683,8 +691,301 @@ void stk500_close(PROGRAMMER * pgm) } +static int loadaddr(PROGRAMMER * pgm, uint16_t addr) +{ + unsigned char buf[16]; + int tries; + + tries = 0; + retry: + tries++; + buf[0] = Cmnd_STK_LOAD_ADDRESS; + buf[1] = addr & 0xff; + buf[2] = (addr >> 8) & 0xff; + buf[3] = Sync_CRC_EOP; + + send(pgm, buf, 4); + + recv(pgm, buf, 1); + if (buf[0] == Resp_STK_NOSYNC) { + if (tries > 33) { + fprintf(stderr, "%s: loadaddr(): can't get into sync\n", + progname); + return -1; + } + getsync(pgm); + goto retry; + } + else if (buf[0] != Resp_STK_INSYNC) { + fprintf(stderr, + "%s: loadaddr(): (a) protocol error, " + "expect=0x%02x, resp=0x%02x\n", + progname, Resp_STK_INSYNC, buf[0]); + return -1; + } + + recv(pgm, buf, 1); + if (buf[0] == Resp_STK_OK) { + return 0; + } + + fprintf(stderr, + "%s: loadaddr(): (a) protocol error, " + "expect=0x%02x, resp=0x%02x\n", + progname, Resp_STK_INSYNC, buf[0]); + return -1; +} + + +int stk500_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, int n_bytes) +{ + unsigned char buf[16]; + int memtype; + unsigned int addr; + int a_div; + int i; + int tries; + unsigned int n; + + if (!m->paged) + return -1; + + if (strcmp(m->desc, "flash") == 0) { + memtype = 'F'; + } + else if (strcmp(m->desc, "flash") == 0) { + memtype = 'E'; + } + else { + return -2; + } + + if (m->op[AVR_OP_LOADPAGE_LO]) + a_div = 2; + else + a_div = 1; + + if (n_bytes > m->size) { + n_bytes = m->size; + n = m->size; + } + else { + if ((n_bytes % m->page_size) != 0) { + n = n_bytes + m->page_size - (n_bytes % m->page_size); + } + else { + n = n_bytes; + } + } + + for (addr = 0; addr < n; addr += m->page_size) { + fprintf(stderr, "\r \r%6u", addr); + tries = 0; + retry: + tries++; + loadaddr(pgm, addr/a_div); + buf[0] = Cmnd_STK_PROG_PAGE; + buf[1] = (m->page_size >> 8) & 0xff; + buf[2] = m->page_size & 0xff; + buf[3] = memtype; + send(pgm, buf, 4); + for (i=0; ipage_size; i++) { + buf[0] = m->buf[addr + i]; + send(pgm, buf, 1); + } + buf[0] = Sync_CRC_EOP; + send(pgm, buf, 1); + + recv(pgm, buf, 1); + if (buf[0] == Resp_STK_NOSYNC) { + if (tries > 33) { + fprintf(stderr, "\n%s: stk500_paged_write(): can't get into sync\n", + progname); + return -3; + } + getsync(pgm); + goto retry; + } + else if (buf[0] != Resp_STK_INSYNC) { + fprintf(stderr, + "\n%s: stk500_paged_write(): (a) protocol error, " + "expect=0x%02x, resp=0x%02x\n", + progname, Resp_STK_INSYNC, buf[0]); + return -4; + } + + recv(pgm, buf, 1); + if (buf[0] != Resp_STK_OK) { + fprintf(stderr, + "\n%s: stk500_paged_write(): (a) protocol error, " + "expect=0x%02x, resp=0x%02x\n", + progname, Resp_STK_INSYNC, buf[0]); + return -5; + } + } + fprintf(stderr, "\r \r%6u", addr-1); + fprintf(stderr, "\n"); + + return n; +} + + +int stk500_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, int n_bytes) +{ + unsigned char buf[16]; + int memtype; + unsigned int addr; + int a_div; + int tries; + unsigned int n; + + if (!m->paged) + return -1; + + if (strcmp(m->desc, "flash") == 0) { + memtype = 'F'; + } + else if (strcmp(m->desc, "flash") == 0) { + memtype = 'E'; + } + else { + return -2; + } + + if (m->op[AVR_OP_LOADPAGE_LO]) + a_div = 2; + else + a_div = 1; + + if (n_bytes > m->size) { + n_bytes = m->size; + n = m->size; + } + else { + if ((n_bytes % m->page_size) != 0) { + n = n_bytes + m->page_size - (n_bytes % m->page_size); + } + else { + n = n_bytes; + } + } + + for (addr = 0; addr < n; addr += m->page_size) { + fprintf(stderr, "\r \r%6u", addr); + tries = 0; + retry: + tries++; + loadaddr(pgm, addr/a_div); + buf[0] = Cmnd_STK_READ_PAGE; + buf[1] = (m->page_size >> 8) & 0xff; + buf[2] = m->page_size & 0xff; + buf[3] = memtype; + buf[4] = Sync_CRC_EOP; + send(pgm, buf, 5); + + recv(pgm, buf, 1); + if (buf[0] == Resp_STK_NOSYNC) { + if (tries > 33) { + fprintf(stderr, "\n%s: stk500_paged_load(): can't get into sync\n", + progname); + return -3; + } + getsync(pgm); + goto retry; + } + else if (buf[0] != Resp_STK_INSYNC) { + fprintf(stderr, + "\n%s: stk500_paged_load(): (a) protocol error, " + "expect=0x%02x, resp=0x%02x\n", + progname, Resp_STK_INSYNC, buf[0]); + return -4; + } + + recv(pgm, &m->buf[addr], m->page_size); + + recv(pgm, buf, 1); + if (buf[0] != Resp_STK_OK) { + fprintf(stderr, + "\n%s: stk500_paged_load(): (a) protocol error, " + "expect=0x%02x, resp=0x%02x\n", + progname, Resp_STK_INSYNC, buf[0]); + return -5; + } + } + fprintf(stderr, "\r \r%6u", addr-1); + fprintf(stderr, "\n"); + + return n; +} + + +static int getparm(PROGRAMMER * pgm, unsigned parm, unsigned * value) +{ + unsigned char buf[16]; + unsigned v; + int tries = 0; + + retry: + tries++; + buf[0] = Cmnd_STK_GET_PARAMETER; + buf[1] = parm; + buf[2] = Sync_CRC_EOP; + + send(pgm, buf, 3); + + recv(pgm, buf, 1); + if (buf[0] == Resp_STK_NOSYNC) { + if (tries > 33) { + fprintf(stderr, "\n%s: getparm(): can't get into sync\n", + progname); + return -1; + } + getsync(pgm); + goto retry; + } + else if (buf[0] != Resp_STK_INSYNC) { + fprintf(stderr, + "\n%s: getparm(): (a) protocol error, " + "expect=0x%02x, resp=0x%02x\n", + progname, Resp_STK_INSYNC, buf[0]); + return -2; + } + + recv(pgm, buf, 1); + v = buf[0]; + + recv(pgm, buf, 1); + if (buf[0] == Resp_STK_FAILED) { + fprintf(stderr, + "\n%s: getparm(): parameter 0x%02x failed\n", + progname, v); + return -3; + } + else if (buf[0] != Resp_STK_OK) { + fprintf(stderr, + "\n%s: getparm(): (a) protocol error, " + "expect=0x%02x, resp=0x%02x\n", + progname, Resp_STK_INSYNC, buf[0]); + return -3; + } + + *value = v; + + return 0; +} + + void stk500_display(PROGRAMMER * pgm, char * p) { + unsigned maj, min, hdw; + + getparm(pgm, Parm_STK_HW_VER, &hdw); + getparm(pgm, Parm_STK_SW_MAJOR, &maj); + getparm(pgm, Parm_STK_SW_MINOR, &min); + + fprintf(stderr, "%sHardware Version: %d\n", p, hdw); + fprintf(stderr, "%sFirmware Version: %d.%d\n", p, maj, min); + return; } @@ -693,6 +994,9 @@ void stk500_initpgm(PROGRAMMER * pgm) { strcpy(pgm->type, "STK500"); + /* + * mandatory functions + */ pgm->rdy_led = stk500_rdy_led; pgm->err_led = stk500_err_led; pgm->pgm_led = stk500_pgm_led; @@ -710,6 +1014,12 @@ void stk500_initpgm(PROGRAMMER * pgm) pgm->cmd = stk500_cmd; pgm->open = stk500_open; pgm->close = stk500_close; + + /* + * optional functions + */ + pgm->paged_write = stk500_paged_write; + pgm->paged_load = stk500_paged_load; }