Xeeprom.c

Fra Hougaard

Skift til: Navigation, Søgning
/*********************************************************************
 *
 *               Data EEPROM Access Routines
 *
 *********************************************************************
 * FileName:        xeeprom.c
 * Dependencies:    compiler.h
 *                  xeeprom.h
 * Processor:       PIC18
 * Complier:        MCC18 v1.00.50 or higher
 *                  HITECH PICC-18 V8.10PL1 or higher
 * Company:         Microchip Technology, Inc.
 *
 * Software License Agreement
 *
 * The software supplied herewith by Modtronix Engineering is based on v2.20.04.01
 * of the Microchip TCP/IP stack. The original code base is owned by Microchip
 * Technology Incorporated (the Company), and is protected under applicable
 * copyright laws. The modifications are owned by Modtronix Engineering, and is
 * protected under applicable copyright laws. The software supplied herewith is
 * intended and supplied to you, the Company customer, for use solely and
 * exclusively on Microchip PICmicro Microcontroller based products manufactured
 * by Modtronix Engineering. The code may be modified and can be used free of charge
 * for non commercial and commercial applications. All rights are reserved. Any use
 * in violation of the foregoing restrictions may subject the user to criminal
 * sanctions under applicable laws, as well as to civil liability for the breach
 * of the terms and conditions of this license.
 *
 * THIS SOFTWARE IS PROVIDED IN AN 'AS IS' CONDITION. NO WARRANTIES, WHETHER EXPRESS,
 * IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE
 * COMPANY SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR
 * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
 *
 * This is a modified version of C18 library functions.
 * This version supports data EEPROM with two bytes of address.
 * It still uses some of the routines from C18 library.
 *
 *
 * HiTech PICC18 Compiler Options excluding device selection:
 *                  -FAKELOCAL -G -O -Zg -E -C
 *
 *
 * Author               Date        Comment
 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 * Nilesh Rajbharti     5/20/02     Original (Rev. 1.0)
********************************************************************/
#include "xeeprom.h"
 
#define IdleI2C()       while ( ( SSPCON2 & 0x1F ) | ( SSPSTAT_R_W ) );
#define StartI2C()      SSPCON2_SEN=1
#define RestartI2C()    SSPCON2_RSEN=1
#define StopI2C()       SSPCON2_PEN=1
#define NotAckI2C()     SSPCON2_ACKDT=1, SSPCON2_ACKEN=1
 
static unsigned char getcI2C( void );
static unsigned char WriteI2C( unsigned char data_out );
XEE_RESULT XEEClose(void);
 
 
 
/*********************************************************************
 * Function:        void XEEInit(unsigned char baud)
 *
 * PreCondition:    None
 *
 * Input:           baud    - SSPADD value for bit rate.
 *
 * Output:          None
 *
 * Side Effects:    None
 *
 * Overview:        Initialize I2C module to communicate to serial
 *                  EEPROM.
 *
 * Note:            None
 ********************************************************************/
#define   MASTER    8     /* I2C Master mode                    */
/* SSPSTAT REGISTER */
#define   SLEW_OFF  0xC0  /* Slew rate disabled for 100kHz mode */
#define   SLEW_ON   0x00  /* Slew rate enabled for 400kHz mode  */
#define   SSPENB    0x20  /* Enable serial port and configures
                             SCK, SDO, SDI                      */
void XEEInit(unsigned char baud)
{
  SSPSTAT &= 0x3F;              // power on state
  SSPCON1 = 0x00;               // power on state
  SSPCON2 = 0x00;               // power on state
  SSPCON1 |= MASTER;            // select serial mode
  SSPSTAT |= SLEW_ON;           // slew rate on/off
 
  TRISC_RC3 = 1;                // Set SCL (PORTC,3) pin to input
  TRISC_RC4 = 1;                // Set SDA (PORTC,4) pin to input. Is controlled by I2C hardware
 
  SSPCON1 |= SSPENB;            // enable synchronous serial port
 
  SSPADD = baud;
}
 
 
/*********************************************************************
 * Function:        XEE_RESULT XEESetAddr(unsigned char control,
 *                                        XEE_ADDR address)
 *
 * PreCondition:    XEEInit() is already called.
 *
 * Input:           control     - data EEPROM control code
 *                  address     - address to be set
 *
 * Output:          XEE_SUCCESS if successful
 *                  other value if failed.
 *
 * Side Effects:    None
 *
 * Overview:        Modifies internal address counter of EEPROM.
 *
 * Note:            This function does not release the I2C bus.
 *                  User must close XEEClose() after this function
 *                  is called.
 ********************************************************************/
