| Line No. | Rev | Author | Line |
|---|---|---|---|
| 1 | 32 | kaklik | /********************************************************************* |
| 2 | * |
||
| 3 | * SPI Flash Interface Headers |
||
| 4 | * - Tested with SST 25VF016B |
||
| 5 | * Expected compatibility with all SST 25VFxxxB devices |
||
| 6 | * - Tested with Spansion 25FL040A |
||
| 7 | * Compatible with other Spansion parts with minor modifications |
||
| 8 | * |
||
| 9 | ********************************************************************* |
||
| 10 | * FileName: SPIFlash.c |
||
| 11 | * Dependencies: None |
||
| 12 | * Processor: PIC18, PIC24F, PIC24H, dsPIC30F, dsPIC33F, PIC32 |
||
| 13 | * Compiler: Microchip C32 v1.05 or higher |
||
| 14 | * Microchip C30 v3.12 or higher |
||
| 15 | * Microchip C18 v3.30 or higher |
||
| 16 | * HI-TECH PICC-18 PRO 9.63PL2 or higher |
||
| 17 | * Company: Microchip Technology, Inc. |
||
| 18 | * |
||
| 19 | * Software License Agreement |
||
| 20 | * |
||
| 21 | * Copyright (C) 2002-2009 Microchip Technology Inc. All rights |
||
| 22 | * reserved. |
||
| 23 | * |
||
| 24 | * Microchip licenses to you the right to use, modify, copy, and |
||
| 25 | * distribute: |
||
| 26 | * (i) the Software when embedded on a Microchip microcontroller or |
||
| 27 | * digital signal controller product ("Device") which is |
||
| 28 | * integrated into Licensee's product; or |
||
| 29 | * (ii) ONLY the Software driver source files ENC28J60.c, ENC28J60.h, |
||
| 30 | * ENCX24J600.c and ENCX24J600.h ported to a non-Microchip device |
||
| 31 | * used in conjunction with a Microchip ethernet controller for |
||
| 32 | * the sole purpose of interfacing with the ethernet controller. |
||
| 33 | * |
||
| 34 | * You should refer to the license agreement accompanying this |
||
| 35 | * Software for additional information regarding your rights and |
||
| 36 | * obligations. |
||
| 37 | * |
||
| 38 | * THE SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS" WITHOUT |
||
| 39 | * WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT |
||
| 40 | * LIMITATION, ANY WARRANTY OF MERCHANTABILITY, FITNESS FOR A |
||
| 41 | * PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL |
||
| 42 | * MICROCHIP BE LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR |
||
| 43 | * CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF |
||
| 44 | * PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY OR SERVICES, ANY CLAIMS |
||
| 45 | * BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE |
||
| 46 | * THEREOF), ANY CLAIMS FOR INDEMNITY OR CONTRIBUTION, OR OTHER |
||
| 47 | * SIMILAR COSTS, WHETHER ASSERTED ON THE BASIS OF CONTRACT, TORT |
||
| 48 | * (INCLUDING NEGLIGENCE), BREACH OF WARRANTY, OR OTHERWISE. |
||
| 49 | * |
||
| 50 | * |
||
| 51 | * Author Date Comment |
||
| 52 | *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
||
| 53 | * E. Wood 3/20/08 Original |
||
| 54 | ********************************************************************/ |
||
| 55 | #define __SPIFLASH_C |
||
| 56 | |||
| 57 | #include "HardwareProfile.h" |
||
| 58 | |||
| 59 | #if defined(SPIFLASH_CS_TRIS) |
||
| 60 | |||
| 61 | #include "TCPIP Stack/TCPIP.h" |
||
| 62 | |||
| 63 | #define READ 0x03 // SPI Flash opcode: Read up up to 25MHz |
||
| 64 | #define READ_FAST 0x0B // SPI Flash opcode: Read up to 50MHz with 1 dummy byte |
||
| 65 | #define ERASE_4K 0x20 // SPI Flash opcode: 4KByte sector erase |
||
| 66 | #define ERASE_32K 0x52 // SPI Flash opcode: 32KByte block erase |
||
| 67 | #define ERASE_SECTOR 0xD8 // SPI Flash opcode: sector block erase |
||
| 68 | #define ERASE_ALL 0x60 // SPI Flash opcode: Entire chip erase |
||
| 69 | #define WRITE 0x02 // SPI Flash opcode: Write one byte |
||
| 70 | #define WRITE_STREAM 0xAD // SPI Flash opcode: Write continuous stream of words (AAI mode) |
||
| 71 | #define RDSR 0x05 // SPI Flash opcode: Read Status Register |
||
| 72 | #define EWSR 0x50 // SPI Flash opcode: Enable Write Status Register |
||
| 73 | #define WRSR 0x01 // SPI Flash opcode: Write Status Register |
||
| 74 | #define WREN 0x06 // SPI Flash opcode: Write Enable |
||
| 75 | #define WRDI 0x04 // SPI Flash opcode: Write Disable / End AAI mode |
||
| 76 | #define RDID 0x90 // SPI Flash opcode: Read ID |
||
| 77 | #define JEDEC_ID 0x9F // SPI Flash opcode: Read JEDEC ID |
||
| 78 | #define EBSY 0x70 // SPI Flash opcode: Enable write BUSY status on SO pin |
||
| 79 | #define DBSY 0x80 // SPI Flash opcode: Disable write BUSY status on SO pin |
||
| 80 | |||
| 81 | #define BUSY 0x01 // Mask for Status Register BUSY bit |
||
| 82 | #define WEL 0x02 // Mask for Status Register BUSY bit |
||
| 83 | #define BP0 0x04 // Mask for Status Register BUSY bit |
||
| 84 | #define BP1 0x08 // Mask for Status Register BUSY bit |
||
| 85 | #define BP2 0x10 // Mask for Status Register BUSY bit |
||
| 86 | #define BP3 0x20 // Mask for Status Register BUSY bit |
||
| 87 | #define AAI 0x40 // Mask for Status Register BUSY bit |
||
| 88 | #define BPL 0x80 // Mask for Status Register BUSY bit |
||
| 89 | |||
| 90 | #if defined(__PIC24F__) || defined(__PIC24FK__) |
||
| 91 | #define PROPER_SPICON1 (0x001B | 0x0120) // 1:1 primary prescale, 2:1 secondary prescale, CKE=1, MASTER mode |
||
| 92 | #elif defined(__dsPIC33F__) || defined(__PIC24H__) |
||
| 93 | #define PROPER_SPICON1 (0x000F | 0x0120) // 1:1 primary prescale, 5:1 secondary prescale, CKE=1, MASTER mode |
||
| 94 | #elif defined(__dsPIC30F__) |
||
| 95 | #define PROPER_SPICON1 (0x0017 | 0x0120) // 1:1 primary prescale, 3:1 secondary prescale, CKE=1, MASTER mode |
||
| 96 | #elif defined(__PIC32MX__) |
||
| 97 | #define PROPER_SPICON1 (_SPI2CON_ON_MASK | _SPI2CON_FRZ_MASK | _SPI2CON_CKE_MASK | _SPI2CON_MSTEN_MASK) |
||
| 98 | #else |
||
| 99 | #define PROPER_SPICON1 (0x20) // SSPEN bit is set, SPI in master mode, FOSC/4, IDLE state is low level |
||
| 100 | #endif |
||
| 101 | |||
| 102 | // Maximum speed of SPI Flash part in Hz |
||
| 103 | // Should theoretically operate at 25MHz, but need to account for level-shifting delays |
||
| 104 | #define SPIFLASH_MAX_SPI_FREQ (16000000ul) |
||
| 105 | |||
| 106 | #if defined (__18CXX) |
||
| 107 | #define ClearSPIDoneFlag() {SPIFLASH_SPI_IF = 0;} |
||
| 108 | #define WaitForDataByte() {while(!SPIFLASH_SPI_IF); SPIFLASH_SPI_IF = 0;} |
||
| 109 | #define SPI_ON_BIT (SPIFLASH_SPICON1bits.SSPEN) |
||
| 110 | #elif defined(__C30__) |
||
| 111 | #define ClearSPIDoneFlag() |
||
| 112 | static inline __attribute__((__always_inline__)) void WaitForDataByte( void ) |
||
| 113 | { |
||
| 114 | while ((SPIFLASH_SPISTATbits.SPITBF == 1) || (SPIFLASH_SPISTATbits.SPIRBF == 0)); |
||
| 115 | } |
||
| 116 | |||
| 117 | #define SPI_ON_BIT (SPIFLASH_SPISTATbits.SPIEN) |
||
| 118 | #elif defined( __PIC32MX__ ) |
||
| 119 | #define ClearSPIDoneFlag() |
||
| 120 | static inline __attribute__((__always_inline__)) void WaitForDataByte( void ) |
||
| 121 | { |
||
| 122 | while (!SPIFLASH_SPISTATbits.SPITBE || !SPIFLASH_SPISTATbits.SPIRBF); |
||
| 123 | } |
||
| 124 | |||
| 125 | #define SPI_ON_BIT (SPIFLASH_SPICON1bits.ON) |
||
| 126 | #else |
||
| 127 | #error Determine SPI flag mechanism |
||
| 128 | #endif |
||
| 129 | |||
| 130 | // Internal pointer to address being written |
||
| 131 | DWORD dwWriteAddr; |
||
| 132 | |||
| 133 | |||
| 134 | void _SendCmd(BYTE cmd); |
||
| 135 | void _WaitWhileBusy(void); |
||
| 136 | //void _GetStatus(void); |
||
| 137 | |||
| 138 | |||
| 139 | /***************************************************************************** |
||
| 140 | Function: |
||
| 141 | void SPIFlashInit(void) |
||
| 142 | |||
| 143 | Description: |
||
| 144 | Initializes SPI Flash module. |
||
| 145 | |||
| 146 | Precondition: |
||
| 147 | None |
||
| 148 | |||
| 149 | Parameters: |
||
| 150 | None |
||
| 151 | |||
| 152 | Returns: |
||
| 153 | None |
||
| 154 | |||
| 155 | Remarks: |
||
| 156 | This function is only called once during the lifetime of the application. |
||
| 157 | |||
| 158 | Internal: |
||
| 159 | This function sends WRDI to clear any pending write operation, and also |
||
| 160 | clears the software write-protect on all memory locations. |
||
| 161 | ***************************************************************************/ |
||
| 162 | void SPIFlashInit(void) |
||
| 163 | { |
||
| 164 | volatile BYTE Dummy; |
||
| 165 | BYTE vSPIONSave; |
||
| 166 | #if defined(__18CXX) |
||
| 167 | BYTE SPICON1Save; |
||
| 168 | #elif defined(__C30__) |
||
| 169 | WORD SPICON1Save; |
||
| 170 | #else |
||
| 171 | DWORD SPICON1Save; |
||
| 172 | #endif |
||
| 173 | |||
| 174 | SPIFLASH_CS_IO = 1; |
||
| 175 | SPIFLASH_CS_TRIS = 0; // Drive SPI Flash chip select pin |
||
| 176 | |||
| 177 | SPIFLASH_SCK_TRIS = 0; // Set SCK pin as an output |
||
| 178 | SPIFLASH_SDI_TRIS = 1; // Make sure SDI pin is an input |
||
| 179 | SPIFLASH_SDO_TRIS = 0; // Set SDO pin as an output |
||
| 180 | |||
| 181 | // Save SPI state (clock speed) |
||
| 182 | SPICON1Save = SPIFLASH_SPICON1; |
||
| 183 | vSPIONSave = SPI_ON_BIT; |
||
| 184 | |||
| 185 | // Configure SPI |
||
| 186 | SPI_ON_BIT = 0; |
||
| 187 | SPIFLASH_SPICON1 = PROPER_SPICON1; |
||
| 188 | SPI_ON_BIT = 1; |
||
| 189 | |||
| 190 | ClearSPIDoneFlag(); |
||
| 191 | #if defined(__C30__) |
||
| 192 | SPIFLASH_SPICON2 = 0; |
||
| 193 | SPIFLASH_SPISTAT = 0; // clear SPI |
||
| 194 | SPIFLASH_SPISTATbits.SPIEN = 1; |
||
| 195 | #elif defined(__C32__) |
||
| 196 | SPIFLASH_SPIBRG = (GetPeripheralClock()-1ul)/2ul/SPIFLASH_MAX_SPI_FREQ; |
||
| 197 | #elif defined(__18CXX) |
||
| 198 | SPIFLASH_SPISTATbits.CKE = 1; // Transmit data on rising edge of clock |
||
| 199 | SPIFLASH_SPISTATbits.SMP = 0; // Input sampled at middle of data output time |
||
| 200 | #endif |
||
| 201 | |||
| 202 | |||
| 203 | // Clear any pre-existing AAI write mode |
||
| 204 | // This may occur if the PIC is reset during a write, but the Flash is |
||
| 205 | // not tied to the same hardware reset. |
||
| 206 | _SendCmd(WRDI); |
||
| 207 | |||
| 208 | // Execute Enable-Write-Status-Register (EWSR) instruction |
||
| 209 | _SendCmd(EWSR); |
||
| 210 | |||
| 211 | // Clear Write-Protect on all memory locations |
||
| 212 | SPIFLASH_CS_IO = 0; |
||
| 213 | SPIFLASH_SSPBUF = WRSR; |
||
| 214 | WaitForDataByte(); |
||
| 215 | Dummy = SPIFLASH_SSPBUF; |
||
| 216 | |||
| 217 | SPIFLASH_SSPBUF = 0x00; // Clear all block protect bits |
||
| 218 | WaitForDataByte(); |
||
| 219 | Dummy = SPIFLASH_SSPBUF; |
||
| 220 | |||
| 221 | SPIFLASH_CS_IO = 1; |
||
| 222 | |||
| 223 | // Restore SPI state |
||
| 224 | SPI_ON_BIT = 0; |
||
| 225 | SPIFLASH_SPICON1 = SPICON1Save; |
||
| 226 | SPI_ON_BIT = vSPIONSave; |
||
| 227 | } |
||
| 228 | |||
| 229 | |||
| 230 | /***************************************************************************** |
||
| 231 | Function: |
||
| 232 | void SPIFlashReadArray(DWORD dwAddress, BYTE *vData, WORD wLength) |
||
| 233 | |||
| 234 | Description: |
||
| 235 | Reads an array of bytes from the SPI Flash module. |
||
| 236 | |||
| 237 | Precondition: |
||
| 238 | SPIFlashInit has been called, and the chip is not busy (should be |
||
| 239 | handled elsewhere automatically.) |
||
| 240 | |||
| 241 | Parameters: |
||
| 242 | dwAddress - Address from which to read |
||
| 243 | vData - Where to store data that has been read |
||
| 244 | wLength - Length of data to read |
||
| 245 | |||
| 246 | Returns: |
||
| 247 | None |
||
| 248 | ***************************************************************************/ |
||
| 249 | void SPIFlashReadArray(DWORD dwAddress, BYTE *vData, WORD wLength) |
||
| 250 | { |
||
| 251 | volatile BYTE Dummy; |
||
| 252 | BYTE vSPIONSave; |
||
| 253 | #if defined(__18CXX) |
||
| 254 | BYTE SPICON1Save; |
||
| 255 | #elif defined(__C30__) |
||
| 256 | WORD SPICON1Save; |
||
| 257 | #else |
||
| 258 | DWORD SPICON1Save; |
||
| 259 | #endif |
||
| 260 | |||
| 261 | // Ignore operations when the destination is NULL or nothing to read |
||
| 262 | if(vData == NULL || wLength == 0) |
||
| 263 | return; |
||
| 264 | |||
| 265 | // Save SPI state (clock speed) |
||
| 266 | SPICON1Save = SPIFLASH_SPICON1; |
||
| 267 | vSPIONSave = SPI_ON_BIT; |
||
| 268 | |||
| 269 | // Configure SPI |
||
| 270 | SPI_ON_BIT = 0; |
||
| 271 | SPIFLASH_SPICON1 = PROPER_SPICON1; |
||
| 272 | SPI_ON_BIT = 1; |
||
| 273 | |||
| 274 | // Activate chip select |
||
| 275 | SPIFLASH_CS_IO = 0; |
||
| 276 | ClearSPIDoneFlag(); |
||
| 277 | |||
| 278 | // Send READ opcode |
||
| 279 | SPIFLASH_SSPBUF = READ; |
||
| 280 | WaitForDataByte(); |
||
| 281 | Dummy = SPIFLASH_SSPBUF; |
||
| 282 | |||
| 283 | // Send address |
||
| 284 | SPIFLASH_SSPBUF = ((BYTE*)&dwAddress)[2]; |
||
| 285 | WaitForDataByte(); |
||
| 286 | Dummy = SPIFLASH_SSPBUF; |
||
| 287 | |||
| 288 | SPIFLASH_SSPBUF = ((BYTE*)&dwAddress)[1]; |
||
| 289 | WaitForDataByte(); |
||
| 290 | Dummy = SPIFLASH_SSPBUF; |
||
| 291 | |||
| 292 | SPIFLASH_SSPBUF = ((BYTE*)&dwAddress)[0]; |
||
| 293 | WaitForDataByte(); |
||
| 294 | Dummy = SPIFLASH_SSPBUF; |
||
| 295 | |||
| 296 | // Read data |
||
| 297 | while(wLength--) |
||
| 298 | { |
||
| 299 | SPIFLASH_SSPBUF = 0; |
||
| 300 | WaitForDataByte(); |
||
| 301 | *vData++ = SPIFLASH_SSPBUF; |
||
| 302 | }; |
||
| 303 | |||
| 304 | // Deactivate chip select |
||
| 305 | SPIFLASH_CS_IO = 1; |
||
| 306 | |||
| 307 | // Restore SPI state |
||
| 308 | SPI_ON_BIT = 0; |
||
| 309 | SPIFLASH_SPICON1 = SPICON1Save; |
||
| 310 | SPI_ON_BIT = vSPIONSave; |
||
| 311 | } |
||
| 312 | |||
| 313 | /***************************************************************************** |
||
| 314 | Function: |
||
| 315 | void SPIFlashBeginWrite(DWORD dwAddr) |
||
| 316 | |||
| 317 | Summary: |
||
| 318 | Prepares the SPI Flash module for writing. |
||
| 319 | |||
| 320 | Description: |
||
| 321 | Prepares the SPI Flash module for writing. Subsequent calls to |
||
| 322 | SPIFlashWrite or SPIFlashWriteArray will begin at this location and |
||
| 323 | continue sequentially. |
||
| 324 | |||
| 325 | SPI Flash |
||
| 326 | |||
| 327 | Precondition: |
||
| 328 | SPIFlashInit has been called. |
||
| 329 | |||
| 330 | Parameters: |
||
| 331 | dwAddr - Address where the writing will begin |
||
| 332 | |||
| 333 | Returns: |
||
| 334 | None |
||
| 335 | |||
| 336 | Remarks: |
||
| 337 | Flash parts have large sector sizes, and can only erase entire sectors |
||
| 338 | at once. The SST parts for which this library was written have sectors |
||
| 339 | that are 4kB in size. Your application must ensure that writes begin on |
||
| 340 | a sector boundary so that the SPIFlashWrite functions will erase the |
||
| 341 | sector before attempting to write. Entire sectors need not be written |
||
| 342 | at once, so applications can begin writing to the front of a sector, |
||
| 343 | perform other tasks, then later call SPIFlashBeginWrite and point to an |
||
| 344 | address in this sector that has not yet been programmed. However, care |
||
| 345 | must taken to ensure that writes are not attempted on addresses that are |
||
| 346 | not in the erased state. The chip will provide no indication that the |
||
| 347 | write has failed, and will silently ignore the command. |
||
| 348 | ***************************************************************************/ |
||
| 349 | void SPIFlashBeginWrite(DWORD dwAddr) |
||
| 350 | { |
||
| 351 | dwWriteAddr = dwAddr; |
||
| 352 | } |
||
| 353 | |||
| 354 | /***************************************************************************** |
||
| 355 | Function: |
||
| 356 | void SPIFlashWrite(BYTE vData) |
||
| 357 | |||
| 358 | Summary: |
||
| 359 | Writes a byte to the SPI Flash part. |
||
| 360 | |||
| 361 | Description: |
||
| 362 | This function writes a byte to the SPI Flash part. If the current |
||
| 363 | address pointer indicates the beginning of a 4kB sector, the entire |
||
| 364 | sector will first be erased to allow writes to proceed. If the current |
||
| 365 | address pointer indicates elsewhere, it will be assumed that the sector |
||
| 366 | has already been erased. If this is not true, the chip will silently |
||
| 367 | ignore the write command. |
||
| 368 | |||
| 369 | Precondition: |
||
| 370 | SPIFlashInit and SPIFlashBeginWrite have been called, and the current |
||
| 371 | address is either the front of a 4kB sector or has already been erased. |
||
| 372 | |||
| 373 | Parameters: |
||
| 374 | vData - The byte to write to the next memory location. |
||
| 375 | |||
| 376 | Returns: |
||
| 377 | None |
||
| 378 | |||
| 379 | Remarks: |
||
| 380 | See Remarks in SPIFlashBeginWrite for important information about Flash |
||
| 381 | memory parts. |
||
| 382 | ***************************************************************************/ |
||
| 383 | void SPIFlashWrite(BYTE vData) |
||
| 384 | { |
||
| 385 | volatile BYTE Dummy; |
||
| 386 | BYTE vSPIONSave; |
||
| 387 | #if defined(__18CXX) |
||
| 388 | BYTE SPICON1Save; |
||
| 389 | #elif defined(__C30__) |
||
| 390 | WORD SPICON1Save; |
||
| 391 | #else |
||
| 392 | DWORD SPICON1Save; |
||
| 393 | #endif |
||
| 394 | |||
| 395 | // Save SPI state (clock speed) |
||
| 396 | SPICON1Save = SPIFLASH_SPICON1; |
||
| 397 | vSPIONSave = SPI_ON_BIT; |
||
| 398 | |||
| 399 | // Configure SPI |
||
| 400 | SPI_ON_BIT = 0; |
||
| 401 | SPIFLASH_SPICON1 = PROPER_SPICON1; |
||
| 402 | SPI_ON_BIT = 1; |
||
| 403 | |||
| 404 | // If address is a boundary, erase a sector first |
||
| 405 | if((dwWriteAddr & SPI_FLASH_SECTOR_MASK) == 0) |
||
| 406 | SPIFlashEraseSector(dwWriteAddr); |
||
| 407 | |||
| 408 | // Enable writing |
||
| 409 | _SendCmd(WREN); |
||
| 410 | |||
| 411 | // Activate the chip select |
||
| 412 | SPIFLASH_CS_IO = 0; |
||
| 413 | ClearSPIDoneFlag(); |
||
| 414 | |||
| 415 | // Issue WRITE command with address |
||
| 416 | SPIFLASH_SSPBUF = WRITE; |
||
| 417 | WaitForDataByte(); |
||
| 418 | Dummy = SPIFLASH_SSPBUF; |
||
| 419 | |||
| 420 | SPIFLASH_SSPBUF = ((BYTE*)&dwWriteAddr)[2]; |
||
| 421 | WaitForDataByte(); |
||
| 422 | Dummy = SPIFLASH_SSPBUF; |
||
| 423 | |||
| 424 | SPIFLASH_SSPBUF = ((BYTE*)&dwWriteAddr)[1]; |
||
| 425 | WaitForDataByte(); |
||
| 426 | Dummy = SPIFLASH_SSPBUF; |
||
| 427 | |||
| 428 | SPIFLASH_SSPBUF = ((BYTE*)&dwWriteAddr)[0]; |
||
| 429 | WaitForDataByte(); |
||
| 430 | Dummy = SPIFLASH_SSPBUF; |
||
| 431 | |||
| 432 | // Write the byte |
||
| 433 | SPIFLASH_SSPBUF = vData; |
||
| 434 | WaitForDataByte(); |
||
| 435 | Dummy = SPIFLASH_SSPBUF; |
||
| 436 | dwWriteAddr++; |
||
| 437 | |||
| 438 | // Deactivate chip select and wait for write to complete |
||
| 439 | SPIFLASH_CS_IO = 1; |
||
| 440 | _WaitWhileBusy(); |
||
| 441 | |||
| 442 | // Restore SPI state |
||
| 443 | SPI_ON_BIT = 0; |
||
| 444 | SPIFLASH_SPICON1 = SPICON1Save; |
||
| 445 | SPI_ON_BIT = vSPIONSave; |
||
| 446 | } |
||
| 447 | |||
| 448 | /***************************************************************************** |
||
| 449 | Function: |
||
| 450 | void SPIFlashWriteArray(BYTE* vData, WORD wLen) |
||
| 451 | |||
| 452 | Summary: |
||
| 453 | Writes an array of bytes to the SPI Flash part. |
||
| 454 | |||
| 455 | Description: |
||
| 456 | This function writes an array of bytes to the SPI Flash part. When the |
||
| 457 | address pointer crosses a sector boundary (and has more data to write), |
||
| 458 | the next sector will automatically be erased. If the current address |
||
| 459 | pointer indicates an address that is not a sector boundary and is not |
||
| 460 | already erased, the chip will silently ignore the write command until the |
||
| 461 | next sector boundary is crossed. |
||
| 462 | |||
| 463 | Precondition: |
||
| 464 | SPIFlashInit and SPIFlashBeginWrite have been called, and the current |
||
| 465 | address is either the front of a sector or has already been erased. |
||
| 466 | |||
| 467 | Parameters: |
||
| 468 | vData - The array to write to the next memory location |
||
| 469 | wLen - The length of the data to be written |
||
| 470 | |||
| 471 | Returns: |
||
| 472 | None |
||
| 473 | |||
| 474 | Remarks: |
||
| 475 | See Remarks in SPIFlashBeginWrite for important information about Flash |
||
| 476 | memory parts. |
||
| 477 | ***************************************************************************/ |
||
| 478 | void SPIFlashWriteArray(BYTE* vData, WORD wLen) |
||
| 479 | { |
||
| 480 | volatile BYTE Dummy; |
||
| 481 | BYTE vSPIONSave; |
||
| 482 | #if defined(__18CXX) |
||
| 483 | BYTE SPICON1Save; |
||
| 484 | #elif defined(__C30__) |
||
| 485 | WORD SPICON1Save; |
||
| 486 | #else |
||
| 487 | DWORD SPICON1Save; |
||
| 488 | #endif |
||
| 489 | BOOL isStarted; |
||
| 490 | |||
| 491 | // Save SPI state (clock speed) |
||
| 492 | SPICON1Save = SPIFLASH_SPICON1; |
||
| 493 | vSPIONSave = SPI_ON_BIT; |
||
| 494 | |||
| 495 | // Configure SPI |
||
| 496 | SPI_ON_BIT = 0; |
||
| 497 | SPIFLASH_SPICON1 = PROPER_SPICON1; |
||
| 498 | SPI_ON_BIT = 1; |
||
| 499 | |||
| 500 | #if defined(SPI_FLASH_SST) |
||
| 501 | // If starting at an odd address, write a single byte |
||
| 502 | if((dwWriteAddr & 0x01) && wLen) |
||
| 503 | { |
||
| 504 | SPIFlashWrite(*vData); |
||
| 505 | vData++; |
||
| 506 | wLen--; |
||
| 507 | } |
||
| 508 | |||
| 509 | isStarted = FALSE; |
||
| 510 | |||
| 511 | // Loop over all remaining WORDs |
||
| 512 | while(wLen > 1) |
||
| 513 | { |
||
| 514 | // Don't do anything until chip is ready |
||
| 515 | _WaitWhileBusy(); |
||
| 516 | |||
| 517 | // If address is a sector boundary |
||
| 518 | if((dwWriteAddr & SPI_FLASH_SECTOR_MASK) == 0) |
||
| 519 | SPIFlashEraseSector(dwWriteAddr); |
||
| 520 | |||
| 521 | // If not yet started, initiate AAI mode |
||
| 522 | if(!isStarted) |
||
| 523 | { |
||
| 524 | // Enable writing |
||
| 525 | _SendCmd(WREN); |
||
| 526 | |||
| 527 | // Activate the chip select |
||
| 528 | SPIFLASH_CS_IO = 0; |
||
| 529 | ClearSPIDoneFlag(); |
||
| 530 | |||
| 531 | // Issue WRITE_STREAM command with address |
||
| 532 | SPIFLASH_SSPBUF = WRITE_STREAM; |
||
| 533 | WaitForDataByte(); |
||
| 534 | Dummy = SPIFLASH_SSPBUF; |
||
| 535 | |||
| 536 | SPIFLASH_SSPBUF = ((BYTE*)&dwWriteAddr)[2]; |
||
| 537 | WaitForDataByte(); |
||
| 538 | Dummy = SPIFLASH_SSPBUF; |
||
| 539 | |||
| 540 | SPIFLASH_SSPBUF = ((BYTE*)&dwWriteAddr)[1]; |
||
| 541 | WaitForDataByte(); |
||
| 542 | Dummy = SPIFLASH_SSPBUF; |
||
| 543 | |||
| 544 | SPIFLASH_SSPBUF = ((BYTE*)&dwWriteAddr)[0]; |
||
| 545 | WaitForDataByte(); |
||
| 546 | Dummy = SPIFLASH_SSPBUF; |
||
| 547 | |||
| 548 | isStarted = TRUE; |
||
| 549 | } |
||
| 550 | // Otherwise, just write the AAI command again |
||
| 551 | else |
||
| 552 | { |
||
| 553 | // Assert the chip select pin |
||
| 554 | SPIFLASH_CS_IO = 0; |
||
| 555 | ClearSPIDoneFlag(); |
||
| 556 | |||
| 557 | // Issue the WRITE_STREAM command for continuation |
||
| 558 | SPIFLASH_SSPBUF = WRITE_STREAM; |
||
| 559 | WaitForDataByte(); |
||
| 560 | Dummy = SPIFLASH_SSPBUF; |
||
| 561 | } |
||
| 562 | |||
| 563 | // Write the two bytes |
||
| 564 | SPIFLASH_SSPBUF = *vData++; |
||
| 565 | WaitForDataByte(); |
||
| 566 | Dummy = SPIFLASH_SSPBUF; |
||
| 567 | |||
| 568 | SPIFLASH_SSPBUF = *vData++; |
||
| 569 | WaitForDataByte(); |
||
| 570 | Dummy = SPIFLASH_SSPBUF; |
||
| 571 | |||
| 572 | // Release the chip select to begin the write |
||
| 573 | SPIFLASH_CS_IO = 1; |
||
| 574 | |||
| 575 | // Increment the address, decrement length |
||
| 576 | dwWriteAddr += 2; |
||
| 577 | wLen -= 2; |
||
| 578 | |||
| 579 | // If a boundary was reached, end the write |
||
| 580 | if((dwWriteAddr & SPI_FLASH_SECTOR_MASK) == 0) |
||
| 581 | { |
||
| 582 | _WaitWhileBusy(); |
||
| 583 | _SendCmd(WRDI); |
||
| 584 | isStarted = FALSE; |
||
| 585 | } |
||
| 586 | } |
||
| 587 | |||
| 588 | // Wait for write to complete, then exit AAI mode |
||
| 589 | _WaitWhileBusy(); |
||
| 590 | _SendCmd(WRDI); |
||
| 591 | |||
| 592 | // If a byte remains, write the odd address |
||
| 593 | if(wLen) |
||
| 594 | SPIFlashWrite(*vData); |
||
| 595 | |||
| 596 | #elif defined(SPI_FLASH_SPANSION) |
||
| 597 | |||
| 598 | // Loop over all data to be written |
||
| 599 | while(wLen) |
||
| 600 | { |
||
| 601 | // If address is a sector boundary, erase a sector first |
||
| 602 | if((dwWriteAddr & SPI_FLASH_SECTOR_MASK) == 0) |
||
| 603 | SPIFlashEraseSector(dwWriteAddr); |
||
| 604 | |||
| 605 | // Enable writing |
||
| 606 | _SendCmd(WREN); |
||
| 607 | |||
| 608 | // Activate the chip select |
||
| 609 | SPIFLASH_CS_IO = 0; |
||
| 610 | ClearSPIDoneFlag(); |
||
| 611 | |||
| 612 | // Issue WRITE command with address |
||
| 613 | SPIFLASH_SSPBUF = WRITE; |
||
| 614 | WaitForDataByte(); |
||
| 615 | Dummy = SPIFLASH_SSPBUF; |
||
| 616 | |||
| 617 | SPIFLASH_SSPBUF = ((BYTE*)&dwWriteAddr)[2]; |
||
| 618 | WaitForDataByte(); |
||
| 619 | Dummy = SPIFLASH_SSPBUF; |
||
| 620 | |||
| 621 | SPIFLASH_SSPBUF = ((BYTE*)&dwWriteAddr)[1]; |
||
| 622 | WaitForDataByte(); |
||
| 623 | Dummy = SPIFLASH_SSPBUF; |
||
| 624 | |||
| 625 | SPIFLASH_SSPBUF = ((BYTE*)&dwWriteAddr)[0]; |
||
| 626 | WaitForDataByte(); |
||
| 627 | Dummy = SPIFLASH_SSPBUF; |
||
| 628 | |||
| 629 | // Write the bytes, up to a page boundary |
||
| 630 | do |
||
| 631 | { |
||
| 632 | SPIFLASH_SSPBUF = *vData++; |
||
| 633 | WaitForDataByte(); |
||
| 634 | Dummy = SPIFLASH_SSPBUF; |
||
| 635 | |||
| 636 | dwWriteAddr++; |
||
| 637 | wLen--; |
||
| 638 | } while(wLen && (dwWriteAddr & SPI_FLASH_PAGE_MASK)); |
||
| 639 | |||
| 640 | // Deactivate chip select and wait for write to complete |
||
| 641 | SPIFLASH_CS_IO = 1; |
||
| 642 | _WaitWhileBusy(); |
||
| 643 | } |
||
| 644 | #endif |
||
| 645 | |||
| 646 | // Restore SPI state |
||
| 647 | SPI_ON_BIT = 0; |
||
| 648 | SPIFLASH_SPICON1 = SPICON1Save; |
||
| 649 | SPI_ON_BIT = vSPIONSave; |
||
| 650 | } |
||
| 651 | |||
| 652 | |||
| 653 | /***************************************************************************** |
||
| 654 | Function: |
||
| 655 | void SPIFlashEraseSector(DWORD dwAddr) |
||
| 656 | |||
| 657 | Summary: |
||
| 658 | Erases a sector. |
||
| 659 | |||
| 660 | Description: |
||
| 661 | This function erases a sector in the Flash part. It is called |
||
| 662 | internally by the SPIFlashWrite functions whenever a write is attempted |
||
| 663 | on the first byte in a sector. |
||
| 664 | |||
| 665 | Precondition: |
||
| 666 | SPIFlashInit has been called. |
||
| 667 | |||
| 668 | Parameters: |
||
| 669 | dwAddr - The address of the sector to be erased. |
||
| 670 | |||
| 671 | Returns: |
||
| 672 | None |
||
| 673 | |||
| 674 | Remarks: |
||
| 675 | See Remarks in SPIFlashBeginWrite for important information about Flash |
||
| 676 | memory parts. |
||
| 677 | ***************************************************************************/ |
||
| 678 | void SPIFlashEraseSector(DWORD dwAddr) |
||
| 679 | { |
||
| 680 | volatile BYTE Dummy; |
||
| 681 | BYTE vSPIONSave; |
||
| 682 | #if defined(__18CXX) |
||
| 683 | BYTE SPICON1Save; |
||
| 684 | #elif defined(__C30__) |
||
| 685 | WORD SPICON1Save; |
||
| 686 | #else |
||
| 687 | DWORD SPICON1Save; |
||
| 688 | #endif |
||
| 689 | |||
| 690 | // Save SPI state (clock speed) |
||
| 691 | SPICON1Save = SPIFLASH_SPICON1; |
||
| 692 | vSPIONSave = SPI_ON_BIT; |
||
| 693 | |||
| 694 | // Configure SPI |
||
| 695 | SPI_ON_BIT = 0; |
||
| 696 | SPIFLASH_SPICON1 = PROPER_SPICON1; |
||
| 697 | SPI_ON_BIT = 1; |
||
| 698 | |||
| 699 | // Enable writing |
||
| 700 | _SendCmd(WREN); |
||
| 701 | |||
| 702 | // Activate the chip select |
||
| 703 | SPIFLASH_CS_IO = 0; |
||
| 704 | ClearSPIDoneFlag(); |
||
| 705 | |||
| 706 | // Issue ERASE command with address |
||
| 707 | #if defined(SPI_FLASH_SST) |
||
| 708 | SPIFLASH_SSPBUF = ERASE_4K; |
||
| 709 | #elif defined(SPI_FLASH_SPANSION) |
||
| 710 | SPIFLASH_SSPBUF = ERASE_SECTOR; |
||
| 711 | #endif |
||
| 712 | WaitForDataByte(); |
||
| 713 | Dummy = SPIFLASH_SSPBUF; |
||
| 714 | |||
| 715 | SPIFLASH_SSPBUF = ((BYTE*)&dwAddr)[2]; |
||
| 716 | WaitForDataByte(); |
||
| 717 | Dummy = SPIFLASH_SSPBUF; |
||
| 718 | |||
| 719 | SPIFLASH_SSPBUF = ((BYTE*)&dwAddr)[1]; |
||
| 720 | WaitForDataByte(); |
||
| 721 | Dummy = SPIFLASH_SSPBUF; |
||
| 722 | |||
| 723 | SPIFLASH_SSPBUF = ((BYTE*)&dwAddr)[0]; |
||
| 724 | WaitForDataByte(); |
||
| 725 | Dummy = SPIFLASH_SSPBUF; |
||
| 726 | |||
| 727 | // Deactivate chip select to perform the erase |
||
| 728 | SPIFLASH_CS_IO = 1; |
||
| 729 | |||
| 730 | // Wait for erase to complete |
||
| 731 | _WaitWhileBusy(); |
||
| 732 | |||
| 733 | // Restore SPI state |
||
| 734 | SPI_ON_BIT = 0; |
||
| 735 | SPIFLASH_SPICON1 = SPICON1Save; |
||
| 736 | SPI_ON_BIT = vSPIONSave; |
||
| 737 | } |
||
| 738 | |||
| 739 | /***************************************************************************** |
||
| 740 | Function: |
||
| 741 | void _SendCmd(BYTE cmd) |
||
| 742 | |||
| 743 | Summary: |
||
| 744 | Sends a single-byte command to the SPI Flash part. |
||
| 745 | |||
| 746 | Description: |
||
| 747 | This function sends a single-byte command to the SPI Flash part. It is |
||
| 748 | used for commands such as WREN, WRDI, and EWSR that must have the chip |
||
| 749 | select activated, then deactivated immediately after the command is |
||
| 750 | transmitted. |
||
| 751 | |||
| 752 | Precondition: |
||
| 753 | SPIFlashInit has been called. |
||
| 754 | |||
| 755 | Parameters: |
||
| 756 | cmd - The single-byte command code to send |
||
| 757 | |||
| 758 | Returns: |
||
| 759 | None |
||
| 760 | ***************************************************************************/ |
||
| 761 | void _SendCmd(BYTE cmd) |
||
| 762 | { |
||
| 763 | // Activate chip select |
||
| 764 | SPIFLASH_CS_IO = 0; |
||
| 765 | ClearSPIDoneFlag(); |
||
| 766 | |||
| 767 | // Send Read Status Register instruction |
||
| 768 | SPIFLASH_SSPBUF = cmd; |
||
| 769 | WaitForDataByte(); |
||
| 770 | cmd = SPIFLASH_SSPBUF; |
||
| 771 | |||
| 772 | // Deactivate chip select |
||
| 773 | SPIFLASH_CS_IO = 1; |
||
| 774 | } |
||
| 775 | |||
| 776 | |||
| 777 | /***************************************************************************** |
||
| 778 | Function: |
||
| 779 | void _WaitWhileBusy(void) |
||
| 780 | |||
| 781 | Summary: |
||
| 782 | Waits for the SPI Flash part to indicate it is idle. |
||
| 783 | |||
| 784 | Description: |
||
| 785 | This function waits for the SPI Flash part to indicate it is idle. It is |
||
| 786 | used in the programming functions to wait for operations to complete. |
||
| 787 | |||
| 788 | Precondition: |
||
| 789 | SPIFlashInit has been called. |
||
| 790 | |||
| 791 | Parameters: |
||
| 792 | None |
||
| 793 | |||
| 794 | Returns: |
||
| 795 | None |
||
| 796 | ***************************************************************************/ |
||
| 797 | void _WaitWhileBusy(void) |
||
| 798 | { |
||
| 799 | volatile BYTE Dummy; |
||
| 800 | |||
| 801 | // Activate chip select |
||
| 802 | SPIFLASH_CS_IO = 0; |
||
| 803 | ClearSPIDoneFlag(); |
||
| 804 | |||
| 805 | // Send Read Status Register instruction |
||
| 806 | SPIFLASH_SSPBUF = RDSR; |
||
| 807 | WaitForDataByte(); |
||
| 808 | Dummy = SPIFLASH_SSPBUF; |
||
| 809 | |||
| 810 | // Poll the BUSY bit |
||
| 811 | do |
||
| 812 | { |
||
| 813 | SPIFLASH_SSPBUF = 0x00; |
||
| 814 | WaitForDataByte(); |
||
| 815 | Dummy = SPIFLASH_SSPBUF; |
||
| 816 | } while(Dummy & BUSY); |
||
| 817 | |||
| 818 | // Deactivate chip select |
||
| 819 | SPIFLASH_CS_IO = 1; |
||
| 820 | } |
||
| 821 | |||
| 822 | /***************************************************************************** |
||
| 823 | Function: |
||
| 824 | void _GetStatus() |
||
| 825 | |||
| 826 | Summary: |
||
| 827 | Reads the status register of the part. |
||
| 828 | |||
| 829 | Description: |
||
| 830 | This function reads the status register of the part. It was written |
||
| 831 | for debugging purposes, and is not needed for normal operation. Place |
||
| 832 | a breakpoint at the last instruction and check the "status" variable to |
||
| 833 | see the result. |
||
| 834 | |||
| 835 | Precondition: |
||
| 836 | SPIFlashInit has been called. |
||
| 837 | |||
| 838 | Parameters: |
||
| 839 | None |
||
| 840 | |||
| 841 | Returns: |
||
| 842 | None |
||
| 843 | ***************************************************************************/ |
||
| 844 | //void _GetStatus() |
||
| 845 | //{ |
||
| 846 | // volatile BYTE Dummy; |
||
| 847 | // static BYTE statuses[16]; |
||
| 848 | // static BYTE *status = statuses; |
||
| 849 | // |
||
| 850 | // // Activate chip select |
||
| 851 | // SPIFLASH_CS_IO = 0; |
||
| 852 | // ClearSPIDoneFlag(); |
||
| 853 | // |
||
| 854 | // // Send Read Status Register instruction |
||
| 855 | // SPIFLASH_SSPBUF = RDSR; |
||
| 856 | // WaitForDataByte(); |
||
| 857 | // Dummy = SPIFLASH_SSPBUF; |
||
| 858 | // |
||
| 859 | // SPIFLASH_SSPBUF = 0x00; |
||
| 860 | // WaitForDataByte(); |
||
| 861 | // *status = SPIFLASH_SSPBUF; |
||
| 862 | // status++; |
||
| 863 | // |
||
| 864 | // // Deactivate chip select |
||
| 865 | // SPIFLASH_CS_IO = 1; |
||
| 866 | // |
||
| 867 | // if(status == &statuses[10]) |
||
| 868 | // statuses[15] = 0; |
||
| 869 | //} |
||
| 870 | |||
| 871 | #endif //#if defined(SPIFLASH_CS_TRIS) |
||
| 872 |
Powered by WebSVN v2.8.3