commit 2e3fb8371b6dcb924729d42f8af5b5e285d21d02 Author: bsd <bsd@81a1dc3b-b13d-400b-aceb-764788c761c2> Date: Sat Aug 5 05:12:50 2000 +0000 This commit was generated by cvs2svn to compensate for changes in r2, which included commits to RCS files with non-trunk default branches. git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk/avrdude@3 81a1dc3b-b13d-400b-aceb-764788c761c2 diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..fabd1ac1 --- /dev/null +++ b/Makefile @@ -0,0 +1,16 @@ +# +# $Id$ +# + +TARGET = avrprog + +all : ${TARGET} + +CFLAGS = -Wall + +${TARGET} : avrprog.c + ${CC} ${CFLAGS} -o ${TARGET} avrprog.c + +clean : + rm -f *.o ${TARGET} *~ + diff --git a/avrprog.c b/avrprog.c new file mode 100644 index 00000000..5898b946 --- /dev/null +++ b/avrprog.c @@ -0,0 +1,716 @@ +/* + * Copyright 2000, Brian Dean + * All Rights Reserved. + */ + +/* $Id$ */ + +/* + * Code to program an Atmel AVR device using the parallel port. + * + * Make the following connections: + * + * Pin 2 -> PB7(SCK) CLOCK IN (data bit 0) + * Pin 3 -> PB5(MOSI) Instruction input (data bit 1) + * Pin 4 -> /RESET (data bit 2) + * Pin 10 <- PB6(MISO) Data out (status bit 6) + * + */ + +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> +#include <sys/ioctl.h> +#include <stdarg.h> +#include <sys/stat.h> +#include </sys/dev/ppbus/ppi.h> +#include </sys/dev/ppbus/ppbconf.h> + +#define PARALLEL "/dev/ppi0" + +char * progname; + + +#define AVR_CLOCK 0x01 /* bit 0 of data register */ +#define AVR_INSTR 0x02 /* bit 1 of data register */ +#define AVR_RESET 0x04 /* bit 2 of data register */ +#define AVR_DATA 0x40 /* bit 6 of status register */ + + +enum { + PPIDATA, + PPICTRL, + PPISTATUS +}; + + +enum { + AVR_EEPROM, + AVR_FLASH, + AVR_FLASH_LO, + AVR_FLASH_HI +}; + + +int dprintf ( FILE * f, char * format, ... ) +{ +#if DEBUG + va_list ap; + int rc; + + va_start(ap,format); + rc = vfprintf(f,format,ap); + va_end(ap); + + return rc; +#else + return 0; +#endif +} + + +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; +} + + +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; +} + + +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; +} + + +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); +} + + +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); + + v &= ~bit; + ioctl(fd, set, &v); + + return 0; +} + + +int avr_txrx_bit ( int fd, int bit ) +{ + unsigned char d; + int r; + + ioctl(fd, PPIGDATA, &d); + + r = ppi_get(fd, PPISTATUS, AVR_DATA); + + if (bit) + ppi_set(fd, PPIDATA, AVR_INSTR); + else + ppi_clr(fd, PPIDATA, AVR_INSTR); + + ppi_toggle(fd, PPIDATA, AVR_CLOCK); + + return r; +} + + +unsigned char avr_txrx ( int fd, unsigned char byte ) +{ + int i; + unsigned char r, b, rbyte; + + rbyte = 0; + for (i=0; i<8; i++) { + b = (byte >> (7-i)) & 0x01; + r = avr_txrx_bit ( fd, b ); + rbyte = rbyte | (r << (7-i)); + } + + return rbyte; +} + + +unsigned char avr_read_byte ( int fd, unsigned short addr, int memtype ) +{ + unsigned char r; + + switch (memtype) { + case AVR_FLASH_LO: + avr_txrx(fd, 0x20); + break; + case AVR_FLASH_HI: + avr_txrx(fd, 0x28); + break; + case AVR_EEPROM: + avr_txrx(fd, 0xa0); + addr &= 0x7f; + break; + default: + fprintf(stderr, "%s: avr_read_byte(); internal error: invalid memtype=%d\n", + progname, memtype); + exit(1); + break; + } + + avr_txrx(fd, addr >> 8); /* high order bits of address */ + avr_txrx(fd, addr & 0x0ff); /* low order bits of address */ + r = avr_txrx(fd, 0); /* don't care */ + + return r; +} + + +int avr_read ( int fd, int memtype, unsigned start, unsigned n, + unsigned char * buf, int bufsize ) +{ + unsigned char rbyte; + unsigned short data; + unsigned short end, i, bi; + + switch (memtype) { + case AVR_FLASH : + case AVR_EEPROM : + 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<end; i++) { + if (memtype == AVR_FLASH) { + rbyte = avr_read_byte(fd, i, AVR_FLASH_LO); /* flash low byte */ + fprintf ( stderr, " \r%4u 0x%02x", i, rbyte ); + data = rbyte; + if (bi < bufsize) { + buf[bi++] = rbyte; + } + + rbyte = avr_read_byte(fd, i, AVR_FLASH_HI); /* flash high byte */ + fprintf ( stderr, " 0x%02x", rbyte ); + data |= (rbyte << 8); + if (bi < bufsize) { + buf[bi++] = rbyte; + } + } + else { + rbyte = avr_read_byte(fd, i, memtype); /* eeprom byte */ + fprintf ( stderr, " \r%4u 0x%02x", i, rbyte ); + if (bi < bufsize) { + buf[bi++] = rbyte; + } + } + + } + + fprintf ( stderr, "\n" ); + + return 0; +} + + +int avr_write_byte ( int fd, int memtype, unsigned short addr, unsigned char data ) +{ + unsigned char r; + int ready; + int tries; + + switch (memtype) { + case AVR_FLASH_LO: + avr_txrx(fd, 0x40); + break; + case AVR_FLASH_HI: + avr_txrx(fd, 0x48); + break; + case AVR_EEPROM: + avr_txrx(fd, 0xc0); + addr &= 0x7f; + break; + default: + fprintf(stderr, "%s: avr_write_byte(); internal error: invalid memtype=%d\n", + progname, memtype); + exit(1); + break; + } + + avr_txrx(fd, addr >> 8); /* high order bits of address */ + avr_txrx(fd, addr & 0x0ff); /* low order bits of address */ + avr_txrx(fd, data); /* data */ + + tries = 0; + ready = 0; + while (!ready) { + usleep(5000); /* flash write delay */ + r = avr_read_byte ( fd, addr, memtype ); + if (data == 0x7f) { + usleep(20000); + ready = 1; + } + else if (r == data) { + ready = 1; + } + tries++; + if (!ready && tries > 10) { + fprintf(stderr, "**" ); + ready = 1; + } + } + + return 0; +} + + +int avr_write ( int fd, int memtype, unsigned start, + unsigned char * buf, int size ) +{ + unsigned char data; + unsigned short end, i, bi; + + switch (memtype) { + case AVR_FLASH : + end = start+size/2; + break; + case AVR_EEPROM : + end = start+size; + break; + default: + fprintf(stderr, "%s: avr_write(); internal error: invalid memtype=%d\n", + progname, memtype); + exit(1); + break; + } + + bi = 0; + + for (i=start; i<end; i++) { + if (memtype == AVR_FLASH) { + /* low byte */ + data = buf[bi++]; + avr_write_byte(fd, AVR_FLASH_LO, i, data ); + fprintf ( stderr, " \r%4u 0x%02x", i, data ); + + /* high byte */ + data = buf[bi++]; + avr_write_byte(fd, AVR_FLASH_HI, i, data ); + fprintf ( stderr, " 0x%02x", data ); + } + else { + data = buf[bi++]; + avr_write_byte(fd, memtype, i, data ); + fprintf ( stderr, " \r%4u 0x%02x", i, data ); + } + + } + + fprintf ( stderr, "\n" ); + + return 0; +} + + +int avr_program_enable ( int fd ) +{ + unsigned char data[4] = {0xac, 0x53, 0x00, 0x00}; + unsigned char byte, rbyte; + int avrok; + int i; + + avrok = 0; + + for (i=0; i<4; i++) { + byte = data[i]; + rbyte = avr_txrx ( fd, byte ); + if (i == 2) { + if (rbyte == data[1]) + avrok = 1; + } + } + + if (!avrok) + return -1; + + return 0; +} + + +int avr_chip_erase ( int fd ) +{ + unsigned char data[4] = {0xac, 0x80, 0x00, 0x00}; + int i; + + for (i=0; i<4; i++) { + avr_txrx ( fd, data[i] ); + } + + usleep(20000); + + return 0; +} + + +int avr_initialize ( int fd ) +{ + int rc; + int tries; + + ppi_clr(fd, PPIDATA, AVR_CLOCK); + ppi_clr(fd, PPIDATA, AVR_RESET); + ppi_toggle(fd, PPIDATA, AVR_RESET); + + usleep(20000); /* 20 ms */ + + tries = 0; + do { + rc = avr_program_enable ( fd ); + if (rc == 0) + break; + ppi_toggle(fd, PPIDATA, AVR_CLOCK); + tries++; + } while (tries < 32); + if (tries == 32) { + fprintf ( stderr, "%s: AVR device not responding\n", progname ); + return -1; + } + return 0; +} + + +int ppi_sense_test ( int fd ) +{ + unsigned char v, pv; + + pv = 1; + do { + v = ppi_get(fd, PPISTATUS, AVR_DATA); + if (v != pv) { + fprintf ( stderr, "PPISTATUS bit = %d\n", v ); + } + pv = v; + } while(1); + + return 0; +} + + + +/* vars for getopt() */ +char *optarg; +int optind; +int optopt; +int opterr; +int optreset; + + +void usage ( void ) +{ + fprintf ( stderr, + "\nUsage: %s [-r] [-e|-f] [-u InputFile|-o Outputfile]\n" + "\n" + " Available Options:\n" + " -r : erase the flash and eeprom (required before programming)\n" + " -e : select eeprom for reading or writing\n" + " -f : select flash for reading or writing\n" + " -u InputFile : write data from this file\n" + " -o OutputFile : write data to this file\n" + "\n", + progname ); +} + + +int main ( int argc, char * argv [] ) +{ + int fd; + int rc; + unsigned char buf[2048]; + int ch; + int iofd; + int flash, eeprom, doread, erase; + int size; + char * outputf; + char * inputf; + + iofd = -1; + outputf = NULL; + inputf = NULL; + doread = 1; + eeprom = 0; + flash = 0; + erase = 0; + + progname = rindex(argv[0],'/'); + if (progname) + progname++; + else + progname = argv[0]; + + while ((ch = getopt(argc,argv,"?efo:ru:")) != -1) { + switch (ch) { + case 'e': + if (flash) { + fprintf(stderr,"%s: -e and -f are incompatible\n", progname); + return 1; + } + eeprom = 1; + break; + case 'r': + erase = 1; + break; + case 'f': + if (eeprom) { + fprintf(stderr,"%s: -e and -f are incompatible\n", progname); + return 1; + } + flash = 1; + break; + case 'o': + if (inputf) { + fprintf(stderr,"%s: -o and -u are incompatible\n", progname); + return 1; + } + doread = 1; + outputf = optarg; + if (strcmp(outputf,"-")==0) { + iofd = fileno(stdout); + } + else { + iofd = open ( outputf, O_WRONLY|O_CREAT|O_TRUNC, + S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); + if (iofd < 0) { + fprintf(stderr, "%s: can't open output file \"%s\": %s\n", + progname, outputf, strerror(errno)); + return 1; + } + } + break; + case 'u': + if (outputf) { + fprintf(stderr,"%s: -o and -u are incompatible\n", progname); + return 1; + } + doread = 0; + inputf = optarg; + iofd = open ( inputf, O_RDONLY, 0); + if (iofd < 0) { + fprintf(stderr, "%s: can't open input file \"%s\": %s\n", + progname, inputf, strerror(errno)); + return 1; + } + break; + case '?': + usage(); + return 1; + break; + default: + fprintf(stderr, "%s: invalid option -%c\n", progname, ch); + usage(); + return 1; + break; + } + } + + fd = open ( PARALLEL, O_RDWR ); + if (fd < 0) { + fprintf ( stderr, "%s: can't open device \"%s\": %s\n", + progname, PARALLEL, strerror(errno) ); + return 1; + } + + fprintf ( stderr, "%s: initializing\n", progname ); + rc = avr_initialize(fd); + if (rc < 0) { + fprintf ( stderr, "%s: initialization failed, rc=%d\n", progname, rc ); + return 1; + } + + fprintf ( stderr, "%s: AVR device initialized and ready to accept instructions\n", + progname ); + + if (erase) { + fprintf(stderr, "%s: erasing chip\n", progname ); + avr_chip_erase(fd); + avr_initialize(fd); + fprintf(stderr, "%s: done.\n", progname ); + } + + if (iofd < 0) { + fprintf(stderr, "%s: you must specify an input or an output file\n", + progname); + return 1; + } + + if (!(eeprom||flash)) { + fprintf(stderr, + "%s: please specify either the eeprom (-e) or the flash (-f) memory\n", + progname); + return 1; + } + + if (doread) { + /* + * read device memory + */ + if (flash) { + size = 2048; + fprintf ( stderr, "%s: reading flash memory:\n", progname ); + rc = avr_read ( fd, AVR_FLASH, 0, size/2, buf, size ); + if (rc) { + fprintf ( stderr, "%s: failed to read all of flash memory, rc=%d\n", + progname, rc ); + return 1; + } + } + else if (eeprom) { + size = 128; + fprintf ( stderr, "%s: reading eeprom memory:\n", progname ); + rc = avr_read ( fd, AVR_EEPROM, 0, size, buf, size ); + if (rc) { + fprintf ( stderr, "%s: failed to read all of eeprom memory, rc=%d\n", + progname, rc ); + return 1; + } + } + + rc = write ( iofd, buf, size ); + if (rc < 0) { + fprintf(stderr, "%s: write error: %s\n", progname, strerror(errno)); + return 1; + } + else if (rc != size) { + fprintf(stderr, "%s: wrote only %d bytes of the expected %d\n", + progname, rc, size); + return 1; + } + } + else { + /* + * write device memory + */ + if (flash) { + size = 2048; + } + else if (eeprom) { + size = 128; + } + + /* read in the data file */ + rc = read(iofd, buf, size); + if (rc < 0) { + fprintf(stderr, "%s: read error from \"%s\": %s\n", + progname, inputf, strerror(errno)); + return 1; + } + else if (rc != size) { + fprintf(stderr, "%s: read only %d bytes of the expected %d from \"%s\"\n", + progname, rc, size, inputf); + return 1; + } + + if (flash) { + fprintf ( stderr, "%s: writing flash memory:\n", progname ); + rc = avr_write ( fd, AVR_FLASH, 0, buf, size ); + if (rc) { + fprintf ( stderr, "%s: failed to write flash memory, rc=%d\n", + progname, rc ); + return 1; + } + } + else if (eeprom) { + fprintf ( stderr, "%s: writing eeprom memory:\n", progname ); + rc = avr_write ( fd, AVR_EEPROM, 0, buf, size ); + if (rc) { + fprintf ( stderr, "%s: failed to write eeprom memory, rc=%d\n", + progname, rc ); + return 1; + } + } + } + + close(fd); + close(iofd); + + return 0; +} + +