#include #include #include #include #include #include #define DEVICE "/dev/usb/tts/0" #define BAUDRATE B38400 #define TIMEOUT 1000 struct chip_ { char shortname[8]; char longname[16]; char signature[3]; char devicecode; int flash_size; int eeprom_size; }; typedef struct chip_ CHIP; CHIP chips[] = { { "1200", "AT90S1200", { 0x00, 0x90, 0x1E }, 0x13, 0x200, 0x40 }, { "2313", "AT90S2313", { 0x01, 0x91, 0x1E }, 0x12, 0x400, 0x80 }, // unknown devicecode! { "8515", "AT90S8515", { 0x01, 0x93, 0x1E }, 0x38, 0x1000, 0x200 }, { "m103", "ATMega103", { 0x00, 0x00, 0x00 }, 0x41, 0x20000, 0x1000 }, { "m128", "ATMega128", { 0x00, 0x00, 0x00 }, 0x00, 0x20000, 0x1000 }, // unknown devicecode! { "\0", "\0", { 0, 0, 0 }, 0, 0, 0 } }; #define F_FLASH 0x01 #define F_FLASH_FILE 0x02 #define F_EEPROM 0x04 #define F_EEPROM_FILE 0x08 #define F_VERIFY 0x10 #define F_RESET 0x20 struct _cfg { int mode; CHIP *avr; char *flash_file; int fd_flash; char *eeprom_file; int fd_eeprom; char *ser_device; int fd_ser; struct termios oldtio; } cfg; int debug = 0; int isp_check(int fd) { char buf[8]; write(fd, "S", 1); read_ser(fd, buf, 7); if (debug) printf(" (expected: 'AVR ISP', got: '%7s')\n", buf); return strncmp(buf, "AVR ISP", 7); } int isp_set_device(int fd, char device) { char buf[2]; buf[0] = 'T'; buf[1] = device; write(fd, buf, 2); read_ser(fd, buf, 1); if (debug) printf(" (expected: '0x0D', got: '0x%X')\n", buf[0]); return (buf[0] != 0x0D); } int isp_enter_progmode(int fd) { char buf; write(fd, "P", 1); read_ser(fd, &buf, 1); if (debug) printf(" (expected: '0x0D', got: '0x%X')\n", buf); return (buf != 0x0D); } int isp_led(int fd, int mode) { char buf= (mode == 0) ? 'y' : 'x'; write(fd, &buf, 1); read_ser(fd, &buf, 1); if (debug) printf(" (expected: '0x0D', got: '0x%X')\n", buf); return (buf != 0x0D); } void isp_led_off() { isp_led(cfg.fd_ser, 0); } int isp_check_sig(int fd, char *sig) { char buf[3]; write(fd, "s", 1); read_ser(fd, buf, 3); if (debug) printf(" (expected: '0x%X 0x%X 0x%X', got: '0x%X 0x%X 0x%X')\n", (*sig & 0xFF), (*(sig+1) & 0xFF), (*(sig+2) & 0xFF), (buf[0] & 0xFF), (buf[1] & 0xFF), (buf[2] & 0xFF)); return !((buf[0] & 0xFF) == (*sig & 0xFF) && (buf[1] & 0xFF) == (*(sig+1) & 0xFF) && (buf[2] & 0xFF) == (*(sig+2) & 0xFF)); } int isp_chip_erase(int fd) { char buf; write(fd, "e", 1); read_ser(fd, &buf, 1); if (debug) printf(" (expected: '0x0D', got: '0x%X')\n", buf); return (buf != 0x0D); } int isp_leave_progmode(int fd) { char buf; write(fd, "L", 1); read_ser(fd, &buf, 1); if (debug) printf(" (expected: '0x0D', got: '0x%X')\n", buf); return (buf != 0x0D); } int isp_set_address(int fd, int addr) { char buf[3]; buf[0] = 'A'; buf[1] = (addr >> 8) & 0xFF; buf[2] = addr & 0xFF; write(fd, buf, 3); read_ser(fd, buf, 1); return (buf[0] != 0x0D); } int isp_prg_flash(int fd, char *buf) { char outbuf[2]; char ret[2]; outbuf[0] = 0x63; outbuf[1] = *buf & 0xFF; write(fd, outbuf, 2); read_ser(fd, &ret[0], 1); outbuf[0] = 0x43; outbuf[1] = *(buf +1) & 0xFF; write(fd, outbuf, 2); read_ser(fd, &ret[1], 1); return !(ret[0] == 0x0D && ret[1] == 0x0D); } int isp_verify_flash(int fd, char *buf) { char inbuf[2]; write(fd, "R", 1); read_ser(fd, inbuf, 2); if (debug) printf(" (expected: '0x%X 0x%X', got: '0x%X 0x%X')\n", (*buf & 0xFF), (*(buf+1) & 0xFF), (inbuf[1] & 0xFF), (inbuf[0] & 0xFF)); return !((inbuf[1] & 0xFF) == (*buf & 0xFF) && (inbuf[0] & 0xFF) == (*(buf+1) & 0xFF)); } int isp_prg_eeprom(int fd, char val) { char buf[2]; buf[0] = 'D'; buf[1] = val & 0xFF; write(fd, buf, 2); read_ser(fd, buf, 1); return (buf[0] != 0x0D); } int isp_verify_eeprom(int fd, char val) { char buf; write(fd, "d", 1); read_ser(fd, &buf, 1); if (debug) printf(" (expected: '0x%X', got: '0x%X')\n", (val & 0xFF), (buf & 0xFF)); return (val != buf); } void init_ser() { struct termios newtio; /* open rs232-device */ if ((cfg.fd_ser = open(cfg.ser_device, O_RDWR | O_NOCTTY | O_NONBLOCK)) <= 0) { perror("init_ser(): open()"); exit(-1); } /* save old settings */ if (tcgetattr(cfg.fd_ser, &cfg.oldtio) != 0) { perror("init_ser(): tcgetattr()"); exit(-1); } /* alte settings on exit wiederherstellen */ if (atexit(close_ser) != 0) { perror("init_ser(): atexit()"); exit(-1); } /* neue settings */ bzero(&newtio, sizeof(newtio)); newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD; newtio.c_iflag = IGNPAR; newtio.c_oflag = 0; newtio.c_lflag = 0; /* set input mode (non-canonical, no echo,...) */ newtio.c_cc[VTIME] = 100; /* inter-character timer unused */ newtio.c_cc[VMIN] = 100; /* blocking read until 5 chars received */ /* buffer flushen */ tcflush(cfg.fd_ser, TCIOFLUSH); /* neue settings schreiben */ if (tcsetattr(cfg.fd_ser, TCSANOW, &newtio) != 0) { perror("init_ser(): tcsetattr()"); exit(-1); } } void close_ser() { tcsetattr(cfg.fd_ser, TCSANOW, &cfg.oldtio); close(cfg.fd_ser); } ssize_t read_ser(int fd, void *buf, size_t count) { int timeouts = 10; int mytimeout = TIMEOUT; size_t myread = 0; ssize_t retval; while (count > 0 && timeouts > 0) { usleep(mytimeout); retval = read(fd, buf + myread, count); if (retval > 0) { myread+= retval; count-= retval; } timeouts--; mytimeout*= 2; } return myread; } void show_usage() { CHIP *p = chips; printf("USAGE:\n"); printf(" isp_down [OPTIONS] \n\n"); printf("OPTIONS:\n"); printf(" -avr selects AVR-device\n"); while (p->shortname[0] != 0) { printf(" %s -> %s %6d byte FLASH %4d byte EEPROM\n", p->shortname, p->longname, p->flash_size, p->eeprom_size); p++; } printf(" -dev selects RS232-device (default: "DEVICE")\n"); printf(" -flash Write (1st) file to FLASH\n"); printf(" -eeprom Write (2nd) file to EEPROM\n"); printf(" -verify Verify writing\n"); printf(" -reset Only resets AVR\n"); printf(" -debug Prints debugging Information\n"); } int main(int argc, char *argv[]) { CHIP *p; int arg; /* Usage anzeigen */ if (argc <= 1) { show_usage(); exit(-1); } /* cfg structur loeschen */ bzero(&cfg, sizeof(cfg)); cfg.ser_device = DEVICE; for (arg = 1; arg < argc; arg++) { if (!strcmp(argv[arg], "-avr")) { /* check AVR-device */ if (++arg == argc) { printf("ERROR: No AVR-Device\n\n"); exit(-1); } /* shortname suchen */ p = chips; while (p->shortname[0] != 0) { if (!strcmp(argv[arg], p->shortname)) { cfg.avr = p; break; } p++; } if (cfg.avr == NULL) { printf(" ERROR: Unknown AVR-Device\n"); exit(-1); } } else if (!strcmp (argv[arg], "-dev")) { /* check RS232 device */ if (++arg == argc) { printf(" ERROR: No RS232-device\n"); exit(-1); } cfg.ser_device = argv[arg]; } else if (!strcmp (argv[arg], "-flash")) { /* check flash */ if (++arg == argc) { printf(" ERROR: No FLASH File\n"); exit(-1); } cfg.mode |= F_FLASH; cfg.flash_file = argv[arg]; } else if (!strcmp (argv[arg], "-eeprom")) { /* check eeprom */ if (++arg == argc) { printf(" ERROR: No EEPROM File\n"); exit(-1); } cfg.mode |= F_EEPROM; cfg.eeprom_file = argv[arg]; } else if (!strcmp (argv[arg], "-verify")) { /* check verify */ cfg.mode |= F_VERIFY; } else if (!strcmp (argv[arg], "-reset")) { /* check reset */ cfg.mode |= F_RESET; } else if (!strcmp (argv[arg], "-debug")) { /* check debug */ debug= 1; } else { /* wrong parameter */ printf(" ERROR: Unknown parameter\n"); exit(-1); } } if (!(cfg.mode & (F_FLASH | F_EEPROM | F_RESET))) { printf (" ERROR: Nothing to do\n"); exit(-1); } if (cfg.mode & F_FLASH) { if ((cfg.fd_flash = open(cfg.flash_file, O_RDONLY)) <= 0) { perror("init_files(): open(flash_file)"); exit(-1); } } if (cfg.mode & F_EEPROM) { if ((cfg.fd_eeprom = open(cfg.eeprom_file, O_RDONLY)) <= 0) { perror("init_files(): open(eeprom_file)"); exit(-1); } } init_ser(); /* checken ob ein adapter vorhanden ist */ printf("checking avrisp\n"); if (isp_check(cfg.fd_ser)) { printf(" ERROR: avr isp adapter not found\n"); exit(-1); } /* device code setzen */ printf("setting device code for %s\n", cfg.avr->longname); if (isp_set_device(cfg.fd_ser, cfg.avr->devicecode)) { printf(" ERROR: could not set device type\n"); exit(-1); } /* progammiermodus */ printf("entering programming mode\n"); if (isp_enter_progmode(cfg.fd_ser)) { printf(" ERROR: could not enter programming mode\n"); exit(-1); } /* rote led an */ isp_led(cfg.fd_ser, 1); atexit(isp_led_off); /* signatur checken */ printf("checking signature\n"); if (isp_check_sig(cfg.fd_ser, cfg.avr->signature)) { printf(" ERROR: wrong signature\n"); exit(-1); } /* chip loeschen */ if (cfg.mode & (F_FLASH | F_EEPROM)) { printf("erase flash & eeprom\n"); if (isp_chip_erase(cfg.fd_ser)) { printf(" ERROR: chip erase failed\n"); exit(-1); } } /* progmode verlassen */ if (cfg.mode & (F_FLASH | F_EEPROM | F_RESET)) { printf("resetting device\n"); if (isp_leave_progmode(cfg.fd_ser)) { printf(" ERROR: device reset failed\n"); exit(-1); } } /* -reset abgeschlossen */ if (cfg.mode & F_RESET) { exit(0); } /* progammiermodus erneut aufrufen, da zwischenzeitlich reset */ if (cfg.mode & (F_FLASH | F_EEPROM)) { printf("entering programming mode\n"); if (isp_enter_progmode(cfg.fd_ser)) { printf(" ERROR: could not enter programming mode\n"); exit(-1); } } if (cfg.mode & F_FLASH) { int addr= 0; char buf[2]; printf("programming flash\n"); while ((read(cfg.fd_flash, buf, 2) > 0) && (addr < (cfg.avr->flash_size/2))) { if (isp_set_address(cfg.fd_ser, addr)) { printf(" ERROR: could not set address %d\n", addr); exit(-1); } if (isp_prg_flash(cfg.fd_ser, buf)) { printf(" ERROR: programming failed on addr %d\n", addr); exit(-1); } addr++; } printf("programming flash successful\n"); if (cfg.mode & F_VERIFY) { addr= 0; lseek(cfg.fd_flash, 0, SEEK_SET); printf("verify flash\n"); while ((read(cfg.fd_flash, buf, 2) > 0) && (addr < (cfg.avr->flash_size/2))) { if (isp_set_address(cfg.fd_ser, addr)) { printf(" ERROR: could not set address %d\n", addr); exit(-1); } if (isp_verify_flash(cfg.fd_ser, buf)) { printf(" ERROR: verify failed on addr %d\n", addr); exit(-1); } addr++; } printf("verify flash successful\n"); } } if (cfg.mode & F_EEPROM) { int addr= 0; char buf; printf("programming eeprom\n"); while ((read(cfg.fd_eeprom, &buf, 1) > 0) && (addr < cfg.avr->eeprom_size)) { if (isp_set_address(cfg.fd_ser, addr)) { printf(" ERROR: could not set address %d\n", addr); exit(-1); } if (isp_prg_eeprom(cfg.fd_ser, buf)) { printf(" ERROR: programming failed on addr %d\n", addr); exit(-1); } addr++; } printf("programming eeprom successful\n"); if (cfg.mode & F_EEPROM) { addr= 0; lseek(cfg.fd_eeprom, 0, SEEK_SET); printf("verify eeprom\n"); while ((read(cfg.fd_eeprom, &buf, 1) > 0) && (addr < cfg.avr->eeprom_size)) { if (isp_set_address(cfg.fd_ser, addr)) { printf(" ERROR: could not set address %d\n", addr); exit(-1); } if (isp_verify_eeprom(cfg.fd_ser, buf)) { printf(" ERROR: verify failed on addr %d\n", addr); exit(-1); } addr++; } printf("verify eeprom successful\n"); } } /* progmode verlassen */ printf("resetting device\n"); if (isp_leave_progmode(cfg.fd_ser)) { printf(" ERROR: device reset failed\n"); exit(-1); } exit(0); }