[Description]
Location = "ST\EEPROM\I2C EEPROM\ST24E16";

Info = " Module for programming 2-Wire(I2C) serial EEPROMs memory types ST24E16.",
    " ----------------------------------------------------------------------------------------------------------------------",
    " Bus: I2C.",
    " Size: 2048 bytes",
    " ---------------------------------------------------------------------------------------------------------------------- ",
    " Supported modes: Read, write, verify.",
    " ---------------------------------------------------------------------------------------------------------------------- ",
    " Author: ETL";

Buffer1 = "EEPROM",2048;
Picture = "24CXX.bmp";
VCC = 8;
GND = 4;
Voltage = 5.0;

[Menu]

Read    = "&Read",ReadButton,"Read chip",F2;
Div0    = "-";
Write   = "&Write",WriteButton,"Write chip",F5;
WriteChanges= "Write &changes",WriteChangesButton,"Write changes",F6;
Div1    = "-";
Compare = "&Verify",CheckButton,"Compare with buffer",F3;
Div3    = "-";
Info    = "&About module",ModuleInfoButton,"Show module info",F1;

[Interface]

CheckBox(UsePageWrite,"Use page write",5,5,1);

// ==================================================
//                  Host section
// ==================================================

[Host]

define  END_ADR 2048

Proc Read {
    
    var Address,Error,Value;
    print("");
    print("  Reading chip...");
    Run(Read);
    Address = 0;PBPos = 0;PBMax = END_ADR;
    Error = USB;
    if(Error = 0)
    {
        while(Address != END_ADR)
        {
            Value = USB;
            FBUF[Address] = Value;
            Address++;
            PBPos++;
        }        
    }
    if(Error = 0x8000)
    {
        print("  Reading error: Time out");
    }
    if(Error = 0)
    {
        if(ForceCloseAfterRead != 0) { return(0x7FFFFFFF); }
        else { print("   Reading is done. %i bytes were read.",Address); }
    }
    else
    {
        if(Error != 0x8000)
        {
            print("  Reading error. Device not response.",Error);
        }
    }
}

Proc Write  {

    var Address,Error,Value,Counter,Temp;
    print("");
    print("  Writing chip...");
    Address = 0;PBPos = 0;PBMax = END_ADR;
    Run(Write);
    if(UsePageWrite = 1)
    {
        USB = 1;
        USB = 16;    
        Value = 16;
        print("  Page mode. Page size %i bytes",Value);
        while(Address != END_ADR)
        {
            Error = USB;
            if(Error != 0) { break; }
            Counter = Value;
            BeginBlock;
            while(Counter != 0)
            {
                Temp = FBUF[Address];
                USB = Temp;
                Counter--;
                Address++;   
            }
            EndBlock;
            PBPos = Address;
        }
    }
    else
    {
        // writing in byte mode

        USB = 0;
        print("  Byte mode.");
        while(Address != END_ADR)
        {
            Value = FBUF[Address];
            USB = Value;
            Error = USB;
            if(Error != 0) { break; }
            Address++;
            PBPos++;
        }
    }
    if(Error = 0x8000)
    {
        print("  Writing error: Time out");
    }
    if(Error = 0xFF)
    {
        print("  Wrintig error. Address %i", Address);
    }
    if(Error = 0)
    {
        if(GlobalVerify != 0) { Compare(); }
        if(ForceCloseAfterWrite != 0) { return(0x7FFFFFFF); }
        else { print("   Writing is done. %i bytes were write.",Address); }
    }
}

Proc Compare {

    var Address,Error,Value,Value2,Mismatch;
    print("");
    print("  Verifying chip...");
    Run(Read);
    Address = 0;PBPos = 0;PBMax = END_ADR;Mismatch = 0;
    Error = USB;
    if(Error = 0)
    {
        while(Address != END_ADR)
        {
            Value = USB;
            Value2 = FBUF[Address];
            if(Value != Value2)
            {
                Mismatch++;
                FSEL[Address] = 0;    
            }
            else
            {
                FSEL[Address] = 1;
            }
            Address++;
            PBPos++;
        }
    }
    if(Error = 0x8000)
    {
        print("  Reading error: Time out");
    }
    if(Error = 0)
    {
        if(ForceCloseAfterVerify != 0) { return(0x7FFFFFFF); }
        else
        {
            print("  Verifying is done. %i bytes were read. Number of mismatch: %i",Address,Mismatch);
        }
    }
}


