You are on page 1of 14

Parallel Port - Programming Serial EEPROM 93C56

Programming Serial EEPROM 93C46


copyright Peter H. Anderson, Morgan State University
Baltimore, MD 21239, Dec, '96 & K.S.Sankar Mostek 2003

Introduction.
This piece discusses how to program such serial EEPROM devices as the 93C46/56/66 using the parallel port.
93c46=1k 93c56=2k 93c56=4k memory.
There is some confusion in the industry as National Semiconductor markets a device under the same number
(NM93C56A) and the protocol differs slightly from the Microchip series.
This discussion deals specifically with the Microchip 93C56 serial EEPROM. Data sheet from Amtel for an
AT93C56 and the protocol appears to also be the same as Microchip.
All of this may sound confusing, and indeed it is. I do know that the following routines will work with the
Microchip devices and it will work with the devices which are currently marketed by Jameco.
I found the Microchip data sheet to be the most readable. This may be downloaded in .pdf format from
http://www.microchip.com and then read or printed using an Acrobat reader.
Hardware Connection of Parallel Port to EEPROM.
Parallel Port 93C56

Data_0 (term 2) ------> CS (term 1)


Data_1 (term 3) ------> SK (term 2) at mostek -> DI
Data_2 (term 4) ------> DI (term 3) st Mostek -> SK

Status_4 (term 13) <--- DO (term 4)

Ground (term 18)

+5 ---- V_cc (term 8)


GRD ---- GRD (term 5)
GRD ---- ORG (term 6) (8 X 256 organization)
Programs.
EEPROM1.C.

The intent of program EEPROM1.C is to illustrate all feature of the protocol.


Each line is fetched and the data is programmed into the specified address.
When completed, the user is instructed to turn off power and then turn it on to demonstrate the data has been
indeed stored in ROM. The content of the 256 locations is then displayed.
This routine contains functions to enable and disable the erase and write feature (write_enable() and
disable_eeprom()), to erase all locations (erase_all()), to erase a single location (erase()), to write a fixed value to
all locations (write_all()), to write data to a specific address (write_byte()) and to read from an address location
(read_byte()).

file:///C|/My Documents/eeprom/eeprom.html (1 of 14) [8/10/2003 7:36:36 PM]


Parallel Port - Programming Serial EEPROM 93C56

Each command consists of twelve bits (three nibbles) which are shifted out, beginning with the most significant
bit, using function send instruction(). In the #defines below, note that each instruction begins with a start bit, which
is logic one. The ne xt two, three or four bits are used by the EEPROM to determine the nature of the operation.
The lower eight bits are the address.
Note however, there is no address associated with the enable and disable and the erase all and write all commands.
Thus, in these functions, the lower bits are set to logic zero. For commands dealing with a specific address, the
high nibble opcode defin ing the operation is ored with the address in the lower two nibbles. Thus, all commands
are 12 bits. (The National Semiconductor device uses an 11 bit format).
In writing data, this 12 bit instruction is followed with the 8 bits of data. This is implemented in function send_8().
For commands involving either an erase or a write, the CS is brought momentarily low and the EEPROM output
DO is monitored until it assumes a logic one, indicating the EEPROM has completed the operation. This is read on
the SELECT input on the parallel p ort. This is implemented in function check_done(). Note that this is not done
for the enable, disable and read commands.
For the read command, the data is read on parallel port input Select (Term 13). This is implemented in function
get_data().
I am hopeful this is a sufficient description to enable you to use and modify my code to suit your purposes. It is
suggested that you also use a data sheet.
/*
** EEPROM1.C
**
** Illustrates how to program 93C56 Serial EEPROM using the Parallel
** Port. Device is first enabled for Write and Erase (EWEN). All
** locations are erased (ERAL).
**
** A text file containing the addresses and the bytes to be programmed
** in that address is then opened. Each line in the file is then read
** in turn and the data is programmed to the specified location using
** the write_byte function.
**
** Upon completion, the erase and write function is disabled and all
** locations are dumped to the terminal using the read_byte function.
**
** Peter Anderson, MSU, Dec 14, '96
**
*/