XEE_RESULT XEESetAddr(unsigned char control, XEE_ADDR address)
{
    union
    {
        unsigned short int Val;
        struct
        {
            unsigned char LSB;
            unsigned char MSB;
        } bytes;
    } tempAddress;
 
    tempAddress.Val = address;
 
    IdleI2C();                      // ensure module is idle
    StartI2C();                     // initiate START condition
    while ( SSPCON2_SEN );      // wait until start condition is over
    if ( PIR2_BCLIF )           // test for bus collision
        return XEE_BUS_COLLISION;                // return with Bus Collision error
 
    if ( WriteI2C( control ) )    // write 1 byte
        return XEE_BUS_COLLISION;              // set error for write collision
 
    IdleI2C();                    // ensure module is idle
    if ( !SSPCON2_ACKSTAT )   // test for ACK condition, if received
    {
				if (control == 0xa0)
				{
	        if ( WriteI2C( tempAddress.bytes.MSB ) )  // WRITE word address to EEPROM
	            return XEE_BUS_COLLISION;            // return with write collision error
 
	        IdleI2C();                  // ensure module is idle
 
	          if ( WriteI2C( tempAddress.bytes.LSB ) )  // WRITE word address to EEPROM
	              return XEE_BUS_COLLISION;            // return with write collision error
	      }
	      else
	      {
		      // Devices with 1 bytes address
	        if (WriteI2C(tempAddress.bytes.LSB))
	        	return XEE_BUS_COLLISION;
	       }
 
        IdleI2C();                  // ensure module is idle
        if ( !SSPCON2_ACKSTAT ) // test for ACK condition received
            return XEE_SUCCESS;
        else
            return XEE_NAK;            // return with Not Ack error
    }
    else
        return XEE_NAK;              // return with Not Ack error
}
 
/*********************************************************************
 * Function:        XEE_RESULT XEEBeginRead(unsigned char control,
 *                                          XEE_ADDR address)
 *
 * PreCondition:    XEEInit() is already called.
 *
 * Input:           control - EEPROM control and address code.
 *                  address - Address at which read is to be performed.
 *
 * Output:          XEE_SUCCESS if successful
 *                  other value if failed.
 *
 * Side Effects:    None
 *
 * Overview:        Sets internal address counter to given address.
 *                  Puts EEPROM in sequential read mode.
 *
 * Note:            This function does not release I2C bus.
 *                  User must call XEEEndRead() when read is not longer
 *                  needed; I2C bus will released after XEEEndRead()
 *                  is called.
 ********************************************************************/
XEE_RESULT XEEBeginRead(unsigned char control, XEE_ADDR address )
{
    unsigned char r;
 
    r = XEESetAddr(control, address);
    if ( r != XEE_SUCCESS )
        return r;
 
    r = XEEClose();
    if ( r != XEE_SUCCESS )
        return r;
 
 
    IdleI2C();
    StartI2C();
    while( SSPCON2_SEN );
    if ( PIR2_BCLIF )
        return XEE_BUS_COLLISION;
 
    if ( WriteI2C(control+1) )
        return XEE_BUS_COLLISION;
 
    IdleI2C();
    if ( !SSPCON2_ACKSTAT )
        return XEE_SUCCESS;
    return XEE_NAK;
}
 
 
XEE_RESULT XEEWrite(unsigned char val)
{
    IdleI2C();                  // ensure module is idle
 
    if ( WriteI2C( val ) )   // data byte for EEPROM
        return XEE_BUS_COLLISION;          // set error for write collision
 
    IdleI2C();
    if ( !SSPCON2_ACKSTAT )
        return XEE_SUCCESS;
    return XEE_NAK;
}
 
