/* * 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 #include #include #include #include #include #include #include #include #include #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> 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