/* > > > > > > > > > > > > >  24xx00-16_EEPROM.c < < < < < < < < < < < < < < < */

// <editor-fold defaultstate="collapsed" desc="Title">
/******************************************************************************/
/*                        © John William Darsow                               */
/* Created on May 2, 2014, 6:44 PM                                            */
/* Current Version Date: (see File Date)                                      */
/* Working & Clean May 24, 2014                                               */
/*                                                                            */
/*  Discription:                                                              */
/* Microchip 24xx00(128bit) to 24xx16(16K) I²C Serial EEPROM Routines         */
/*                                                                            */
/* 24xx00/16x Control Byte [1 0 1 0 b2 b1 b0 R/W]                             */
/* Input addr limited to  FF, Bank 0      b2, b1 & b0 is "Don't Care"     '02 */
/* Input addr limited to 1FF, Banks 0 & 1     b2 & b1 is "Don't Care"     '04 */
/* Input addr limited to 3FF, Banks 0, 1, 2 & 3    b2 is "Don't Care"     '08 */
/* Input addr limited to 7FF, Banks 0, 1, 2, 3, 4, 5, 6 & 7               '16 */
/*                                                                            */
/*  Compiled using:     MPLAB X IDE v2.30                                     */
/*                      XC8 v1.31                                             */
/*                                                                            */
/* Modifications,UpDates and ToDo:                                            */
/*                                                                            */
/*                                                                            */
/******************************************************************************/
// </editor-fold>

// <editor-fold defaultstate="collapsed" desc="INCLUDEs">
/********************************** INCLUDEs **********************************/
#include <xc.h>
#include "EEPROM_24xx00-16.h"
// </editor-fold>

// <editor-fold defaultstate="collapsed" desc="GLOBAL VARIABLES">
/***************************** GLOBAL  VARIABLES ******************************/
volatile Byte BlockSelect;
// </editor-fold>

/********************************* FUNCTIONS **********************************/

/*──────────────────── Write byte to an EEPROM address ───────────────────────*/
void xeeprom_wr_byte(uInt16 addr, Byte data)
{
/* Upper 2bits addr need to be combined with control code & R/nW bit */
   BlockSelect = addr >> 8;                 // Drop low Byte (fill upper nibble w/0)
   BlockSelect = BlockSelect | EEPROMaddr;  // Combine Block address with bus address
   BlockSelect = (unsigned) BlockSelect << 1U;         // Make room for R/nW bit, filled w/0, Write
    
   i2c_start();                             // generate Start COndition
   i2c_byte_out(BlockSelect);               // Control Byte
   i2c_byte_out(addr & 0x00ff);             // Addr Low Byte
   i2c_byte_out(data);                      // send data
   i2c_stop();                              // initiate Stop Condition
   i2c_PollAck(BlockSelect);                // Wait for write cycle
}

/*────────────────── Write upto 16 Bytes to an EEPROM address ────────────────*/
void xeeprom_wr_page(uInt16 addr,Byte *data, uInt8 length)
{
unsigned char i = 0;

/* Upper 2bits addr need to be combined with control code & R/nW bit */
   BlockSelect = addr >> 8;                 // Drop low Byte (fill upper nibble w/0)
   BlockSelect = BlockSelect | EEPROMaddr;  // Combine Block address with bus address
   BlockSelect = (unsigned) BlockSelect << 1U;         // Make room for R/nW bit, filled w/0, Write

   i2c_start();                             // generate Start COndition
   i2c_byte_out(BlockSelect);               // Control Byte
   i2c_byte_out(addr & 0x00ff);             // Addr Low Byte
   for (i = 0; i <= length; i++)
      i2c_byte_out(data[i]);                // Write up to 16 data bytes
   i2c_stop();                              // send Stop condition
}

/*──────────────────────────── Read the next byte ────────────────────────────*/
Byte xeeprom_rd_next_byte(void)
{
Byte data;

/* Use previous BlockSelect  */
   i2c_start();                             // generate Start COndition
   i2c_byte_out(BlockSelect | 1U);          // Send CtrlByte w/Block Select & R/nW=1
   data = i2c_byte_in();                    // read data
   i2c_stop();                              // send Stop Condition

   return data;                             // return data from I2C buffer
}

/*──────────────────── Read byte from an EEPROM address ──────────────────────*/
Byte xeeprom_rd_byte(uInt16 addr)
{
Byte data;

/* Upper 2bits addr need to be combined with control code & R/nW bit */
   BlockSelect = addr >> 8;                 // Drop lower Byte (fill upper nibble w/0)
   BlockSelect = BlockSelect | EEPROMaddr;  // Combine Block address with bus address
   BlockSelect = (unsigned) BlockSelect << 1;    // Make room for R/nW bit, filled w/0, Write

   i2c_start();                             // generate 1st Start Condition
   i2c_byte_out(BlockSelect);               // Send CtrlByte w/Block Select & R/nW=0
   i2c_byte_out(addr & 0x00ff);             // Send Addr Byte
   i2c_start();                             // generate 2nd Start Condition
   i2c_byte_out(BlockSelect | 1u);          // Make R/nW=1, Read, send READ command
   data = i2c_byte_in();                    // read data
   i2c_GiveAck(NACK);                       // Send NACK bit
   i2c_stop();                              // send Stop Condition

   return data;                             // return data from I2C buffer
}

/*───────────────── Read Sequentially from an EEPROM address ─────────────────*/
void xeeprom_rd_page(uInt16 addr, Byte *data, uInt8 length)
{
unsigned char i = 0;

/* Upper 2bits addr need to be combined with control code & R/nW bit */
   BlockSelect = addr >> 8;                 // Drop lower Byte (fill upper nibble w/0)
   BlockSelect = BlockSelect | EEPROMaddr;  // Combine Block address with bus address
   BlockSelect = (unsigned) BlockSelect << 1;    // Make room for R/nW bit, filled w/0, Write

   i2c_start();                             // generate 1st Start COndition
   i2c_byte_out(BlockSelect);               // Send CtrlByte w/Block Select & R/nW=0
   i2c_byte_out(addr & 0x00ff);             // Send Addr Byte
   i2c_start();                             // generate 2nd Start COndition
   i2c_byte_out(BlockSelect | 1u);          // Make R/nW=1 send READ command
   for (i=0; i <= length - 1; i++)          // loop through the number of bytes
      data[i]=i2c_byte_in();                // Read next byte to array, Send nACK
   data[i]=i2c_byte_in();                   // Read last byte to array, Send NACK
   i2c_stop();                              // send Stop Condition
}