/*********************************************************************
 * Function:        XEE_RESULT XEEEndWrite(void)
 *
 * PreCondition:    XEEInit() && XEEBeginWrite() are already called.
 *
 * Input:           None
 *
 * Output:          XEE_SUCCESS if successful
 *                  other value if failed.
 *
 * Side Effects:    None
 *
 * Overview:        Instructs EEPROM to begin write cycle.
 *
 * Note:            Call this function after either page full of bytes
 *                  written or no more bytes are left to load.
 *                  This function initiates the write cycle.
 *                  User must call for XEEWait() to ensure that write
 *                  cycle is finished before calling any other
 *                  routine.
 ********************************************************************/
XEE_RESULT XEEEndWrite(void)
{
    IdleI2C();
    StopI2C();
    while(SSPCON2_PEN);
    return XEE_SUCCESS;
}
 
 
 
/*********************************************************************
 * Function:        XEE_RESULT XEERead(void)
 *
 * PreCondition:    XEEInit() && XEEBeginRead() are already called.
 *
 * Input:           None
 *
 * Output:          XEE_SUCCESS if successful
 *                  other value if failed.
 *
 * Side Effects:    None
 *
 * Overview:        Reads next byte from EEPROM; internal address
 *                  is incremented by one.
 *
 * Note:            This function does not release I2C bus.
 *                  User must call XEEEndRead() when read is not longer
 *                  needed; I2C bus will released after XEEEndRead()
 *                  is called.
 ********************************************************************/
unsigned char XEERead(void)
{
    getcI2C();
    while( SSPCON2_RCEN );  // check that receive sequence is over.
 
    SSPCON2_ACKDT = 0;      // Set ack bit
    SSPCON2_ACKEN = 1;
    while( SSPCON2_ACKEN );
 
    return SSPBUF;
}
 
/*********************************************************************
 * Function:        XEE_RESULT XEEEndRead(void)
 *
 * PreCondition:    XEEInit() && XEEBeginRead() are already called.
 *
 * Input:           None
 *
 * Output:          XEE_SUCCESS if successful
 *                  other value if failed.
 *
 * Side Effects:    None
 *
 * Overview:        Ends sequential read cycle.
 *
 * Note:            This function ends seuential cycle that was in
 *                  progress.  It releases I2C bus.
 ********************************************************************/
XEE_RESULT XEEEndRead(void)
{
    getcI2C();
    while( SSPCON2_RCEN );  // check that receive sequence is over.
 
    NotAckI2C();
    while( SSPCON2_ACKEN );
 
    StopI2C();
    while( SSPCON2_PEN );
 
    return XEE_SUCCESS;
}
 
 
/*********************************************************************
 * Function:        XEE_RESULT XEEReadArray(unsigned char control,
 *                                          XEE_ADDR address,
 *                                          unsigned char *buffer,
 *                                          unsigned char length)
 *
 * PreCondition:    XEEInit() is already called.
 *
 * Input:           control     - EEPROM control and address code.
 *                  address     - Address from where array is to be read
 *                  buffer      - Caller supplied buffer to hold the data
 *                  length      - Number of bytes to read.
 *
 * Output:          XEE_SUCCESS if successful
 *                  other value if failed.
 *
 * Side Effects:    None
 *
 * Overview:        Reads desired number of bytes in sequential mode.
 *                  This function performs all necessary steps
 *                  and releases the bus when finished.
 *
 * Note:            None
 ********************************************************************/
XEE_RESULT XEEReadArray(unsigned char control,
                        XEE_ADDR address,
                        unsigned char *buffer,
                        unsigned char length)
{
    XEE_RESULT r;
 
    r = XEEBeginRead(control, address);
    if ( r != XEE_SUCCESS )
        return r;
 
    while( length-- )
        *buffer++ = XEERead();
 
    r = XEEEndRead();
 
    return r;
}
 
 
 
 
XEE_RESULT XEEClose(void)
{
    IdleI2C();
    StopI2C();
    while( SSPCON2_PEN );           // wait until stop condition is over.
    if ( PIR2_BCLIF )
        return XEE_BUS_COLLISION;
    return XEE_SUCCESS;
}
 
 
 
/*********************************************************************
 * Function:        XEE_RESULT XEEIsBusy(unsigned char control)
 *
 * PreCondition:    XEEInit() is already called.
 *
 * Input:           control     - EEPROM control and address code.
 *
 * Output:          XEE_READY if EEPROM is not busy
 *                  XEE_BUSY if EEPROM is busy
 *                  other value if failed.
 *
 * Side Effects:    None
 *
 * Overview:        Requests ack from EEPROM.
 *
 * Note:            None
 ********************************************************************/
XEE_RESULT XEEIsBusy(unsigned char control)
{
    XEE_RESULT r;
 
    IdleI2C();                      // ensure module is idle
    StartI2C();                     // initiate START condition
    while ( SSPCON2_SEN );      // wait until start condition is over
    if ( PIR2_BCLIF )           // test for bus collision
    {
        return XEE_BUS_COLLISION;                // return with Bus Collision error
    }
 
    else
    {
        if ( WriteI2C( control ) )    // write byte - R/W bit should be 0
            return XEE_BUS_COLLISION;              // set error for write collision
 
        IdleI2C();                    // ensure module is idle
        if ( PIR2_BCLIF )         // test for bus collision
            return XEE_BUS_COLLISION;              // return with Bus Collision error
 
        if ( !SSPCON2_ACKSTAT )
            r = XEE_READY;
        else
            r = XEE_BUSY;
 
#if 0
        while ( SSPCON2_ACKSTAT ) // test for ACK condition received
        {
            RestartI2C();               // initiate Restart condition
            while ( SSPCON2_RSEN ); // wait until re-start condition is over
            if ( PIR2_BCLIF )       // test for bus collision
                return XEE_BUS_COLLISION;            // return with Bus Collision error
 
            if ( WriteI2C( control ) )  // write byte - R/W bit should be 0
                return XEE_BUS_COLLISION;            // set error for write collision
 
            IdleI2C();                  // ensure module is idle
        }
#endif
    }
 
 
    StopI2C();                      // send STOP condition
    while ( SSPCON2_PEN );      // wait until stop condition is over
    if ( PIR2_BCLIF )           // test for bus collision
        return XEE_BUS_COLLISION;                // return with Bus Collision error
 
    return r;
    //return XEE_READY;                   // return with no error
}
 
 
/********************************************************************
*     Function Name:    WriteI2C                                    *
*     Return Value:     Status byte for WCOL detection.             *
*     Parameters:       Single data byte for I2C bus.               *
*     Description:      This routine writes a single byte to the    *
*                       I2C bus.                                    *
********************************************************************/
static unsigned char WriteI2C( unsigned char data_out )
{
  SSPBUF = data_out;           // write single byte to SSPBUF
  if ( SSPCON1_WCOL )      // test if write collision occurred
   return ( -1 );              // if WCOL bit is set return negative #
  else
  {
    while( SSPSTAT_BF );   // wait until write cycle is complete
    return ( 0 );              // if WCOL bit is not set return non-negative #
  }
}
 
 
 
/********************************************************************
*     Function Name:    ReadI2C                                     *
*     Return Value:     contents of SSPBUF register                 *
*     Parameters:       void                                        *
*     Description:      Read single byte from I2C bus.              *
********************************************************************/
static unsigned char getcI2C( void )
{
  SSPCON2_RCEN = 1;           // enable master for 1 byte reception
  while ( !SSPSTAT_BF );      // wait until byte received
  return ( SSPBUF );              // return with read byte
}