Date: Mon, 07 Jul 1997 10:03:43 -0800 From: P. Faasse To: Multiple recipients of list CHIPDIR-L Subject: RE: NM93C46 Daniel Roganti asked: > Anyone know of a PC utility to program a 93C46 EEPROM Microwire > bus via the parallel port. Either MSDOS or Windows is OK. > thanks, Daniel Your question was the last push I needed to start on my long-postponed 93CX6 programmer. I have got a working prototype, including program code. I am no windows fanatic (rather unix-oriented) so do not expect any fancy user interface. Reading and erasing of 93C06 and 93C46 eeproms has been tested. I can write data to the eeprom, but I still have to hardcode the data bytes in the program source. Reading, writing and erasing are all the functions I intend to implement. This contraption does however not work via the parallel port, but via the RS-232 port. The parallel port has to the best of my knowledge no reliable +5V supply. The RS-232 ports have +/- 12 Volts (ideal case) available. The contraption I made has the following system layout: (I hope you can reas ASCII schematics...) RS232: 3 x Shottky diode RTS ------|>|-----+ +-----------+ | | 78L05 | sys 5 Volts DSR ------|>|-----+-----+-------+in out+----+--- | | | gnd | | TXD ------|>|-----+ === +-----+-----+ === --- 220uF | --- 10uF gnd -----+ | 16V | | 10V | | | | gnd gnd gnd gnd Power supply part of the 93CX6 programmer ----------------------------------------- This part makes a stabilized 5 Volts supply (sys 5 Volts) from three of the RS-232 output signals. RTS, DSR, TXD and GND are RS-232 signal names. For each of the signals RTS, DSR and TXD the following circuit: Shottky diode +-------|>|-----+ sys 5 Volts 10KOhm | TXD +-------+ SI-diode | SK of 93Cxx DTR ------+ +----|>|----+---------------+ CS of 93Cxx RTS +-------+ | DI of 93Cxx +++ | | | | 10 KOhm +++ | | gnd Level converter for 93CX6 programmer ------------------------------------ This little circuit limits the +/- 12 Volts of the RS232 line to 0 .. 5 Volts levels for the eeprom. Each of the signals TXD, DTR and RTS must be provided with such a circuit. TXD --> SK; DTR --> CS; RTS --> DI of the 93Cx6. The output of the 93cx6 to the serial port is extremely simple: DO of 93CX6 --------- RS232 CTS signal Output circuit of the 93CX6 programmer -------------------------------------- I use the following program to control this thing: >>>>>>>>>>>>>>>>> start of program <<<<<<<<<<<<<<<<<< /* 93C46 programmer for RS232 serial I/O programmer The system configuration is the following: A small programmer is connected to the RS232 serial port The modem control lines are used to control the 4 I/O lines of the 93C46 */ #include /* global defines */ /* 8250 registers */ int rbr = 0x00; /* receiver buffer register */ int thr = 0x00; /* transmitter holding register */ int ier = 0x01; /* interrupt enable register */ int iir = 0x02; /* interrupt indentifiacion register */ int lcr = 0x03; /* line control register */ int mcr = 0x04; /* modem control register */ int lsr = 0x05; /* line status register */ int msr = 0x06; /* modem status register */ int csr = 0x07; /* scratch register */ int dll = 0x00; /* divisor latch low */ int dlm = 0x01; /* divisor latch high */ /* 93C46 programmer's use of the registers */ /* masks in output register */ int csm = 0x01; /* CS bit mask (really DTR) */ int dim = 0x02; /* DI bit mask (really RTS) */ /* masks in input register */ int dom = 0x10; /* DO bit mask (really CTS) */ /* I/O adressen */ int inadr,outadr,stsadr;/* for data I/O */ int cladr; /* address for clock pulse */ /* 93C46 command codes */ int eeread = 0x80; /* read opcode | adres */ int eewen = 0x30; /* write enable */ int eeerase = 0xc0; /* erase opcode | adres */ int eewrite = 0x40; /* write opcode | adres */ int eeerall = 0x20; /* erase all opcode */ int eewrall = 0x10; /* write all opcode */ int eewdis = 0x00; /* write disable */ main(argc,argv) int argc; /* command parameter count */ char *argv[]; /* command parameters */ {int portbase = 0x3f8; /* serial port base address */ unsigned int databuf[256]; /* data I/O buffer */ int tmp; /* temporary use */ int dataptr; /* data buffer pointer */ int eeadres; /* eeprom address */ int lastadr = 16; /* last address in eeprom */ /* actions to perform */ int doread = 0; /* do read if != 0 */ int dowrite = 0; /* do write if != 0 */ int doerase = 0; /* do erase if != 0 */ int dover = 0; /* give version info if != 0 */ /* a file interface for writing */ FILE *fp; /* write file file pointer */ /* declare the functions/subroutines */ void setcs(); /* set the cs input */ void clrcs(); /* clear the cs input */ void setdi(); /* set the di input */ void clrdi(); /* clear the di input */ void pulscl(); /* pulse the sk input */ int readdo(); /* sample do pin */ void delay(); /* generate setup delay time */ void writecommand(); /* write a command to the eeprom */ void writedata(); /* write data to the eeprom */ void waitready(); /* wait till eeprom ready */ unsigned int readdata(); /* read data from eeprom */ /* state save registers for the 8250 */ int sier,slcr,smcr,sdll,sdlm; /* the values I found on entry */ /* read the command line parameters */ if (argc == 1) { fprintf(stderr,"\n"); fprintf(stderr,"Usage: %s [/t{0|4|5|6}] [/c{1|2}] [/r] [/e] [/w ]\n",argv[0]); fprintf(stderr,"/t = type of eeprom, 0 -> NM93C06, 4 -> NM93C46 etc.., default = NM93C06\n"); fprintf(stderr,"/c = COM port to use, 1 -> COM1, 2 -> COM2, default = COM1\n"); fprintf(stderr,"/r = read eeprom\n"); fprintf(stderr,"/e = erase eeprom\n"); fprintf(stderr,"/w = write file to eeprom\n"); fprintf(stderr,"/v = version info\n"); exit(1); } /* do real command-line parsing */ tmp = 1; while (tmp < argc) { if (strcmp(argv[tmp],"/t0") == 0) { lastadr = 16; } else { if (strcmp(argv[tmp],"/t4") == 0) { lastadr = 64; } else { if (strcmp(argv[tmp],"/t5") == 0) { printf("93C56 not (yet) supported\n"); exit(1); lastadr = 128; } else { if (strcmp(argv[tmp],"/t6") == 0) { printf("93C66 not (yet) supported\n"); exit(1); lastadr = 256; } else { if (strcmp(argv[tmp],"/c1") == 0) { portbase = 0x3F8; } else { if (strcmp(argv[tmp],"/c2") == 0) { portbase = 0x2F8; } else { if (strcmp(argv[tmp],"/r") == 0) { doread = 1; } else { if (strcmp(argv[tmp],"/w") == 0) { dowrite = tmp + 1; tmp = tmp + 1; } else { if (strcmp(argv[tmp],"/e") == 0) { doerase = 1; } else { if (strcmp(argv[tmp],"/v") == 0) { dover = 1; } else { fprintf(stderr,"unknown command line option: %s\n",argv[tmp]); exit(2); }}}}}}}}}} tmp = tmp + 1; } if (dover != 0) { /* give init message */ fprintf(stderr,"93X6 programmer v1.0\n"); fprintf(stderr,"by P.Faasse\n"); if ((doread == 0) && (dowrite == 0) && (doerase == 0)) { /* nothing else to do, quit */ exit(0); } } if (dowrite != 0) { /* init data buffer */ databuf[ 0] = 0x0000; databuf[ 1] = 0x0300; databuf[ 2] = 0x3b21; databuf[ 3] = 0xc000; databuf[ 4] = 0x0000; databuf[ 5] = 0x0000; databuf[ 6] = 0x0000; databuf[ 7] = 0x0000; databuf[ 8] = 0x0000; databuf[ 9] = 0x0000; databuf[10] = 0x0000; databuf[11] = 0x0000; databuf[12] = 0x0000; databuf[13] = 0x0000; databuf[14] = 0x0110; databuf[15] = 0x0030; } /* init I/O adresses */ inadr = portbase + msr; /* msr for input */ outadr = portbase + mcr; /* mcr for output */ cladr = portbase + thr; /* thr to generate clock pulse */ stsadr = portbase + lsr; /* status from lsr */ /* save the sio's state as I found it */ sier = inportb(portbase+ier); slcr = inportb(portbase+lcr); smcr = inportb(portbase+mcr); outportb(portbase+lcr,0x83); /* get divisor latch */ sdll = inportb(portbase+dll); sdlm = inportb(portbase+dlm); outportb(portbase+lcr,0x03); /* back to data output */ /* setup my desired state */ outportb(portbase+ier,0x00); /* disable all interrupts */ outportb(portbase+lcr,0x83); outportb(portbase+dll,0x0c); /* set 9600 baud */ outportb(portbase+dlm,0x00); /* */ outportb(portbase+lcr,0x00); /* power up the programmer */ fprintf(stderr,"Power-up of the programmer\n"); setdi(); /* set power on via di */ setcs(); /* and cs */ sleep(1); /* wait till power stabile */ /* set zero state */ clrcs(); /* process doerase */ if (doerase != 0) { fprintf(stderr,"Erasing\n"); writecommand(eewen); writecommand(eeerall); waitready(); writecommand(eewdis); } /* process dowrite */ if (dowrite != 0) { fprintf(stderr,"Writing\n"); writecommand(eewen); /* write databuffer to eeprom */ dataptr = 0; /* write databuffer to eeprom */ while (dataptr < lastadr) { eeadres = dataptr & 0x3f; writecommand(eewrite | eeadres); writedata(databuf[dataptr]); waitready(); dataptr = dataptr + 1; } /* clear write enable */ writecommand(eewdis); } /* process doread */ if (doread != 0) { /* give user message */ fprintf(stderr,"Reading\n"); /* set data pointer to beginning of the buffer */ dataptr = 0; /* read all words from the eeprom */ while (dataptr < lastadr) { eeadres = dataptr & 0x3f; writecommand(eeread | eeadres); databuf[dataptr] = readdata(); dataptr = dataptr + 1; } /* print the thing */ dataptr = 0; while (dataptr < lastadr) { printf("%02X %04X\n",dataptr,databuf[dataptr]); dataptr = dataptr + 1; } } /* power down the programmer */ fprintf(stderr,"Power-down the programmer\n"); clrcs(); clrdi(); sleep(2); /* reset the serial portm to what you found */ /* I cheat with the mcr, activating the DTR and RTS would keep my */ /* programmer powered-up; I do not want that to happen */ outportb(portbase+ier,sier); outportb(portbase+mcr,smcr & 0xfffc); /* a little cheating... */ outportb(portbase+lcr,0x83); /* get divisor latch */ outportb(portbase+dll,sdll); outportb(portbase+dlm,sdlm); outportb(portbase+lcr,0x03); /* back to data output */ outportb(portbase+lcr,slcr); } /************************************************/ /* make enough delay to get the signals through */ /************************************************/ void delay() {unsigned int count; count = 1000; while (count != 0) { count = count - 1; } } /*****************/ /* set eeprom CS */ /*****************/ void setcs() {int current; current = inportb(outadr); outportb(outadr,current|csm); delay(); } /*******************/ /* clear eeprom CS */ /*******************/ void clrcs() {int current; current = inportb(outadr); outportb(outadr,current&~csm); delay(); } /*****************/ /* set eeprom DI */ /*****************/ void setdi() {int current; current = inportb(outadr); outportb(outadr,current|dim); delay(); } /*******************/ /* clear eeprom DI */ /*******************/ void clrdi() {int current; current = inportb(outadr); outportb(outadr,current&~dim); delay(); } /*******************/ /* pulse eeprom CL */ /*******************/ void pulscl() {int tmp; /* write data 00H to ouput for __/--\__ clock pulse */ outportb(cladr,0x00); tmp = inportb(stsadr); /* wait for transmitter empty */ while ((tmp & 0x40) == 0) { tmp = inportb(stsadr); } /* wait another while */ delay(); } /**************************************/ /* read the data output of the eeprom */ /**************************************/ int readdo() {int tmp; delay(); tmp = inportb(inadr); tmp = (tmp & dom) >> 4; return(tmp); } /**************************************/ /* write a command byte to the eeprom */ /**************************************/ void writecommand(int command) {int wcnt; int tmp; unsigned long count; /* pulse cs to 0 */ clrdi(); clrcs(); setcs(); /* send the start bit */ setdi(); pulscl(); /* send the command */ tmp = command; wcnt = 8; while(wcnt != 0) { /* set bit outside */ if ((tmp & 0x80) != 0) { setdi(); } else { clrdi(); } /* pulse clock */ pulscl(); /* get next bit into tmp.7 */ tmp = tmp << 1; /* repeat for all 8 bits */ wcnt = wcnt - 1; } /* clear the data input */ clrdi(); } /***********************************/ /* write a data word to the eeprom */ /***********************************/ void writedata(unsigned int data) { unsigned int tmp; int cnt; tmp = data; cnt = 16; while (cnt != 0) { if ((tmp & 0x8000) != 0) { setdi(); } else { clrdi(); } pulscl(); tmp = tmp << 1; cnt = cnt - 1; } clrdi(); } /****************************************/ /* wait till eeprom signals ready state */ /****************************************/ void waitready() {int tmp; int max; /* timeout */ max = 10000; clrdi(); clrcs(); setcs(); tmp = readdo(); while ((tmp == 0) && (max != 0)) { tmp = readdo(); max = max - 1; } if (max == 0) { printf("wait for eeprom ready timed out\n"); exit(1); } } /************************************/ /* read a data word from the eeprom */ /************************************/ unsigned int readdata() {int tmp; unsigned long waithalf; int cnt; unsigned int inbits; inbits = 0; cnt = 16; /* clear input bit as shown in the datasheet */ clrdi(); /* get all 16 data bits */ while (cnt != 0) { /* pulse clock for data bit */ pulscl(); /* get a data bit */ inbits = inbits << 1; if (readdo() != 0) { inbits = inbits | 0x0001; } /* do for all 16 bits */ cnt = cnt - 1; } /* return the result */ return (inbits); } >>>>>>>>>>>>>>>>>>>> end of program <<<<<<<<<<<<<<<<<<< This I compile using a turbo-C compiler version 1.0. As you can see the thing is not yet complete, but very nearly so. I hope to finish the code tonight (or maybe tomorrow). Anyway, with a half-proper compiler and the above circuit description this should be a workable contraption. Tested till now: read: gives a hexdump of the eeprom's contents. write: writes hard-coded data to eeprom (can be read back later). erase: leaves you with an eeprom filled with FFFFH I tried with two 93C06's from SGS-thompson, they work ok with this thing. and with one CAT93C46P from CSI. This one too works. By the way: I also have a few NMC9306 's (National Semiconductor). I think they are a close relative to the 93C06. National does not help.. They refuse to be programmed by means of the above-mentioned programmer. I first thought the programmer was wrong, till I tried some other 93C06 from SGS-Thomson and a 93C46 from CSI. They DO work fine. I am still confused about what goes wrong with the NMC9306 from National, or are these completely something else??? P.R. Faasse