Subversion Repositories HomeAutomation

Rev

Rev 363 | Blame | Compare with Previous | Last modification | View Log | SVN | RSS feed

  1. /*********************************************************************
  2.  *
  3.  *               Data I2C EEPROM Access Routines
  4.  *
  5.  *********************************************************************
  6.  * FileName:        I2CEEPROM.c
  7.  * Dependencies:    Compiler.h
  8.  *                  XEEPROM.h
  9.  * Processor:       PIC18
  10.  * Complier:        Microchip C18 v3.03 or higher
  11.  * Company:         Microchip Technology, Inc.
  12.  *
  13.  * Software License Agreement
  14.  *
  15.  * This software is owned by Microchip Technology Inc. ("Microchip")
  16.  * and is supplied to you for use exclusively as described in the
  17.  * associated software agreement.  This software is protected by
  18.  * software and other intellectual property laws.  Any use in
  19.  * violation of the software license may subject the user to criminal
  20.  * sanctions as well as civil liability.  Copyright 2006 Microchip
  21.  * Technology Inc.  All rights reserved.
  22.  *
  23.  * This software is provided "AS IS."  MICROCHIP DISCLAIMS ALL
  24.  * WARRANTIES, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, NOT LIMITED
  25.  * TO MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
  26.  * INFRINGEMENT.  Microchip shall in no event be liable for special,
  27.  * incidental, or consequential damages.
  28.  *
  29.  *
  30.  * Author               Date        Comment
  31.  *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  32.  * Nilesh Rajbharti     5/20/02     Original (Rev. 1.0)
  33.  * Howard Schlunder     8/10/06     Renamed registers/bits to use
  34.  *                                  C18/C30 style standard names
  35. ********************************************************************/
  36. #include "..\Include\Compiler.h"
  37. #include "..\Include\XEEPROM.h"
  38.  
  39. #if defined(MPFS_USE_EEPROM)
  40.  
  41. #if !defined(PICDEMNET)
  42.     #error "PICDEMNET is not defined, but I2CEEPROM.c is included.  Was SPIEEPROM.c supposed to be included instead?"
  43. #endif
  44.  
  45. #define IdleI2C()       while( (EEPROM_SPICON2 & 0x1F) | (EEPROM_SPISTATbits.R_W) );
  46. #define StartI2C()      EEPROM_SPICON2bits.SEN=1
  47. #define RestartI2C()    EEPROM_SPICON2bits.RSEN=1
  48. #define StopI2C()       EEPROM_SPICON2bits.PEN=1
  49. #define NotAckI2C()     EEPROM_SPICON2bits.ACKDT=1, EEPROM_SPICON2bits.ACKEN=1
  50.  
  51. static unsigned char getcI2C( void );
  52. static unsigned char WriteI2C( unsigned char data_out );
  53. XEE_RESULT XEEClose(void);
  54.  
  55.  
  56.  
  57. /*********************************************************************
  58.  * Function:        void XEEInit(unsigned char baud)
  59.  *
  60.  * PreCondition:    None
  61.  *
  62.  * Input:           baud    - SSPADD value for bit rate.
  63.  *
  64.  * Output:          None
  65.  *
  66.  * Side Effects:    None
  67.  *
  68.  * Overview:        Initialize I2C module to communicate to serial
  69.  *                  EEPROM.
  70.  *
  71.  * Note:            None
  72.  ********************************************************************/
  73. #define   MASTER    8     /* I2C Master mode                    */
  74. /* SSPSTAT REGISTER */
  75. #define   SLEW_OFF  0xC0  /* Slew rate disabled for 100kHz mode */
  76. #define   SLEW_ON   0x00  /* Slew rate enabled for 400kHz mode  */
  77. #define   SSPENB    0x20  /* Enable serial port and configures
  78.                              SCK, SDO, SDI                      */
  79. void XEEInit(unsigned char baud)
  80. {
  81.   SSPSTAT &= 0x3F;                // power on state
  82.   SSPCON1 = 0x00;                 // power on state
  83.   EEPROM_SPICON2 = 0x00;                 // power on state
  84.   SSPCON1 |= MASTER;            // select serial mode
  85.   SSPSTAT |= SLEW_ON;                // slew rate on/off
  86.  
  87.   EEPROM_SCL_TRIS = 1;           // Set SCL (PORTC,3) pin to input
  88.   EEPROM_SDA_TRIS = 1;           // Set SDA (PORTC,4) pin to input
  89.  
  90.   SSPCON1 |= SSPENB;              // enable synchronous serial port
  91.  
  92.   SSPADD = baud;
  93. }
  94.  
  95.  
  96. /*********************************************************************
  97.  * Function:        XEE_RESULT XEESetAddr(unsigned char control,
  98.  *                                        XEE_ADDR address)
  99.  *
  100.  * PreCondition:    XEEInit() is already called.
  101.  *
  102.  * Input:           control     - data EEPROM control code
  103.  *                  address     - address to be set
  104.  *
  105.  * Output:          XEE_SUCCESS if successful
  106.  *                  other value if failed.
  107.  *
  108.  * Side Effects:    None
  109.  *
  110.  * Overview:        Modifies internal address counter of EEPROM.
  111.  *
  112.  * Note:            This function does not release the I2C bus.
  113.  *                  User must close XEEClose() after this function
  114.  *                  is called.
  115.  ********************************************************************/
  116. XEE_RESULT XEESetAddr(unsigned char control, XEE_ADDR address)
  117. {
  118.     union
  119.     {
  120.         unsigned short int Val;
  121.         struct
  122.         {
  123.             unsigned char LSB;
  124.             unsigned char MSB;
  125.         } bytes;
  126.     } tempAddress;
  127.  
  128.     tempAddress.Val = address;
  129.  
  130.     IdleI2C();                      // ensure module is idle
  131.     StartI2C();                     // initiate START condition
  132.     while ( EEPROM_SPICON2bits.SEN );      // wait until start condition is over
  133.     if ( PIR2bits.BCLIF )           // test for bus collision
  134.         return XEE_BUS_COLLISION;                // return with Bus Collision error
  135.  
  136.     if ( WriteI2C( control ) )    // write 1 byte
  137.         return XEE_BUS_COLLISION;              // set error for write collision
  138.  
  139.     IdleI2C();                    // ensure module is idle
  140.     if ( !EEPROM_SPICON2bits.ACKSTAT )   // test for ACK condition, if received
  141.     {
  142.         if ( WriteI2C( tempAddress.bytes.MSB ) )  // WRITE word address to EEPROM
  143.             return XEE_BUS_COLLISION;            // return with write collision error
  144.  
  145.         IdleI2C();                  // ensure module is idle
  146.  
  147.         if ( WriteI2C( tempAddress.bytes.LSB ) )  // WRITE word address to EEPROM
  148.             return XEE_BUS_COLLISION;            // return with write collision error
  149.  
  150.         IdleI2C();                  // ensure module is idle
  151.         if ( !EEPROM_SPICON2bits.ACKSTAT ) // test for ACK condition received
  152.             return XEE_SUCCESS;
  153.         else
  154.             return XEE_NAK;            // return with Not Ack error
  155.     }
  156.     else
  157.         return XEE_NAK;              // return with Not Ack error
  158. }
  159.  
  160. /*********************************************************************
  161.  * Function:        XEE_RESULT XEEBeginRead(unsigned char control,
  162.  *                                          XEE_ADDR address)
  163.  *
  164.  * PreCondition:    XEEInit() is already called.
  165.  *
  166.  * Input:           control - EEPROM control and address code.
  167.  *                  address - Address at which read is to be performed.
  168.  *
  169.  * Output:          XEE_SUCCESS if successful
  170.  *                  other value if failed.
  171.  *
  172.  * Side Effects:    None
  173.  *
  174.  * Overview:        Sets internal address counter to given address.
  175.  *                  Puts EEPROM in sequential read mode.
  176.  *
  177.  * Note:            This function does not release I2C bus.
  178.  *                  User must call XEEEndRead() when read is not longer
  179.  *                  needed; I2C bus will released after XEEEndRead()
  180.  *                  is called.
  181.  ********************************************************************/
  182. XEE_RESULT XEEBeginRead(unsigned char control, XEE_ADDR address )
  183. {
  184.     unsigned char r;
  185.  
  186.     r = XEESetAddr(control, address);
  187.     if ( r != XEE_SUCCESS )
  188.         return r;
  189.  
  190.     r = XEEClose();
  191.     if ( r != XEE_SUCCESS )
  192.         return r;
  193.  
  194.  
  195.     IdleI2C();
  196.     StartI2C();
  197.     while( EEPROM_SPICON2bits.SEN );
  198.     if ( PIR2bits.BCLIF )
  199.         return XEE_BUS_COLLISION;
  200.  
  201.     if ( WriteI2C(control+1) )
  202.         return XEE_BUS_COLLISION;
  203.  
  204.     IdleI2C();
  205.     if ( !EEPROM_SPICON2bits.ACKSTAT )
  206.         return XEE_SUCCESS;
  207.     return XEE_NAK;
  208. }
  209.  
  210.  
  211. XEE_RESULT XEEWrite(unsigned char val)
  212. {
  213.     IdleI2C();                  // ensure module is idle
  214.  
  215.     if ( WriteI2C( val ) )   // data byte for EEPROM
  216.         return XEE_BUS_COLLISION;          // set error for write collision
  217.  
  218.     IdleI2C();
  219.     if ( !EEPROM_SPICON2bits.ACKSTAT )
  220.         return XEE_SUCCESS;
  221.     return XEE_NAK;
  222. }
  223.  
  224. /*********************************************************************
  225.  * Function:        XEE_RESULT XEEEndWrite(void)
  226.  *
  227.  * PreCondition:    XEEInit() && XEEBeginWrite() are already called.
  228.  *
  229.  * Input:           None
  230.  *
  231.  * Output:          XEE_SUCCESS if successful
  232.  *                  other value if failed.
  233.  *
  234.  * Side Effects:    None
  235.  *
  236.  * Overview:        Instructs EEPROM to begin write cycle.
  237.  *
  238.  * Note:            Call this function after either page full of bytes
  239.  *                  written or no more bytes are left to load.
  240.  *                  This function initiates the write cycle.
  241.  *                  User must call for XEEWait() to ensure that write
  242.  *                  cycle is finished before calling any other
  243.  *                  routine.
  244.  ********************************************************************/
  245. XEE_RESULT XEEEndWrite(void)
  246. {
  247.     IdleI2C();
  248.     StopI2C();
  249.     while(EEPROM_SPICON2bits.PEN);
  250.     return XEE_SUCCESS;
  251. }
  252.  
  253.  
  254.  
  255. /*********************************************************************
  256.  * Function:        XEE_RESULT XEERead(void)
  257.  *
  258.  * PreCondition:    XEEInit() && XEEBeginRead() are already called.
  259.  *
  260.  * Input:           None
  261.  *
  262.  * Output:          XEE_SUCCESS if successful
  263.  *                  other value if failed.
  264.  *
  265.  * Side Effects:    None
  266.  *
  267.  * Overview:        Reads next byte from EEPROM; internal address
  268.  *                  is incremented by one.
  269.  *
  270.  * Note:            This function does not release I2C bus.
  271.  *                  User must call XEEEndRead() when read is not longer
  272.  *                  needed; I2C bus will released after XEEEndRead()
  273.  *                  is called.
  274.  ********************************************************************/
  275. unsigned char XEERead(void)
  276. {
  277.     getcI2C();
  278.     while( EEPROM_SPICON2bits.RCEN );  // check that receive sequence is over.
  279.  
  280.     EEPROM_SPICON2bits.ACKDT = 0;      // Set ack bit
  281.     EEPROM_SPICON2bits.ACKEN = 1;
  282.     while( EEPROM_SPICON2bits.ACKEN );
  283.  
  284.     return EEPROM_SSPBUF;
  285. }
  286.  
  287. /*********************************************************************
  288.  * Function:        XEE_RESULT XEEEndRead(void)
  289.  *
  290.  * PreCondition:    XEEInit() && XEEBeginRead() are already called.
  291.  *
  292.  * Input:           None
  293.  *
  294.  * Output:          XEE_SUCCESS if successful
  295.  *                  other value if failed.
  296.  *
  297.  * Side Effects:    None
  298.  *
  299.  * Overview:        Ends sequential read cycle.
  300.  *
  301.  * Note:            This function ends seuential cycle that was in
  302.  *                  progress.  It releases I2C bus.
  303.  ********************************************************************/
  304. XEE_RESULT XEEEndRead(void)
  305. {
  306.     getcI2C();
  307.     while( EEPROM_SPICON2bits.RCEN );  // check that receive sequence is over.
  308.  
  309.     NotAckI2C();
  310.     while( EEPROM_SPICON2bits.ACKEN );
  311.  
  312.     StopI2C();
  313.     while( EEPROM_SPICON2bits.PEN );
  314.  
  315.     return XEE_SUCCESS;
  316. }
  317.  
  318.  
  319. /*********************************************************************
  320.  * Function:        XEE_RESULT XEEReadArray(unsigned char control,
  321.  *                                          XEE_ADDR address,
  322.  *                                          unsigned char *buffer,
  323.  *                                          unsigned char length)
  324.  *
  325.  * PreCondition:    XEEInit() is already called.
  326.  *
  327.  * Input:           control     - EEPROM control and address code.
  328.  *                  address     - Address from where array is to be read
  329.  *                  buffer      - Caller supplied buffer to hold the data
  330.  *                  length      - Number of bytes to read.
  331.  *
  332.  * Output:          XEE_SUCCESS if successful
  333.  *                  other value if failed.
  334.  *
  335.  * Side Effects:    None
  336.  *
  337.  * Overview:        Reads desired number of bytes in sequential mode.
  338.  *                  This function performs all necessary steps
  339.  *                  and releases the bus when finished.
  340.  *
  341.  * Note:            None
  342.  ********************************************************************/
  343. XEE_RESULT XEEReadArray(unsigned char control,
  344.                         XEE_ADDR address,
  345.                         unsigned char *buffer,
  346.                         unsigned char length)
  347. {
  348.     XEE_RESULT r;
  349.  
  350.     r = XEEBeginRead(control, address);
  351.     if ( r != XEE_SUCCESS )
  352.         return r;
  353.  
  354.     while( length-- )
  355.         *buffer++ = XEERead();
  356.  
  357.     r = XEEEndRead();
  358.  
  359.     return r;
  360. }
  361.  
  362.  
  363.  
  364.  
  365. XEE_RESULT XEEClose(void)
  366. {
  367.     IdleI2C();
  368.     StopI2C();
  369.     while( EEPROM_SPICON2bits.PEN );           // wait until stop condition is over.
  370.     if ( PIR2bits.BCLIF )
  371.         return XEE_BUS_COLLISION;
  372.     return XEE_SUCCESS;
  373. }
  374.  
  375.  
  376.  
  377. /*********************************************************************
  378.  * Function:        XEE_RESULT XEEIsBusy(unsigned char control)
  379.  *
  380.  * PreCondition:    XEEInit() is already called.
  381.  *
  382.  * Input:           control     - EEPROM control and address code.
  383.  *
  384.  * Output:          XEE_READY if EEPROM is not busy
  385.  *                  XEE_BUSY if EEPROM is busy
  386.  *                  other value if failed.
  387.  *
  388.  * Side Effects:    None
  389.  *
  390.  * Overview:        Requests ack from EEPROM.
  391.  *
  392.  * Note:            None
  393.  ********************************************************************/
  394. XEE_RESULT XEEIsBusy(unsigned char control)
  395. {
  396.     XEE_RESULT r;
  397.  
  398.     IdleI2C();                      // ensure module is idle
  399.     StartI2C();                     // initiate START condition
  400.     while ( EEPROM_SPICON2bits.SEN );      // wait until start condition is over
  401.     if ( PIR2bits.BCLIF )           // test for bus collision
  402.     {
  403.         return XEE_BUS_COLLISION;                // return with Bus Collision error
  404.     }
  405.  
  406.     else
  407.     {
  408.         if ( WriteI2C( control ) )    // write byte - R/W bit should be 0
  409.             return XEE_BUS_COLLISION;              // set error for write collision
  410.  
  411.         IdleI2C();                    // ensure module is idle
  412.         if ( PIR2bits.BCLIF )         // test for bus collision
  413.             return XEE_BUS_COLLISION;              // return with Bus Collision error
  414.  
  415.         if ( !EEPROM_SPICON2bits.ACKSTAT )
  416.             r = XEE_READY;
  417.         else
  418.             r = XEE_BUSY;
  419.  
  420. #if 0
  421.         while ( EEPROM_SPICON2bits.ACKSTAT ) // test for ACK condition received
  422.         {
  423.             RestartI2C();               // initiate Restart condition
  424.             while ( EEPROM_SPICON2bits.RSEN ); // wait until re-start condition is over
  425.             if ( PIR2bits.BCLIF )       // test for bus collision
  426.                 return XEE_BUS_COLLISION;            // return with Bus Collision error
  427.  
  428.             if ( WriteI2C( control ) )  // write byte - R/W bit should be 0
  429.                 return XEE_BUS_COLLISION;            // set error for write collision
  430.  
  431.             IdleI2C();                  // ensure module is idle
  432.         }
  433. #endif
  434.     }
  435.  
  436.  
  437.     StopI2C();                      // send STOP condition
  438.     while ( EEPROM_SPICON2bits.PEN );      // wait until stop condition is over
  439.     if ( PIR2bits.BCLIF )           // test for bus collision
  440.         return XEE_BUS_COLLISION;                // return with Bus Collision error
  441.  
  442.     return r;
  443.     //return XEE_READY;                   // return with no error
  444. }
  445.  
  446.  
  447. /********************************************************************
  448. *     Function Name:    WriteI2C                                    *
  449. *     Return Value:     Status byte for WCOL detection.             *
  450. *     Parameters:       Single data byte for I2C bus.               *
  451. *     Description:      This routine writes a single byte to the    *
  452. *                       I2C bus.                                    *
  453. ********************************************************************/
  454. static unsigned char WriteI2C( unsigned char data_out )
  455. {
  456.   EEPROM_SSPBUF = data_out;           // write single byte to EEPROM_SSPBUF
  457.   if ( SSPCON1bits.WCOL )      // test if write collision occurred
  458.    return ( -1 );              // if WCOL bit is set return negative #
  459.   else
  460.   {
  461.     while( SSPSTATbits.BF );   // wait until write cycle is complete
  462.     return ( 0 );              // if WCOL bit is not set return non-negative #
  463.   }
  464. }
  465.  
  466.  
  467.  
  468. /********************************************************************
  469. *     Function Name:    ReadI2C                                     *
  470. *     Return Value:     contents of EEPROM_SSPBUF register                 *
  471. *     Parameters:       void                                        *
  472. *     Description:      Read single byte from I2C bus.              *
  473. ********************************************************************/
  474. static unsigned char getcI2C( void )
  475. {
  476.     EEPROM_SPICON2bits.RCEN = 1;        // enable master for 1 byte reception
  477.     while(!SSPSTATbits.BF);     // wait until byte received
  478.     return EEPROM_SSPBUF;               // return with read byte
  479. }
  480.  
  481.  
  482. #endif //#if defined(MPFS_USE_EEPROM)
  483.