Merge pull request #1018 from stefanrueger/issue995

Fix Issue #995 ft245r paged read for ATmega2560 et al
This commit is contained in:
Stefan Rueger 2022-07-12 14:55:44 +01:00 committed by GitHub
commit 04f790ad85
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 162 additions and 177 deletions

View File

@ -108,9 +108,9 @@ void ft245r_initpgm(PROGRAMMER * pgm) {
#else #else
#define FT245R_CYCLES 2 #define FT245R_CYCLES 2
#define FT245R_FRAGMENT_SIZE 512 #define FT245R_CMD_SIZE (4 * 8*FT245R_CYCLES)
#define FT245R_FRAGMENT_SIZE (8 * FT245R_CMD_SIZE)
#define REQ_OUTSTANDINGS 10 #define REQ_OUTSTANDINGS 10
//#define USE_INLINE_WRITE_PAGE
#define FT245R_DEBUG 0 #define FT245R_DEBUG 0
/* /*
@ -992,39 +992,17 @@ static void ft245r_display(PROGRAMMER * pgm, const char * p) {
pgm_display_generic_mask(pgm, p, SHOW_ALL_PINS); pgm_display_generic_mask(pgm, p, SHOW_ALL_PINS);
} }
static int ft245r_paged_write_gen(PROGRAMMER *pgm, AVRPART *p, AVRMEM *m, static int ft245r_paged_write_gen(PROGRAMMER *pgm, AVRPART *p, AVRMEM *m,
unsigned int page_size, unsigned int addr, unsigned int page_size, unsigned int addr, unsigned int n_bytes) {
unsigned int n_bytes) {
unsigned long i, pa;
int rc;
for (i=0; i<n_bytes; i++, addr++) { for(int i=0; i < (int) n_bytes; i++, addr++)
rc = avr_write_byte_default(pgm, p, m, addr, m->buf[addr]); if(avr_write_byte_default(pgm, p, m, addr, m->buf[addr]) != 0)
if (rc != 0) {
return -2; return -2;
return n_bytes;
} }
if (m->paged) {
// Can this piece of code ever be activated?? Do AVRs exist that
// have paged non-flash memories? -- REW
// XXX Untested code below.
/*
* check to see if it is time to flush the page with a page
* write
*/
if (((addr % m->page_size) == m->page_size-1) || (i == n_bytes-1)) {
pa = addr - (addr % m->page_size);
rc = avr_write_page(pgm, p, m, pa);
if (rc != 0) {
return -2;
}
}
}
}
return i;
}
static struct ft245r_request { static struct ft245r_request {
int addr; int addr;
@ -1081,179 +1059,186 @@ static int do_request(PROGRAMMER * pgm, AVRMEM *m) {
return 1; return 1;
} }
static int ft245r_paged_write_flash(PROGRAMMER *pgm, AVRPART *p, AVRMEM *m, static int ft245r_paged_write_flash(PROGRAMMER *pgm, AVRPART *p, AVRMEM *m,
int page_size, int addr, int n_bytes) { unsigned int page_size, unsigned int addr, unsigned int n_bytes) {
unsigned int i,j;
int addr_save,buf_pos,do_page_write,req_count;
unsigned char buf[FT245R_FRAGMENT_SIZE+1+128];
req_count = 0; int i, j, addr_save, buf_pos, req_count, do_page_write;
for (i=0; i<n_bytes; ) { unsigned char buf[FT245R_FRAGMENT_SIZE+1];
addr_save = addr;
buf_pos = 0;
do_page_write = 0;
for (j=0; j< FT245R_FRAGMENT_SIZE/8/FT245R_CYCLES/4; j++) {
buf_pos += set_data(pgm, buf+buf_pos, (addr & 1)?0x48:0x40 );
buf_pos += set_data(pgm, buf+buf_pos, (addr >> 9) & 0xff );
buf_pos += set_data(pgm, buf+buf_pos, (addr >> 1) & 0xff );
buf_pos += set_data(pgm, buf+buf_pos, m->buf[addr]);
addr ++;
i++;
if ( (m->paged) &&
(((i % m->page_size) == 0) || (i == n_bytes))) {
do_page_write = 1;
break;
}
}
#if defined(USE_INLINE_WRITE_PAGE)
if (do_page_write) {
int addr_wk = addr_save - (addr_save % m->page_size);
/* If this device has a "load extended address" command, issue it. */
if (m->op[AVR_OP_LOAD_EXT_ADDR]) {
unsigned char cmd[4]; unsigned char cmd[4];
OPCODE *lext = m->op[AVR_OP_LOAD_EXT_ADDR];
memset(cmd, 0, 4); if(m->op[AVR_OP_LOADPAGE_LO] == NULL || m->op[AVR_OP_LOADPAGE_HI] == NULL) {
avr_set_bits(lext, cmd); avrdude_message(MSG_INFO, "AVR_OP_LOADPAGE_HI/LO command not defined for %s\n", p->desc);
avr_set_addr(lext, cmd, addr_wk/2); return -1;
buf_pos += set_data(pgm, buf+buf_pos, cmd[0]);
buf_pos += set_data(pgm, buf+buf_pos, cmd[1]);
buf_pos += set_data(pgm, buf+buf_pos, cmd[2]);
buf_pos += set_data(pgm, buf+buf_pos, cmd[3]);
} }
buf_pos += set_data(pgm, buf+buf_pos, 0x4C); /* Issue Page Write */
buf_pos += set_data(pgm, buf+buf_pos,(addr_wk >> 9) & 0xff); do_page_write = req_count = i = j = buf_pos = 0;
buf_pos += set_data(pgm, buf+buf_pos,(addr_wk >> 1) & 0xff); addr_save = addr;
buf_pos += set_data(pgm, buf+buf_pos, 0); while(i < (int) n_bytes) {
} int spi = addr&1? AVR_OP_LOADPAGE_HI: AVR_OP_LOADPAGE_LO;
#endif
// put the SPI loadpage command as FT245R_CMD_SIZE bytes into buffer
memset(cmd, 0, sizeof cmd);
avr_set_bits(m->op[spi], cmd);
avr_set_addr(m->op[spi], cmd, addr/2);
avr_set_input(m->op[spi], cmd, m->buf[addr]);
for(int k=0; k<sizeof cmd; k++)
buf_pos += set_data(pgm, buf+buf_pos, cmd[k]);
i++; j++; addr++;
if(m->paged && (i%m->page_size == 0 || i >= (int) n_bytes))
do_page_write = 1;
// page boundary, finished or buffer exhausted? queue up requests
if(do_page_write || i >= (int) n_bytes || j >= FT245R_FRAGMENT_SIZE/FT245R_CMD_SIZE) {
if(i >= n_bytes) { if(i >= n_bytes) {
ft245r_out = SET_BITS_0(ft245r_out,pgm,PIN_AVR_SCK,0); // sck down ft245r_out = SET_BITS_0(ft245r_out, pgm, PIN_AVR_SCK, 0); // SCK down
buf[buf_pos++] = ft245r_out; buf[buf_pos++] = ft245r_out;
} } else {
else { // stretch sequence to allow correct readout, see extract_data()
/* stretch sequence to allow correct readout, see extract_data() */
buf[buf_pos] = buf[buf_pos - 1]; buf[buf_pos] = buf[buf_pos - 1];
buf_pos++; buf_pos++;
} }
ft245r_send(pgm, buf, buf_pos); ft245r_send(pgm, buf, buf_pos);
put_request(addr_save, buf_pos, 0); put_request(addr_save, buf_pos, 0);
//ft245r_sync(pgm);
#if 0 if(++req_count > REQ_OUTSTANDINGS)
avrdude_message(MSG_INFO, "send addr 0x%04x bufsize %d [%02x %02x] page_write %d\n",
addr_save,buf_pos,
extract_data_out(pgm, buf , (0*4 + 3) ),
extract_data_out(pgm, buf , (1*4 + 3) ),
do_page_write);
#endif
req_count++;
if (req_count > REQ_OUTSTANDINGS)
do_request(pgm, m); do_request(pgm, m);
if(do_page_write) { if(do_page_write) {
#if defined(USE_INLINE_WRITE_PAGE)
while(do_request(pgm, m)) while(do_request(pgm, m))
; continue;
ft245r_usleep(pgm, m->max_write_delay); if(avr_write_page(pgm, p, m, addr_save - (addr_save % m->page_size)) != 0)
#else
int addr_wk = addr_save - (addr_save % m->page_size);
int rc;
while (do_request(pgm, m))
;
rc = avr_write_page(pgm, p, m, addr_wk);
if (rc != 0) {
return -2; return -2;
do_page_write = req_count = 0;
} }
#endif
req_count = 0; // reset buffer variables
j = buf_pos = 0;
addr_save = addr;
} }
} }
while(do_request(pgm, m)) while(do_request(pgm, m))
; continue;
return i;
return n_bytes;
} }
static int ft245r_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, static int ft245r_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
unsigned int page_size, unsigned int addr, unsigned int n_bytes) { unsigned int page_size, unsigned int addr, unsigned int n_bytes) {
if (strcmp(m->desc, "flash") == 0) {
if(!n_bytes)
return 0;
if(strcmp(m->desc, "flash") == 0)
return ft245r_paged_write_flash(pgm, p, m, page_size, addr, n_bytes); return ft245r_paged_write_flash(pgm, p, m, page_size, addr, n_bytes);
} else if (strcmp(m->desc, "eeprom") == 0) {
if(strcmp(m->desc, "eeprom") == 0)
return ft245r_paged_write_gen(pgm, p, m, page_size, addr, n_bytes); return ft245r_paged_write_gen(pgm, p, m, page_size, addr, n_bytes);
} else {
return -2; return -2;
} }
}
static int ft245r_paged_load_gen(PROGRAMMER *pgm, AVRPART *p, AVRMEM *m, static int ft245r_paged_load_gen(PROGRAMMER *pgm, AVRPART *p, AVRMEM *m,
unsigned int page_size, unsigned int addr, unsigned int page_size, unsigned int addr, unsigned int n_bytes) {
int n_bytes) {
unsigned char rbyte;
unsigned long i;
int rc;
for (i=0; i<n_bytes; i++) { for(int i=0; i < (int) n_bytes; i++) {
rc = avr_read_byte_default(pgm, p, m, i+addr, &rbyte); unsigned char rbyte;
if (rc != 0) {
if(avr_read_byte_default(pgm, p, m, addr+i, &rbyte) != 0)
return -2; return -2;
m->buf[addr+i] = rbyte;
} }
m->buf[i+addr] = rbyte;
}
return 0; return 0;
} }
static int ft245r_paged_load_flash(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
unsigned int page_size, unsigned int addr,
unsigned int n_bytes) {
unsigned long i,j,n;
int addr_save,buf_pos;
int req_count = 0;
unsigned char buf[FT245R_FRAGMENT_SIZE+1];
for (i=0; i<n_bytes; ) { static int ft245r_paged_load_flash(PROGRAMMER *pgm, AVRPART *p, AVRMEM *m,
unsigned int page_size, unsigned int addr, unsigned int n_bytes) {
int i, j, addr_save, buf_pos, req_count;
unsigned char buf[FT245R_FRAGMENT_SIZE+1];
unsigned char cmd[4];
if(m->op[AVR_OP_READ_LO] == NULL || m->op[AVR_OP_READ_HI] == NULL) {
avrdude_message(MSG_INFO, "AVR_OP_READ_HI/LO command not defined for %s\n", p->desc);
return -1;
}
// always called with addr at page boundary, and n_bytes == m->page_size;
// hence, OK to prepend load extended address command (at most) once
if(m->op[AVR_OP_LOAD_EXT_ADDR]) {
memset(cmd, 0, sizeof cmd);
avr_set_bits(m->op[AVR_OP_LOAD_EXT_ADDR], cmd);
avr_set_addr(m->op[AVR_OP_LOAD_EXT_ADDR], cmd, addr/2);
buf_pos = 0; buf_pos = 0;
for(int k=0; k<sizeof cmd; k++)
buf_pos += set_data(pgm, buf+buf_pos, cmd[k]);
ft245r_send_and_discard(pgm, buf, buf_pos);
}
req_count = i = j = buf_pos = 0;
addr_save = addr; addr_save = addr;
for (j=0; j< FT245R_FRAGMENT_SIZE/8/FT245R_CYCLES/4; j++) { while(i < (int) n_bytes) {
if (i >= n_bytes) break; int spi = addr&1? AVR_OP_READ_HI: AVR_OP_READ_LO;
buf_pos += set_data(pgm, buf+buf_pos, (addr & 1)?0x28:0x20 );
buf_pos += set_data(pgm, buf+buf_pos, (addr >> 9) & 0xff ); // put the SPI read command as FT245R_CMD_SIZE bytes into buffer
buf_pos += set_data(pgm, buf+buf_pos, (addr >> 1) & 0xff ); memset(cmd, 0, sizeof cmd);
buf_pos += set_data(pgm, buf+buf_pos, 0); avr_set_bits(m->op[spi], cmd);
addr ++; avr_set_addr(m->op[spi], cmd, addr/2);
i++; for(int k=0; k<sizeof cmd; k++)
} buf_pos += set_data(pgm, buf+buf_pos, cmd[k]);
if (i >= n_bytes) {
ft245r_out = SET_BITS_0(ft245r_out,pgm,PIN_AVR_SCK,0); // sck down i++; j++; addr++;
// finished or buffer exhausted? queue up requests
if(i >= (int) n_bytes || j >= FT245R_FRAGMENT_SIZE/FT245R_CMD_SIZE) {
if(i >= (int) n_bytes) {
ft245r_out = SET_BITS_0(ft245r_out, pgm, PIN_AVR_SCK, 0); // SCK down
buf[buf_pos++] = ft245r_out; buf[buf_pos++] = ft245r_out;
} } else {
else { // stretch sequence to allow correct readout, see extract_data()
/* stretch sequence to allow correct readout, see extract_data() */
buf[buf_pos] = buf[buf_pos - 1]; buf[buf_pos] = buf[buf_pos - 1];
buf_pos++; buf_pos++;
} }
n = j;
ft245r_send(pgm, buf, buf_pos); ft245r_send(pgm, buf, buf_pos);
put_request(addr_save, buf_pos, n); put_request(addr_save, buf_pos, j);
req_count++;
if (req_count > REQ_OUTSTANDINGS) if(++req_count > REQ_OUTSTANDINGS)
do_request(pgm, m); do_request(pgm, m);
// reset buffer variables
j = buf_pos = 0;
addr_save = addr;
} }
}
while(do_request(pgm, m)) while(do_request(pgm, m))
; continue;
return 0; return 0;
} }
static int ft245r_paged_load(PROGRAMMER *pgm, AVRPART *p, AVRMEM *m, static int ft245r_paged_load(PROGRAMMER *pgm, AVRPART *p, AVRMEM *m,
unsigned int page_size, unsigned int addr, unsigned int page_size, unsigned int addr, unsigned int n_bytes) {
unsigned int n_bytes) {
if (strcmp(m->desc, "flash") == 0) { if(!n_bytes)
return 0;
if(strcmp(m->desc, "flash") == 0)
return ft245r_paged_load_flash(pgm, p, m, page_size, addr, n_bytes); return ft245r_paged_load_flash(pgm, p, m, page_size, addr, n_bytes);
} else if (strcmp(m->desc, "eeprom") == 0) {
if(strcmp(m->desc, "eeprom") == 0)
return ft245r_paged_load_gen(pgm, p, m, page_size, addr, n_bytes); return ft245r_paged_load_gen(pgm, p, m, page_size, addr, n_bytes);
} else {
return -2; return -2;
} }
}
void ft245r_initpgm(PROGRAMMER * pgm) { void ft245r_initpgm(PROGRAMMER * pgm) {
strcpy(pgm->type, "ftdi_syncbb"); strcpy(pgm->type, "ftdi_syncbb");