📄 avr.c
字号:
/* * avrdude - A Downloader/Uploader for AVR device programmers * Copyright (C) 2000, 2001, 2002, 2003 Brian S. Dean <bsd@bsdhome.com> * * 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 * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *//* $Id: avr.c,v 1.52 2003/03/05 04:30:20 bdean Exp $ */#include "ac_cfg.h"#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include "avr.h"#include "config.h"#include "lists.h"#include "pindefs.h"#include "ppi.h"#define DEBUG 0extern char * progname;extern char progbuf[];extern PROGRAMMER * pgm;extern int do_cycles;AVRPART * avr_new_part(void){ AVRPART * p; p = (AVRPART *)malloc(sizeof(AVRPART)); if (p == NULL) { fprintf(stderr, "new_part(): out of memory\n"); exit(1); } memset(p, 0, sizeof(*p)); p->id[0] = 0; p->desc[0] = 0; p->reset_disposition = RESET_DEDICATED; p->retry_pulse = PIN_AVR_SCK; p->flags = AVRPART_SERIALOK | AVRPART_PARALLELOK; p->config_file[0] = 0; p->lineno = 0; p->mem = lcreat(NULL, 0); return p;}OPCODE * avr_new_opcode(void){ OPCODE * m; m = (OPCODE *)malloc(sizeof(*m)); if (m == NULL) { fprintf(stderr, "avr_new_opcode(): out of memory\n"); exit(1); } memset(m, 0, sizeof(*m)); return m;}AVRMEM * avr_new_memtype(void){ AVRMEM * m; m = (AVRMEM *)malloc(sizeof(*m)); if (m == NULL) { fprintf(stderr, "avr_new_memtype(): out of memory\n"); exit(1); } memset(m, 0, sizeof(*m)); return m;}AVRMEM * avr_dup_mem(AVRMEM * m){ AVRMEM * n; n = avr_new_memtype(); *n = *m; n->buf = (unsigned char *)malloc(n->size); if (n->buf == NULL) { fprintf(stderr, "avr_dup_mem(): out of memory (memsize=%d)\n", n->size); exit(1); } memset(n->buf, 0, n->size); return n;}AVRPART * avr_dup_part(AVRPART * d){ AVRPART * p; LISTID save; LNODEID ln; p = avr_new_part(); save = p->mem; *p = *d; p->mem = save; for (ln=lfirst(d->mem); ln; ln=lnext(ln)) { ladd(p->mem, avr_dup_mem(ldata(ln))); } return p;}AVRMEM * avr_locate_mem(AVRPART * p, char * desc){ AVRMEM * m, * match; LNODEID ln; int matches; int l; l = strlen(desc); matches = 0; match = NULL; for (ln=lfirst(p->mem); ln; ln=lnext(ln)) { m = ldata(ln); if (strncmp(desc, m->desc, l) == 0) { match = m; matches++; } } if (matches == 1) return match; return NULL;}/* * avr_set_bits() * * Set instruction bits in the specified command based on the opcode. */int avr_set_bits(OPCODE * op, unsigned char * cmd){ int i, j, bit; unsigned char mask; for (i=0; i<32; i++) { if (op->bit[i].type == AVR_CMDBIT_VALUE) { j = 3 - i / 8; bit = i % 8; mask = 1 << bit; if (op->bit[i].value) cmd[j] = cmd[j] | mask; else cmd[j] = cmd[j] & ~mask; } } return 0;}/* * avr_set_addr() * * Set address bits in the specified command based on the opcode, and * the address. */int avr_set_addr(OPCODE * op, unsigned char * cmd, unsigned long addr){ int i, j, bit; unsigned long value; unsigned char mask; for (i=0; i<32; i++) { if (op->bit[i].type == AVR_CMDBIT_ADDRESS) { j = 3 - i / 8; bit = i % 8; mask = 1 << bit; value = addr >> op->bit[i].bitno & 0x01; if (value) cmd[j] = cmd[j] | mask; else cmd[j] = cmd[j] & ~mask; } } return 0;}/* * avr_set_input() * * Set input data bits in the specified command based on the opcode, * and the data byte. */int avr_set_input(OPCODE * op, unsigned char * cmd, unsigned char data){ int i, j, bit; unsigned char value; unsigned char mask; for (i=0; i<32; i++) { if (op->bit[i].type == AVR_CMDBIT_INPUT) { j = 3 - i / 8; bit = i % 8; mask = 1 << bit; value = data >> op->bit[i].bitno & 0x01; if (value) cmd[j] = cmd[j] | mask; else cmd[j] = cmd[j] & ~mask; } } return 0;}/* * avr_get_output() * * Retreive output data bits from the command results based on the * opcode data. */int avr_get_output(OPCODE * op, unsigned char * res, unsigned char * data){ int i, j, bit; unsigned char value; unsigned char mask; for (i=0; i<32; i++) { if (op->bit[i].type == AVR_CMDBIT_OUTPUT) { j = 3 - i / 8; bit = i % 8; mask = 1 << bit; value = ((res[j] & mask) >> bit) & 0x01; value = value << op->bit[i].bitno; if (value) *data = *data | value; else *data = *data & ~value; } } return 0;}/* * read a byte of data from the indicated memory region */int avr_read_byte(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; pgm->pgm_led(pgm, ON); pgm->err_led(pgm, OFF); /* * 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) {#if DEBUG fprintf(stderr, "avr_read_byte(): operation not supported on memory type \"%s\"\n", p->desc);#endif return -1; } 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); pgm->pgm_led(pgm, OFF); *value = data; return 0;}/* * Read the entirety of the specified memory type into the * corresponding buffer of the avrpart pointed to by 'p'. If size = * 0, read the entire contents, otherwise, read 'size' bytes. * * Return the number of bytes read, or < 0 if an error occurs. */int avr_read(PROGRAMMER * pgm, AVRPART * p, char * memtype, int size, int verbose){ unsigned char rbyte; unsigned long i; unsigned char * buf; AVRMEM * mem; int rc; int printed; mem = avr_locate_mem(p, memtype); if (mem == NULL) { fprintf(stderr, "No \"%s\" memory for part %s\n", memtype, p->desc); return -1; } buf = mem->buf; if (size == 0) { size = mem->size; } if ((strcmp(mem->desc, "flash")==0) || (strcmp(mem->desc, "eeprom")==0)) { if (pgm->paged_load != NULL) { /* * the programmer supports a paged mode read, perhaps more * efficiently than we can read it directly, so use its routine * instead */ if (mem->paged) { return pgm->paged_load(pgm, p, mem, mem->page_size, size); } else { return pgm->paged_load(pgm, p, mem, pgm->page_size, size); } } } printed = 0; for (i=0; i<size; i++) { rc = avr_read_byte(pgm, p, mem, i, &rbyte); if (rc != 0) { fprintf(stderr, "avr_read(): error reading address 0x%04lx\n", i); if (rc == -1) fprintf(stderr, " read operation not supported for memory \"%s\"\n", memtype); return -2; } buf[i] = rbyte; if (verbose) { if ((i % 16 == 0)||(i == (size-1))) { printed = 1; fprintf(stderr, "\r \r%6lu", i); } } } if (printed) { fprintf(stderr, "\n"); } return i;}/* * 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; wp = mem->op[AVR_OP_WRITEPAGE]; if (wp == NULL) { fprintf(stderr, "avr_write_page(): memory \"%s\" not configured for page writes\n", 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; pgm->pgm_led(pgm, ON); pgm->err_led(pgm, OFF); 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); pgm->pgm_led(pgm, OFF); return 0;}/* * write a byte of data at the specified address */int avr_write_byte(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 char b; unsigned short caddr; OPCODE * writeop; int rc; int readok=0; 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 = avr_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->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) {#if DEBUG fprintf(stderr, "avr_write_byte(): write not supported for memory type \"%s\"\n", mem->desc);#endif return -1; } pgm->pgm_led(pgm, ON); pgm->err_led(pgm, OFF); 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. */ pgm->pgm_led(pgm, OFF); 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 */ pgm->pgm_led(pgm, OFF); return 0; } tries = 0; ready = 0; while (!ready) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -