Subversion Repositories HomeAutomation

Rev

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

Rev Author Line No. Line
363 johboh 1
/*********************************************************************
2
 *
3
 *               Data SPI EEPROM Access Routines
4
 *
5
 *********************************************************************
6
 * FileName:        SPIEEPROM.c
7
 * Dependencies:    Compiler.h
8
 *                  XEEPROM.h
9
 * Processor:       PIC18, PIC24F, PIC24H, dsPIC30F, dsPIC33F
10
 * Complier:        Microchip C18 v3.02 or higher
11
 *                  Microchip C30 v2.01 or higher
12
 * Company:         Microchip Technology, Inc.
13
 *
14
 * Software License Agreement
15
 *
16
 * This software is owned by Microchip Technology Inc. ("Microchip")
17
 * and is supplied to you for use exclusively as described in the
18
 * associated software agreement.  This software is protected by
19
 * software and other intellectual property laws.  Any use in
20
 * violation of the software license may subject the user to criminal
21
 * sanctions as well as civil liability.  Copyright 2006 Microchip
22
 * Technology Inc.  All rights reserved.
23
 *
24
 * This software is provided "AS IS."  MICROCHIP DISCLAIMS ALL
25
 * WARRANTIES, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, NOT LIMITED
26
 * TO MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
27
 * INFRINGEMENT.  Microchip shall in no event be liable for special,
28
 * incidental, or consequential damages.
29
 *
30
 *
31
 * Author               Date        Comment
32
 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
33
 * Nilesh Rajbharti     5/20/02     Original (Rev. 1.0)
34
 * Howard Schlunder     9/01/04     Rewritten for SPI EEPROMs
35
 * Howard Schlunder     8/10/06     Modified to control SPI module
36
 *                                  frequency whenever EEPROM accessed
37
 *                                  to allow bus sharing with different
38
 *                                  frequencies.
39
********************************************************************/
40
#include "..\Include\Compiler.h"
41
#include "..\Include\XEEPROM.h"
42
#include "..\Include\StackTsk.h"
43
 
44
#if defined(MPFS_USE_EEPROM)
45
 
46
#if defined(PICDEMNET)
47
    #error "PICDEMNET is defined, but the PICDEM.net demo board does not have an SPI EEPROM on it.  Is I2CEEPROM.c intended instead?"
48
#endif
49
 
50
 
51
// IMPORTANT SPI NOTE: The code in this file expects that the SPI interrupt 
52
//      flag (EEPROM_SPI_IF) be clear at all times.  If the SPI is shared with 
53
//      other hardware, the other code should clear the EEPROM_SPI_IF when it is 
54
//      done using the SPI.
55
 
56
 
57
// EEPROM SPI opcodes
58
#define READ    0b00000011  // Read data from memory array beginning at selected address
59
#define WRITE   0b00000010  // Write data to memory array beginning at selected address
60
#define WRDI    0b00000100  // Reset the write enable latch (disable write operations)
61
#define WREN    0b00000110  // Set the write enable latch (enable write operations)
62
#define RDSR    0b00000101  // Read Status register
63
#define WRSR    0b00000001  // Write Status register
64
 
65
void DoWrite(void);
66
 
67
WORD EEPROMAddress;
68
BYTE EEPROMBuffer[EEPROM_BUFFER_SIZE];
69
BYTE *EEPROMBufferPtr;
70
 
71
/*********************************************************************
72
 * Function:        void XEEInit(unsigned char speed)
73
 *
74
 * PreCondition:    None
75
 *
76
 * Input:           speed - not used (included for compatibility only)
77
 *
78
 * Output:          None
79
 *
80
 * Side Effects:    None
81
 *
82
 * Overview:        Initialize SPI module to communicate to serial
83
 *                  EEPROM.
84
 *
85
 * Note:            Code sets SPI clock to Fosc/16.  
86
 ********************************************************************/
87
#if defined(HPC_EXPLORER) && !defined(__18F87J10)
88
    #define PROPER_SPICON1  (0x20)      /* SSPEN bit is set, SPI in master mode, FOSC/4, IDLE state is low level */