#include &ltstdio.h>
#include &ltdos.h>
#include &ltconio.h>

#define DATA 0x03bc


#define STATUS DATA+1

#define READ 0xc00 /* 1 10 A8 A7A6A5A4 A3A2A1A0 */


#define EWEN 0x980 /* 1 001 1XXX XXXX */
#define ERASE 0xe00 /* 1 11 A8 A7A6A5A4 A3A2A1A0 */
#define WRITE 0xa00 /* 1 01 A8 A7A6A5A4 A3A2A1A0 */
#define ERAL 0x900 /* 1 00 1 0A6A5A4 A3A2A1A0 */
#define WRAL 0x880 /* 1 00 0 1A6A5A4 A3A2A1A0 */
#define EWDS 0x800 /* 1 00 0 0A6A5A4 A3A2A1A0 */

#define TIME 10

file:///C|/My Documents/eeprom/eeprom.html (2 of 14) [8/10/2003 7:36:36 PM]


Parallel Port - Programming Serial EEPROM 93C56

int data=0x00;

void write_byte(int adr, int d);


int read_byte(int adr);
int get_data(void);

void write_enable(void);
void erase_all(void);
void write_all(int d);
void erase(int adr);
void disable_eeprom(void);

void send_instruction(int instr);


void send_data(int d);
void check_done(void);

void clock(void);
void cs_high(void);
void cs_low(void);

void t_delay(int t);

