Interfacing with a 24LC256 EEPROM



/* 24LC256.C
**
** Illustrates an interface with a 24LC256 (32K X 8) I2C EEPROM.
**
** Assumes device address (A2, A1, A0) is strapped for 0x0.
**
** Writes 10 values to memory locations beginning at memory address 0x0700.
** Reads them back and displays on the local console.
**
** Flashlite V25        24LC256
**
** SDA P2.0 ---------------- term 5 on 24lc256
** SCL P2.1 ---------------- term 6 on 24lc256
**
** Note that as the Flashlite V25 has the capability to save data to its
** own flash memory by opening a file, interfacing with an external EEPROM
** probably is none too practical.  However, it is a simple example of an
** implementation of I2C routines.
**
** copyright, Peter H. Anderson, Baltimore, MD, Sept, '00
*/

#include <stdio.h>
#include <dos.h>

#define SEG 0xf000
#define P2_OFFSET 0xff10
#define PM2_OFFSET 0xff11
#define PMC2_OFFSET 0xff12

typedef unsigned char byte;

void random_write(byte dev_adr, unsigned int mem_adr, byte dat);
byte random_read(byte dev_adr, unsigned int mem_adr);

/* standard I2C routines */
byte i2c_in_byte(void);
void i2c_out_byte(byte o_byte);
void i2c_nack(void);
void i2c_ack(void);
void i2c_start(void);
void i2c_stop(void);
void i2c_high_sda(void);
void i2c_low_sda(void);
void i2c_high_scl(void);
void i2c_low_scl(void);

byte far *p2, *pm2, *pmc2;      /* note global */
byte dirs2, outs2;

void main(void)
{
   byte dat;
   unsigned int mem_adr, n;
   p2 = MK_FP(SEG, P2_OFFSET);
   pm2 = MK_FP(SEG, PM2_OFFSET);
   pmc2 = MK_FP(SEG, PMC2_OFFSET);

   dirs2 = 0xff;

   *pmc2 = 0x00;    /* not special purpose */
   *pm2 = dirs2;    /* configure as all inputs */

    while(1)
    {

       mem_adr = 0x0700;

       for(n=0; n<10; n++, mem_adr++)
       {
      dat = 0xfe - n;
      random_write(0x00, mem_adr, dat);
       }

       mem_adr = 0x0700;

       for(n=0; n<10; n++, mem_adr++)
       {
          dat = random_read(0x00, mem_adr);
          printf("%x\n", dat);
          delay(100);
       }
       printf("..\n");
   }
}

void random_write(byte dev_adr, unsigned int mem_adr, byte dat)
{
   i2c_start();
   i2c_out_byte(0xa0 | (dev_adr << 1));
   i2c_nack();
   i2c_out_byte((mem_adr >> 8) & 0xff);
   i2c_nack();
   i2c_out_byte(mem_adr & 0xff);
   i2c_nack();
   i2c_out_byte(dat);
   i2c_nack();
   i2c_stop();
   delay(25); /* allow for the programming of the eeprom */
}

byte random_read(byte dev_adr, unsigned int mem_adr)
{
   byte y;
   i2c_start();
   i2c_out_byte(0xa0 | (dev_adr << 1));
   i2c_nack();
   i2c_out_byte((mem_adr >> 8) & 0xff);
   i2c_nack();
   i2c_out_byte(mem_adr & 0xff);
   i2c_nack();

   i2c_start();
   i2c_out_byte(0xa1 | (dev_adr << 1));
   i2c_nack();
   y=i2c_in_byte();
    /* no ack prior to stop */
   i2c_stop();
   return(y);
}


byte i2c_in_byte(void)
{
   byte i_byte, n;
   i2c_high_sda();
   for (n=0; n<8; n++)
   {
      i2c_high_scl();

      if (*(p2) & 0x01)
      {
         i_byte = (i_byte << 1) | 0x01; /* msbit first */
      }
      else
      {
         i_byte = i_byte << 1;
      }
      i2c_low_scl();
   }
   return(i_byte);
}

void i2c_out_byte(byte o_byte)
{
   byte n;
   for(n=0; n<8; n++)
   {
      if(o_byte&0x80)
      {
         i2c_high_sda();
      }
      else
      {
         i2c_low_sda();
      }
      i2c_high_scl();
      i2c_low_scl();
      o_byte = o_byte << 1;
   }
   i2c_high_sda();
}

void i2c_nack(void)
{
   i2c_high_sda();  /* data at one */
   i2c_high_scl();  /* clock pulse */
   i2c_low_scl();
}

void i2c_ack(void)
{
   i2c_low_sda();       /* bring data low and clock */
   i2c_high_scl();
   i2c_low_scl();
   i2c_high_sda();
}

void i2c_start(void)
{
   i2c_low_scl();
   i2c_high_sda();
   i2c_high_scl();  /* bring SDA low while SCL is high */
   i2c_low_sda();
   i2c_low_scl();
}

void i2c_stop(void)
{
   i2c_low_scl();
   i2c_low_sda();
   i2c_high_scl();
   i2c_high_sda();  /* bring SDA high while SCL is high */
   /* idle is SDA high and SCL high */
}

void i2c_high_sda(void)
{
   dirs2 = dirs2 | 0x01;
   *pm2 = dirs2;
#ifdef D    /* used for debugging */
   printf("SDA_HIGH %x\n", dirs2);
   delay(500);
#endif
}

void i2c_low_sda(void)
{
   outs2 = outs2 & (~0x01); /* zero the output pin */
   *p2 = outs2;
   dirs2 = dirs2 & (~0x01);    /* and output */
   *pm2 = dirs2;
#ifdef D
   printf("SDA_LOW %x\n", dirs2);
   delay(500);
#endif
}

void i2c_high_scl(void)
{
   dirs2 = dirs2 | 0x02;  /* bring SCL to high impedance */
   *pm2 = dirs2;
#ifdef D
   printf("SCL_HIGH %x\n", dirs2);
   delay(500);
#endif
}

void i2c_low_scl(void)
{
   outs2 = outs2 & (~0x02);
   *p2 = outs2;             /* zero the output pin */
   dirs2 = dirs2 & (~0x02);    /* and output */
   *pm2 = dirs2;
#ifdef D
   printf("SCL_LOW %x\n", dirs2);
   delay(500);
#endif
}