89
#elif defined(__PIC24F__)
90
    #define PROPER_SPICON1  (0x0013 | 0x0120)   /* 1:1 primary prescale, 4:1 secondary prescale, CKE=1, MASTER mode */
91
#elif defined(__dsPIC30F__)
92
    #define PROPER_SPICON1  (0x0017 | 0x0120)   /* 1:1 primary prescale, 3:1 secondary prescale, CKE=1, MASTER mode */
93
#elif defined(__dsPIC33F__) || defined(__PIC24H__)
94
    #define PROPER_SPICON1  (0x0003 | 0x0120)   /* 1:1 primary prescale, 8:1 secondary prescale, CKE=1, MASTER mode */
95
#else
96
    //#define PROPER_SPICON1    (0x21)      /* SSPEN bit is set, SPI in master mode, FOSC/16, IDLE state is low level */
97
    #define PROPER_SPICON1  (0x22)      /* SSPEN bit is set, SPI in master mode, FOSC/16, IDLE state is low level */
98
#endif
99
 
100
void XEEInit(unsigned char speed)
101
{
102
    EEPROM_CS_IO = 1;
103
    EEPROM_CS_TRIS = 0;     // Drive SPI EEPROM chip select pin
104
 
105
    EEPROM_SCK_TRIS = 0;    // Set SCK pin as an output
106
    EEPROM_SDI_TRIS = 1;    // Make sure SDI pin is an input
107
    EEPROM_SDO_TRIS = 0;    // Set SDO pin as an output
108
 
109
    EEPROM_SPICON1 = PROPER_SPICON1; // See PROPER_SPICON1 definition above
110
    #if defined(__C30__)
111
        EEPROM_SPICON2 = 0;
112
        EEPROM_SPISTAT = 0;    // clear SPI
113
        EEPROM_SPISTATbits.SPIEN = 1;
114
    #elif defined(__18CXX)
115
        EEPROM_SPI_IF = 0;
116
        EEPROM_SPISTATbits.CKE = 1;     // Transmit data on rising edge of clock
117
        EEPROM_SPISTATbits.SMP = 0;     // Input sampled at middle of data output time
118
    #endif
119
}
120
 
121
 
122
/*********************************************************************
123
 * Function:        XEE_RESULT XEEBeginRead(unsigned char control,
124
 *                                          XEE_ADDR address)
125
 *
126
 * PreCondition:    XEEInit() is already called.
127
 *
128
 * Input:           control - EEPROM control and address code.
129
 *                  address - Address at which read is to be performed.
130
 *
131
 * Output:          XEE_SUCCESS if successful
132
 *                  other value if failed.
133
 *
134
 * Side Effects:    None
135
 *
136
 * Overview:        Sets internal address counter to given address.
137
 *                  Puts EEPROM in sequential read mode.
138
 *
139
 * Note:            This function does not release I2C bus.
140
 *                  User must call XEEEndRead() when read is not longer
141
 *                  needed; I2C bus will released after XEEEndRead()
142
 *                  is called.
143
 ********************************************************************/
144
XEE_RESULT XEEBeginRead(unsigned char control, XEE_ADDR address )
145
{
146
    // Save the address and emptry the contents of our local buffer
147
    EEPROMAddress = address;
148
    EEPROMBufferPtr = EEPROMBuffer + EEPROM_BUFFER_SIZE;
149
    return XEE_SUCCESS;
150
}
151
 
152
 
153
/*********************************************************************
154
 * Function:        XEE_RESULT XEERead(void)
155
 *
156
 * PreCondition:    XEEInit() && XEEBeginRead() are already called.
157
 *
158
 * Input:           None
159
 *
160
 * Output:          XEE_SUCCESS if successful
161
 *                  other value if failed.
162
 *
163
 * Side Effects:    None
164
 *
165
 * Overview:        Reads next byte from EEPROM; internal address
166
 *                  is incremented by one.
167
 *
168
 * Note:            This function does not release I2C bus.
169
 *                  User must call XEEEndRead() when read is not longer
170
 *                  needed; I2C bus will released after XEEEndRead()
171
 *                  is called.
172
 ********************************************************************/
