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