From b211c95bfed61b65c20b1720511d66cd826afb78 Mon Sep 17 00:00:00 2001 From: bsd Date: Fri, 19 Jan 2001 02:46:50 +0000 Subject: [PATCH] The program was getting too large for a single file. Split it up into more modular pieces. Also, accept command abbreviations as long as they are not ambiguous. git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk/avrdude@38 81a1dc3b-b13d-400b-aceb-764788c761c2 --- Makefile | 22 +- avr.c | 627 ++++++++++++++ avr.h | 116 +++ avrprog.c | 2461 ----------------------------------------------------- fileio.c | 492 +++++++++++ fileio.h | 64 ++ main.c | 603 +++++++++++++ ppi.c | 224 +++++ ppi.h | 62 ++ term.c | 622 ++++++++++++++ term.h | 39 + 11 files changed, 2865 insertions(+), 2467 deletions(-) create mode 100644 avr.c create mode 100644 avr.h delete mode 100644 avrprog.c create mode 100644 fileio.c create mode 100644 fileio.h create mode 100644 main.c create mode 100644 ppi.c create mode 100644 ppi.h create mode 100644 term.c create mode 100644 term.h diff --git a/Makefile b/Makefile index aabe0623..7045bf6a 100644 --- a/Makefile +++ b/Makefile @@ -2,8 +2,7 @@ # # $Id$ # -# Makefile -# + TARGET = avrprog @@ -12,20 +11,31 @@ BINDIR = ${PREFIX}/bin INSTALL = /usr/bin/install -c -o root -g wheel -CFLAGS += -Wall --pedantic +CFLAGS += -Wall --pedantic + +LDFLAGS = INSTALL_PROGRAM = ${INSTALL} -m 555 -s INSTALL_DATA = ${INSTALL} -m 444 INSTALL_MANUAL = ${INSTALL_DATA} +OBJS = avr.o fileio.o main.o ppi.o term.o +LIBS = -lreadline + all : $(TARGET) -$(TARGET) : avrprog.c - $(CC) $(CFLAGS) -o $(TARGET) $< -lreadline +$(TARGET) : $(OBJS) + $(CC) $(LDFLAGS) -o $(TARGET) $(OBJS) $(LIBS) + +main.o : avr.h fileio.h ppi.h term.h +avr.o : avr.h ppi.h +fileio.o : fileio.h avr.h +ppi.o : ppi.h +term.o : term.h avr.h clean : - rm -f *~ *.core $(TARGET) + rm -f *~ *.core $(TARGET) *.o install : ${BINDIR}/$(TARGET) diff --git a/avr.c b/avr.c new file mode 100644 index 00000000..06cffe4c --- /dev/null +++ b/avr.c @@ -0,0 +1,627 @@ +/* + * Copyright 2000 Brian S. Dean + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BRIAN S. DEAN ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BRIAN S. DEAN BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + */ + +/* $Id$ */ + +#include +#include +#include + + +#include "avr.h" +#include "ppi.h" + + +extern char * progname; +extern char progbuf[]; + + + + +/* Need to add information for 2323, 2343, and 4414 */ + +struct avrpart parts[] = { + { "AT90S1200", "1200", 1024, 64, 0xff, { 0x00, 0xff }, + 9000, 20000, 20000, NULL, NULL }, + + { "AT90S2313", "2313", 2048, 128, 0x7f, { 0x80, 0x7f }, + 9000, 20000, 20000, NULL, NULL }, + + { "AT90S2333", "2333", 2048, 128, 0xff, { 0x00, 0xff }, + 9000, 20000, 20000, NULL, NULL }, + + { "AT90S4433", "4433", 4096, 256, 0xff, { 0x00, 0xff }, + 9000, 20000, 20000, NULL, NULL }, + + { "AT90S4434", "4434", 4096, 256, 0xff, { 0x00, 0xff }, + 9000, 20000, 20000, NULL, NULL }, + + { "AT90S8515", "8515", 8192, 512, 0x7f, { 0x80, 0x7f }, + 9000, 20000, 20000, NULL, NULL }, + + { "AT90S8535", "8535", 8192, 512, 0xff, { 0x00, 0xff }, + 9000, 20000, 20000, NULL, NULL }, +}; + +#define N_AVRPARTS (sizeof(parts)/sizeof(struct avrpart)) + + + + +int avr_list_parts ( FILE * f, char * prefix ) +{ + int i; + + for (i=0; i> (7-i)) & 0x01; + r = avr_txrx_bit ( fd, b ); + rbyte = rbyte | (r << (7-i)); + } + + return rbyte; +} + + +/* + * transmit an AVR device command and return the results; 'cmd' and + * 'res' must point to at least a 4 byte data buffer + */ +int avr_cmd ( int fd, unsigned char cmd[4], unsigned char res[4] ) +{ + int i; + + for (i=0; i<4; i++) { + res[i] = avr_txrx(fd, cmd[i]); + } + + return 0; +} + + +/* + * read a byte of data from the indicated memory region + */ +unsigned char avr_read_byte ( int fd, struct avrpart * p, + AVRMEM memtype, unsigned short addr ) +{ + unsigned char cmd[4]; + unsigned char res[4]; + + switch (memtype) { + case AVR_FLASH_LO: + cmd[0] = 0x20; + break; + case AVR_FLASH_HI: + cmd[0] = 0x28; + break; + case AVR_EEPROM: + cmd[0] = 0xa0; + break; + default: + fprintf(stderr, + "%s: avr_read_byte(); internal error: invalid memtype=%d\n", + progname, memtype); + exit(1); + break; + } + + cmd[1] = addr >> 8; /* high order bits of address */ + cmd[2] = addr & 0x0ff; /* low order bits of address */ + cmd[3] = 0; /* don't care */ + + avr_cmd(fd, cmd, res); + + return res[3]; +} + + +/* + * read the entirety of the specified memory type into the + * corresponding buffer of the avrpart pointed to by 'p'. + */ +int avr_read ( int fd, struct avrpart * p, AVRMEM memtype ) +{ + unsigned char rbyte, memt; + unsigned short n, start, end, i, bi; + unsigned char * buf; + int bufsize; + + start = 0; + + switch (memtype) { + case AVR_FLASH : + memt = AVR_FLASH_LO; + buf = p->flash; + n = p->flash_size/2; + bufsize = p->flash_size; + break; + + case AVR_EEPROM : + memt = memtype; + buf = p->eeprom; + n = p->eeprom_size; + bufsize = p->eeprom_size; + break; + + default: + fprintf(stderr, "%s: avr_read(); internal error: invalid memtype=%d\n", + progname, memtype); + exit(1); + break; + } + + end = start+n; + + bi = 0; + + for (i=start; i> 8; /* high order bits of address */ + cmd[2] = addr & 0x0ff; /* low order bits of address */ + cmd[3] = data; /* data */ + + avr_cmd(fd, cmd, res); + + tries = 0; + ready = 0; + while (!ready) { + usleep(p->min_write_delay); /* typical flash/eeprom write delay */ + r = avr_read_byte(fd, p, memtype, addr); + if ((data == p->f_readback) || + (data == p->e_readback[0]) || (data == p->e_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(p->max_write_delay); + ready = 1; + } + else if (r == data) { + ready = 1; + } + + tries++; + if (!ready && tries > 10) { + /* + * we couldn't write the data, indicate our displeasure by + * returning an error code + */ + return -1; + } + } + + return 0; +} + + +/* + * Write the whole memory region (flash or eeprom, specified by + * 'memtype') from the corresponding buffer of the avrpart pointed to + * by 'p'. All of the memory is updated, however, input data of 0xff + * is not actually written out, because empty flash and eeprom + * contains 0xff, and you can't actually write 1's, only 0's. + */ +int avr_write ( int fd, struct avrpart * p, AVRMEM memtype ) +{ + unsigned char data, memt; + unsigned short start, end, i, bi; + int nl; + int rc; + unsigned char * buf; + int bufsize; + + start = 0; + + switch (memtype) { + case AVR_FLASH : + buf = p->flash; + bufsize = p->flash_size; + end = start+bufsize/2; + memt = AVR_FLASH_LO; + break; + case AVR_EEPROM : + buf = p->eeprom; + bufsize = p->eeprom_size; + end = start+bufsize; + memt = memtype; + break; + default: + fprintf(stderr, "%s: avr_write(); internal error: invalid memtype=%d\n", + progname, memtype); + exit(1); + break; + } + + bi = 0; + + for (i=start; ichip_erase_delay); + avr_initialize(fd, p); + + return 0; +} + + +/* + * read the AVR device's signature bytes + */ +int avr_signature ( int fd, unsigned char sig[4] ) +{ + unsigned char cmd[4] = {0x30, 0x00, 0x00, 0x00}; + unsigned char res[4]; + int i; + + for (i=0; i<4; i++) { + cmd[2] = i; + avr_cmd(fd, cmd, res); + sig[i] = res[3]; + } + + return 0; +} + + +/* + * apply power to the AVR processor + */ +void avr_powerup ( int fd ) +{ + ppi_set(fd, PPIDATA, AVR_POWER); /* power up */ + usleep(100000); +} + + +/* + * remove power from the AVR processor + */ +void avr_powerdown ( int fd ) +{ + ppi_clr(fd, PPIDATA, AVR_POWER); /* power down */ +} + + +/* + * initialize the AVR device and prepare it to accept commands + */ +int avr_initialize ( int fd, struct avrpart * p ) +{ + int rc; + int tries; + + avr_powerup(fd); + + ppi_clr(fd, PPIDATA, AVR_CLOCK); + ppi_clr(fd, PPIDATA, AVR_RESET); + ppi_pulse(fd, PPIDATA, AVR_RESET); + + usleep(20000); /* 20 ms XXX should be a per-chip parameter */ + + /* + * Enable programming mode. If we are programming an AT90S1200, we + * can only issue the command and hope it worked. If we are using + * one of the other chips, the chip will echo 0x53 when issuing the + * third byte of the command. In this case, try up to 32 times in + * order to possibly get back into sync with the chip if we are out + * of sync. + */ + if (strcmp(p->partdesc, "AT90S1200")==0) { + avr_program_enable ( fd ); + } + else { + tries = 0; + do { + rc = avr_program_enable ( fd ); + if (rc == 0) + break; + ppi_pulse(fd, PPIDATA, AVR_CLOCK); + tries++; + } while (tries < 32); + + /* + * can't sync with the device, maybe it's not attached? + */ + if (tries == 32) { + fprintf ( stderr, "%s: AVR device not responding\n", progname ); + return -1; + } + } + + return 0; +} + + + +char * avr_memtstr ( AVRMEM memtype ) +{ + switch (memtype) { + case AVR_EEPROM : return "eeprom"; break; + case AVR_FLASH : return "flash"; break; + default : return "unknown-memtype"; break; + } +} + + + +int avr_initmem ( struct avrpart * p ) +{ + p->flash = (unsigned char *) malloc(p->flash_size); + if (p->flash == NULL) { + fprintf(stderr, "%s: can't alloc buffer for flash size of %d bytes\n", + progname, p->flash_size); + exit(1); + } + + p->eeprom = (unsigned char *) malloc(p->eeprom_size); + if (p->eeprom == NULL) { + fprintf(stderr, "%s: can't alloc buffer for eeprom size of %d bytes\n", + progname, p->eeprom_size); + exit(1); + } + + return 0; +} + + +int avr_verify(struct avrpart * p, struct avrpart * v, AVRMEM memtype) +{ + int i; + unsigned char * buf1, * buf2; + int size; + + switch (memtype) { + case AVR_FLASH: + buf1 = p->flash; + buf2 = v->flash; + size = p->flash_size; + break; + + case AVR_EEPROM: + buf1 = p->eeprom; + buf2 = v->eeprom; + size = p->eeprom_size; + break; + + default: + fprintf(stderr, "%s: invalid memory type = %d for data verification\n", + progname, memtype); + return -1; + } + + for (i=0; ipartdesc, + prefix, p->flash_size, + prefix, p->eeprom_size, + prefix, p->min_write_delay, p->max_write_delay, + prefix, p->chip_erase_delay, + prefix, p->f_readback, + prefix, p->e_readback[0], p->e_readback[1]); +} + diff --git a/avr.h b/avr.h new file mode 100644 index 00000000..a0f06eb1 --- /dev/null +++ b/avr.h @@ -0,0 +1,116 @@ +/* + * Copyright 2000 Brian S. Dean + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BRIAN S. DEAN ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BRIAN S. DEAN BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + */ + +/* $Id$ */ + +#ifndef __avr_h__ +#define __avr_h__ + +#include + +/* + * bit definitions for AVR device connections + */ +#define AVR_POWER 0xf1 /* bit 0 and 4...7 of data register */ +#define AVR_CLOCK 0x02 /* bit 1 of data register */ +#define AVR_INSTR 0x04 /* bit 2 of data register */ +#define AVR_RESET 0x08 /* bit 3 of data register */ +#define AVR_DATA 0x40 /* bit 6 of status register */ + + +/* + * AVR memory designations + */ +typedef enum { + AVR_EEPROM, + AVR_FLASH, + AVR_FLASH_LO, + AVR_FLASH_HI +} AVRMEM; + +struct avrpart { + char * partdesc; /* long part name */ + char * optiontag; /* short part name */ + int flash_size; /* size in bytes of flash */ + int eeprom_size; /* size in bytes of eeprom */ + unsigned char f_readback; /* flash write polled readback value */ + unsigned char e_readback[2]; /* eeprom write polled readback values */ + int min_write_delay; /* microseconds */ + int max_write_delay; /* microseconds */ + int chip_erase_delay; /* microseconds */ + unsigned char * flash; + unsigned char * eeprom; +}; + +extern struct avrpart parts[]; + + + +int avr_list_parts ( FILE * f, char * prefix ); + +struct avrpart * avr_find_part ( char * p ); + +int avr_txrx_bit ( int fd, int bit ); + +unsigned char avr_txrx ( int fd, unsigned char byte ); + +int avr_cmd ( int fd, unsigned char cmd[4], unsigned char res[4] ); + +unsigned char avr_read_byte ( int fd, struct avrpart * p, + AVRMEM memtype, unsigned short addr ); + +int avr_read ( int fd, struct avrpart * p, AVRMEM memtype ); + +int avr_write_byte ( int fd, struct avrpart * p, AVRMEM memtype, + unsigned short addr, unsigned char data ); + +int avr_write ( int fd, struct avrpart * p, AVRMEM memtype ); + +int avr_program_enable ( int fd ); + +int avr_chip_erase ( int fd, struct avrpart * p ); + +int avr_signature ( int fd, unsigned char sig[4] ); + +void avr_powerup ( int fd ); + +void avr_powerdown ( int fd ); + +int avr_initialize ( int fd, struct avrpart * p ); + +char * avr_memtstr ( AVRMEM memtype ); + +int avr_initmem ( struct avrpart * p ); + +int avr_verify(struct avrpart * p, struct avrpart * v, AVRMEM memtype); + +void avr_display ( FILE * f, struct avrpart * p, char * prefix ); + + +#endif diff --git a/avrprog.c b/avrprog.c deleted file mode 100644 index 4113d685..00000000 --- a/avrprog.c +++ /dev/null @@ -1,2461 +0,0 @@ -/* - * Copyright 2000 Brian S. Dean - * All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY BRIAN S. DEAN ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BRIAN S. DEAN BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - */ - -/* $Id$ */ - -/* - * Code to program an Atmel AVR AT90S device using the parallel port. - * - * Make the following connections: - * - * Parallel Port Atmel AVR - * ------------- ---------------------------- - * Pin 2 -> Vcc (see NOTE below) - * Pin 3 -> SCK CLOCK IN - * Pin 4 -> MOSI Instruction input - * Pin 5 -> /RESET - * Pin 6,7,8,9 -> Vcc (Can be tied together with Schottky diodes) - * Pin 10 <- MISO Data out - * Pin 18 <- GND - * - * NOTE on Vcc connection: make sure your parallel port can supply an - * adequate amount of current to power your device. 6-10 mA is - * common for parallel port signal lines, but is not guaranteed, - * especially for notebook computers. Optionally, you can tie pins - * 6, 7, 8, and 9 also to Vcc with Schottky diodes to supply - * additional current. If in doubt, don't risk damaging your - * parallel port, use an external power supply. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define DEFAULT_PARALLEL "/dev/ppi0" - -char * version = "$Id$"; - -char * progname; -char progbuf[PATH_MAX]; /* temporary buffer of spaces the same - length as progname; used for lining up - multiline messages */ - - -/* - * bit definitions for AVR device connections - */ -#define AVR_POWER 0xf1 /* bit 0 and 4...7 of data register */ -#define AVR_CLOCK 0x02 /* bit 1 of data register */ -#define AVR_INSTR 0x04 /* bit 2 of data register */ -#define AVR_RESET 0x08 /* bit 3 of data register */ -#define AVR_DATA 0x40 /* bit 6 of status register */ - - -/* - * PPI registers - */ -enum { - PPIDATA, - PPICTRL, - PPISTATUS -}; - - -/* - * AVR memory designations - */ -typedef enum { - AVR_EEPROM, - AVR_FLASH, - AVR_FLASH_LO, - AVR_FLASH_HI -} AVRMEM; - -typedef enum { - FMT_AUTO, - FMT_SREC, - FMT_IHEX, - FMT_RBIN -} FILEFMT; - -struct avrpart { - char * partdesc; /* long part name */ - char * optiontag; /* short part name */ - int flash_size; /* size in bytes of flash */ - int eeprom_size; /* size in bytes of eeprom */ - unsigned char f_readback; /* flash write polled readback value */ - unsigned char e_readback[2]; /* eeprom write polled readback values */ - int min_write_delay; /* microseconds */ - int max_write_delay; /* microseconds */ - int chip_erase_delay; /* microseconds */ - unsigned char * flash; - unsigned char * eeprom; -}; - - - -/* Need to add information for 2323, 2343, and 4414 */ - -struct avrpart parts[] = { - { "AT90S1200", "1200", 1024, 64, 0xff, { 0x00, 0xff }, - 9000, 20000, 20000, NULL, NULL }, - - { "AT90S2313", "2313", 2048, 128, 0x7f, { 0x80, 0x7f }, - 9000, 20000, 20000, NULL, NULL }, - - { "AT90S2333", "2333", 2048, 128, 0xff, { 0x00, 0xff }, - 9000, 20000, 20000, NULL, NULL }, - - { "AT90S4433", "4433", 4096, 256, 0xff, { 0x00, 0xff }, - 9000, 20000, 20000, NULL, NULL }, - - { "AT90S4434", "4434", 4096, 256, 0xff, { 0x00, 0xff }, - 9000, 20000, 20000, NULL, NULL }, - - { "AT90S8515", "8515", 8192, 512, 0x7f, { 0x80, 0x7f }, - 9000, 20000, 20000, NULL, NULL }, - - { "AT90S8535", "8535", 8192, 512, 0xff, { 0x00, 0xff }, - 9000, 20000, 20000, NULL, NULL }, -}; - -#define N_AVRPARTS (sizeof(parts)/sizeof(struct avrpart)) - - -struct fioparms { - int op; - char * mode; - char * iodesc; - char * dir; - char * rw; -}; - -enum { - FIO_READ, - FIO_WRITE -}; - - -int cmd_dump(int fd, struct avrpart * p, int argc, char *argv[]); -int cmd_write(int fd, struct avrpart * p, int argc, char *argv[]); -int cmd_erase(int fd, struct avrpart * p, int argc, char *argv[]); -int cmd_sig(int fd, struct avrpart * p, int argc, char *argv[]); -int cmd_part(int fd, struct avrpart * p, int argc, char *argv[]); -int cmd_help(int fd, struct avrpart * p, int argc, char *argv[]); -int cmd_quit(int fd, struct avrpart * p, int argc, char *argv[]); - -struct command { - char * name; - int (*func)(int fd, struct avrpart * p, int argc, char *argv[]); - char * desc; -}; - - -struct command cmd[] = { - { "dump", cmd_dump, "dump memory : %s [eeprom|flash] " }, - { "write", cmd_write, "write memory : %s [eeprom|flash] ... " }, - { "erase", cmd_erase, "perform a chip erase" }, - { "sig", cmd_sig, "display device signature bytes" }, - { "part", cmd_part, "display the current part settings" }, - { "help", cmd_help, "help" }, - { "?", cmd_help, "help" }, - { "quit", cmd_quit, "quit" } -}; - -#define NCMDS (sizeof(cmd)/sizeof(struct command)) - - - - -#define MAX_LINE_LEN 256 /* max line length for ASCII format input files */ - - -char * usage_text = -"\n" -"Usage: avrprog [options]\n" -"\n" -" Available Options:\n" -"\n" -" -m MemType : select memory type for reading or writing\n" -" \"e\", \"eeprom\" = EEPROM\n" -" \"f\", \"flash\" = FLASH (default)\n" -"\n" -" -i Filename : select input file, \"-\" = stdin\n" -"\n" -" -o Filename : select output file, \"-\" = stdout\n" -"\n" -" -f Format : select input / output file format\n" -" \"i\" = Intel Hex\n" -" \"s\" = Motorola S-Record\n" -" \"r\" = Raw binary (default for output)\n" -" \"a\" = Auto detect (default for input)\n" -" (valid for input only)\n" -" \n" -"\n" -" -p Part : select Atmel part number (see below for valid parts)\n" -"\n" -" -P Parallel : select parallel port device name (default = /dev/ppi0)\n" -"\n" -" -F : override invalid device signature check\n" -"\n" -" -t : enter terminal mode (or read commands from stdin)\n" -"\n" -" -E exitspec[,...]: specify which bits to set/reset on exit\n" -" \"[no]reset\" = [don't] activate /RESET\n" -" \"[no]vcc\" = [don't] activate Vcc\n" -"\n" -" -e : perform a chip erase (required before programming)\n" -"\n"; - - - -int avr_txrx_bit ( int fd, int bit ); - -unsigned char avr_txrx ( int fd, unsigned char byte ); - -int avr_cmd ( int fd, unsigned char cmd[4], unsigned char res[4] ); - -unsigned char avr_read_byte ( int fd, struct avrpart * p, - AVRMEM memtype, unsigned short addr ); - -int avr_read ( int fd, struct avrpart * p, AVRMEM memtype ); - -int avr_write_byte ( int fd, struct avrpart * p, AVRMEM memtype, - unsigned short addr, unsigned char data ); - -int avr_write ( int fd, struct avrpart * p, AVRMEM memtype ); - -int avr_program_enable ( int fd ); - -int avr_chip_erase ( int fd, struct avrpart * p ); - -int avr_signature ( int fd, unsigned char sig[4] ); - -void avr_powerup ( int fd ); - -void avr_powerdown ( int fd ); - -int avr_initialize ( int fd, struct avrpart * p ); - -int avr_initmem ( struct avrpart * p ); - -void display_part ( FILE * f, struct avrpart * p, char * prefix ); - - - - -int list_valid_parts ( FILE * f, char * prefix ) -{ - int i; - - for (i=0; i> (7-i)) & 0x01; - r = avr_txrx_bit ( fd, b ); - rbyte = rbyte | (r << (7-i)); - } - - return rbyte; -} - - -/* - * transmit an AVR device command and return the results; 'cmd' and - * 'res' must point to at least a 4 byte data buffer - */ -int avr_cmd ( int fd, unsigned char cmd[4], unsigned char res[4] ) -{ - int i; - - for (i=0; i<4; i++) { - res[i] = avr_txrx(fd, cmd[i]); - } - - return 0; -} - - -/* - * read a byte of data from the indicated memory region - */ -unsigned char avr_read_byte ( int fd, struct avrpart * p, - AVRMEM memtype, unsigned short addr ) -{ - unsigned char cmd[4]; - unsigned char res[4]; - - switch (memtype) { - case AVR_FLASH_LO: - cmd[0] = 0x20; - break; - case AVR_FLASH_HI: - cmd[0] = 0x28; - break; - case AVR_EEPROM: - cmd[0] = 0xa0; - break; - default: - fprintf(stderr, - "%s: avr_read_byte(); internal error: invalid memtype=%d\n", - progname, memtype); - exit(1); - break; - } - - cmd[1] = addr >> 8; /* high order bits of address */ - cmd[2] = addr & 0x0ff; /* low order bits of address */ - cmd[3] = 0; /* don't care */ - - avr_cmd(fd, cmd, res); - - return res[3]; -} - - -/* - * read the entirety of the specified memory type into the - * corresponding buffer of the avrpart pointed to by 'p'. - */ -int avr_read ( int fd, struct avrpart * p, AVRMEM memtype ) -{ - unsigned char rbyte, memt; - unsigned short n, start, end, i, bi; - unsigned char * buf; - int bufsize; - - start = 0; - - switch (memtype) { - case AVR_FLASH : - memt = AVR_FLASH_LO; - buf = p->flash; - n = p->flash_size/2; - bufsize = p->flash_size; - break; - - case AVR_EEPROM : - memt = memtype; - buf = p->eeprom; - n = p->eeprom_size; - bufsize = p->eeprom_size; - break; - - default: - fprintf(stderr, "%s: avr_read(); internal error: invalid memtype=%d\n", - progname, memtype); - exit(1); - break; - } - - end = start+n; - - bi = 0; - - for (i=start; i> 8; /* high order bits of address */ - cmd[2] = addr & 0x0ff; /* low order bits of address */ - cmd[3] = data; /* data */ - - avr_cmd(fd, cmd, res); - - tries = 0; - ready = 0; - while (!ready) { - usleep(p->min_write_delay); /* typical flash/eeprom write delay */ - r = avr_read_byte(fd, p, memtype, addr); - if ((data == p->f_readback) || - (data == p->e_readback[0]) || (data == p->e_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(p->max_write_delay); - ready = 1; - } - else if (r == data) { - ready = 1; - } - - tries++; - if (!ready && tries > 10) { - /* - * we couldn't write the data, indicate our displeasure by - * returning an error code - */ - return -1; - } - } - - return 0; -} - - -/* - * Write the whole memory region (flash or eeprom, specified by - * 'memtype') from the corresponding buffer of the avrpart pointed to - * by 'p'. All of the memory is updated, however, input data of 0xff - * is not actually written out, because empty flash and eeprom - * contains 0xff, and you can't actually write 1's, only 0's. - */ -int avr_write ( int fd, struct avrpart * p, AVRMEM memtype ) -{ - unsigned char data, memt; - unsigned short start, end, i, bi; - int nl; - int rc; - unsigned char * buf; - int bufsize; - - start = 0; - - switch (memtype) { - case AVR_FLASH : - buf = p->flash; - bufsize = p->flash_size; - end = start+bufsize/2; - memt = AVR_FLASH_LO; - break; - case AVR_EEPROM : - buf = p->eeprom; - bufsize = p->eeprom_size; - end = start+bufsize; - memt = memtype; - break; - default: - fprintf(stderr, "%s: avr_write(); internal error: invalid memtype=%d\n", - progname, memtype); - exit(1); - break; - } - - bi = 0; - - for (i=start; ichip_erase_delay); - avr_initialize(fd, p); - - return 0; -} - - -/* - * read the AVR device's signature bytes - */ -int avr_signature ( int fd, unsigned char sig[4] ) -{ - unsigned char cmd[4] = {0x30, 0x00, 0x00, 0x00}; - unsigned char res[4]; - int i; - - for (i=0; i<4; i++) { - cmd[2] = i; - avr_cmd(fd, cmd, res); - sig[i] = res[3]; - } - - return 0; -} - - -/* - * apply power to the AVR processor - */ -void avr_powerup ( int fd ) -{ - ppi_set(fd, PPIDATA, AVR_POWER); /* power up */ - usleep(100000); -} - - -/* - * remove power from the AVR processor - */ -void avr_powerdown ( int fd ) -{ - ppi_clr(fd, PPIDATA, AVR_POWER); /* power down */ -} - - -/* - * initialize the AVR device and prepare it to accept commands - */ -int avr_initialize ( int fd, struct avrpart * p ) -{ - int rc; - int tries; - - avr_powerup(fd); - - ppi_clr(fd, PPIDATA, AVR_CLOCK); - ppi_clr(fd, PPIDATA, AVR_RESET); - ppi_pulse(fd, PPIDATA, AVR_RESET); - - usleep(20000); /* 20 ms XXX should be a per-chip parameter */ - - /* - * Enable programming mode. If we are programming an AT90S1200, we - * can only issue the command and hope it worked. If we are using - * one of the other chips, the chip will echo 0x53 when issuing the - * third byte of the command. In this case, try up to 32 times in - * order to possibly get back into sync with the chip if we are out - * of sync. - */ - if (strcmp(p->partdesc, "AT90S1200")==0) { - avr_program_enable ( fd ); - } - else { - tries = 0; - do { - rc = avr_program_enable ( fd ); - if (rc == 0) - break; - ppi_pulse(fd, PPIDATA, AVR_CLOCK); - tries++; - } while (tries < 32); - - /* - * can't sync with the device, maybe it's not attached? - */ - if (tries == 32) { - fprintf ( stderr, "%s: AVR device not responding\n", progname ); - return -1; - } - } - - return 0; -} - - - -/* - * infinite loop, sensing on the pin that we use to read data out of - * the device; this is a debugging aid, you can insert a call to this - * function in 'main()' and can use it to determine whether your sense - * pin is actually sensing. - */ -int ppi_sense_test ( int fd ) -{ - unsigned char v, pv; - - pv = 1; - do { - usleep(100000); /* check every 100 ms */ - v = ppi_get(fd, PPISTATUS, AVR_DATA); - if (v != pv) { - fprintf ( stderr, "sense bit = %d\n", v ); - } - pv = v; - } while(1); - - return 0; -} - - -/* - * usage message - */ -void usage ( void ) -{ - fprintf ( stderr, "%s", usage_text ); - - fprintf(stderr, " Valid Parts for the -p option are:\n"); - list_valid_parts(stderr, " "); - fprintf(stderr, "\n"); -} - - -char * fmtstr ( FILEFMT format ) -{ - switch (format) { - case FMT_AUTO : return "auto-detect"; break; - case FMT_SREC : return "Motorola S-Record"; break; - case FMT_IHEX : return "Intel Hex"; break; - case FMT_RBIN : return "raw binary"; break; - default : return "invalid format"; break; - }; -} - - - -int b2ihex ( unsigned char * inbuf, int bufsize, - int recsize, int startaddr, - char * outfile, FILE * outf ) -{ - unsigned char * buf; - unsigned int nextaddr; - int n; - int i; - unsigned char cksum; - - if (recsize > 255) { - fprintf ( stderr, "%s: recsize=%d, must be < 256\n", - progname, recsize ); - return -1; - } - - nextaddr = startaddr; - - buf = inbuf; - while (bufsize) { - n = recsize; - if (n > bufsize) - n = bufsize; - - if (n) { - cksum = 0; - fprintf ( outf, ":%02X%04X00", n, nextaddr ); - cksum += n + ((nextaddr >> 8) & 0x0ff) + (nextaddr & 0x0ff); - for (i=0; i> 8) & 0x0ff) + (nextaddr & 0x0ff); - cksum = -cksum; - fprintf ( outf, "%02X\n", cksum ); - - return 0; -} - - -int ihex2b ( char * infile, FILE * inf, - unsigned char * outbuf, int bufsize ) -{ - unsigned char buffer [ MAX_LINE_LEN ]; - unsigned char * buf; - unsigned int prevaddr, nextaddr; - unsigned int b; - int n; - int i, j; - unsigned int cksum, rectype; - int lineno; - - lineno = 0; - prevaddr = 0; - buf = outbuf; - - while (fgets((char *)buffer,MAX_LINE_LEN,inf)!=NULL) { - lineno++; - if (buffer[0] != ':') - continue; - if (sscanf((char *)&buffer[1], - "%02x%04x%02x", &n, &nextaddr, &rectype) != 3) { - fprintf(stderr, "%s: invalid record at line %d of \"%s\"\n", - progname, lineno, infile); - exit(1); - } - - if ((rectype != 0) && (rectype != 1)) { - fprintf(stderr, - "%s: don't know how to deal with rectype=%d " - "at line %d of %s\n", - progname, rectype, lineno, infile); - exit(1); - } - - if (n && ((nextaddr + n) > bufsize)) { - fprintf(stderr, "%s: address 0x%04x out of range at line %d of %s\n", - progname, nextaddr+n, lineno, infile); - return -1; - } - - /* start computing a checksum */ - cksum = n + ((nextaddr >> 8 ) & 0x0ff) + (nextaddr & 0x0ff); - - for (i=0; iop) { - case FIO_READ: - rc = fread(buf, 1, size, f); - break; - case FIO_WRITE: - rc = fwrite(buf, 1, size, f); - break; - default: - fprintf(stderr, "%s: fileio: invalid operation=%d\n", - progname, fio->op); - return -1; - } - - if (rc < size) { - fprintf(stderr, - "%s: %s error %s %s: %s; %s %d of the expected %d bytes\n", - progname, fio->iodesc, fio->dir, filename, strerror(errno), - fio->rw, rc, size); - return -1; - } - - return rc; -} - - -int fileio_ihex ( struct fioparms * fio, - char * filename, FILE * f, unsigned char * buf, int size ) -{ - int rc; - - switch (fio->op) { - case FIO_WRITE: - rc = b2ihex(buf, size, 32, 0, filename, f); - if (rc) { - return -1; - } - break; - - case FIO_READ: - rc = ihex2b(filename, f, buf, size); - if (rc) - return -1; - break; - - default: - fprintf(stderr, "%s: invalid Intex Hex file I/O operation=%d\n", - progname, fio->op); - return -1; - break; - } - - return 0; -} - - -int fileio_srec ( struct fioparms * fio, - char * filename, FILE * f, unsigned char * buf, int size ) -{ - fprintf(stderr, "%s: Motorola S-Record %s format not yet supported\n", - progname, fio->iodesc); - return -1; -} - - -int fileio_setparms ( int op, struct fioparms * fp ) -{ - fp->op = op; - - switch (op) { - case FIO_READ: - fp->mode = "r"; - fp->iodesc = "input"; - fp->dir = "from"; - fp->rw = "read"; - break; - - case FIO_WRITE: - fp->mode = "w"; - fp->iodesc = "output"; - fp->dir = "to"; - fp->rw = "wrote"; - break; - - default: - fprintf(stderr, "%s: invalid I/O operation %d\n", - progname, op); - return -1; - break; - } - - return 0; -} - - - -int fmt_autodetect ( char * fname ) -{ - FILE * f; - unsigned char buf[MAX_LINE_LEN]; - int i; - int len; - int found; - - f = fopen(fname, "r"); - if (f == NULL) { - fprintf(stderr, "%s: error opening %s: %s\n", - progname, fname, strerror(errno)); - return -1; - } - - while (fgets((char *)buf, MAX_LINE_LEN, f)!=NULL) { - buf[MAX_LINE_LEN-1] = 0; - len = strlen((char *)buf); - if (buf[len-1] == '\n') - buf[--len] = 0; - - /* check for binary data */ - found = 0; - for (i=0; i 127) { - found = 1; - break; - } - } - if (found) - return FMT_RBIN; - - /* check for lines that look like intel hex */ - if ((buf[0] == ':') && (len >= 11)) { - found = 1; - for (i=1; i= 10) && isdigit(buf[1])) { - found = 1; - for (i=1; ieeprom; - size = p->eeprom_size; - break; - - case AVR_FLASH: - buf = p->flash; - size = p->flash_size; - break; - - default: - fprintf(stderr, "%s: invalid memory type for %s: %d\n", - progname, fio.iodesc, memtype); - return -1; - } - - if (fio.op == FIO_READ) { - /* 0xff fill unspecified memory */ - for (i=0; i> 4]; - b[j++] = hexdata[(p[i] & 0x0f)]; - if (i < 15) - b[j++] = ' '; - } - - for (i=j; i len) - n = len; - hexdump_line(dst1, p, n, 48); - chardump_line(dst2, p, n, 16); - fprintf(stdout, "%04x %s |%s|\n", addr, dst1, dst2); - len -= n; - addr += n; - p += n; - } - - return 0; -} - - -int cmd_dump ( int fd, struct avrpart * p, int argc, char * argv[] ) -{ - char * e; - int i, j; - int len, maxsize; - AVRMEM memtype; - unsigned short addr, daddr; - char * buf; - - if (argc != 4) { - fprintf(stderr, "Usage: dump flash|eeprom \n"); - return -1; - } - - if (strcmp(argv[1],"flash")==0) { - memtype = AVR_FLASH; - maxsize = p->flash_size; - } - else if (strcmp(argv[1],"eeprom")==0) { - memtype = AVR_EEPROM; - maxsize = p->eeprom_size; - } - else { - fprintf(stderr, "%s (dump): invalid memory type \"%s\"\n", - progname, argv[1]); - return -1; - } - - addr = strtoul(argv[2], &e, 0); - if (*e || (e == argv[2])) { - fprintf(stderr, "%s (dump): can't parse address \"%s\"\n", - progname, argv[2]); - return -1; - } - - len = strtol(argv[3], &e, 0); - if (*e || (e == argv[3])) { - fprintf(stderr, "%s (dump): can't parse length \"%s\"\n", - progname, argv[3]); - return -1; - } - - if (addr > maxsize) { - fprintf(stderr, - "%s (dump): address 0x%04x is out of range for %s memory\n", - progname, addr, memtypestr(memtype)); - return -1; - } - - if ((addr + len) > maxsize) { - fprintf(stderr, - "%s (dump): selected address and length exceed " - "range for %s memory\n", - progname, memtypestr(memtype)); - return -1; - } - - buf = malloc(len); - if (buf == NULL) { - fprintf(stderr, "%s (dump): out of memory\n", progname); - return -1; - } - - j = 0; - daddr = addr; - if (memtype == AVR_FLASH) { - daddr = addr / 2; - if (addr & 0x01) { - buf[j++] = avr_read_byte( fd, p, AVR_FLASH_HI, daddr); - daddr++; - } - } - - i = daddr; - while (j < len) { - if (memtype == AVR_FLASH) { - buf[j++] = avr_read_byte( fd, p, AVR_FLASH_LO, i); - if (j < len) { - buf[j++] = avr_read_byte( fd, p, AVR_FLASH_HI, i); - } - } - else { - buf[j++] = avr_read_byte( fd, p, AVR_EEPROM, i); - } - i++; - } - - hexdump_buf(stdout, addr, buf, len); - - fprintf(stdout, "\n"); - - free(buf); - - return 0; -} - -int cmd_write ( int fd, struct avrpart * p, int argc, char * argv[] ) -{ - char * e; - int i, j; - int len, maxsize; - AVRMEM memtype; - unsigned short addr, daddr; - char * buf; - int rc; - - if (argc < 4) { - fprintf(stderr, - "Usage: write flash|eeprom ... byteN>\n"); - return -1; - } - - if (strcmp(argv[1],"flash")==0) { - memtype = AVR_FLASH; - maxsize = p->flash_size; - } - else if (strcmp(argv[1],"eeprom")==0) { - memtype = AVR_EEPROM; - maxsize = p->eeprom_size; - } - else { - fprintf(stderr, "%s (write): invalid memory type \"%s\"\n", - progname, argv[1]); - return -1; - } - - addr = strtoul(argv[2], &e, 0); - if (*e || (e == argv[2])) { - fprintf(stderr, "%s (write): can't parse address \"%s\"\n", - progname, argv[2]); - return -1; - } - - if (addr > maxsize) { - fprintf(stderr, - "%s (write): address 0x%04x is out of range for %s memory\n", - progname, addr, memtypestr(memtype)); - return -1; - } - - /* number of bytes to write at the specified address */ - len = argc - 3; - - if ((addr + len) > maxsize) { - fprintf(stderr, - "%s (write): selected address and # bytes exceed " - "range for %s memory\n", - progname, memtypestr(memtype)); - return -1; - } - - buf = malloc(len); - if (buf == NULL) { - fprintf(stderr, "%s (write): out of memory\n", progname); - return -1; - } - - for (i=3; i ")) != NULL) { - len = strlen(cmdbuf); - if (len > 1) - add_history(cmdbuf); - - /* - * find the start of the command, skipping any white space - */ - q = cmdbuf; - while (*q && isspace(*q)) - q++; - - /* skip blank lines and comments */ - if (!*q || (*q == '#')) - continue; - - /* tokenize command line */ - argc = tokenize(q, &argv); - - fprintf(stdout, ">>> "); - for (i=0; i 0) { - rc = 0; - break; - } - free(cmdbuf); - } - - return rc; -} - - - -int avr_initmem ( struct avrpart * p ) -{ - p->flash = (unsigned char *) malloc(p->flash_size); - if (p->flash == NULL) { - fprintf(stderr, "%s: can't alloc buffer for flash size of %d bytes\n", - progname, p->flash_size); - exit(1); - } - - p->eeprom = (unsigned char *) malloc(p->eeprom_size); - if (p->eeprom == NULL) { - fprintf(stderr, "%s: can't alloc buffer for eeprom size of %d bytes\n", - progname, p->eeprom_size); - exit(1); - } - - return 0; -} - - -int verify_data(struct avrpart * p, struct avrpart * v, AVRMEM memtype) -{ - int i; - unsigned char * buf1, * buf2; - int size; - - switch (memtype) { - case AVR_FLASH: - buf1 = p->flash; - buf2 = v->flash; - size = p->flash_size; - break; - - case AVR_EEPROM: - buf1 = p->eeprom; - buf2 = v->eeprom; - size = p->eeprom_size; - break; - - default: - fprintf(stderr, "%s: invalid memory type = %d for data verification\n", - progname, memtype); - return -1; - } - - for (i=0; ipartdesc, - prefix, p->flash_size, - prefix, p->eeprom_size, - prefix, p->min_write_delay, p->max_write_delay, - prefix, p->chip_erase_delay, - prefix, p->f_readback, - prefix, p->e_readback[0], p->e_readback[1]); -} - -/* - * parse the -E string - */ -int getexitspecs ( char *s, int *set, int *clr ) -{ - char *cp; - - while ((cp = strtok(s, ","))) { - if (strcmp(cp, "reset") == 0) { *clr |= AVR_RESET; } - else if (strcmp(cp, "noreset") == 0) { *set |= AVR_RESET; } - else if (strcmp(cp, "vcc") == 0) { *set |= AVR_POWER; } - else if (strcmp(cp, "novcc") == 0) { *clr |= AVR_POWER; } - else - return -1; - s = 0; /* strtok() should be called with the actual string only once */ - } - - return 0; -} - -/* - * main routine - */ -int main ( int argc, char * argv [] ) -{ - int fd; /* file descriptor for parallel port */ - int rc; /* general return code checking */ - int exitrc; /* exit code for main() */ - int i; /* general loop counter */ - int ch; /* options flag */ - int size; /* size of memory region */ - int len; /* length for various strings */ - char * p1; /* used to parse CVS Id */ - char * p2; /* used to parse CVS Ed */ - unsigned char sig[4]; /* AVR signature bytes */ - unsigned char nulldev[4]; /* 0xff signature bytes for comparison */ - struct avrpart * p, ap1; /* which avr part we are programming */ - struct avrpart * v, ap2; /* used for verify */ - int readorwrite; /* true if a chip read/write op was selected */ - int ppidata; /* cached value of the ppi data register */ - - /* options / operating mode variables */ - int memtype; /* AVR_FLASH or AVR_EEPROM */ - int doread; /* 0=reading, 1=writing */ - int erase; /* 1=erase chip, 0=don't */ - char * outputf; /* output file name */ - char * inputf; /* input file name */ - int ovsigck; /* 1=override sig check, 0=don't */ - char * parallel; /* parallel port device */ - int terminal; /* 1=enter terminal mode, 0=don't */ - FILEFMT filefmt; /* FMT_AUTO, FMT_IHEX, FMT_SREC, FMT_RBIN */ - int nowrite; /* don't actually write anything to the chip */ - int verify; /* perform a verify operation */ - int ppisetbits; /* bits to set in ppi data register at exit */ - int ppiclrbits; /* bits to clear in ppi data register at exit */ - - readorwrite = 0; - parallel = DEFAULT_PARALLEL; - outputf = NULL; - inputf = NULL; - doread = 1; - memtype = AVR_FLASH; - erase = 0; - p = NULL; - ovsigck = 0; - terminal = 0; - filefmt = FMT_AUTO; - nowrite = 0; - verify = 1; /* on by default; XXX can't turn it off */ - ppisetbits = ppiclrbits = 0; - - progname = rindex(argv[0],'/'); - if (progname) - progname++; - else - progname = argv[0]; - - len = strlen(progname) + 2; - for (i=0; iflash or p->eeprom) is the - * same as what is on the chip - */ - fprintf(stderr, "%s: verifying %s memory against %s:\n", - progname, memtypestr(memtype), inputf); - fprintf(stderr, "%s: reading on-chip %s data:\n", - progname, memtypestr(memtype)); - rc = avr_read ( fd, v, memtype ); - if (rc) { - fprintf(stderr, "%s: failed to read all of %s memory, rc=%d\n", - progname, memtypestr(memtype), rc); - exitrc = 1; - goto main_exit; - } - - fprintf(stderr, "%s: verifying\n", progname); - rc = verify_data(p, v, memtype); - if (rc) { - fprintf(stderr, "%s: verification error; content mismatch\n", - progname); - exitrc = 1; - goto main_exit; - } - - fprintf(stderr, "%s: data verified\n", progname); - } - - - - main_exit: - - /* - * program complete - */ - - avr_powerdown(fd); - ppi_setall(fd, PPIDATA, ppidata); - - close(fd); - - fprintf(stderr, "\n%s done. Thank you.\n\n", progname); - - return exitrc; -} - diff --git a/fileio.c b/fileio.c new file mode 100644 index 00000000..7c35f4f5 --- /dev/null +++ b/fileio.c @@ -0,0 +1,492 @@ +/* + * Copyright 2000 Brian S. Dean + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BRIAN S. DEAN ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BRIAN S. DEAN BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + */ + +/* $Id$ */ + +#include +#include +#include +#include + +#include "avr.h" +#include "fileio.h" + + +extern char * progname; +extern char progbuf[]; + + +int b2ihex ( unsigned char * inbuf, int bufsize, + int recsize, int startaddr, + char * outfile, FILE * outf ); + +int ihex2b ( char * infile, FILE * inf, + unsigned char * outbuf, int bufsize ); + +int fileio_rbin ( struct fioparms * fio, + char * filename, FILE * f, unsigned char * buf, int size ); + +int fileio_ihex ( struct fioparms * fio, + char * filename, FILE * f, unsigned char * buf, int size ); + +int fileio_srec ( struct fioparms * fio, + char * filename, FILE * f, unsigned char * buf, int size ); + +int fmt_autodetect ( char * fname ); + + + +char * fmtstr ( FILEFMT format ) +{ + switch (format) { + case FMT_AUTO : return "auto-detect"; break; + case FMT_SREC : return "Motorola S-Record"; break; + case FMT_IHEX : return "Intel Hex"; break; + case FMT_RBIN : return "raw binary"; break; + default : return "invalid format"; break; + }; +} + + + +int b2ihex ( unsigned char * inbuf, int bufsize, + int recsize, int startaddr, + char * outfile, FILE * outf ) +{ + unsigned char * buf; + unsigned int nextaddr; + int n; + int i; + unsigned char cksum; + + if (recsize > 255) { + fprintf ( stderr, "%s: recsize=%d, must be < 256\n", + progname, recsize ); + return -1; + } + + nextaddr = startaddr; + + buf = inbuf; + while (bufsize) { + n = recsize; + if (n > bufsize) + n = bufsize; + + if (n) { + cksum = 0; + fprintf ( outf, ":%02X%04X00", n, nextaddr ); + cksum += n + ((nextaddr >> 8) & 0x0ff) + (nextaddr & 0x0ff); + for (i=0; i> 8) & 0x0ff) + (nextaddr & 0x0ff); + cksum = -cksum; + fprintf ( outf, "%02X\n", cksum ); + + return 0; +} + + +int ihex2b ( char * infile, FILE * inf, + unsigned char * outbuf, int bufsize ) +{ + unsigned char buffer [ MAX_LINE_LEN ]; + unsigned char * buf; + unsigned int prevaddr, nextaddr; + unsigned int b; + int n; + int i, j; + unsigned int cksum, rectype; + int lineno; + + lineno = 0; + prevaddr = 0; + buf = outbuf; + + while (fgets((char *)buffer,MAX_LINE_LEN,inf)!=NULL) { + lineno++; + if (buffer[0] != ':') + continue; + if (sscanf((char *)&buffer[1], + "%02x%04x%02x", &n, &nextaddr, &rectype) != 3) { + fprintf(stderr, "%s: invalid record at line %d of \"%s\"\n", + progname, lineno, infile); + exit(1); + } + + if ((rectype != 0) && (rectype != 1)) { + fprintf(stderr, + "%s: don't know how to deal with rectype=%d " + "at line %d of %s\n", + progname, rectype, lineno, infile); + exit(1); + } + + if (n && ((nextaddr + n) > bufsize)) { + fprintf(stderr, "%s: address 0x%04x out of range at line %d of %s\n", + progname, nextaddr+n, lineno, infile); + return -1; + } + + /* start computing a checksum */ + cksum = n + ((nextaddr >> 8 ) & 0x0ff) + (nextaddr & 0x0ff); + + for (i=0; iop) { + case FIO_READ: + rc = fread(buf, 1, size, f); + break; + case FIO_WRITE: + rc = fwrite(buf, 1, size, f); + break; + default: + fprintf(stderr, "%s: fileio: invalid operation=%d\n", + progname, fio->op); + return -1; + } + + if (rc < size) { + fprintf(stderr, + "%s: %s error %s %s: %s; %s %d of the expected %d bytes\n", + progname, fio->iodesc, fio->dir, filename, strerror(errno), + fio->rw, rc, size); + return -1; + } + + return rc; +} + + +int fileio_ihex ( struct fioparms * fio, + char * filename, FILE * f, unsigned char * buf, int size ) +{ + int rc; + + switch (fio->op) { + case FIO_WRITE: + rc = b2ihex(buf, size, 32, 0, filename, f); + if (rc) { + return -1; + } + break; + + case FIO_READ: + rc = ihex2b(filename, f, buf, size); + if (rc) + return -1; + break; + + default: + fprintf(stderr, "%s: invalid Intex Hex file I/O operation=%d\n", + progname, fio->op); + return -1; + break; + } + + return 0; +} + + +int fileio_srec ( struct fioparms * fio, + char * filename, FILE * f, unsigned char * buf, int size ) +{ + fprintf(stderr, "%s: Motorola S-Record %s format not yet supported\n", + progname, fio->iodesc); + return -1; +} + + +int fileio_setparms ( int op, struct fioparms * fp ) +{ + fp->op = op; + + switch (op) { + case FIO_READ: + fp->mode = "r"; + fp->iodesc = "input"; + fp->dir = "from"; + fp->rw = "read"; + break; + + case FIO_WRITE: + fp->mode = "w"; + fp->iodesc = "output"; + fp->dir = "to"; + fp->rw = "wrote"; + break; + + default: + fprintf(stderr, "%s: invalid I/O operation %d\n", + progname, op); + return -1; + break; + } + + return 0; +} + + + +int fmt_autodetect ( char * fname ) +{ + FILE * f; + unsigned char buf[MAX_LINE_LEN]; + int i; + int len; + int found; + + f = fopen(fname, "r"); + if (f == NULL) { + fprintf(stderr, "%s: error opening %s: %s\n", + progname, fname, strerror(errno)); + return -1; + } + + while (fgets((char *)buf, MAX_LINE_LEN, f)!=NULL) { + buf[MAX_LINE_LEN-1] = 0; + len = strlen((char *)buf); + if (buf[len-1] == '\n') + buf[--len] = 0; + + /* check for binary data */ + found = 0; + for (i=0; i 127) { + found = 1; + break; + } + } + if (found) + return FMT_RBIN; + + /* check for lines that look like intel hex */ + if ((buf[0] == ':') && (len >= 11)) { + found = 1; + for (i=1; i= 10) && isdigit(buf[1])) { + found = 1; + for (i=1; ieeprom; + size = p->eeprom_size; + break; + + case AVR_FLASH: + buf = p->flash; + size = p->flash_size; + break; + + default: + fprintf(stderr, "%s: invalid memory type for %s: %d\n", + progname, fio.iodesc, memtype); + return -1; + } + + if (fio.op == FIO_READ) { + /* 0xff fill unspecified memory */ + for (i=0; i + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BRIAN S. DEAN ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BRIAN S. DEAN BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + */ + +/* $Id$ */ + +#ifndef __fileio_h__ +#define __fileio_h__ + +typedef enum { + FMT_AUTO, + FMT_SREC, + FMT_IHEX, + FMT_RBIN +} FILEFMT; + +struct fioparms { + int op; + char * mode; + char * iodesc; + char * dir; + char * rw; +}; + +enum { + FIO_READ, + FIO_WRITE +}; + +#define MAX_LINE_LEN 256 /* max line length for ASCII format input files */ + +char * fmtstr ( FILEFMT format ); + +int fileio_setparms ( int op, struct fioparms * fp ); + +int fileio ( int op, char * filename, FILEFMT format, + struct avrpart * p, AVRMEM memtype ); + +#endif diff --git a/main.c b/main.c new file mode 100644 index 00000000..3a00d746 --- /dev/null +++ b/main.c @@ -0,0 +1,603 @@ +/* + * Copyright 2000 Brian S. Dean + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BRIAN S. DEAN ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BRIAN S. DEAN BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + */ + +/* $Id$ */ + +/* + * Code to program an Atmel AVR AT90S device using the parallel port. + * + * Make the following connections: + * + * Parallel Port Atmel AVR + * ------------- ---------------------------- + * Pin 2 -> Vcc (see NOTE below) + * Pin 3 -> SCK CLOCK IN + * Pin 4 -> MOSI Instruction input + * Pin 5 -> /RESET + * Pin 6,7,8,9 -> Vcc (Can be tied together with Schottky diodes) + * Pin 10 <- MISO Data out + * Pin 18 <- GND + * + * NOTE on Vcc connection: make sure your parallel port can supply an + * adequate amount of current to power your device. 6-10 mA is + * common for parallel port signal lines, but is not guaranteed, + * especially for notebook computers. Optionally, you can tie pins + * 6, 7, 8, and 9 also to Vcc with Schottky diodes to supply + * additional current. If in doubt, don't risk damaging your + * parallel port, use an external power supply. + */ + +#include +#include +#include +#include +#include +#include + +#include "avr.h" +#include "fileio.h" +#include "ppi.h" +#include "term.h" + + +#define DEFAULT_PARALLEL "/dev/ppi0" + + +char * version = "1.1"; + +char * progname; +char progbuf[PATH_MAX]; /* temporary buffer of spaces the same + length as progname; used for lining up + multiline messages */ + +char * usage_text = +"\n" +"Usage: avrprog [options]\n" +"\n" +" Available Options:\n" +"\n" +" -m MemType : select memory type for reading or writing\n" +" \"e\", \"eeprom\" = EEPROM\n" +" \"f\", \"flash\" = FLASH (default)\n" +"\n" +" -i Filename : select input file, \"-\" = stdin\n" +"\n" +" -o Filename : select output file, \"-\" = stdout\n" +"\n" +" -f Format : select input / output file format\n" +" \"i\" = Intel Hex\n" +" \"s\" = Motorola S-Record\n" +" \"r\" = Raw binary (default for output)\n" +" \"a\" = Auto detect (default for input)\n" +" (valid for input only)\n" +" \n" +"\n" +" -p Part : select Atmel part number (see below for valid parts)\n" +"\n" +" -P Parallel : select parallel port device name (default = /dev/ppi0)\n" +"\n" +" -F : override invalid device signature check\n" +"\n" +" -t : enter terminal mode (or read commands from stdin)\n" +"\n" +" -E exitspec[,...]: specify which bits to set/reset on exit\n" +" \"[no]reset\" = [don't] activate /RESET\n" +" \"[no]vcc\" = [don't] activate Vcc\n" +"\n" +" -e : perform a chip erase (required before programming)\n" +"\n"; + + + +/* + * usage message + */ +void usage ( void ) +{ + fprintf ( stderr, "%s", usage_text ); + + fprintf(stderr, " Valid Parts for the -p option are:\n"); + avr_list_parts(stderr, " "); + fprintf(stderr, "\n"); +} + + +/* + * parse the -E string + */ +int getexitspecs ( char *s, int *set, int *clr ) +{ + char *cp; + + while ((cp = strtok(s, ","))) { + if (strcmp(cp, "reset") == 0) { + *clr |= AVR_RESET; + } + else if (strcmp(cp, "noreset") == 0) { + *set |= AVR_RESET; + } + else if (strcmp(cp, "vcc") == 0) { + *set |= AVR_POWER; + } + else if (strcmp(cp, "novcc") == 0) { + *clr |= AVR_POWER; + } + else { + return -1; + } + s = 0; /* strtok() should be called with the actual string only once */ + } + + return 0; +} + + +/* + * main routine + */ +int main ( int argc, char * argv [] ) +{ + int fd; /* file descriptor for parallel port */ + int rc; /* general return code checking */ + int exitrc; /* exit code for main() */ + int i; /* general loop counter */ + int ch; /* options flag */ + int size; /* size of memory region */ + int len; /* length for various strings */ + unsigned char sig[4]; /* AVR signature bytes */ + unsigned char nulldev[4]; /* 0xff signature bytes for comparison */ + struct avrpart * p, ap1; /* which avr part we are programming */ + struct avrpart * v, ap2; /* used for verify */ + int readorwrite; /* true if a chip read/write op was selected */ + int ppidata; /* cached value of the ppi data register */ + + /* options / operating mode variables */ + int memtype; /* AVR_FLASH or AVR_EEPROM */ + int doread; /* 0=reading, 1=writing */ + int erase; /* 1=erase chip, 0=don't */ + char * outputf; /* output file name */ + char * inputf; /* input file name */ + int ovsigck; /* 1=override sig check, 0=don't */ + char * parallel; /* parallel port device */ + int terminal; /* 1=enter terminal mode, 0=don't */ + FILEFMT filefmt; /* FMT_AUTO, FMT_IHEX, FMT_SREC, FMT_RBIN */ + int nowrite; /* don't actually write anything to the chip */ + int verify; /* perform a verify operation */ + int ppisetbits; /* bits to set in ppi data register at exit */ + int ppiclrbits; /* bits to clear in ppi data register at exit */ + + readorwrite = 0; + parallel = DEFAULT_PARALLEL; + outputf = NULL; + inputf = NULL; + doread = 1; + memtype = AVR_FLASH; + erase = 0; + p = NULL; + ovsigck = 0; + terminal = 0; + filefmt = FMT_AUTO; + nowrite = 0; + verify = 1; /* on by default; XXX can't turn it off */ + ppisetbits = ppiclrbits = 0; + + progname = rindex(argv[0],'/'); + if (progname) + progname++; + else + progname = argv[0]; + + len = strlen(progname) + 2; + for (i=0; iflash or p->eeprom) is the + * same as what is on the chip + */ + fprintf(stderr, "%s: verifying %s memory against %s:\n", + progname, avr_memtstr(memtype), inputf); + fprintf(stderr, "%s: reading on-chip %s data:\n", + progname, avr_memtstr(memtype)); + rc = avr_read ( fd, v, memtype ); + if (rc) { + fprintf(stderr, "%s: failed to read all of %s memory, rc=%d\n", + progname, avr_memtstr(memtype), rc); + exitrc = 1; + goto main_exit; + } + + fprintf(stderr, "%s: verifying\n", progname); + rc = avr_verify(p, v, memtype); + if (rc) { + fprintf(stderr, "%s: verification error; content mismatch\n", + progname); + exitrc = 1; + goto main_exit; + } + + fprintf(stderr, "%s: data verified\n", progname); + } + + + + main_exit: + + /* + * program complete + */ + + avr_powerdown(fd); + ppi_setall(fd, PPIDATA, ppidata); + + close(fd); + + fprintf(stderr, "\n%s done. Thank you.\n\n", progname); + + return exitrc; +} + diff --git a/ppi.c b/ppi.c new file mode 100644 index 00000000..0c85a3ba --- /dev/null +++ b/ppi.c @@ -0,0 +1,224 @@ +/* + * Copyright 2000 Brian S. Dean + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BRIAN S. DEAN ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BRIAN S. DEAN BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + */ + +/* $Id$ */ + +#include +#include +#include + +#include "ppi.h" + +extern char * progname; + +/* + * set 'get' and 'set' appropriately for subsequent passage to ioctl() + * to get/set the specified PPI registers. + */ +int ppi_getops ( int reg, unsigned long * get, unsigned long * set ) +{ + switch (reg) { + case PPIDATA: + *set = PPISDATA; + *get = PPIGDATA; + break; + case PPICTRL: + *set = PPISCTRL; + *get = PPIGCTRL; + break; + case PPISTATUS: + *set = PPISSTATUS; + *get = PPIGSTATUS; + break; + default: + fprintf(stderr, "%s: avr_set(): invalid register=%d\n", + progname, reg ); + return -1; + break; + } + + return 0; +} + + +/* + * set the indicated bit of the specified register. + */ +int ppi_set ( int fd, int reg, int bit ) +{ + unsigned char v; + unsigned long get, set; + int rc; + + rc = ppi_getops ( reg, &get, &set ); + if (rc) + return -1; + + ioctl(fd, get, &v); + v |= bit; + ioctl(fd, set, &v); + + return 0; +} + + +/* + * clear the indicated bit of the specified register. + */ +int ppi_clr ( int fd, int reg, int bit ) +{ + unsigned char v; + unsigned long get, set; + int rc; + + rc = ppi_getops ( reg, &get, &set ); + if (rc) + return -1; + + ioctl(fd, get, &v); + v &= ~bit; + ioctl(fd, set, &v); + + return 0; +} + + +/* + * get the indicated bit of the specified register. + */ +int ppi_get ( int fd, int reg, int bit ) +{ + unsigned char v; + unsigned long get, set; + int rc; + + rc = ppi_getops ( reg, &get, &set ); + if (rc) + return -1; + + ioctl(fd, get, &v); + v &= bit; + + return (v == bit); +} + +/* + * toggle the indicated bit of the specified register. + */ +int ppi_toggle ( int fd, int reg, int bit ) +{ + unsigned char v; + unsigned long get, set; + int rc; + + rc = ppi_getops ( reg, &get, &set ); + if (rc) + return -1; + + ioctl(fd, get, &v); + v ^= bit; + ioctl(fd, set, &v); + + return 0; +} + + +/* + * get all bits of the specified register. + */ +int ppi_getall ( int fd, int reg ) +{ + unsigned char v; + unsigned long get, set; + int rc; + + rc = ppi_getops ( reg, &get, &set ); + if (rc) + return -1; + + ioctl(fd, get, &v); + + return (int)v; +} + +/* + * set all bits of the specified register to val. + */ +int ppi_setall ( int fd, int reg, int val ) +{ + unsigned char v; + unsigned long get, set; + int rc; + + rc = ppi_getops ( reg, &get, &set ); + if (rc) + return -1; + + v = val; + ioctl(fd, set, &v); + + return 0; +} + +/* + * pulse the indicated bit of the specified register. + */ +int ppi_pulse ( int fd, int reg, int bit ) +{ + ppi_toggle(fd, reg, bit); + ppi_toggle(fd, reg, bit); + + return 0; +} + + +/* + * infinite loop, sensing on the pin that we use to read data out of + * the device; this is a debugging aid, you can insert a call to this + * function in 'main()' and can use it to determine whether your sense + * pin is actually sensing. + */ +int ppi_sense_test ( int fd, int reg, int bit ) +{ + unsigned char v, pv; + + pv = 1; + do { + usleep(100000); /* check every 100 ms */ + v = ppi_get(fd, reg, bit); + if (v != pv) { + fprintf ( stderr, "sense bit = %d\n", v ); + } + pv = v; + } while(1); + + return 0; +} + + diff --git a/ppi.h b/ppi.h new file mode 100644 index 00000000..66c51764 --- /dev/null +++ b/ppi.h @@ -0,0 +1,62 @@ +/* + * Copyright 2000 Brian S. Dean + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BRIAN S. DEAN ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BRIAN S. DEAN BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + */ + +/* $Id$ */ + +#ifndef __ppi_h__ +#define __ppi_h__ + +/* + * PPI registers + */ +enum { + PPIDATA, + PPICTRL, + PPISTATUS +}; + +int ppi_getops ( int reg, unsigned long * get, unsigned long * set ); + +int ppi_set ( int fd, int reg, int bit ); + +int ppi_clr ( int fd, int reg, int bit ); + +int ppi_get ( int fd, int reg, int bit ); + +int ppi_toggle ( int fd, int reg, int bit ); + +int ppi_getall ( int fd, int reg ); + +int ppi_setall ( int fd, int reg, int val ); + +int ppi_pulse ( int fd, int reg, int bit ); + +#endif + + diff --git a/term.c b/term.c new file mode 100644 index 00000000..d801ecdc --- /dev/null +++ b/term.c @@ -0,0 +1,622 @@ +/* + * Copyright 2000 Brian S. Dean + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BRIAN S. DEAN ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BRIAN S. DEAN BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + */ + +/* $Id$ */ + + +#include +#include +#include +#include +#include + +#include "avr.h" + + +extern char * progname; +extern char progbuf[]; + + +struct command { + char * name; + int (*func)(int fd, struct avrpart * p, int argc, char *argv[]); + char * desc; +}; + + +int cmd_dump (int fd, struct avrpart * p, int argc, char *argv[]); + +int cmd_write (int fd, struct avrpart * p, int argc, char *argv[]); + +int cmd_erase (int fd, struct avrpart * p, int argc, char *argv[]); + +int cmd_sig (int fd, struct avrpart * p, int argc, char *argv[]); + +int cmd_part (int fd, struct avrpart * p, int argc, char *argv[]); + +int cmd_help (int fd, struct avrpart * p, int argc, char *argv[]); + +int cmd_quit (int fd, struct avrpart * p, int argc, char *argv[]); + + +struct command cmd[] = { + { "dump", cmd_dump, "dump memory : %s [eeprom|flash] " }, + { "write", cmd_write, "write memory : %s [eeprom|flash] ... " }, + { "erase", cmd_erase, "perform a chip erase" }, + { "sig", cmd_sig, "display device signature bytes" }, + { "part", cmd_part, "display the current part settings" }, + { "help", cmd_help, "help" }, + { "?", cmd_help, "help" }, + { "quit", cmd_quit, "quit" } +}; + +#define NCMDS (sizeof(cmd)/sizeof(struct command)) + + + + + +int nexttok ( char * buf, char ** tok, char ** next ) +{ + char * q, * n; + + q = buf; + while (isspace(*q)) + q++; + + /* isolate first token */ + n = q+1; + while (*n && !isspace(*n)) + n++; + + if (*n) { + *n = 0; + n++; + } + + /* find start of next token */ + while (isspace(*n)) + n++; + + *tok = q; + *next = n; + + return 0; +} + + +int hexdump_line ( char * buffer, unsigned char * p, int n, int pad ) +{ + char * hexdata = "0123456789abcdef"; + char * b; + int i, j; + + b = buffer; + + j = 0; + for (i=0; i> 4]; + b[j++] = hexdata[(p[i] & 0x0f)]; + if (i < 15) + b[j++] = ' '; + } + + for (i=j; i len) + n = len; + hexdump_line(dst1, p, n, 48); + chardump_line(dst2, p, n, 16); + fprintf(stdout, "%04x %s |%s|\n", addr, dst1, dst2); + len -= n; + addr += n; + p += n; + } + + return 0; +} + + +int cmd_dump ( int fd, struct avrpart * p, int argc, char * argv[] ) +{ + char * e; + int i, j; + int len, maxsize; + AVRMEM memtype; + unsigned short addr, daddr; + char * buf; + + if (argc != 4) { + fprintf(stderr, "Usage: dump flash|eeprom \n"); + return -1; + } + + if (strcmp(argv[1],"flash")==0) { + memtype = AVR_FLASH; + maxsize = p->flash_size; + } + else if (strcmp(argv[1],"eeprom")==0) { + memtype = AVR_EEPROM; + maxsize = p->eeprom_size; + } + else { + fprintf(stderr, "%s (dump): invalid memory type \"%s\"\n", + progname, argv[1]); + return -1; + } + + addr = strtoul(argv[2], &e, 0); + if (*e || (e == argv[2])) { + fprintf(stderr, "%s (dump): can't parse address \"%s\"\n", + progname, argv[2]); + return -1; + } + + len = strtol(argv[3], &e, 0); + if (*e || (e == argv[3])) { + fprintf(stderr, "%s (dump): can't parse length \"%s\"\n", + progname, argv[3]); + return -1; + } + + if (addr > maxsize) { + fprintf(stderr, + "%s (dump): address 0x%04x is out of range for %s memory\n", + progname, addr, avr_memtstr(memtype)); + return -1; + } + + if ((addr + len) > maxsize) { + fprintf(stderr, + "%s (dump): selected address and length exceed " + "range for %s memory\n", + progname, avr_memtstr(memtype)); + return -1; + } + + buf = malloc(len); + if (buf == NULL) { + fprintf(stderr, "%s (dump): out of memory\n", progname); + return -1; + } + + j = 0; + daddr = addr; + if (memtype == AVR_FLASH) { + daddr = addr / 2; + if (addr & 0x01) { + buf[j++] = avr_read_byte( fd, p, AVR_FLASH_HI, daddr); + daddr++; + } + } + + i = daddr; + while (j < len) { + if (memtype == AVR_FLASH) { + buf[j++] = avr_read_byte( fd, p, AVR_FLASH_LO, i); + if (j < len) { + buf[j++] = avr_read_byte( fd, p, AVR_FLASH_HI, i); + } + } + else { + buf[j++] = avr_read_byte( fd, p, AVR_EEPROM, i); + } + i++; + } + + hexdump_buf(stdout, addr, buf, len); + + fprintf(stdout, "\n"); + + free(buf); + + return 0; +} + +int cmd_write ( int fd, struct avrpart * p, int argc, char * argv[] ) +{ + char * e; + int i, j; + int len, maxsize; + AVRMEM memtype; + unsigned short addr, daddr; + char * buf; + int rc; + + if (argc < 4) { + fprintf(stderr, + "Usage: write flash|eeprom ... byteN>\n"); + return -1; + } + + if (strcmp(argv[1],"flash")==0) { + memtype = AVR_FLASH; + maxsize = p->flash_size; + } + else if (strcmp(argv[1],"eeprom")==0) { + memtype = AVR_EEPROM; + maxsize = p->eeprom_size; + } + else { + fprintf(stderr, "%s (write): invalid memory type \"%s\"\n", + progname, argv[1]); + return -1; + } + + addr = strtoul(argv[2], &e, 0); + if (*e || (e == argv[2])) { + fprintf(stderr, "%s (write): can't parse address \"%s\"\n", + progname, argv[2]); + return -1; + } + + if (addr > maxsize) { + fprintf(stderr, + "%s (write): address 0x%04x is out of range for %s memory\n", + progname, addr, avr_memtstr(memtype)); + return -1; + } + + /* number of bytes to write at the specified address */ + len = argc - 3; + + if ((addr + len) > maxsize) { + fprintf(stderr, + "%s (write): selected address and # bytes exceed " + "range for %s memory\n", + progname, avr_memtstr(memtype)); + return -1; + } + + buf = malloc(len); + if (buf == NULL) { + fprintf(stderr, "%s (write): out of memory\n", progname); + return -1; + } + + for (i=3; i ")) != NULL) { + len = strlen(cmdbuf); + if (len > 1) + add_history(cmdbuf); + + /* + * find the start of the command, skipping any white space + */ + q = cmdbuf; + while (*q && isspace(*q)) + q++; + + /* skip blank lines and comments */ + if (!*q || (*q == '#')) + continue; + + /* tokenize command line */ + argc = tokenize(q, &argv); + + fprintf(stdout, ">>> "); + for (i=0; i 0) { + rc = 0; + break; + } + free(cmdbuf); + } + + return rc; +} + + diff --git a/term.h b/term.h new file mode 100644 index 00000000..8cfa6ab1 --- /dev/null +++ b/term.h @@ -0,0 +1,39 @@ +/* + * Copyright 2000 Brian S. Dean + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BRIAN S. DEAN ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BRIAN S. DEAN BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + */ + +/* $Id$ */ + +#ifndef __term_h__ +#define __term_h__ + +#include "avr.h" + +int terminal_mode ( int fd, struct avrpart * p ); + +#endif