173
unsigned char XEERead(void)
174
{
175
    // Check if no more bytes are left in our local buffer
176
    if( EEPROMBufferPtr == EEPROMBuffer + EEPROM_BUFFER_SIZE )
177
    {
178
        // Get a new set of bytes
179
        XEEReadArray(0, EEPROMAddress, EEPROMBuffer, EEPROM_BUFFER_SIZE);
180
        EEPROMAddress += EEPROM_BUFFER_SIZE;
181
        EEPROMBufferPtr = EEPROMBuffer;
182
    }
183
 
184
    // Return a byte from our local buffer
185
    return *EEPROMBufferPtr++;
186
}
187
 
188
/*********************************************************************
189
 * Function:        XEE_RESULT XEEEndRead(void)
190
 *
191
 * PreCondition:    XEEInit() && XEEBeginRead() are already called.
192
 *
193
 * Input:           None
194
 *
195
 * Output:          XEE_SUCCESS if successful
196
 *                  other value if failed.
197
 *
198
 * Side Effects:    None
199
 *
200
 * Overview:        Ends sequential read cycle.
201
 *
202
 * Note:            This function ends sequential cycle that was in
203
 *                  progress.  It releases I2C bus.
204
 ********************************************************************/
205
XEE_RESULT XEEEndRead(void)
206
{
207
    return XEE_SUCCESS;
208
}
209
 
210
 
211
/*********************************************************************
212
 * Function:        XEE_RESULT XEEReadArray(unsigned char control,
213
 *                                          XEE_ADDR address,
214
 *                                          unsigned char *buffer,
215
 *                                          unsigned char length)
216
 *
217
 * PreCondition:    XEEInit() is already called.
218
 *
219
 * Input:           control     - Unused
220
 *                  address     - Address from where array is to be read
221
 *                  buffer      - Caller supplied buffer to hold the data
222
 *                  length      - Number of bytes to read.
223
 *
224
 * Output:          XEE_SUCCESS if successful
225
 *                  other value if failed.
226
 *
227
 * Side Effects:    None
228
 *
229
 * Overview:        Reads desired number of bytes in sequential mode.
230
 *                  This function performs all necessary steps
231
 *                  and releases the bus when finished.
232
 *
233
 * Note:            None
234
 ********************************************************************/
235
XEE_RESULT XEEReadArray(unsigned char control,
236
                        XEE_ADDR address,
237
                        unsigned char *buffer,
238
                        unsigned char length)
239
{
240
    BYTE Dummy;
241
    #if defined(__18CXX)
242
    BYTE SPICON1Save;
243
    #else
244
    WORD SPICON1Save;
245
    #endif  
246
 
247
    // Save SPI state (clock speed)
248
    SPICON1Save = EEPROM_SPICON1;
249
    EEPROM_SPICON1 = PROPER_SPICON1;
250
 
251
    EEPROM_CS_IO = 0;
252
 
253
    // Send READ opcode
254
    EEPROM_SSPBUF = READ;
255
    while(!EEPROM_SPI_IF);
256
    Dummy = EEPROM_SSPBUF;
257
    EEPROM_SPI_IF = 0;
258
 
259
    // Send address
260
    EEPROM_SSPBUF = ((WORD_VAL*)&address)->v[1];
261
    while(!EEPROM_SPI_IF);
262
    Dummy = EEPROM_SSPBUF;
263
    EEPROM_SPI_IF = 0;
264
    EEPROM_SSPBUF = ((WORD_VAL*)&address)->v[0];
265
    while(!EEPROM_SPI_IF);
266
    Dummy = EEPROM_SSPBUF;
267
    EEPROM_SPI_IF = 0;
268
 
269
    while(length--)
270
    {
271
        EEPROM_SSPBUF = 0;
272
        while(!EEPROM_SPI_IF);
273
        *buffer++ = EEPROM_SSPBUF;
274
        EEPROM_SPI_IF = 0;
275
    };
276
 
277
    EEPROM_CS_IO = 1;
278
 
279
    // Restore SPI state
280
    EEPROM_SPICON1 = SPICON1Save;
281
 
282
    return XEE_SUCCESS;
283
}
284
 