void main(void)
{
char str[80];
int adr, byte, n;

FILE *f1;

clrscr();

write_enable();
erase_all();

f1=fopen("a:eeprom.dat", "rt"); /* open the data file */

while(1)
{
if (fgets(str, 80, f1) == NULL) /* do until no more lines */
{
break; /*end of file */
}
else
{
sscanf(str, "%d %d", &adr, &byte); /* write data to adr */
write_byte(adr, byte);
}
}
printf("Programming Completed\n");
disable_eeprom();
fclose(f1);

printf("Power down and then power up the EEPROM.\


Type any key to continue.");

while(!kbhit()) /*loop until a key is hit*/ ;


getch();
/* now list the content of the EEPROM */
for(n=0; n<256; n++)
{
if(n==0x80) /* if half way in displaying data */

file:///C|/My Documents/eeprom/eeprom.html (3 of 14) [8/10/2003 7:36:36 PM]


Parallel Port - Programming Serial EEPROM 93C56

{
printf("\n****MORE****\n");
while(!kbhit()) /*loop until a key is hit*/ ;
getch();
}

if(n%16 == 0) /* start a new line */


{
printf("\n%.2x:", n);
}
byte=read_byte(n);
printf(" %.2x", byte);
}
}

void write_byte(int adr, int d)


/* writes byte d to location adr */
{
int instr;
cs_high();
instr=WRITE + adr;
send_instruction(instr);
send_data(d);
check_done();
cs_low();
}

int read_byte(int adr)


/* returns byte at location adr */
{
int d, instr;
cs_high();
instr= READ+adr;
send_instruction(instr);
d = get_data();
cs_low();
return(d);
}

int get_data(void)
/* fetch each bit in turn, ms bit first */
{
int in, d=0, n;
for(n=7; n>=0; n--)
{
clock();
in = (((inportb(STATUS)^0x80) >> 4) &0x01);
d = d | (in << n);
}
return(d);
}

void write_enable(void)
/* enable eeprom for writes and erases */
{
int instr;
cs_high();
instr=EWEN;
send_instruction(instr);
cs_low();
}

file:///C|/My Documents/eeprom/eeprom.html (4 of 14) [8/10/2003 7:36:36 PM]


Parallel Port - Programming Serial EEPROM 93C56

void erase_all(void)
/* erases all bytes */
{
int instr;
cs_high();
instr=ERAL;
send_instruction(instr);
check_done();
cs_low();
}

void write_all(int d)
/* writes specified byte d to all locations */
{
int instr;
cs_high();
instr= WRAL;
send_instruction(instr);
send_data(d);
check_done();
cs_low();
}

void erase(int adr)


/* earses specified location */
{
int instr;
cs_high();
instr=ERASE + adr;
send_instruction(instr);
check_done();
cs_low();
}

void disable_eeprom(void)
/* disable write and erase */
{
int instr;
cs_high();
instr=EWDS;
send_instruction(instr);
cs_low();
}

void send_instruction(int instr)


/* sends 11 bit instruction */
{
int n, di;
for(n=11; n>=0; n--)
{
di=(instr>>n) & 0x01;
data=(data & (~0x04)) | (di<&lt2);
outportb(DATA, data);
clock();
}
data=data&(~0x04);
outportb(DATA, data);
}

void send_data(int d)

file:///C|/My Documents/eeprom/eeprom.html (5 of 14) [8/10/2003 7:36:36 PM]


Parallel Port - Programming Serial EEPROM 93C56

/* sends 8 bit data d */


{
int n, di;
for(n=7; n>=0; n--)
{
di=(d>>n) & 0x01;
data=(data & (~0x04) | (di<&lt2));
outportb(DATA, data);
clock();
}
}

void check_done(void)
/* brings CS low and then high and waits until eeprom is ready */
/* used by all erase and write commands */
{
cs_low();
t_delay(TIME);
cs_high();
while(( ((inportb(STATUS)^0x80) >> 4)&0x01) == 0) /* wait */ ;
}

void clock(void)
{
data=data | 0x02;
outportb(DATA, data);
t_delay(TIME);
data=data & (~0x02);
outportb(DATA, data);
t_delay(TIME);
}

void cs_high(void)
{
data= 0x01;
outportb(DATA, data);
}

void cs_low(void)
{
data=0x00;
outportb(DATA, data);
}

void t_delay(int t)
/* for timing between clock pulses and CS 0 pulses */
{
int n;
for(n=0; n&ltt; n++) /* just loop */ ;
}
EEPROM2.C
Program EEPROM2.C illustrates how to program strings into a serial EEPROM. This is similar to program
EEPROM1.C, except that functions write_string and read_string have been added.
Function void write_string(int adr, char *s) writes the string pointed to by s beginning at address location adr. Note
that the null character which terminates the string is also written to memory. Thus, in reading the string using a
STAMP or similar, t he programmer must test for zero to determine the end of the message.
/*

file:///C|/My Documents/eeprom/eeprom.html (6 of 14) [8/10/2003 7:36:36 PM]


Parallel Port - Programming Serial EEPROM 93C56

** EEPROM2.C
**
** Illustrates how to program 93C56 Serial EEPROM using the Parallel
** Port.
**
** Device is first enabled for Write and Erase. All locations are
** erased. Strings are written to addresses beginning at locations
** 0x00 and 0x50. Device is disabled. Strings are then immediately
** read and after power down.
**
** Peter Anderson, MSU, Dec 14, '96
*/

#include &ltstdio.h>
#include &ltdos.h>
#include &ltconio.h>

#define DATA 0x03bc


#define STATUS DATA+1

#define READ 0xc00 /* 1 10 A8 A7A6A5A4 A3A2A1A0 */


#define EWEN 0x980 /* 1 001 1XXX XXXX */
#define ERASE 0xe00 /* 1 11 A8 A7A6A5A4 A3A2A1A0 */
#define WRITE 0xa00 /* 1 01 A8 A7A6A5A4 A3A2A1A0 */
#define ERAL 0x900 /* 1 00 1 0A6A5A4 A3A2A1A0 */
#define WRAL 0x880 /* 1 00 0 1A6A5A4 A3A2A1A0 */
#define EWDS 0x800 /* 1 00 0 0A6A5A4 A3A2A1A0 */

#define TIME 10

int data=0x00;

void write_string(int address, char *s);


void write_byte(int adr, int d);

void read_string (int address, char *s);


int read_byte(int adr);
int get_data(void);

void write_enable(void);
void erase_all(void);
void write_all(int d);
void erase(int adr);
void disable_eeprom(void);

void send_instruction(int instr);


void send_data(int d);
void check_done(void);

void clock(void);

file:///C|/My Documents/eeprom/eeprom.html (7 of 14) [8/10/2003 7:36:36 PM]


Parallel Port - Programming Serial EEPROM 93C56

void cs_high(void);
void cs_low(void);

void t_delay(int t);

void main(void)
{
char str1[80], str2[80];
int dummy;

clrscr();

write_enable();
erase_all();
/* program one string to eeprom */
strcpy(str1, "abcdefghijklmnopqrstuvwxyz1234567890ABCDEFGHIJKLMNOPQRSTUVW\
XYZ!@#$%^&*()_+\n\n");
write_string(0x00, str1);

/* now another */
strcpy(str1, "!234567890\n\n");
write_string(0x50, str1);

erase(0x50); /* erase location 0x50 and replace with a '1'*/


write(0x50, '1');

disable_eeprom();
printf("Programming Complete\n\n");

read_string(0x00, str2);
printf("%s", str2);
read_string(0x50, str2);
printf("%s", str2);

printf("Power down and then power up the EEPROM.\


Hit any digit to continue.\n");
while(!kbhit()) /* loop until a key is hit */

read_string(0x00, str2);
printf("%s", str2);
read_string(0x50, str2);
printf("%s", str2);
}

void write_string(int address, char *s)


/* writes string s, beginning at location specified in address */
{
int n;
char c;
for(n=0; n&lt80; n++)

file:///C|/My Documents/eeprom/eeprom.html (8 of 14) [8/10/2003 7:36:36 PM]


Parallel Port - Programming Serial EEPROM 93C56

{
c=s[n];
write_byte(address,(int) c);
++address;
if (c == '\0') /* Note that \0 is also written to eeprom */
{
break;
}
}
}

void read_string (int address, char *s)


/* reads string s from location beginning at specified address */
/* expects NULL terminated string */
{
int n;
for(n=0; n&lt80; n++)
{
s[n]= read_byte(address);
++address;
if (s[n] == '\0')
{
break;
}
}
}

void write_byte(int adr, int d)


/* writes byte d to location adr */
{
int instr;
cs_high();
instr=WRITE + adr;
send_instruction(instr);
send_data(d);
check_done();
cs_low();
}

int read_byte(int adr)


/* returns byte at location adr */
{
int d, instr;
cs_high();
instr= READ+adr;
send_instruction(instr);
d = get_data();
cs_low();
return(d);
}

file:///C|/My Documents/eeprom/eeprom.html (9 of 14) [8/10/2003 7:36:36 PM]


Parallel Port - Programming Serial EEPROM 93C56

int get_data(void)
/* fetch each bit in turn, ms bit first */
{
int in, d=0, n;
for(n=7; n>=0; n--)
{
clock();
in = (((inportb(STATUS)^0x80) >> 4) &0x01);
d = d | (in << n);
}
return(d);
}

void write_enable(void)
/* enable eeprom for writes and erases */
{
int instr;
cs_high();
instr=EWEN;
send_instruction(instr);
cs_low();
}

void erase_all(void)
/* erases all bytes */
{
int instr;
cs_high();
instr=ERAL;
send_instruction(instr);
check_done();
cs_low();
}

void write_all(int d)
/* writes specified byte d to all locations */
{
int instr;
cs_high();
instr= WRAL;
send_instruction(instr);
send_data(d);
check_done();
cs_low();
}

void erase(int adr)


/* earses specified location */
{

file:///C|/My Documents/eeprom/eeprom.html (10 of 14) [8/10/2003 7:36:36 PM]


Parallel Port - Programming Serial EEPROM 93C56

int instr;
cs_high();
instr=ERASE + adr;
send_instruction(instr);
check_done();
cs_low();
}

void disable_eeprom(void)
/* disable write and erase */
{
int instr;
cs_high();
instr=EWDS;
send_instruction(instr);
cs_low();
}

void send_instruction(int instr)


/* sends 11 bit instruction */
{
int n, di;
for(n=11; n>=0; n--)
{
di=(instr>>n) & 0x01;
data=(data & (~0x04)) | (di<&lt2);
outportb(DATA, data);
clock();
}
data=data&(~0x04);
outportb(DATA, data);
}

void send_data(int d)
/* sends 8 bit data d */
{
int n, di;
for(n=7; n>=0; n--)
{
di=(d>>n) & 0x01;
data=(data & (~0x04) | (di<&lt2));
outportb(DATA, data);
clock();
}
}

void check_done(void)
/* brings CS low and then high and waits until eeprom is ready */
/* used by all erase and write commands */
{

file:///C|/My Documents/eeprom/eeprom.html (11 of 14) [8/10/2003 7:36:36 PM]


Parallel Port - Programming Serial EEPROM 93C56

cs_low();
t_delay(TIME);
cs_high();
while(( ((inportb(STATUS)^0x80) >> 4)&0x01) == 0) /* wait */ ;
}

void clock(void)
{
data=data | 0x02;
outportb(DATA, data);
t_delay(TIME);
data=data & (~0x02);
outportb(DATA, data);
t_delay(TIME);
}

void cs_high(void)
{
data= 0x01;
outportb(DATA, data);
}

void cs_low(void)
{
data=0x00;
outportb(DATA, data);
}

void t_delay(int t)
/* for timing between clock pulses and CS 0 pulses */
{
int n;
for(n=0; n&ltt; n++) /* just loop */ ;
}
/* end */
93c46
What is it, Why use a serial EEPROM?
Serial EEPROMs are small Electronically Erasable Programmable Read Only Memory chips. These devices are
usually used to store user configurable parameters and device serial numbers. They use a serial bus interface,
which allows them to be packaged in inexpensive 8 pin packages.
These little chips offer a nifty way to store a small amount of data in non-volatile memory, using only a few of the
port pins, and without raising the system's cost much. They are usually specified to retain the data for 10 years and
to endure 100,000 write operations before failure. They only require a 5 volt power supply (some 3V only
versions exist too).
Because these chips use a serial interface, they can not be read quickly enough to serve as
conventional memory. In addition, a considerable length of time (milliseconds) is required to perform a
write operation. They typically hold less than 1024 bytes of memory. However, they usually cost less

file:///C|/My Documents/eeprom/eeprom.html (12 of 14) [8/10/2003 7:36:36 PM]


Parallel Port - Programming Serial EEPROM 93C56

than $1.00 (US) for single piece quantities, making them pretty desirable memory devices for storing
configuration parameters or other bits of information that should be retained when the power is lost.
Types of Serial EEPROM Chips
There are several types of Serial EEPROMs, but most of them fall into either a 2-wire or 3-wire interface
category. Usually, the 3-wire devices require an addition wire (beyond the 3 for data transfer) for each
chip to be used. The 2-wire interface, called I2C or IIC or "I squared C" uses only two wires, regardless of
how many chips are attached. I2C is a trademard of Philips. The three wire interfaces include SPI and
Microwire, which is a trademark of National Semiconductor.
As the pressure on engineers to make products smaller has grown, semiconductor manufacturers have
introduced several new interfaces, usually aimed at lower a product's size and cost... and undoubtedly
many more will appear in the future.
As a practical matter, the code offered below only works with the Microwire 3 Wire interface, and is
specifically intended to work with the 93C46, which is a standard part available from a variety of
distributors.
Where to get a Serial EEPROM?
The code below works with the 93CS46 Serial EEPROM. It can be used without much difficulty with a
93C46, by avoiding calls to the routines that manipulate the extended features of the 93CS46.
Manufacturers
Atmel has data sheets on-line for most of their EEPROM and microcontroller products.
MicroChip now has data sheets on-line for most of their products. They offer the 93C46, as well as a
variety of other EEPROMs.
SGS Thompson made the chips I used when I wrote this code. I used the National datasheet to write the
code, but the SGS Thompson parts worked flawlessly. They offer quite a few different types of serial
eeproms, including of course the 93CS46 and 93C46.
Xicor offers 2-Wire interface and SPI interface serial EEPROMs, but apparantly nothing which will work
with the code below. Xicor once had a considerable collection of example code on-line, but they appear
to have removed it.
Distributors
Within the United States, the easiest way to get ahold of a 93C46 is to call DigiKey 800-344-4539
(MicroChip, maybe National) or Mouser Electronics 800-346-6873 (SGS Thompson). Both have a
minimum order, appox $25, and these serial EEPROMs are only about $1 each. There are lots of other
distributors too, but Mouser and DigiKey are probably the easiest, since they give out a free catalog

Compability with other 3-Wire serial EEPROMs


The 93C46 chip should be usable, but care should be taken not to make calls to the functions which
access the protection register within the 93CS46. The two extra pins not required for the 93C46 are
manipulated by all the routines. To reclaim these pins, remove all the instructions that use "pe" and
"pre" symbols. A simpler approach may be to set the bit addresses of these bits in the .equ statements
to a bit within the 16 byte bit-addressable space, or perhaps one of the general purpose flag bits in the
PSW, if you're not using it. It's up to you. I might make another version of the code specifically for the

file:///C|/My Documents/eeprom/eeprom.html (13 of 14) [8/10/2003 7:36:37 PM]


Parallel Port - Programming Serial EEPROM 93C56

plain 93C46, if anyone wants it enough to let me know. Please explain the difficulty you have using the
code with a 93C46 (or the trouble you think you may have).
Early versions of this code worked with the 93C56 and 93C57, which have more memory. Unfortunately,
these chips use an 8 bit address field, whereas the 93C46 uses only 6. The code can be adapted to
work with these larger chips... good luck. The early versions are long since gone.. they were buggy
anyways.
The code is basically designed to manipulate a single 93CS46 chip, connected to six of the port pins.
Two versions of the code are available, one with a little menu driven user interface (via a terminal
connected to the UART) and the other with only the routines to include in your existing program. The
user interface is simple and shouldn't need documentation. The routines available for your code are:
Routines for both the 93C46 and 93CS46
READ
Reads the sixteen bit value from the location pointed to by R0. Data is returned in R2 (LSB) and
R3 (MSB). This routine should always work regardless of calls to WEN and WDS, but it should not
be called immediately following a call to PREN. Valid address range for R0 is 0 to 63.
WEN
Enable writing. This operation must be performed before a write may be issued. This applies to
both the 93C46 and 93CS46. Unlike PREN below, writing should remain enabled until a WDS is
called.
WRITE
Writes the sixteen bit data in R2 (LSB) and R3 (MSB) to the location pointed to by R0. Writing
must have been enabled using WEN. For the 93CS46, if this location is "protected", no data will be
written, regardless of calls to WEN and WDS. Writing takes a considerable length of time
(milliseconds). This routine just waits for it to finish before returning... hope you don't have any
polled I/O you wanted to keep doing!
WDS
Disable writing. This disables write operations. It applies to both the 93C46 and 93CS46 chips. It
is advisable to disable writing if no additional write operations are expected soon. In this state, the
chip may have better resistance to accidental data loss due to problems on the power supply,
noise on signal lines, etc.
It is not necessary to erase memory locations before writing. The erase functions provided in the 93C46
are unnecessary (for the chips I've used, double check your data sheet). The erase functions are not
implemented here.
Disclaimer
These 93C46 Serial EEPROM devices are used in many commercial products where the data contained
within the chip, though only 128 bytes, is considered confidential and proprietary. This code library may
not be used to "break into" the data stored within devices in commerical products. Use of this code
library to modify the behavior of commercial products, without the expressed written authorization of the
manufacturer, is also prohibited. (e.g. modifing ethernet card hardware addresses, etc)
end

file:///C|/My Documents/eeprom/eeprom.html (14 of 14) [8/10/2003 7:36:37 PM]

You might also like