Subversion Repositories HomeAutomation

Rev

Details | Last modification | View Log | SVN | RSS feed

Rev Author Line No. Line
363 johboh 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)