Proc WriteChanges
{
    var Address,Temp,Value,Mismatch,Error;
    Address = 0;Temp = 0;
    print("");
    while(Address != END_ADR)
    {
        Value = FSEL[Address];
        if(Value = 0) {Temp++;}
        Address++;    
    }
    if(Temp = 0)
    {        
        print("   Any mismatch is not found. Writing is canceled.");
        return;
    }
    else
    {
        Mismatch = 0;
        print("   Writing changes...");
        PBpos = 0; PBMax = END_ADR;Address = 0;Error = 0;
        while(Address != END_ADR)
        {
            Temp = FSEL[Address];
            if(Temp = 0)
            {
                Run(WriteByte);
                BeginBlock;
                USB = Address;
                Temp = Address >> 8;
                USB = Temp;
                Temp = FBUF[Address];
                USB = Temp;
                EndBlock;
                Error = USB;
                if(Error != 0) { break;}
                Mismatch++;
            }
            Address++;
            PBPos++;
        }
    }
    if(Error = 0x8000)
    {
        print("  Writing error: Time out. Address: %i",Address);
    }
    if(Error = 0xFF)
    {
        print("  Wrintig error. Device not response. Address %i", Address);
    }
    if(Error = 0)
    {
        if(GlobalVerify != 0) { Compare(); }
        if(ForceCloseAfterWrite != 0) { return(0x7FFFFFFF); }
        else { print("   Writing is done. %i bytes were write.",Mismatch); }
    }
}

Proc Info
{
  print("");
  print("  Module for programming 2-Wire(I2C) serial EEPROMs memory types 24C32.");
  print("");
  print("  Copyright (C) 2006 ETL.");
}

// ========================================================
//                    Device section
// ========================================================

[Device]

define      END_ADR     2048    
define      SDAOUT      POUT.4
define      SDAIN       PIN.4
define      SCL         POUT.5

// Variables

var Address,Error,Temp,Byte,Counter,Data,PageSize;


//***********************************************************
//*       Read                                             **
//***********************************************************
Proc Read {
 
    Error = 0;Address = 0;

    Init;
    StartI2C;

    // -----  Load command byte 0xA0 ----

    Byte = 0xa0;ShiftByteToI2C;CheckAck;
    if(Error != 0) { USB = 0xFF;return; }

    // ----- Load two addres byte 0000

    Byte = 0x00;ShiftByteToI2C;CheckAck;
    if(Error != 0) { USB = 0xFE;return; }
    Byte = 0x00;ShiftByteToI2C;CheckAck;
    if(Error != 0) { USB = 0xFE;return; }

    StopI2C;

    // -----  Load Read command ------

    StartI2C;Byte = 0xa1;ShiftByteToI2C;CheckAck;
    if(Error != 0) { USB = 0xFD;return; }

    USB = 0;
    // -----  Read loop  -------------
    while
    {
        ShiftByteFromI2C;
        USB = Byte;
        Address++;
        if(Address != END_ADR) { SDAOUT = 0;SCL = 1; SCL = 0;}
        else                   { SDAOUT = 1;SCL = 1; SCL = 0; break;} 
    }

    // ----- Read end ----------------
    SDAOUT = 0;
    StopI2C;
}