285
 
286
/*********************************************************************
287
 * Function:        XEE_RESULT XEESetAddr(unsigned char control,
288
 *                                        XEE_ADDR address)
289
 *
290
 * PreCondition:    XEEInit() is already called.
291
 *
292
 * Input:           control     - data EEPROM control code
293
 *                  address     - address to be set for writing
294
 *
295
 * Output:          XEE_SUCCESS if successful
296
 *                  other value if failed.
297
 *
298
 * Side Effects:    None
299
 *
300
 * Overview:        Modifies internal address counter of EEPROM.
301
 *
302
 * Note:            Unlike XEESetAddr() in xeeprom.c for I2C EEPROM
303
 *                   memories, this function is used only for writing
304
 *                   to the EEPROM.  Reads must use XEEBeginRead(),
305
 *                   XEERead(), and XEEEndRead().
306
 *                  This function does not release the SPI bus.
307
 *                  User must close XEEClose() after this function
308
 *                   is called.
309
 ********************************************************************/
310
XEE_RESULT XEESetAddr(unsigned char control, XEE_ADDR address)
311
{
312
    EEPROMAddress = address;
313
    EEPROMBufferPtr = EEPROMBuffer;
314
    return XEE_SUCCESS;
315
}
316
 
317
 
318
/*********************************************************************
319
 * Function:        XEE_RESULT XEEWrite(unsigned char val)
320
 *
321
 * PreCondition:    XEEInit() && XEEBeginWrite() are already called.
322
 *
323
 * Input:           val - Byte to be written
324
 *
325
 * Output:          XEE_SUCCESS
326
 *
327
 * Side Effects:    None
328
 *
329
 * Overview:        Adds a byte to the current page to be writen when
330
 *                  XEEEndWrite() is called.
331
 *
332
 * Note:            Page boundary cannot be exceeded or the byte
333
 *                  to be written will be looped back to the
334
 *                  beginning of the page.
335
 ********************************************************************/
336
XEE_RESULT XEEWrite(unsigned char val)
337
{
338
    *EEPROMBufferPtr++ = val;
339
    if( EEPROMBufferPtr == EEPROMBuffer + EEPROM_BUFFER_SIZE )
340
    {
341
        DoWrite();
342
    }
343
 
344
    return XEE_SUCCESS;
345
}
346
 
347
 
348
/*********************************************************************
349
 * Function:        XEE_RESULT XEEEndWrite(void)
350
 *
351
 * PreCondition:    XEEInit() && XEEBeginWrite() are already called.
352
 *
353
 * Input:           None
354
 *
355
 * Output:          XEE_SUCCESS if successful
356
 *                  other value if failed.
357
 *
358
 * Side Effects:    None
359
 *
360
 * Overview:        Instructs EEPROM to begin write cycle.
361
 *
362
 * Note:            Call this function after either page full of bytes
363
 *                  written or no more bytes are left to load.
364
 *                  This function initiates the write cycle.
365
 *                  User must call for XEEIsBusy() to ensure that write
366
 *                  cycle is finished before calling any other
367
 *                  routine.
368
 ********************************************************************/
369
XEE_RESULT XEEEndWrite(void)
370
{
371
    if( EEPROMBufferPtr != EEPROMBuffer )
372
    {
373
        DoWrite();
374
    }
375
 
376
    return XEE_SUCCESS;
377
}
378
 
