int avr_read_byte_default(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem, unsigned long addr, unsigned char * value) { unsigned char cmd[4]; unsigned char res[4]; unsigned char data; OPCODE * readop, * lext; if (pgm->cmd == NULL) { logprintf(LOG_ERR, "%s programmer uses avr_read_byte_default() but does not provide a cmd() method", pgm->type); return -1; } /* * figure out what opcode to use */ if (mem->op[AVR_OP_READ_LO]) { if (addr & 0x00000001) readop = mem->op[AVR_OP_READ_HI]; else readop = mem->op[AVR_OP_READ_LO]; addr = addr / 2; } else { readop = mem->op[AVR_OP_READ]; } if (readop == NULL) { return -1; } /* * If this device has a "load extended address" command, issue it. */ lext = mem->op[AVR_OP_LOAD_EXT_ADDR]; if (lext != NULL) { memset(cmd, 0, sizeof(cmd)); avr_set_bits(lext, cmd); avr_set_addr(lext, cmd, addr); pgm->cmd(pgm, cmd, res); } memset(cmd, 0, sizeof(cmd)); avr_set_bits(readop, cmd); avr_set_addr(readop, cmd, addr); pgm->cmd(pgm, cmd, res); data = 0; avr_get_output(readop, res, &data); *value = data; return 0; }
/* * write a page data at the specified address */ int avr_write_page(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem, unsigned long addr) { unsigned char cmd[4]; unsigned char res[4]; OPCODE * wp, * lext; if (pgm->cmd == NULL) { logprintf(LOG_ERR, "%s programmer uses avr_write_page() but does not provide a cmd() method", pgm->type); return -1; } wp = mem->op[AVR_OP_WRITEPAGE]; if (wp == NULL) { logprintf(LOG_ERR, "avr_write_page(): memory \"%s\" not configured for page writes", mem->desc); return -1; } /* * if this memory is word-addressable, adjust the address * accordingly */ if ((mem->op[AVR_OP_LOADPAGE_LO]) || (mem->op[AVR_OP_READ_LO])) addr = addr / 2; /* * If this device has a "load extended address" command, issue it. */ lext = mem->op[AVR_OP_LOAD_EXT_ADDR]; if (lext != NULL) { memset(cmd, 0, sizeof(cmd)); avr_set_bits(lext, cmd); avr_set_addr(lext, cmd, addr); pgm->cmd(pgm, cmd, res); } memset(cmd, 0, sizeof(cmd)); avr_set_bits(wp, cmd); avr_set_addr(wp, cmd, addr); pgm->cmd(pgm, cmd, res); /* * since we don't know what voltage the target AVR is powered by, be * conservative and delay the max amount the spec says to wait */ usleep(mem->max_write_delay); return 0; }
static int pickit2_commit_page(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem, unsigned long addr) { OPCODE * wp, * lext; wp = mem->op[AVR_OP_WRITEPAGE]; if (wp == NULL) { avrdude_message(MSG_INFO, "pickit2_commit_page(): memory \"%s\" not configured for page writes\n", mem->desc); return -1; } // adjust the address if this memory is word-addressable if ((mem->op[AVR_OP_LOADPAGE_LO]) || (mem->op[AVR_OP_READ_LO])) addr /= 2; unsigned char cmd[8]; memset(cmd, 0, sizeof(cmd)); // use the "load extended address" command, if available lext = mem->op[AVR_OP_LOAD_EXT_ADDR]; if (lext != NULL) { avr_set_bits(lext, cmd); avr_set_addr(lext, cmd, addr); } // make up the write page command in the 2nd cmd position avr_set_bits(wp, &cmd[4]); avr_set_addr(wp, &cmd[4], addr); if (lext != NULL) { // write the load extended address cmd && the write_page cmd pgm->spi(pgm, cmd, NULL, 8); } else { // write just the write_page cmd pgm->spi(pgm, &cmd[4], NULL, 4); } // just delay the max (we could do the delay in the PICkit2 if we wanted) usleep(mem->max_write_delay); return 0; }
/* Paged write function which utilizes the Bus Pirate's "Write then Read" binary SPI instruction */ static int buspirate_paged_write(struct programmer_t *pgm, AVRPART *p, AVRMEM *m, unsigned int page_size, unsigned int base_addr, unsigned int n_data_bytes) { int page, i; int addr = base_addr; int n_page_writes; int this_page_size; char cmd_buf[4096] = {'\0'}; char send_byte, recv_byte; if (!(pgm->flag & BP_FLAG_IN_BINMODE)) { /* Return if we are not in binary mode. */ return -1; } if (pgm->flag & BP_FLAG_NOPAGEDWRITE) { /* Return if we've nominated not to use paged writes. */ return -1; } if (page_size>1024) { /* Page sizes greater than 1kB not yet supported. */ return -1; } if (strcmp(m->desc,"flash") != 0) { /* Only flash memory currently supported. */ return -1; } /* pre-check opcodes */ if (m->op[AVR_OP_LOADPAGE_LO] == NULL) { fprintf(stderr, "%s failure: %s command not defined for %s\n", progname, "AVR_OP_LOADPAGE_LO", p->desc); return -1; } if (m->op[AVR_OP_LOADPAGE_HI] == NULL) { fprintf(stderr, "%s failure: %s command not defined for %s\n", progname, "AVR_OP_LOADPAGE_HI", p->desc); return -1; } /* Calculate total number of page writes needed: */ n_page_writes = n_data_bytes/page_size; if (n_data_bytes%page_size >0) n_page_writes++; /* Ensure error LED is off: */ pgm->err_led(pgm, OFF); /* Loop over pages: */ for (page=0; page<n_page_writes; page++) { /* Determine bytes to write in this page: */ this_page_size = page_size; if (page == n_page_writes-1) this_page_size = n_data_bytes - page_size*page; /* Set up command buffer: */ memset(cmd_buf, 0, 4*this_page_size); for (i=0; i<this_page_size; i++) { addr = base_addr + page*page_size + i; if (i%2 == 0) { avr_set_bits(m->op[AVR_OP_LOADPAGE_LO], &(cmd_buf[4*i])); avr_set_addr(m->op[AVR_OP_LOADPAGE_LO], &(cmd_buf[4*i]), addr/2); avr_set_input(m->op[AVR_OP_LOADPAGE_LO], &(cmd_buf[4*i]), m->buf[addr]); } else { avr_set_bits(m->op[AVR_OP_LOADPAGE_HI], &(cmd_buf[4*i])); avr_set_addr(m->op[AVR_OP_LOADPAGE_HI], &(cmd_buf[4*i]), addr/2); avr_set_input(m->op[AVR_OP_LOADPAGE_HI], &(cmd_buf[4*i]), m->buf[addr]); } } /* 00000100 - Write then read */ send_byte = 0x05; buspirate_send_bin(pgm, &send_byte, 1); /* Number of bytes to write: */ send_byte = (4*this_page_size)/0x100; buspirate_send_bin(pgm, &send_byte, 1); /* High byte */ send_byte = (4*this_page_size)%0x100; buspirate_send_bin(pgm, &send_byte, 1); /* Low byte */ /* Number of bytes to read: */ send_byte = 0x0; buspirate_send_bin(pgm, &send_byte, 1); /* High byte */ buspirate_send_bin(pgm, &send_byte, 1); /* Low byte */ /* Set programming LED: */ pgm->pgm_led(pgm, ON); /* Send command buffer: */ buspirate_send_bin(pgm, cmd_buf, 4*this_page_size); /* Check for write failure: */ if ((buspirate_recv_bin(pgm, &recv_byte, 1) == EOF) || (recv_byte != 0x01)) { fprintf(stderr, "BusPirate: Fatal error: Write Then Read did not succeed.\n"); pgm->pgm_led(pgm, OFF); pgm->err_led(pgm, ON); exit(1); } /* Unset programming LED: */ pgm->pgm_led(pgm, OFF); /* Write loaded page to flash: */ avr_write_page(pgm, p, m, addr); } return n_data_bytes; }
static int ft245r_paged_write_flash(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, int page_size, int n_bytes) { unsigned int i,j; int addr,addr_save,buf_pos,do_page_write,req_count; char buf[FT245R_FRAGMENT_SIZE+1+128]; req_count = 0; addr = 0; for (i=0; i<n_bytes; ) { 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(buf+buf_pos, (addr & 1)?0x48:0x40 ); buf_pos += set_data(buf+buf_pos, (addr >> 9) & 0xff ); buf_pos += set_data(buf+buf_pos, (addr >> 1) & 0xff ); buf_pos += set_data(buf+buf_pos, m->buf[i]); 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]; OPCODE *lext = m->op[AVR_OP_LOAD_EXT_ADDR]; memset(cmd, 0, 4); avr_set_bits(lext, cmd); avr_set_addr(lext, cmd, addr_wk/2); buf_pos += set_data(buf+buf_pos, cmd[0]); buf_pos += set_data(buf+buf_pos, cmd[1]); buf_pos += set_data(buf+buf_pos, cmd[2]); buf_pos += set_data(buf+buf_pos, cmd[3]); } buf_pos += set_data(buf+buf_pos, 0x4C); /* Issue Page Write */ buf_pos += set_data(buf+buf_pos,(addr_wk >> 9) & 0xff); buf_pos += set_data(buf+buf_pos,(addr_wk >> 1) & 0xff); buf_pos += set_data(buf+buf_pos, 0); } #endif if (i >= n_bytes) { buf[buf_pos++] = 0; // sck down } ft245r_send(pgm, buf, buf_pos); put_request(addr_save, buf_pos, 0); //ft245r_sync(pgm); #if 0 fprintf(stderr, "send addr 0x%04x bufsize %d [%02x %02x] page_write %d\n", addr_save,buf_pos, extract_data_out(buf , (0*4 + 3) ), extract_data_out(buf , (1*4 + 3) ), do_page_write); #endif req_count++; if (req_count > REQ_OUTSTANDINGS) do_request(pgm, m); if (do_page_write) { #if defined(USE_INLINE_WRITE_PAGE) while (do_request(pgm, m)) ; usleep(m->max_write_delay); #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; } #endif req_count = 0; } report_progress(i, n_bytes, NULL); } while (do_request(pgm, m)) ; return i; }
// not actually a paged write, but a bulk/batch write static int pickit2_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem, unsigned int page_size, unsigned int addr, unsigned int n_bytes) { // only paged write for flash implemented if (strcmp(mem->desc, "flash") != 0 && strcmp(mem->desc, "eeprom") != 0) { avrdude_message(MSG_INFO, "Part does not support %d paged write of %s\n", page_size, mem->desc); return -1; } DEBUG( "page size %d mem %s supported: %d\n", page_size, mem->desc, mem->paged); DEBUG( "loadpagehi %x, loadpagelow %x, writepage %x\n", (int)mem->op[AVR_OP_LOADPAGE_HI], (int)mem->op[AVR_OP_LOADPAGE_LO], (int)mem->op[AVR_OP_WRITEPAGE]); OPCODE *writeop; uint8_t cmd[SPI_MAX_CHUNK], res[SPI_MAX_CHUNK]; unsigned int addr_base; unsigned int max_addr = addr + n_bytes; pgm->pgm_led(pgm, ON); for (addr_base = addr; addr_base < max_addr; ) { uint32_t blockSize; if (mem->paged) { blockSize = MIN(page_size - (addr_base % page_size), MIN(max_addr - addr_base, SPI_MAX_CHUNK/4) ); // bytes remaining in page } else { blockSize = 1; } memset(cmd, 0, sizeof(cmd)); memset(res, 0, sizeof(res)); uint8_t addr_off; for (addr_off = 0; addr_off < blockSize; addr_off++) { int addr = addr_base + addr_off; int caddr = 0; /* * determine which memory opcode to use */ if (mem->paged && mem->op[AVR_OP_LOADPAGE_HI] && mem->op[AVR_OP_LOADPAGE_LO]) { if (addr & 0x01) writeop = mem->op[AVR_OP_LOADPAGE_HI]; else writeop = mem->op[AVR_OP_LOADPAGE_LO]; caddr = addr / 2; } else if (mem->paged && mem->op[AVR_OP_LOADPAGE_LO]) { writeop = mem->op[AVR_OP_LOADPAGE_LO]; caddr = addr; } else if (mem->op[AVR_OP_WRITE_LO]) { writeop = mem->op[AVR_OP_WRITE_LO]; caddr = addr; // maybe this should divide by 2 & use the write_high opcode also avrdude_message(MSG_INFO, "Error AVR_OP_WRITE_LO defined only (where's the HIGH command?)\n"); return -1; } else { writeop = mem->op[AVR_OP_WRITE]; caddr = addr; } if (writeop == NULL) { pgm->err_led(pgm, ON); // not supported! return -1; } avr_set_bits(writeop, &cmd[addr_off*4]); avr_set_addr(writeop, &cmd[addr_off*4], caddr); avr_set_input(writeop, &cmd[addr_off*4], mem->buf[addr]); } int bytes_read = pgm->spi(pgm, cmd, res, blockSize*4); if (bytes_read < 0) { avrdude_message(MSG_INFO, "Failed @ pgm->spi()\n"); pgm->err_led(pgm, ON); return -1; } addr_base += blockSize; // write the page - this function looks after extended address also if (mem->paged && (((addr_base % page_size) == 0) || (addr_base == max_addr))) { DEBUG( "Calling pickit2_commit_page()\n"); pickit2_commit_page(pgm, p, mem, addr_base-1); } else if (!mem->paged) { usleep(mem->max_write_delay); } } pgm->pgm_led(pgm, OFF); return n_bytes; }
static int pickit2_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem, unsigned int page_size, unsigned int addr, unsigned int n_bytes) { // only supporting flash & eeprom page reads if ((!mem->paged || page_size <= 1) || (strcmp(mem->desc, "flash") != 0 && strcmp(mem->desc, "eeprom") != 0)) { return -1; } DEBUG( "paged read ps %d, mem %s\n", page_size, mem->desc); OPCODE *readop = 0, *lext = mem->op[AVR_OP_LOAD_EXT_ADDR]; uint8_t data = 0, cmd[SPI_MAX_CHUNK], res[SPI_MAX_CHUNK]; unsigned int addr_base; unsigned int max_addr = addr + n_bytes; pgm->pgm_led(pgm, ON); for (addr_base = addr; addr_base < max_addr; ) { if ((addr_base == 0 || (addr_base % /*ext_address_boundary*/ 65536) == 0) && lext != NULL) { memset(cmd, 0, sizeof(cmd)); avr_set_bits(lext, cmd); avr_set_addr(lext, cmd, addr_base); pgm->cmd(pgm, cmd, res); } // bytes to send in the next packet -- not necessary as pickit2_spi() handles breaking up // the data into packets -- but we need to keep transfers frequent so that we can update the // status indicator bar uint32_t blockSize = MIN(65536 - (addr_base % 65536), MIN(max_addr - addr_base, SPI_MAX_CHUNK / 4)); memset(cmd, 0, sizeof(cmd)); memset(res, 0, sizeof(res)); uint8_t addr_off; for (addr_off = 0; addr_off < blockSize; addr_off++) { int addr = addr_base + addr_off, caddr = addr; if (mem->op[AVR_OP_READ_LO] != NULL && mem->op[AVR_OP_READ_HI] != NULL) { if (addr & 0x00000001) readop = mem->op[AVR_OP_READ_HI]; else readop = mem->op[AVR_OP_READ_LO]; caddr /= 2; } else if (mem->op[AVR_OP_READ] != NULL) { readop = mem->op[AVR_OP_READ]; } else { avrdude_message(MSG_INFO, "no read command specified\n"); return -1; } avr_set_bits(readop, &cmd[addr_off*4]); avr_set_addr(readop, &cmd[addr_off*4], caddr); } int bytes_read = pgm->spi(pgm, cmd, res, blockSize*4); if (bytes_read < 0) { avrdude_message(MSG_INFO, "Failed @ pgm->spi()\n"); pgm->err_led(pgm, ON); return -1; } DEBUG( "\npaged_load @ %X, wrote: %d, read: %d bytes\n", addr_base, blockSize*4, bytes_read); for (addr_off = 0; addr_off < bytes_read / 4; addr_off++) { data = 0; avr_get_output(readop, &res[addr_off*4], &data); mem->buf[addr_base + addr_off] = data; DEBUG( "%2X(%c)", (int)data, data<0x20?'.':data); } DEBUG( "\n"); addr_base += blockSize; } pgm->pgm_led(pgm, OFF); return n_bytes; }
int avr_write_byte_default(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem, unsigned long addr, unsigned char data) { unsigned char cmd[4]; unsigned char res[4]; unsigned char r; int ready; int tries; unsigned long start_time; unsigned long prog_time; unsigned char b; unsigned short caddr; OPCODE * writeop; int rc; int readok=0; struct timeval tv; if (pgm->cmd == NULL) { logprintf(LOG_ERR, "%s programmer uses avr_write_byte_default() but does not provide a cmd() method.", pgm->type); return -1; } if (!mem->paged) { /* * check to see if the write is necessary by reading the existing * value and only write if we are changing the value; we can't * use this optimization for paged addressing. */ rc = pgm->read_byte(pgm, p, mem, addr, &b); if (rc != 0) { if (rc != -1) { return -2; } /* * the read operation is not support on this memory type */ } else { readok = 1; if (b == data) { return 0; } } } /* * determine which memory opcode to use */ if (mem->op[AVR_OP_WRITE_LO]) { if (addr & 0x01) writeop = mem->op[AVR_OP_WRITE_HI]; else writeop = mem->op[AVR_OP_WRITE_LO]; caddr = addr / 2; } else if (mem->paged && mem->op[AVR_OP_LOADPAGE_LO]) { if (addr & 0x01) writeop = mem->op[AVR_OP_LOADPAGE_HI]; else writeop = mem->op[AVR_OP_LOADPAGE_LO]; caddr = addr / 2; } else { writeop = mem->op[AVR_OP_WRITE]; caddr = addr; } if (writeop == NULL) { return -1; } memset(cmd, 0, sizeof(cmd)); avr_set_bits(writeop, cmd); avr_set_addr(writeop, cmd, caddr); avr_set_input(writeop, cmd, data); pgm->cmd(pgm, cmd, res); if (mem->paged) { /* * in paged addressing, single bytes to be written to the memory * page complete immediately, we only need to delay when we commit * the whole page via the avr_write_page() routine. */ return 0; } if (readok == 0) { /* * read operation not supported for this memory type, just wait * the max programming time and then return */ usleep(mem->max_write_delay); /* maximum write delay */ return 0; } tries = 0; ready = 0; while (!ready) { if ((data == mem->readback[0]) || (data == mem->readback[1])) { /* * use an extra long delay when we happen to be writing values * used for polled data read-back. In this case, polling * doesn't work, and we need to delay the worst case write time * specified for the chip. */ usleep(mem->max_write_delay); rc = pgm->read_byte(pgm, p, mem, addr, &r); if (rc != 0) { return -5; } } else { gettimeofday (&tv, NULL); start_time = (tv.tv_sec * 1000000) + tv.tv_usec; do { /* * Do polling, but timeout after max_write_delay. */ rc = pgm->read_byte(pgm, p, mem, addr, &r); if (rc != 0) { return -4; } gettimeofday (&tv, NULL); prog_time = (tv.tv_sec * 1000000) + tv.tv_usec; } while ((r != data) && ((prog_time-start_time) < mem->max_write_delay)); } /* * At this point we either have a valid readback or the * max_write_delay is expired. */ if (r == data) { ready = 1; } else if (mem->pwroff_after_write) { /* * The device has been flagged as power-off after write to this * memory type. The reason we don't just blindly follow the * flag is that the power-off advice may only apply to some * memory bits but not all. We only actually power-off the * device if the data read back does not match what we wrote. */ logprintf(LOG_INFO, "this device must be powered off and back on to continue"); if (pgm->pinno[PPI_AVR_VCC]) { logprintf(LOG_INFO, "attempting to do this now ..."); pgm->powerdown(pgm); usleep(250000); rc = pgm->initialize(pgm, p); if (rc < 0) { logprintf(LOG_ERR, "initialization failed, rc=%d", rc); logprintf(LOG_ERR, "can't re-initialize device after programming the %s bits", mem->desc); return -3; } logprintf(LOG_INFO, "device was successfully re-initialized"); return 0; } } tries++; if (!ready && tries > 5) { /* * we wrote the data, but after waiting for what should have * been plenty of time, the memory cell still doesn't match what * we wrote. Indicate a write error. */ return -6; } } return 0; }