/****************************************************************************
* Company: Actel Corporation
*
* File: EEPROM.c
* File history:
*     Revision: Initial version   Date: May 04, 2010
*
* Description:
*             EEPROM(M24512-R from ST) driver.
*             It handles the write and read operation
*
* Author: Pavan Marisetti
*         pavan.marisetti@actel.com
*         Corporate Applications Engineering
*
****************************************************************************/

#include "EEPROM.h"

/***************************************************************************//**
  EEPROM_init()
  See "EEPROM.h" for details of how to use this function.
 */
void EEPROM_init()
{
    MSS_I2C_init( I2C_INSTANCE, EEPROM_SLAVE_ADDRESS, EEPROM_I2C_CLK_FREQ );
}

/***************************************************************************/
/*
  EEPROM_write()
  See "EEPROM.h" for details of how to use this function.
 */

EEPROM_status_t
EEPROM_write
(
    uint16_t start_address,
    uint16_t size_in_bytes,
    uint8_t * write_buffer
)
{
    /* Local buffer to hold the maximum of 128(Page size) bytes with 2 bytes of address*/
    uint8_t write_buffer_local[130];
    /* variable to hold the number of bytes */
    uint8_t no_of_bytes;

    /* Address range checking*/
    if((start_address +  size_in_bytes )< 65537)
    {
       /* Splitting the total data in to pages and writing to the EEPROM*/
       while((size_in_bytes / PAGE_SIZE_IN_BYTES) != 0)
       {
           /* Conversion of 16 bit address in to MSB address bits A15/A7 and
              LSB address bits A6/A0 */
           write_buffer_local[ADDR_FIRST_LOC] = start_address >> 8;
           write_buffer_local[ADDR_SECOND_LOC] = start_address ;
           for(no_of_bytes=0;no_of_bytes<PAGE_SIZE_IN_BYTES;no_of_bytes++)
           {
               write_buffer_local[no_of_bytes + ADDR_LEN_IN_BYTES ] = *write_buffer++;
           }
           MSS_I2C_write( I2C_INSTANCE, EEPROM_SLAVE_ADDRESS, write_buffer_local,
                          (PAGE_SIZE_IN_BYTES + ADDR_LEN_IN_BYTES), MSS_I2C_RELEASE_BUS );
           I2C_STATUS = MSS_I2C_wait_complete( I2C_INSTANCE );
           size_in_bytes = size_in_bytes - PAGE_SIZE_IN_BYTES ;
           start_address = start_address + PAGE_SIZE_IN_BYTES ;
           /* Delay between Stop and Start conditions, This delay can be 2 to 3 cycles
           of I2C clock but here the delay is high. This is because the EEPROM and
           EtherCAT are connected to same I2C bus on the Development Kit. The
           EtherCAT SCL and SDA lines are interchanged with MSS signals. Because
           of this there are noisy trasactions on the I2C bus for every Operation
           of I2C, to skip those transactions the delay is provided */

           delay_btw_transfers (100000);
       }
       if((size_in_bytes > 0) & (size_in_bytes < PAGE_SIZE_IN_BYTES))
       {
           /* Conversion of 16 bit address in to MSB address bits A15/A7 and
              LSB address bits A6/A0 */
           write_buffer_local[ADDR_FIRST_LOC] = start_address >> 8;
           write_buffer_local[ADDR_SECOND_LOC] = start_address ;
           for(no_of_bytes=0; no_of_bytes <= size_in_bytes; no_of_bytes++)
           {
               write_buffer_local[no_of_bytes + ADDR_LEN_IN_BYTES ] = *write_buffer++;
           }

           MSS_I2C_write( I2C_INSTANCE, EEPROM_SLAVE_ADDRESS, write_buffer_local,
                          (size_in_bytes + ADDR_LEN_IN_BYTES), MSS_I2C_RELEASE_BUS );

           I2C_STATUS = MSS_I2C_wait_complete( I2C_INSTANCE );
           /* Delay between Stop and Start conditions, This delay can be 2 to 3 cycles
              of I2C clock but here the delay is high. This is because the EEPROM and
              EtherCAT are connected to same I2C bus on the Development Kit. The
              EtherCAT SCL and SDA lines are interchanged with MSS signals. Because
              of this there are noisy trasactions on the I2C bus for every Operation
              of I2C, to skip those transactions the delay is provided */
           delay_btw_transfers (100000);
       }
       /* Returns the EEPROM write status depending on the I2C status*/
       if(I2C_STATUS == MSS_I2C_SUCCESS)
       {
           return EEPROM_WRITE_SUCCESS;
       }
       else
       {
           return EEPROM_WRITE_UNSUCCESS;
       }
    }
    /* Returns the EEPROM address fault status if the start address + size of the bytes
    crosses the total lenght of the EEPROM*/
    else
    {
        return EEPROM_ADDRESS_FAULT;
    }
}
/***************************************************************************//**
  EEPROM_read()
  See "EEPROM.h" for details of how to use this function.
 */

EEPROM_status_t
EEPROM_read
(
    uint16_t start_address,
    uint16_t size_in_bytes,
    uint8_t  * read_buffer
)
{
    /* Local buffer to hold 2 bytes of address */
    uint16_t read_addr[2];
   /* Conversion of 16 bit address in to MSB address bits A15/A7 and
      LSB address bits A6/A0 */
    read_addr[ADDR_FIRST_LOC] = start_address >> 8;
    read_addr[ADDR_SECOND_LOC] = start_address ;
    /* Address range checking*/
    if((start_address +  size_in_bytes )< 65537)
    {
        MSS_I2C_write( I2C_INSTANCE, EEPROM_SLAVE_ADDRESS, read_addr,
                       (ADDR_LEN_IN_BYTES), MSS_I2C_HOLD_BUS );
        I2C_STATUS = MSS_I2C_wait_complete( I2C_INSTANCE );

        MSS_I2C_read( I2C_INSTANCE, EEPROM_SLAVE_ADDRESS, read_buffer,size_in_bytes, MSS_I2C_RELEASE_BUS );
        I2C_STATUS = MSS_I2C_wait_complete( I2C_INSTANCE );
        /* Delay between Stop and Start conditions, This delay can be 2 to 3 cycles
           of I2C clock but here the delay is high. This is because the EEPROM and
           EtherCAT are connected to same I2C bus on the Development Kit. The
           EtherCAT SCL and SDA lines are interchanged with MSS signals. Because
           of this there are noisy trasactions on the I2C bus for every Operation
           of I2C, to skip those transactions the delay is provided */
        delay_btw_transfers (10000000);
        if(I2C_STATUS == MSS_I2C_SUCCESS)
        {
            return EEPROM_READ_SUCCESS;
        }
        else
        {
            return EEPROM_READ_UNSUCCESS;
        }
    }
    /* Returns the EEPROM address fault status if the start address + size of the bytes
    crosses the total lenght of the EEPROM*/
    else
    {
       return EEPROM_ADDRESS_FAULT;
    }
}

/***************************************************************************//**
  delay_btw_transfers ( volatile uint32_t n)
  See "EEPROM.h" for details of how to use this function.
 */
void delay_btw_transfers ( volatile uint32_t n)
{
    while(n!=0)
    {
        n--;
    }
}
