Fix writing of last word on DWORD TPI parts (#1115)
* Fix writing of last word on DWORD TPI parts * Add n_word_writes AVRMEM config option * TPI word chunk mode in avr_write_mem * Simplify addition of n_words_write mem component to grammar Co-authored-by: Stefan Rueger <stefan.rueger@urclocks.com>
This commit is contained in:
parent
08f4f6c63f
commit
946b701b08
44
src/avr.c
44
src/avr.c
|
@ -856,6 +856,9 @@ int avr_write_mem(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m, int
|
||||||
|
|
||||||
|
|
||||||
if ((p->prog_modes & PM_TPI) && m->page_size > 1 && pgm->cmd_tpi) {
|
if ((p->prog_modes & PM_TPI) && m->page_size > 1 && pgm->cmd_tpi) {
|
||||||
|
unsigned int chunk; /* number of words for each write command */
|
||||||
|
unsigned int j, writeable_chunk;
|
||||||
|
|
||||||
if (wsize == 1) {
|
if (wsize == 1) {
|
||||||
/* fuse (configuration) memory: only single byte to write */
|
/* fuse (configuration) memory: only single byte to write */
|
||||||
return avr_write_byte(pgm, p, m, 0, m->buf[0]) == 0? 1: LIBAVRDUDE_GENERAL_FAILURE;
|
return avr_write_byte(pgm, p, m, 0, m->buf[0]) == 0? 1: LIBAVRDUDE_GENERAL_FAILURE;
|
||||||
|
@ -866,35 +869,50 @@ int avr_write_mem(const PROGRAMMER *pgm, const AVRPART *p, const AVRMEM *m, int
|
||||||
/* setup for WORD_WRITE */
|
/* setup for WORD_WRITE */
|
||||||
avr_tpi_setup_rw(pgm, m, 0, TPI_NVMCMD_WORD_WRITE);
|
avr_tpi_setup_rw(pgm, m, 0, TPI_NVMCMD_WORD_WRITE);
|
||||||
|
|
||||||
/* make sure it's aligned to a word boundary */
|
/*
|
||||||
if (wsize & 0x1) {
|
* Some TPI devices can only program 2 or 4 words (4 or 8 bytes) at a time.
|
||||||
wsize++;
|
* This is set by the n_word_writes option of the AVRMEM config section.
|
||||||
|
* Ensure that we align our write size to this boundary.
|
||||||
|
*/
|
||||||
|
if (m->n_word_writes < 0 || m->n_word_writes > 4 || m->n_word_writes == 3) {
|
||||||
|
avrdude_message(MSG_INFO, "\n%s: ERROR: Unsupported n_word_writes value of %d "
|
||||||
|
"configured for %s memory\n"
|
||||||
|
"%sAborting write\n",
|
||||||
|
progname, m->n_word_writes, m->desc, progbuf);
|
||||||
|
return LIBAVRDUDE_GENERAL_FAILURE;
|
||||||
|
}
|
||||||
|
chunk = m->n_word_writes > 0 ? 2*m->n_word_writes : 2;
|
||||||
|
wsize = (wsize+chunk-1) / chunk * chunk;
|
||||||
|
|
||||||
|
/* write words in chunks, low byte first */
|
||||||
|
for (lastaddr = i = 0; i < wsize; i += chunk) {
|
||||||
|
/* check that at least one byte in this chunk is allocated */
|
||||||
|
for (writeable_chunk = j = 0; !writeable_chunk && j < chunk; j++) {
|
||||||
|
writeable_chunk = m->tags[i+j] & TAG_ALLOCATED;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* write words, low byte first */
|
if (writeable_chunk) {
|
||||||
for (lastaddr = i = 0; i < wsize; i += 2) {
|
|
||||||
if ((m->tags[i] & TAG_ALLOCATED) != 0 ||
|
|
||||||
(m->tags[i + 1] & TAG_ALLOCATED) != 0) {
|
|
||||||
|
|
||||||
if (lastaddr != i) {
|
if (lastaddr != i) {
|
||||||
/* need to setup new address */
|
/* need to setup new address */
|
||||||
avr_tpi_setup_rw(pgm, m, i, TPI_NVMCMD_WORD_WRITE);
|
avr_tpi_setup_rw(pgm, m, i, TPI_NVMCMD_WORD_WRITE);
|
||||||
lastaddr = i;
|
lastaddr = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Write each byte of the chunk. Unallocated bytes should read
|
||||||
|
// as 0xFF, which should no-op.
|
||||||
cmd[0] = TPI_CMD_SST_PI;
|
cmd[0] = TPI_CMD_SST_PI;
|
||||||
cmd[1] = m->buf[i];
|
for (j = 0; j < chunk; j++) {
|
||||||
|
cmd[1] = m->buf[i+j];
|
||||||
rc = pgm->cmd_tpi(pgm, cmd, 2, NULL, 0);
|
rc = pgm->cmd_tpi(pgm, cmd, 2, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
cmd[1] = m->buf[i + 1];
|
lastaddr += chunk;
|
||||||
rc = pgm->cmd_tpi(pgm, cmd, 2, NULL, 0);
|
|
||||||
|
|
||||||
lastaddr += 2;
|
|
||||||
|
|
||||||
while (avr_tpi_poll_nvmbsy(pgm));
|
while (avr_tpi_poll_nvmbsy(pgm));
|
||||||
}
|
}
|
||||||
report_progress(i, wsize, NULL);
|
report_progress(i, wsize, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -148,6 +148,7 @@
|
||||||
# size = <num> ; # bytes
|
# size = <num> ; # bytes
|
||||||
# page_size = <num> ; # bytes
|
# page_size = <num> ; # bytes
|
||||||
# num_pages = <num> ; # numeric
|
# num_pages = <num> ; # numeric
|
||||||
|
# n_word_writes = <num> ; # TPI only: if set, number of words to write
|
||||||
# min_write_delay = <num> ; # micro-seconds
|
# min_write_delay = <num> ; # micro-seconds
|
||||||
# max_write_delay = <num> ; # micro-seconds
|
# max_write_delay = <num> ; # micro-seconds
|
||||||
# readback = <num> <num> ; # pair of byte values
|
# readback = <num> <num> ; # pair of byte values
|
||||||
|
@ -13346,6 +13347,7 @@ part parent ".reduced_core_tiny"
|
||||||
memory "flash"
|
memory "flash"
|
||||||
size = 2048;
|
size = 2048;
|
||||||
page_size = 16;
|
page_size = 16;
|
||||||
|
n_word_writes = 2;
|
||||||
offset = 0x4000;
|
offset = 0x4000;
|
||||||
blocksize = 128;
|
blocksize = 128;
|
||||||
;
|
;
|
||||||
|
@ -13365,6 +13367,7 @@ part parent ".reduced_core_tiny"
|
||||||
memory "flash"
|
memory "flash"
|
||||||
size = 4096;
|
size = 4096;
|
||||||
page_size = 64;
|
page_size = 64;
|
||||||
|
n_word_writes = 4;
|
||||||
offset = 0x4000;
|
offset = 0x4000;
|
||||||
blocksize = 128;
|
blocksize = 128;
|
||||||
;
|
;
|
||||||
|
|
|
@ -70,6 +70,9 @@ Component_t avr_comp[] = {
|
||||||
part_comp_desc(mcuid, COMP_INT),
|
part_comp_desc(mcuid, COMP_INT),
|
||||||
part_comp_desc(n_interrupts, COMP_INT),
|
part_comp_desc(n_interrupts, COMP_INT),
|
||||||
part_comp_desc(n_page_erase, COMP_INT),
|
part_comp_desc(n_page_erase, COMP_INT),
|
||||||
|
|
||||||
|
// AVRMEM
|
||||||
|
mem_comp_desc(n_word_writes, COMP_INT),
|
||||||
};
|
};
|
||||||
|
|
||||||
#define DEBUG 0
|
#define DEBUG 0
|
||||||
|
|
|
@ -746,6 +746,7 @@ static void dev_part_strct(const AVRPART *p, bool tsv, const AVRPART *base, bool
|
||||||
_if_memout(intcmp, m->size > 8192? "0x%x": "%d", size);
|
_if_memout(intcmp, m->size > 8192? "0x%x": "%d", size);
|
||||||
_if_memout(intcmp, "%d", page_size);
|
_if_memout(intcmp, "%d", page_size);
|
||||||
_if_memout(intcmp, "%d", num_pages);
|
_if_memout(intcmp, "%d", num_pages);
|
||||||
|
_if_memout(intcmp, "%d", n_word_writes);
|
||||||
_if_memout(intcmp, "0x%x", offset);
|
_if_memout(intcmp, "0x%x", offset);
|
||||||
_if_memout(intcmp, "%d", min_write_delay);
|
_if_memout(intcmp, "%d", min_write_delay);
|
||||||
_if_memout(intcmp, "%d", max_write_delay);
|
_if_memout(intcmp, "%d", max_write_delay);
|
||||||
|
|
|
@ -1930,6 +1930,7 @@ part
|
||||||
size = <num> ; # bytes
|
size = <num> ; # bytes
|
||||||
page_size = <num> ; # bytes
|
page_size = <num> ; # bytes
|
||||||
num_pages = <num> ; # numeric
|
num_pages = <num> ; # numeric
|
||||||
|
n_word_writes = <num> ; # TPI only: if set, number of words to write
|
||||||
min_write_delay = <num> ; # micro-seconds
|
min_write_delay = <num> ; # micro-seconds
|
||||||
max_write_delay = <num> ; # micro-seconds
|
max_write_delay = <num> ; # micro-seconds
|
||||||
readback = <num> <num> ; # pair of byte values
|
readback = <num> <num> ; # pair of byte values
|
||||||
|
|
|
@ -121,7 +121,7 @@ SIGN [+-]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
prog_modes|mcuid|n_interrupts|n_page_erase { /* Components for assignment */
|
prog_modes|mcuid|n_interrupts|n_page_erase|n_word_writes { /* Components for assignment */
|
||||||
Component_t *cp = cfg_comp_search(yytext, current_strct);
|
Component_t *cp = cfg_comp_search(yytext, current_strct);
|
||||||
if(!cp) {
|
if(!cp) {
|
||||||
yyerror("Unknown component %s in %s", yytext, cfg_strct_name(current_strct));
|
yyerror("Unknown component %s in %s", yytext, cfg_strct_name(current_strct));
|
||||||
|
|
|
@ -309,6 +309,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) */
|
||||||
|
int n_word_writes; /* TPI only: number words to write at a time */
|
||||||
unsigned int offset; /* offset in IO memory (ATxmega) */
|
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 */
|
||||||
|
|
Loading…
Reference in New Issue