Proc Write {

    Init;

    Address = 0;
    Error = USB;       // get from host mode (page mode or byte mode)
    if(Error = 1)
    {
        // writing in page mode

        PageSize = USB;        // get from host page size
        while(Address != END_ADR)
        {
            // prepare write
            StartI2C;           // START condition
            BUSDATA = 0xa0;
            CheckAck;           // Check of acknowlegement
            if(Error != 0) { USB = 0xFF;return; }

            Byte = Address >> 8;// high byte of address
            BUSDATA = Byte;
            CheckAck;           // Check of acknowlegement
            if(Error != 0) { USB = 0xFF;return; }

            BUSDATA = Address;
            CheckAck;           // Check of acknowlegement
            if(Error != 0) { USB = 0xFF;return; }
            
            USB = 0;           // Send to host OK byte

            // Get from host page and shift into chip
            Temp = PageSize;
            while(Temp != 0)
            {
                Byte = USB;
                BUSDATA = Byte;
                CheckAck;           // Check of acknowlegement
                if(Error != 0) { break; }
                Temp--;
                Address++;
            }
            StopI2C;
            if(Error != 0) { USB = 0xFF; break;}
            // ----- Wait until device is ready
            // ----- Internal write cycle in progress

            WaitReady;
        }
    }
    else
    {
        // writing in byte mode    

        while(Address != END_ADR) 
        {
        

            Data = USB;         // Get data byte from host
            StartI2C;           // START condition
            BUSDATA = 0xa0;
            CheckAck;           // Check of acknowlegement
            if(Error != 0) { USB = 0xFF;return; }

            Byte = Address >> 8;// high byte of address
            BUSDATA = Byte;
            CheckAck;           // Check of acknowlegement
            if(Error != 0) { USB = 0xFF;return; }

            BUSDATA = Address;
            CheckAck;           // Check of acknowlegement
            if(Error != 0) { USB = 0xFF;return; }

            BUSDATA = DATA;     // data byte
            CheckAck;           // Check of acknowlegement
            if(Error != 0) { USB = 0xFF;return; }
            StopI2C;            // STOP condition

            // ----- Wait until device is ready
            // ----- Internal write cycle in progress

            WaitReady;

            // ----- Send to host "OK" command

            USB = 0;
            Address++;
        }
    }
}

Proc WriteByte
{
    Init;

        // -------- Get address word from host
        Address = USB;
        Temp = USB;
        Temp = Temp << 8;
        Address = Address | Temp;

        // -------- Get data byte from host
        Data = USB;

        // -------- Write to chip
        StartI2C;

        Byte = 0xa0;        // Shift into chip command byte 0xA0
        ShiftByteToI2C;     // Shift into chip
        CheckAck;           // Check of acknowlegement
        if(Error != 0) { USB = 0xFF;return; }

        Byte = Address >> 8;// high byte of address
        ShiftByteToI2C;     // shift into chip
        CheckAck;           // Check of acknowlegement
        if(Error != 0) { USB = 0xFF;return; }

        Byte = Address;     // low byte of address
        ShiftByteToI2C;     // shift into chip
        CheckAck;           // Check of acknowlegement
        if(Error != 0) { USB = 0xFF;return; }

        // ----- Data byte

        Byte = DATA;ShiftByteToI2C;CheckAck;
        if(Error != 0) { USB = 0xFF;return; }

        StopI2C;

        // ----- Wait until device is ready
        // ----- Internal write cycle in progress

        WaitReady;

        // ----- Send to host "OK" command

        USB = 0;
}

Proc StartI2C {
    SDAOUT = 1; SCL = 1;
    SDAOUT = 0; SCL = 0;
} 

Proc StopI2C {
    SDAOUT = 0; SCL = 0;
    SCL = 1; SDAOUT = 1;
}

Proc ShiftByteToI2C
{
  Counter = 8;
  while(Counter != 0)
  {
    SDAOUT = Byte.7;SCL = 1;SCL = 0;
    Byte = Byte << 1;
    Counter--;
  }
  SDAOUT = 0;
}

Proc ShiftByteFromI2C
{
  Counter = 8;
  SDAOUT = 1;
  Byte = 0;
  while(Counter != 0)
  {
    Byte = Byte << 1;
    SCL = 1;
    Byte.0 = SDAIN;
    SCL = 0;
    Counter--;
  }
}

Proc CheckAck
{
    SDAOUT = 1;SCL = 1;
    Error.0 = SDAIN;
    SCL = 0;
    SDAOUT = 0;
}

Proc Init { POUT = 0b00110000; BusInit(5,4,4,1,1); BUSDELAY = 0;}


Proc WaitReady {
    
  while {
    StartI2C; 
    Byte = 0xa0;
    ShiftByteToI2C;
    CheckAck;
    StopI2C;
    if(Error = 0) { break; }
  }
}