379
void DoWrite(void)
380
{
381
    BYTE Dummy;
382
    BYTE BytesToWrite;
383
    #if defined(__18CXX)
384
    BYTE SPICON1Save;
385
    #else
386
    WORD SPICON1Save;
387
    #endif  
388
 
389
    // Save SPI state (clock speed)
390
    SPICON1Save = EEPROM_SPICON1;
391
    EEPROM_SPICON1 = PROPER_SPICON1;
392
 
393
    // Set the Write Enable latch
394
    EEPROM_CS_IO = 0;
395
    EEPROM_SSPBUF = WREN;
396
    while(!EEPROM_SPI_IF);
397
    Dummy = EEPROM_SSPBUF;
398
    EEPROM_SPI_IF = 0;
399
    EEPROM_CS_IO = 1;
400
 
401
    // Send WRITE opcode
402
    EEPROM_CS_IO = 0;
403
    EEPROM_SSPBUF = WRITE;
404
    while(!EEPROM_SPI_IF);
405
    Dummy = EEPROM_SSPBUF;
406
    EEPROM_SPI_IF = 0;
407
 
408
    // Send address
409
    EEPROM_SSPBUF = ((WORD_VAL*)&EEPROMAddress)->v[1];
410
    while(!EEPROM_SPI_IF);
411
    Dummy = EEPROM_SSPBUF;
412
    EEPROM_SPI_IF = 0;
413
    EEPROM_SSPBUF = ((WORD_VAL*)&EEPROMAddress)->v[0];
414
    while(!EEPROM_SPI_IF);
415
    Dummy = EEPROM_SSPBUF;
416
    EEPROM_SPI_IF = 0;
417
 
418
    BytesToWrite = (BYTE)(EEPROMBufferPtr - EEPROMBuffer);
419
 
420
    EEPROMAddress += BytesToWrite;
421
    EEPROMBufferPtr = EEPROMBuffer;
422
 
423
    while(BytesToWrite--)
424
    {
425
        // Send the byte to write
426
        EEPROM_SSPBUF = *EEPROMBufferPtr++;
427
        while(!EEPROM_SPI_IF);
428
        Dummy = EEPROM_SSPBUF;
429
        EEPROM_SPI_IF = 0;
430
    }
431
 
432
    // Begin the write
433
    EEPROM_CS_IO = 1;
434
 
435
    EEPROMBufferPtr = EEPROMBuffer;
436
 
437
    // Restore SPI State
438
    EEPROM_SPICON1 = SPICON1Save;
439
 
440
    // Wait for write to complete
441
    while( XEEIsBusy(0) );
442
}
443
 
444
 
445
/*********************************************************************
446
 * Function:        XEE_RESULT XEEIsBusy(unsigned char control)
447
 *
448
 * PreCondition:    XEEInit() is already called.
449
 *
450
 * Input:           control     - EEPROM control and address code.
451
 *
452
 * Output:          XEE_READY if EEPROM is not busy
453
 *                  XEE_BUSY if EEPROM is busy
454
 *                  other value if failed.
455
 *
456
 * Side Effects:    None
457
 *
458
 * Overview:        Requests ack from EEPROM.
459
 *
460
 * Note:            None
461
 ********************************************************************/
462
XEE_RESULT XEEIsBusy(unsigned char control)
463
{
464
    BYTE_VAL result;
465
    #if defined(__18CXX)
466
    BYTE SPICON1Save;
467
    #else
468
    WORD SPICON1Save;
469
    #endif  
470
 
471
    // Save SPI state (clock speed)
472
    SPICON1Save = EEPROM_SPICON1;
473
    EEPROM_SPICON1 = PROPER_SPICON1;
474
 
475
    EEPROM_CS_IO = 0;
476
    // Send RDSR - Read Status Register opcode
477
    EEPROM_SSPBUF = RDSR;
478
    while(!EEPROM_SPI_IF);
479
    result.Val = EEPROM_SSPBUF;
480
    EEPROM_SPI_IF = 0;
481
 
482
    // Get register contents
483
    EEPROM_SSPBUF = 0;
484
    while(!EEPROM_SPI_IF);
485
    result.Val = EEPROM_SSPBUF;
486
    EEPROM_SPI_IF = 0;
487
    EEPROM_CS_IO = 1;
488
 
489
    // Restore SPI State
490
    EEPROM_SPICON1 = SPICON1Save;
491
 
492
    return result.bits.b0 ? XEE_BUSY : XEE_SUCCESS;
493
}
494
 
495
 
496
#endif //#if defined(MPFS_USE_EEPROM)