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 |
* Copyright © 2002-2007 Microchip Technology Inc. All rights
|
17 |
* reserved.
|
18 |
*
|
19 |
* Microchip licenses to you the right to use, modify, copy, and
|
20 |
* distribute:
|
21 |
* (i) the Software when embedded on a Microchip microcontroller or
|
22 |
* digital signal controller product (“Device”) which is
|
23 |
* integrated into Licensee’s product; or
|
24 |
* (ii) ONLY the Software driver source files ENC28J60.c and
|
25 |
* ENC28J60.h ported to a non-Microchip device used in
|
26 |
* conjunction with a Microchip ethernet controller for the
|
27 |
* sole purpose of interfacing with the ethernet controller.
|
28 |
*
|
29 |
* You should refer to the license agreement accompanying this
|
30 |
* Software for additional information regarding your rights and
|
31 |
* obligations.
|
32 |
*
|
33 |
* THE SOFTWARE AND DOCUMENTATION ARE PROVIDED “AS IS” WITHOUT
|
34 |
* WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT
|
35 |
* LIMITATION, ANY WARRANTY OF MERCHANTABILITY, FITNESS FOR A
|
36 |
* PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL
|
37 |
* MICROCHIP BE LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR
|
38 |
* CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF
|
39 |
* PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY OR SERVICES, ANY CLAIMS
|
40 |
* BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE
|
41 |
* THEREOF), ANY CLAIMS FOR INDEMNITY OR CONTRIBUTION, OR OTHER
|
42 |
* SIMILAR COSTS, WHETHER ASSERTED ON THE BASIS OF CONTRACT, TORT
|
43 |
* (INCLUDING NEGLIGENCE), BREACH OF WARRANTY, OR OTHERWISE.
|
44 |
*
|
45 |
*
|
46 |
* Author Date Comment
|
47 |
*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
48 |
* Nilesh Rajbharti 5/20/02 Original (Rev. 1.0)
|
49 |
* Howard Schlunder 9/01/04 Rewritten for SPI EEPROMs
|
50 |
* Howard Schlunder 8/10/06 Modified to control SPI module
|
51 |
* frequency whenever EEPROM accessed
|
52 |
* to allow bus sharing with different
|
53 |
* frequencies.
|
54 |
********************************************************************/
|
55 |
#define __SPIEEPROM_C
|
56 |
|
57 |
#include "TCPIP Stack/TCPIP.h"
|
58 |
|
59 |
#if defined(MPFS_USE_EEPROM) && defined(EEPROM_CS_TRIS) && defined(STACK_USE_MPFS)
|
60 |
|
61 |
// IMPORTANT SPI NOTE: The code in this file expects that the SPI interrupt
|
62 |
// flag (EEPROM_SPI_IF) be clear at all times. If the SPI is shared with
|
63 |
// other hardware, the other code should clear the EEPROM_SPI_IF when it is
|
64 |
// done using the SPI.
|
65 |
|
66 |
// SPI Serial EEPROM buffer size. To enhance performance while
|
67 |
// cooperatively sharing the SPI bus with other peripherals, bytes
|
68 |
// read and written to the memory are locally buffered. Legal
|
69 |
// sizes are 1 to the EEPROM page size.
|
70 |
#define EEPROM_BUFFER_SIZE (32)
|
71 |
|
72 |
// EEPROM SPI opcodes
|
73 |
#define READ 0x03 // Read data from memory array beginning at selected address
|
74 |
#define WRITE 0x02 // Write data to memory array beginning at selected address
|
75 |
#define WRDI 0x04 // Reset the write enable latch (disable write operations)
|
76 |
#define WREN 0x06 // Set the write enable latch (enable write operations)
|
77 |
#define RDSR 0x05 // Read Status register
|
78 |
#define WRSR 0x01 // Write Status register
|
79 |
|
80 |
static void DoWrite(void);
|
81 |
|
82 |
static WORD EEPROMAddress;
|
83 |
static BYTE EEPROMBuffer[EEPROM_BUFFER_SIZE];
|
84 |
static BYTE *EEPROMBufferPtr;
|
85 |
|
86 |
/*********************************************************************
|
87 |
* Function: void XEEInit(unsigned char speed)
|
88 |
*
|
89 |
* PreCondition: None
|
90 |
*
|
91 |
* Input: speed - not used (included for compatibility only)
|
92 |
*
|
93 |
* Output: None
|
94 |
*
|
95 |
* Side Effects: None
|
96 |
*
|
97 |
* Overview: Initialize SPI module to communicate to serial
|
98 |
* EEPROM.
|
99 |
*
|
100 |
* Note: Code sets SPI clock to Fosc/16.
|
101 |
********************************************************************/
|
102 |
#if defined(HPC_EXPLORER) && !defined(__18F87J10)
|
103 |
#define PROPER_SPICON1 (0x20) /* SSPEN bit is set, SPI in master mode, FOSC/4, IDLE state is low level */
|
104 |
#elif defined(__PIC24F__)
|
105 |
#define PROPER_SPICON1 (0x0013 | 0x0120) /* 1:1 primary prescale, 4:1 secondary prescale, CKE=1, MASTER mode */
|
106 |
#elif defined(__dsPIC30F__)
|
107 |
#define PROPER_SPICON1 (0x0017 | 0x0120) /* 1:1 primary prescale, 3:1 secondary prescale, CKE=1, MASTER mode */
|
108 |
#elif defined(__dsPIC33F__) || defined(__PIC24H__)
|
109 |
#define PROPER_SPICON1 (0x0003 | 0x0120) /* 1:1 primary prescale, 8:1 secondary prescale, CKE=1, MASTER mode */
|
110 |
#else
|
111 |
#define PROPER_SPICON1 (0x21) /* SSPEN bit is set, SPI in master mode, FOSC/16, IDLE state is low level */
|
112 |
#endif
|
113 |
|
114 |
void XEEInit(void)
|
115 |
{
|
116 |
EEPROM_CS_IO = 1;
|
117 |
EEPROM_CS_TRIS = 0; // Drive SPI EEPROM chip select pin
|
118 |
|
119 |
EEPROM_SCK_TRIS = 0; // Set SCK pin as an output
|
120 |
EEPROM_SDI_TRIS = 1; // Make sure SDI pin is an input
|
121 |
EEPROM_SDO_TRIS = 0; // Set SDO pin as an output
|
122 |
|
123 |
EEPROM_SPICON1 = PROPER_SPICON1; // See PROPER_SPICON1 definition above
|
124 |
#if defined(__C30__)
|
125 |
EEPROM_SPICON2 = 0;
|
126 |
EEPROM_SPISTAT = 0; // clear SPI
|
127 |
EEPROM_SPISTATbits.SPIEN = 1;
|
128 |
#elif defined(__18CXX)
|
129 |
EEPROM_SPI_IF = 0;
|
130 |
EEPROM_SPISTATbits.CKE = 1; // Transmit data on rising edge of clock
|
131 |
EEPROM_SPISTATbits.SMP = 0; // Input sampled at middle of data output time
|
132 |
#endif
|
133 |
}
|
134 |
|
135 |
|
136 |
/*********************************************************************
|
137 |
* Function: XEE_RESULT XEEBeginRead(unsigned char control,
|
138 |
* XEE_ADDR address)
|
139 |
*
|
140 |
* PreCondition: XEEInit() is already called.
|
141 |
*
|
142 |
* Input: control - EEPROM control and address code.
|
143 |
* address - Address at which read is to be performed.
|
144 |
*
|
145 |
* Output: XEE_SUCCESS if successful
|
146 |
* other value if failed.
|
147 |
*
|
148 |
* Side Effects: None
|
149 |
*
|
150 |
* Overview: Sets internal address counter to given address.
|
151 |
* Puts EEPROM in sequential read mode.
|
152 |
*
|
153 |
* Note: This function does not release I2C bus.
|
154 |
* User must call XEEEndRead() when read is not longer
|
155 |
* needed; I2C bus will released after XEEEndRead()
|
156 |
* is called.
|
157 |
********************************************************************/
|
158 |
XEE_RESULT XEEBeginRead(XEE_ADDR address)
|
159 |
{
|
160 |
// Save the address and emptry the contents of our local buffer
|
161 |
EEPROMAddress = address;
|
162 |
EEPROMBufferPtr = EEPROMBuffer + EEPROM_BUFFER_SIZE;
|
163 |
return XEE_SUCCESS;
|
164 |
}
|
165 |
|
166 |
|
167 |
/*********************************************************************
|
168 |
* Function: XEE_RESULT XEERead(void)
|
169 |
*
|
170 |
* PreCondition: XEEInit() && XEEBeginRead() are already called.
|
171 |
*
|
172 |
* Input: None
|
173 |
*
|
174 |
* Output: XEE_SUCCESS if successful
|
175 |
* other value if failed.
|
176 |
*
|
177 |
* Side Effects: None
|
178 |
*
|
179 |
* Overview: Reads next byte from EEPROM; internal address
|
180 |
* is incremented by one.
|
181 |
*
|
182 |
* Note: This function does not release I2C bus.
|
183 |
* User must call XEEEndRead() when read is not longer
|
184 |
* needed; I2C bus will released after XEEEndRead()
|
185 |
* is called.
|
186 |
********************************************************************/
|
187 |
unsigned char XEERead(void)
|
188 |
{
|
189 |
// Check if no more bytes are left in our local buffer
|
190 |
if( EEPROMBufferPtr == EEPROMBuffer + EEPROM_BUFFER_SIZE )
|
191 |
{
|
192 |
// Get a new set of bytes
|
193 |
XEEReadArray(EEPROMAddress, EEPROMBuffer, EEPROM_BUFFER_SIZE);
|
194 |
EEPROMAddress += EEPROM_BUFFER_SIZE;
|
195 |
EEPROMBufferPtr = EEPROMBuffer;
|
196 |
}
|
197 |
|
198 |
// Return a byte from our local buffer
|
199 |
return *EEPROMBufferPtr++;
|
200 |
}
|
201 |
|
202 |
/*********************************************************************
|
203 |
* Function: XEE_RESULT XEEEndRead(void)
|
204 |
*
|
205 |
* PreCondition: XEEInit() && XEEBeginRead() are already called.
|
206 |
*
|
207 |
* Input: None
|
208 |
*
|
209 |
* Output: XEE_SUCCESS if successful
|
210 |
* other value if failed.
|
211 |
*
|
212 |
* Side Effects: None
|
213 |
*
|
214 |
* Overview: Ends sequential read cycle.
|
215 |
*
|
216 |
* Note: This function ends sequential cycle that was in
|
217 |
* progress. It releases I2C bus.
|
218 |
********************************************************************/
|
219 |
XEE_RESULT XEEEndRead(void)
|
220 |
{
|
221 |
return XEE_SUCCESS;
|
222 |
}
|
223 |
|
224 |
|
225 |
/*********************************************************************
|
226 |
* Function: XEE_RESULT XEEReadArray(unsigned char control,
|
227 |
* XEE_ADDR address,
|
228 |
* unsigned char *buffer,
|
229 |
* unsigned char length)
|
230 |
*
|
231 |
* PreCondition: XEEInit() is already called.
|
232 |
*
|
233 |
* Input: control - Unused
|
234 |
* address - Address from where array is to be read
|
235 |
* buffer - Caller supplied buffer to hold the data
|
236 |
* length - Number of bytes to read.
|
237 |
*
|
238 |
* Output: XEE_SUCCESS if successful
|
239 |
* other value if failed.
|
240 |
*
|
241 |
* Side Effects: None
|
242 |
*
|
243 |
* Overview: Reads desired number of bytes in sequential mode.
|
244 |
* This function performs all necessary steps
|
245 |
* and releases the bus when finished.
|
246 |
*
|
247 |
* Note: None
|
248 |
********************************************************************/
|
249 |
XEE_RESULT XEEReadArray(XEE_ADDR address,
|
250 |
unsigned char *buffer,
|
251 |
unsigned char length)
|
252 |
{
|
253 |
BYTE Dummy;
|
254 |
#if defined(__18CXX)
|
255 |
BYTE SPICON1Save;
|
256 |
#else
|
257 |
WORD SPICON1Save;
|
258 |
#endif
|
259 |
|
260 |
// Save SPI state (clock speed)
|
261 |
SPICON1Save = EEPROM_SPICON1;
|
262 |
EEPROM_SPICON1 = PROPER_SPICON1;
|
263 |
|
264 |
EEPROM_CS_IO = 0;
|
265 |
|
266 |
// Send READ opcode
|
267 |
EEPROM_SSPBUF = READ;
|
268 |
while(!EEPROM_SPI_IF);
|
269 |
Dummy = EEPROM_SSPBUF;
|
270 |
EEPROM_SPI_IF = 0;
|
271 |
|
272 |
// Send address
|
273 |
EEPROM_SSPBUF = ((WORD_VAL*)&address)->v[1];
|
274 |
while(!EEPROM_SPI_IF);
|
275 |
Dummy = EEPROM_SSPBUF;
|
276 |
EEPROM_SPI_IF = 0;
|
277 |
EEPROM_SSPBUF = ((WORD_VAL*)&address)->v[0];
|
278 |
while(!EEPROM_SPI_IF);
|
279 |
Dummy = EEPROM_SSPBUF;
|
280 |
EEPROM_SPI_IF = 0;
|
281 |
|
282 |
while(length--)
|
283 |
{
|
284 |
EEPROM_SSPBUF = 0;
|
285 |
while(!EEPROM_SPI_IF);
|
286 |
*buffer++ = EEPROM_SSPBUF;
|
287 |
EEPROM_SPI_IF = 0;
|
288 |
};
|
289 |
|
290 |
EEPROM_CS_IO = 1;
|
291 |
|
292 |
// Restore SPI state
|
293 |
EEPROM_SPICON1 = SPICON1Save;
|
294 |
|
295 |
return XEE_SUCCESS;
|
296 |
}
|
297 |
|
298 |
|
299 |
/*********************************************************************
|
300 |
* Function: XEE_RESULT XEESetAddr(unsigned char control,
|
301 |
* XEE_ADDR address)
|
302 |
*
|
303 |
* PreCondition: XEEInit() is already called.
|
304 |
*
|
305 |
* Input: control - data EEPROM control code
|
306 |
* address - address to be set for writing
|
307 |
*
|
308 |
* Output: XEE_SUCCESS if successful
|
309 |
* other value if failed.
|
310 |
*
|
311 |
* Side Effects: None
|
312 |
*
|
313 |
* Overview: Modifies internal address counter of EEPROM.
|
314 |
*
|
315 |
* Note: Unlike XEESetAddr() in xeeprom.c for I2C EEPROM
|
316 |
* memories, this function is used only for writing
|
317 |
* to the EEPROM. Reads must use XEEBeginRead(),
|
318 |
* XEERead(), and XEEEndRead().
|
319 |
* This function does not release the SPI bus.
|
320 |
********************************************************************/
|
321 |
XEE_RESULT XEEBeginWrite(XEE_ADDR address)
|
322 |
{
|
323 |
EEPROMAddress = address;
|
324 |
EEPROMBufferPtr = EEPROMBuffer;
|
325 |
return XEE_SUCCESS;
|
326 |
}
|
327 |
|
328 |
|
329 |
/*********************************************************************
|
330 |
* Function: XEE_RESULT XEEWrite(unsigned char val)
|
331 |
*
|
332 |
* PreCondition: XEEInit() && XEEBeginWrite() are already called.
|
333 |
*
|
334 |
* Input: val - Byte to be written
|
335 |
*
|
336 |
* Output: XEE_SUCCESS
|
337 |
*
|
338 |
* Side Effects: None
|
339 |
*
|
340 |
* Overview: Adds a byte to the current page to be writen when
|
341 |
* XEEEndWrite() is called.
|
342 |
*
|
343 |
* Note: Page boundary cannot be exceeded or the byte
|
344 |
* to be written will be looped back to the
|
345 |
* beginning of the page.
|
346 |
********************************************************************/
|
347 |
XEE_RESULT XEEWrite(unsigned char val)
|
348 |
{
|
349 |
*EEPROMBufferPtr++ = val;
|
350 |
if( EEPROMBufferPtr == EEPROMBuffer + EEPROM_BUFFER_SIZE )
|
351 |
{
|
352 |
DoWrite();
|
353 |
}
|
354 |
|
355 |
return XEE_SUCCESS;
|
356 |
}
|
357 |
|
358 |
|
359 |
/*********************************************************************
|
360 |
* Function: XEE_RESULT XEEEndWrite(void)
|
361 |
*
|
362 |
* PreCondition: XEEInit() && XEEBeginWrite() are already called.
|
363 |
*
|
364 |
* Input: None
|
365 |
*
|
366 |
* Output: XEE_SUCCESS if successful
|
367 |
* other value if failed.
|
368 |
*
|
369 |
* Side Effects: None
|
370 |
*
|
371 |
* Overview: Instructs EEPROM to begin write cycle.
|
372 |
*
|
373 |
* Note: Call this function after either page full of bytes
|
374 |
* written or no more bytes are left to load.
|
375 |
* This function initiates the write cycle.
|
376 |
* User must call for XEEIsBusy() to ensure that write
|
377 |
* cycle is finished before calling any other
|
378 |
* routine.
|
379 |
********************************************************************/
|
380 |
XEE_RESULT XEEEndWrite(void)
|
381 |
{
|
382 |
if( EEPROMBufferPtr != EEPROMBuffer )
|
383 |
{
|
384 |
DoWrite();
|
385 |
}
|
386 |
|
387 |
return XEE_SUCCESS;
|
388 |
}
|
389 |
|
390 |
static void DoWrite(void)
|
391 |
{
|
392 |
BYTE Dummy;
|
393 |
BYTE BytesToWrite;
|
394 |
#if defined(__18CXX)
|
395 |
BYTE SPICON1Save;
|
396 |
#else
|
397 |
WORD SPICON1Save;
|
398 |
#endif
|
399 |
|
400 |
// Save SPI state (clock speed)
|
401 |
SPICON1Save = EEPROM_SPICON1;
|
402 |
EEPROM_SPICON1 = PROPER_SPICON1;
|
403 |
|
404 |
// Set the Write Enable latch
|
405 |
EEPROM_CS_IO = 0;
|
406 |
EEPROM_SSPBUF = WREN;
|
407 |
while(!EEPROM_SPI_IF);
|
408 |
Dummy = EEPROM_SSPBUF;
|
409 |
EEPROM_SPI_IF = 0;
|
410 |
EEPROM_CS_IO = 1;
|
411 |
|
412 |
// Send WRITE opcode
|
413 |
EEPROM_CS_IO = 0;
|
414 |
EEPROM_SSPBUF = WRITE;
|
415 |
while(!EEPROM_SPI_IF);
|
416 |
Dummy = EEPROM_SSPBUF;
|
417 |
EEPROM_SPI_IF = 0;
|
418 |
|
419 |
// Send address
|
420 |
EEPROM_SSPBUF = ((WORD_VAL*)&EEPROMAddress)->v[1];
|
421 |
while(!EEPROM_SPI_IF);
|
422 |
Dummy = EEPROM_SSPBUF;
|
423 |
EEPROM_SPI_IF = 0;
|
424 |
EEPROM_SSPBUF = ((WORD_VAL*)&EEPROMAddress)->v[0];
|
425 |
while(!EEPROM_SPI_IF);
|
426 |
Dummy = EEPROM_SSPBUF;
|
427 |
EEPROM_SPI_IF = 0;
|
428 |
|
429 |
BytesToWrite = (BYTE)(EEPROMBufferPtr - EEPROMBuffer);
|
430 |
|
431 |
EEPROMAddress += BytesToWrite;
|
432 |
EEPROMBufferPtr = EEPROMBuffer;
|
433 |
|
434 |
while(BytesToWrite--)
|
435 |
{
|
436 |
// Send the byte to write
|
437 |
EEPROM_SSPBUF = *EEPROMBufferPtr++;
|
438 |
while(!EEPROM_SPI_IF);
|
439 |
Dummy = EEPROM_SSPBUF;
|
440 |
EEPROM_SPI_IF = 0;
|
441 |
}
|
442 |
|
443 |
// Begin the write
|
444 |
EEPROM_CS_IO = 1;
|
445 |
|
446 |
EEPROMBufferPtr = EEPROMBuffer;
|
447 |
|
448 |
// Restore SPI State
|
449 |
EEPROM_SPICON1 = SPICON1Save;
|
450 |
|
451 |
// Wait for write to complete
|
452 |
while( XEEIsBusy() );
|
453 |
}
|
454 |
|
455 |
|
456 |
/*********************************************************************
|
457 |
* Function: BOOL XEEIsBusy(void)
|
458 |
*
|
459 |
* PreCondition: XEEInit() is already called.
|
460 |
*
|
461 |
* Input: None
|
462 |
*
|
463 |
* Output: FALSE if EEPROM is not busy
|
464 |
* TRUE if EEPROM is busy
|
465 |
*
|
466 |
* Side Effects: None
|
467 |
*
|
468 |
* Overview: Reads the status register
|
469 |
*
|
470 |
* Note: None
|
471 |
********************************************************************/
|
472 |
BOOL XEEIsBusy(void)
|
473 |
{
|
474 |
BYTE_VAL result;
|
475 |
#if defined(__18CXX)
|
476 |
BYTE SPICON1Save;
|
477 |
#else
|
478 |
WORD SPICON1Save;
|
479 |
#endif
|
480 |
|
481 |
// Save SPI state (clock speed)
|
482 |
SPICON1Save = EEPROM_SPICON1;
|
483 |
EEPROM_SPICON1 = PROPER_SPICON1;
|
484 |
|
485 |
EEPROM_CS_IO = 0;
|
486 |
// Send RDSR - Read Status Register opcode
|
487 |
EEPROM_SSPBUF = RDSR;
|
488 |
while(!EEPROM_SPI_IF);
|
489 |
result.Val = EEPROM_SSPBUF;
|
490 |
EEPROM_SPI_IF = 0;
|
491 |
|
492 |
// Get register contents
|
493 |
EEPROM_SSPBUF = 0;
|
494 |
while(!EEPROM_SPI_IF);
|
495 |
result.Val = EEPROM_SSPBUF;
|
496 |
EEPROM_SPI_IF = 0;
|
497 |
EEPROM_CS_IO = 1;
|
498 |
|
499 |
// Restore SPI State
|
500 |
EEPROM_SPICON1 = SPICON1Save;
|
501 |
|
502 |
return result.bits.b0;
|
503 |
}
|
504 |
|
505 |
|
506 |
#endif //#if defined(MPFS_USE_EEPROM) && defined(EEPROM_CS_TRIS) && defined(STACK_USE_MPFS)
|