#include #include // #include /* in case including i2c.h causes errors, comment out the line above, * and uncomment the one below: */ #define I2C_SLAVE 0x0703 #include #include #include #define MODE_READ 1 #define MODE_WRITE 2 #define MODE_ERASE 3 #define MODE_ID 4 #define MODE_TEST 5 #define STATE_SLEEP 1000 //us #define WRITE_SLEEP 200 //us #define WRITE_TIMEOUT 2000 //us #define RST 192 #define RST_L 192 #define RST_H 128 #define RST_12 0 #define XTAL 32 #define P3_1 16 #define P3_2 8 #define P3_3 4 #define P3_4 2 #define P3_5 1 #define P3_7 1 int pcfbase = 0x20; int curpcf = 0; int dev; char val[2] = {0, 0}; int verbose = 0; int progressbar = 0; // int getopt(int argc, char * const argv[], // const char *optstring); char opt; extern char *optarg; typedef struct s_product_id { char manfid; char prodid; char *desc; int size; } product_id; product_id products[] = { {0x1e, 0x11, "Atmel AT89C1051", 1024}, {0x1e, 0x23, "Atmel AT89C2051", 2048}, {0x1e, 0x21, "Atmel AT89C2051", 2048}, {0x1e, 0x41, "Atmel AT89C4051", 4096}, {0x0, 0x11, "Atmel AT89C1051", 1024}, {0x0, 0x21, "Atmel AT89C2051", 2048}, {0x0, 0x41, "Atmel AT89C4051", 4096}, {0, 0, NULL, 0}, }; product_id chip; #define debug(x, ...) if (verbose > x) { int i; for (i=0; i 2) { int i, p = 1; for (i = 0; i < 8; i++ ) bin[i] = ((buf[0] >> (7-i)) % 2 ? '1' : '0'); debug(2, "Write 0b%s to PCF%d", bin, pcf); } } char get_val(int pcf) { static char buf[2]; static char bin[9] = "12345678"; set_slave(pcf); buf[1] = 0; if (!read(dev, buf, 1)) { perror("read"); exit(1); } if (verbose > 2) { int i, p = 1; for (i = 0; i < 8; i++ ) bin[i] = ((buf[0] >> (7-i)) % 2 ? '1' : '0'); debug(2,"Read 0b%s (0x%hhx) from PCF%d", bin, buf[0], pcf); } return buf[0]; } int init(char *device) { static char b1, b2; debug(0, "Initializing..."); debug(1, "Opening device"); if (!(dev = open(device, O_RDWR|O_EXCL))) { perror("open device"); exit(1); } // check if pcf are responding debug(1, "all PCF outputs := H"); set_val(0, 0xff, 0xff); set_val(1, 0xff, 0xff); // set rst high debug(1, "RST := H"); set_val(1, RST_H, RST); b1 = get_val(0); if (~b1) { printf("Programmer not responding. Maybe you should use/not use -a option?\n"); exit(1); } debug(1, "RST := L"); set_val(1, RST_L, RST); return dev; } void shutdown() { // all pins high (set rst low) debug(0, "Turning uc off"); usleep(STATE_SLEEP); set_val(1, 0xff, 0xff); set_val(0, 0xff, 0xff); usleep(STATE_SLEEP); } void pulse_xtal() { // pulse xtal1 debug(1, "Pulse XTAL1"); set_val(1, XTAL, XTAL); usleep(10); set_val(1, 0, XTAL); } help() { printf("*** Atmel 89Cx051 programmer\n"); printf("*** (c) 2004-2006 Sebastian Zagrodzki\n"); printf("*** http://sokrates.mimuw.edu.pl/~sebek/atmelprog/\n"); printf("*** This software is provided under terms and conditions of GNU GPL license\n"); printf("Options:\n" " -r - read data from flash to \n" " -w - write data from to flash\n" " -W - like -w, with verification\n" " -d - use instead of /dev/i2c0\n" " -s - specify flash size manually\n" " -a - programmer is using PCF8574A chip\n" " -e - erase chip\n" " -h - this help\n" " -v - verbose mode (use multiple to increase verbosity)\n" " -p - show progress bar during read/write\n" " -i - get chip ID\n" " -t - programmer diagnostics\n" ); exit(0); } product_id get_manfid(int size) { char buf[2]; int i; debug(0, "Getting manufacturer's and product's ID"); debug(1, "RST (7&8) and XTAL (6) := L"); set_val(1, RST_L|0, RST|XTAL); usleep(STATE_SLEEP); debug(1, "RST := H (7&8), P3.2 (4) := H"); set_val(1, RST_H|P3_2, RST|P3_2); usleep(STATE_SLEEP); debug(1, "Mode - read signature: P3.3 (3), 3.4 (2), 3.5, 3.7 (1) := L"); set_val(1, 0|0|0|0, P3_3|P3_4|P3_5|P3_7); usleep(STATE_SLEEP); buf[0] = get_val(0); pulse_xtal(); buf[1] = get_val(0); for (i = 0; products[i].desc; i++) { if ((products[i].manfid == buf[0]) && (products[i].prodid == buf[1])) { chip = products[i]; break; } } if (!products[i].desc) { printf("Unknown uc chip: %hhx, %hhx\n", buf[0], buf[1]); chip.desc = "Unknown"; if ((buf[0] == (char)0xff) && (buf[1] == (char)0xff)) printf("No uC found?\n"); if (size) { chip.size = size; return chip; } else { printf("Please use \"-s\" option\n"); chip.size = 0; return chip; } } printf("Known uC chip (%hhx, %hhx): %s\n", buf[0], buf[1], chip.desc); if (size) { chip.size = size; printf("Flash size (user): %d\n", size); } else printf("Flash size: %d\n", chip.size); return chip; } void init_read() { debug(0, "Initializing read mode"); debug(1, "RST and XTAL1 L"); set_val(1, RST_L, RST|XTAL); usleep(STATE_SLEEP); debug(1, "Mode read - 3.3, 3.4 L, 3.5, 3.7 H"); set_val(1, P3_5|P3_7, P3_3|P3_4|P3_5|P3_7); usleep(STATE_SLEEP); debug(1, "RST and P3.2 H"); set_val(1, RST_H|P3_2, RST|P3_2); usleep(STATE_SLEEP); } void do_read(int fd, int size) { int i; char buf[2]; float add, sum = 0; int noofdots = 0, lastten = 1; add = 50 / (float)size; debug(0, "Reading flash: %d bytes", size); // read buf[1] = '\0'; if (progressbar) { printf("0%%"); fflush(stdout); } for (i = 0; i < size; i++) { buf[0] = get_val(0); if (!write(fd, buf, 1)) { perror("write to output file"); exit(1); } pulse_xtal(); if (progressbar) { sum += add; while (sum > noofdots) { printf("."); noofdots++; if ((noofdots % 10) == 0) { printf("%d0%%", 2*lastten); lastten++; } fflush(stdout); } } } printf("\n"); } void do_erase() { debug(0, "Erasing chip"); debug(1, "RST and XTAL1 L"); set_val(1, RST_L, RST|XTAL); usleep(STATE_SLEEP); debug(1, "RST and P3.2 H"); set_val(1, RST_H|P3_2, RST|P3_2); usleep(STATE_SLEEP); debug(1, "Mode erase - P3.3 H, P3.4, 3.5, 3.7 L"); set_val(1, P3_3, P3_3|P3_4|P3_5|P3_7); usleep(STATE_SLEEP); debug(1, "RST 12v"); set_val(1, RST_12, RST); usleep(STATE_SLEEP); debug(1, "P3.2 L for 20ms"); set_val(1, 0, P3_2); usleep(20000); debug(1, "RST L"); set_val(1, RST_L, RST); usleep(STATE_SLEEP); } void user_wait() { static char tmp[3]; printf(" ENTER to continue."); fgets(tmp, 2, stdin); } void diagnostics() { printf("**************************************************************************\n" "Remove uC from the stand. Power led should be now\n" "Measure voltages between given pins and GND.\n" "I assume that your I2C controller works properly.\n" "*************************************************************************\n\n"); user_wait(); set_val(0, 0, 0xff); set_val(1, RST_L, 0xff); printf("Busy led should be off. All pins except p20 = 0v. p20 = 5v."); user_wait(); set_val(1, RST_H, RST); printf("Busy led should be lit. RST (p1) = 5v."); user_wait(); set_val(1, RST_12, RST); printf("Busy led should be brightly lit. RST (p1) = 12v."); user_wait(); set_val(1, RST_L|XTAL, 0xff); printf("Busy led should be off. RST (p1) = 0v. XTAL1 (p5) = H."); user_wait(); set_val(1, RST_L|P3_1, 0xff); printf("XTAL1 (p5) = L. P3.1 (p3) = H."); user_wait(); set_val(1, RST_L|P3_2, 0xff); printf("P3.1 (p3) = L. P3.2 (p6) = H."); user_wait(); set_val(1, RST_L|P3_3, 0xff); printf("P3.2 (p6) = L. P3.3 (p7) = H."); user_wait(); set_val(1, RST_L|P3_4, 0xff); printf("P3.3 (p7) = L. P3.4 (p8) = H."); user_wait(); set_val(1, RST_L|P3_5|P3_7, 0xff); printf("P3.4 (p8) = L. P3.5 (p9) = H. P3.7 (p11) = H."); user_wait(); set_val(1, RST_L, 0xff); printf("All pins except p20 = 0v."); user_wait(); set_val(0, 0xaa, 0xff); printf("Odd data pins (p19, p17, p15, p13) = H\n"); printf("Even data pins (p18, p16, p14, p12) = L\n"); user_wait(); set_val(0, 0x55, 0xff); printf("Odd data pins (p19, p17, p15, p13) = L\n"); printf("Even data pins (p18, p16, p14, p12) = H\n"); user_wait(); printf("Test complete.\n"); } void init_write() { debug(0, "Initializing write mode"); debug(1, "RSH := H, Prog := H"); set_val(1, RST_H|P3_2, RST|P3_2); usleep(STATE_SLEEP); debug(1, "Mode := Write : 3.3 L, 3.4, 3.5, 3.7 H"); set_val(1, P3_4|P3_5|P3_7, P3_3|P3_4|P3_5|P3_7); usleep(STATE_SLEEP); } void do_write(int file, int verify, int size) { char buf[2]; int i; float add, sum = 0; int noofdots = 0, lastten = 1; add = 50 / (float)size; buf[2] = '\0'; debug(0, "Writing flash"); if (verify) debug(0, "Will verify each byte during write"); if (progressbar) { printf("0%%"); fflush(stdout); } debug(2, "Raise RST 12v"); set_val(1, RST_12, RST); while (i = read(file, buf, 1)) { int time = 0; debug(2, "Set PCF0 data"); set_val(0, buf[0], 0xff); debug(2, "Pulse 3.2 (3.2 := L)"); set_val(1, 0, P3_2); usleep(20); debug(2, "Pulse 3.2 (3.2 := H)"); set_val(1, P3_2, P3_2); // poll BUSY bit do { usleep(WRITE_SLEEP); time += WRITE_SLEEP; if (time > WRITE_TIMEOUT) { printf("Timeout while polling BUSY bit\n"); shutdown(); exit(1); } } while (!(get_val(1) & P3_1)); if (verify) { char r; // lower rst to 5v debug(1, "RST := H"); set_val(1, RST_H, RST); debug(1, "EPROM mode to read - P3.4 := L"); // set eprom mode to read - p3.5, p3.7 -> h set_val(1, 0, P3_4); r = get_val(0); if (r != buf[0]) { printf("Verification failed: written 0x%hhx, read 0x%hhx\n", buf[0], r); shutdown(); exit(1); } // set eprom mode to write - p3.3 l, p3.{4,5,7} h debug(1, "EPROM mode to write - P3.4 := H"); set_val(1, P3_4, P3_4); debug(1, "RST := 12v"); set_val(1, RST_12, RST); } pulse_xtal(); if (progressbar) { sum += add; while (sum > noofdots) { printf("."); noofdots++; if ((noofdots % 10) == 0) { printf("%d0%%", 2*lastten); lastten++; } fflush(stdout); } } } printf("\n"); } void ctrlc(int i) { printf("Signal caught\n"); shutdown(); exit(0); } main(int argc, char **argv) { int mode = 0, verify; char *filename; char *device = "/dev/i2c0"; int flashsize = 0; int ignsize = 0; while ((opt = getopt(argc, argv, "r:w:W:d:s:eihvfapt")) > 0) { switch (opt) { case 'r': case 'w': case 'W': case 'e': case 'i': case 't': if (mode) { printf("Options r, w, W, e, t and i are mutually exclusive\n"); exit(1); } mode = MODE_READ; verify = (opt == 'W'); if ((opt == 'W')||(opt == 'w')||(opt == 'r')) filename = optarg; switch (opt) { case 'r': mode = MODE_READ; break; case 'w': case 'W': mode = MODE_WRITE; break; case 'e': mode = MODE_ERASE; break; case 'i': mode = MODE_ID; break; case 't': mode = MODE_TEST; break; } break; case 'h': help(); case 'v': verbose++; break; case 'p': progressbar = 1; break; case 'd': device = optarg; break; case 'f': ignsize = 1; break; case 's': flashsize = atoi(optarg); break; case 'a': pcfbase = 0x38; break; case ':': case '?': exit(1); } } if (mode == 0) { printf("No mode specified\n"); help(); } signal(2, ctrlc); init(device); if (mode == MODE_ID) { get_manfid(flashsize); } else if (mode == MODE_ERASE) { chip = get_manfid(flashsize); do_erase(); } else if (mode == MODE_TEST) { diagnostics(); } else if (mode == MODE_READ) { int file; chip = get_manfid(flashsize); debug(0, "Opening output file"); if (!(file = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0666))) { perror("open output file"); exit(1); } init_read(); do_read(file, chip.size); debug(0, "Closing file"); close(file); } else if (mode == MODE_WRITE) { int file; struct stat s; debug(0, "Opening input file"); if (!(file = open(filename, O_RDONLY))) { perror("open input file"); exit(1); } chip = get_manfid(flashsize); debug(0, "Comparing file and flash size"); if (fstat(file, &s)) { perror("stat input file"); exit(1); } printf("File size: %d\n", s.st_size); if (s.st_size > chip.size) if (ignsize) { printf("WARNING! Program size > flash size. Ignoring due to -f option\n"); } else { printf("WARNING! Program size > flash size. Use -f to override\n"); exit(1); } do_erase(); init_write(); do_write(file, verify, s.st_size); debug(0, "Closing input file"); close(file); } shutdown(); return 0; }