Added page write
[hackover2013-badge-firmware.git] / drivers / spiflash / w25q16bv / w25q16bv.c
1 /**************************************************************************/
2 /*!
3 @file w25q16bv.c
4 @author K. Townsend (microBuilder.eu)
5
6 @section DESCRIPTION
7
8 Driver for Winbond's 16 MBit SPI/Quad-SPI Flash (W25Q16BV)
9
10 @section LICENSE
11
12 Software License Agreement (BSD License)
13
14 Copyright (c) 2010, microBuilder SARL
15 All rights reserved.
16
17 Redistribution and use in source and binary forms, with or without
18 modification, are permitted provided that the following conditions are met:
19 1. Redistributions of source code must retain the above copyright
20 notice, this list of conditions and the following disclaimer.
21 2. Redistributions in binary form must reproduce the above copyright
22 notice, this list of conditions and the following disclaimer in the
23 documentation and/or other materials provided with the distribution.
24 3. Neither the name of the copyright holders nor the
25 names of its contributors may be used to endorse or promote products
26 derived from this software without specific prior written permission.
27
28 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
29 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
30 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
31 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
32 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
33 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
34 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
35 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
37 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 */
39 /**************************************************************************/
40
41 #include "w25q16bv.h"
42 #include "../spiflash.h"
43 #include "core/ssp/ssp.h"
44 #include "core/gpio/gpio.h"
45 #include "core/systick/systick.h"
46
47 // Macros to toggle the CS/SSEL line on the SPI bus
48 #define W25Q16BV_SELECT() gpioSetValue(0, 2, 0)
49 #define W25Q16BV_DESELECT() gpioSetValue(0, 2, 1)
50
51 // Flag to indicate whether the SPI flash has been initialised or not
52 static bool _w25q16bvInitialised = false;
53
54 /**************************************************************************/
55 /* HW Specific Functions */
56 /* ------------------------------------------------------------------- */
57 /* These functions are specific to the chip being used, and are */
58 /* seperate from the 'generic' functions defined in spiflash.h */
59 /* */
60 /**************************************************************************/
61
62 /**************************************************************************/
63 /*!
64 This function both reads and writes data. For write operations, include data
65 to be written as argument. For read ops, use dummy data as arg. Returned
66 data is read byte val.
67 */
68 /**************************************************************************/
69 uint8_t w25q16bv_TransferByte(uint8_t data)
70 {
71 /* Move on only if NOT busy and TX FIFO not full */
72 while ((SSP_SSP0SR & (SSP_SSP0SR_TNF_MASK | SSP_SSP0SR_BSY_MASK)) != SSP_SSP0SR_TNF_NOTFULL);
73 SSP_SSP0DR = data;
74
75 /* Wait until the busy bit is cleared and receive buffer is not empty */
76 while ((SSP_SSP0SR & (SSP_SSP0SR_BSY_MASK | SSP_SSP0SR_RNE_MASK)) != SSP_SSP0SR_RNE_NOTEMPTY);
77
78 // Read the queue
79 return SSP_SSP0DR;
80 }
81
82 /**************************************************************************/
83 /*!
84 @brief Gets the value of the Read Status Register (0x05)
85
86 @return The 8-bit value returned by the Read Status Register
87 */
88 /**************************************************************************/
89 uint8_t w25q16bvGetStatus()
90 {
91 uint8_t status;
92
93 W25Q16BV_SELECT();
94 w25q16bv_TransferByte(W25Q16BV_CMD_READSTAT1); // Send read status 1 cmd
95 status = w25q16bv_TransferByte(0xFF); // Dummy write
96 W25Q16BV_DESELECT();
97
98 return status & (W25Q16BV_STAT1_BUSY | W25Q16BV_STAT1_WRTEN);
99 }
100
101 /**************************************************************************/
102 /*!
103 @brief Waits for the SPI flash to indicate that it is ready (not
104 busy) or until a timeout occurs.
105
106 @return An error message indicating that a timeoout occured
107 (SPIFLASH_ERROR_TIMEOUT_READY) or an OK signal to indicate that
108 the SPI flash is ready (SPIFLASH_ERROR_OK)
109 */
110 /**************************************************************************/
111 spiflashError_e w25q16bvWaitForReady()
112 {
113 uint32_t timeout = 0;
114 uint8_t status;
115
116 while ( timeout < SSP_MAX_TIMEOUT )
117 {
118 status = w25q16bvGetStatus() & W25Q16BV_STAT1_BUSY;
119 if (status == 0)
120 {
121 break;
122 }
123 timeout++;
124 }
125 if ( timeout == SSP_MAX_TIMEOUT )
126 {
127 return SPIFLASH_ERROR_TIMEOUT_READY;
128 }
129
130 return SPIFLASH_ERROR_OK;
131 }
132
133 /**************************************************************************/
134 /*!
135 @brief Gets the unique 64-bit ID assigned to this IC (useful for
136 security purposes to detect if the flash was changed, etc.)
137
138 @param[out] *buffer
139 Pointer to the uint8_t buffer that will store the 8 byte
140 long unique ID
141
142 @note The unique ID is return in bit order 63..0
143 */
144 /**************************************************************************/
145 void w25q16bvGetUniqueID(uint8_t *buffer)
146 {
147 uint8_t i;
148
149 W25Q16BV_SELECT();
150 w25q16bv_TransferByte(W25Q16BV_CMD_READUNIQUEID); // Unique ID cmd
151 w25q16bv_TransferByte(0xFF); // Dummy write
152 w25q16bv_TransferByte(0xFF); // Dummy write
153 w25q16bv_TransferByte(0xFF); // Dummy write
154 w25q16bv_TransferByte(0xFF); // Dummy write
155 // Read 8 bytes worth of data
156 for (i = 0; i < 8; i++)
157 {
158 buffer[i] = w25q16bv_TransferByte(0xFF);
159 }
160 W25Q16BV_DESELECT();
161 }
162
163 /**************************************************************************/
164 /* Generic spiflash.h Functions */
165 /* ------------------------------------------------------------------- */
166 /* These functions are part of the common interface defined in */
167 /* spiflash.h and must be implemented by any spi flash device */
168 /* */
169 /**************************************************************************/
170
171 /**************************************************************************/
172 /*!
173 @brief Tries to initialise the flash device, and setups any HW
174 required by the SPI flash
175 */
176 /**************************************************************************/
177 void spiflashInit (void)
178 {
179 // Initialise the SPI bus
180 sspInit(0, sspClockPolarity_Low, sspClockPhase_RisingEdge);
181
182 // ToDo: Set the WP, Hold, etc. pins to an appropriate state
183
184 _w25q16bvInitialised = TRUE;
185 }
186
187 /**************************************************************************/
188 /*!
189 @brief Gets an instance of spiflashSizeInfo_t that describes the
190 storage limits of the SPI flash like page size (minimum write
191 size) and sector size (minimum erase size).
192 */
193 /**************************************************************************/
194 spiflashSizeInfo_t spiflashGetSizeInfo(void)
195 {
196 spiflashSizeInfo_t size;
197 size.pageSize = W25Q16BV_PAGESIZE;
198 size.pageCount = W25Q16BV_PAGES;
199 size.sectorSize = W25Q16BV_SECTORSIZE;
200 size.sectorCount = W25Q16BV_SECTORS;
201 return size;
202 }
203
204 /**************************************************************************/
205 /*!
206 @brief Gets the 8-bit manufacturer ID and device ID for the flash
207
208 @param[out] *manufID
209 Pointer to the uint8_t that will store the manufacturer ID
210 @param[out] *deviceID
211 Pointer to the uint8_t that will store the device ID
212 */
213 /**************************************************************************/
214 void spiflashGetManufacturerInfo (uint8_t *manufID, uint8_t *deviceID)
215 {
216 if (!_w25q16bvInitialised) spiflashInit();
217
218 // W25Q16BV_CMD_MANUFDEVID (0x90) provides both the JEDEC manufacturer
219 // ID and the device ID
220
221 W25Q16BV_SELECT();
222 w25q16bv_TransferByte(W25Q16BV_CMD_MANUFDEVID);
223 w25q16bv_TransferByte(0x00); // Dummy write
224 w25q16bv_TransferByte(0x00); // Dummy write
225 w25q16bv_TransferByte(0x00); // Dummy write
226 *manufID = w25q16bv_TransferByte(0xFF);
227 *deviceID = w25q16bv_TransferByte(0xFF);
228 W25Q16BV_DESELECT();
229 }
230
231 /**************************************************************************/
232 /*!
233 @brief Sets the write flag on the SPI flash, and if required puts the
234 WP pin in an appropriate state
235
236 @param[in] enable
237 True (1) to enable writing, false (0) to disable it
238 */
239 /**************************************************************************/
240 void spiflashWriteEnable (bool enable)
241 {
242 if (!_w25q16bvInitialised) spiflashInit();
243
244 uint32_t i;
245
246 // ToDo: Put the WP pin in an appropriate state if required
247
248 W25Q16BV_SELECT();
249 w25q16bv_TransferByte(enable ? W25Q16BV_CMD_WRITEENABLE : W25Q16BV_CMD_WRITEDISABLE);
250 W25Q16BV_DESELECT();
251 }
252
253 /**************************************************************************/
254 /*!
255 @brief Reads the specified number of bytes from the supplied address.
256
257 This function will read one or more bytes starting at the supplied
258 address. Please note that bufferLength is zero-based, meaning you
259 should supply '0' to read a single byte, '3' to read 4 bytes of data,
260 etc.
261
262 @param[in] address
263 The 24-bit address where the read will start.
264 @param[out] *buffer
265 Pointer to the buffer that will store the read results
266 @param[in] len
267 Length of the buffer.
268
269 @section EXAMPLE
270
271 @code
272 uint8_t buffer[64];
273 spiflashError_e error;
274 error = spiflashReadBuffer (0, buffer, 64);
275 if (error)
276 {
277 // Check what went wrong
278 switch (error)
279 {
280 case SPIFLASH_ERROR_ADDROUTOFRANGE:
281 // Specified starting address is out of range
282 break;
283 case SPIFLASH_ERROR_TIMEOUT_READY:
284 // Timed out waiting for flash to return ready state
285 break;
286 case SPIFLASH_ERROR_ADDROVERFLOW:
287 // Ran over the upper address during read
288 break;
289 }
290 }
291 @endcode
292 */
293 /**************************************************************************/
294 spiflashError_e spiflashReadBuffer (uint32_t address, uint8_t *buffer, uint32_t len)
295 {
296 if (!_w25q16bvInitialised) spiflashInit();
297
298 uint32_t a, i;
299 a = i = 0;
300
301 // Make sure the address is valid
302 if (address >= W25Q16BV_MAXADDRESS)
303 {
304 return SPIFLASH_ERROR_ADDROUTOFRANGE;
305 }
306
307 // Wait until the device is ready or a timeout occurs
308 if (w25q16bvWaitForReady())
309 return SPIFLASH_ERROR_TIMEOUT_READY;
310
311 // Send the read data command
312 W25Q16BV_SELECT();
313 w25q16bv_TransferByte(W25Q16BV_CMD_READDATA); // 0x03
314 w25q16bv_TransferByte((address >> 16) & 0xFF); // address upper 8
315 w25q16bv_TransferByte((address >> 8) & 0xFF); // address mid 8
316 w25q16bv_TransferByte(address & 0xFF); // address lower 8
317 // Fill response buffer
318 for (a = address; a < address + len; a++, i++)
319 {
320 if (a > W25Q16BV_MAXADDRESS)
321 {
322 // Oops ... we're at the end of the flash memory
323 return SPIFLASH_ERROR_ADDROVERFLOW;
324 }
325 buffer[i] = w25q16bv_TransferByte(0xFF);
326 }
327 W25Q16BV_DESELECT();
328
329 return SPIFLASH_ERROR_OK;
330 }
331
332 /**************************************************************************/
333 /*!
334 @brief Erases the contents of a single sector
335
336 @param[in] sectorNumber
337 The sector number to erase (zero-based).
338
339 @section EXAMPLE
340
341 @code
342 spiflashError_e error;
343 error = spiflashEraseSector(0);
344 if (error)
345 {
346 // Check what went wrong
347 switch (error)
348 {
349 case SPIFLASH_ERROR_ADDROUTOFRANGE:
350 // Specified starting address is out of range
351 break;
352 case SPIFLASH_ERROR_PROTECTIONERR:
353 // Couldn't set the write enable bit
354 break;
355 case SPIFLASH_ERROR_TIMEOUT_READY:
356 // Timed out waiting for flash to return ready state
357 break;
358 }
359 }
360 @endcode
361 */
362 /**************************************************************************/
363 spiflashError_e spiflashEraseSector (uint32_t sectorNumber)
364 {
365 if (!_w25q16bvInitialised) spiflashInit();
366
367 // Make sure the address is valid
368 if (sectorNumber >= W25Q16BV_SECTORS)
369 {
370 return SPIFLASH_ERROR_ADDROUTOFRANGE;
371 }
372
373 // Wait until the device is ready or a timeout occurs
374 if (w25q16bvWaitForReady())
375 return SPIFLASH_ERROR_TIMEOUT_READY;
376
377 // Make sure the chip is write enabled
378 spiflashWriteEnable (TRUE);
379
380 // Make sure the write enable latch is actually set
381 uint8_t status;
382 status = w25q16bvGetStatus();
383 if (!(status & W25Q16BV_STAT1_WRTEN))
384 {
385 // Throw a write protection error (write enable latch not set)
386 return SPIFLASH_ERROR_PROTECTIONERR;
387 }
388
389 // Send the erase sector command
390 uint32_t address = sectorNumber * W25Q16BV_SECTORSIZE;
391 W25Q16BV_SELECT();
392 w25q16bv_TransferByte(W25Q16BV_CMD_SECTERASE4);
393 w25q16bv_TransferByte((address >> 16) & 0xFF); // address upper 8
394 w25q16bv_TransferByte((address >> 8) & 0xFF); // address mid 8
395 w25q16bv_TransferByte(address & 0xFF); // address lower 8
396 W25Q16BV_DESELECT();
397
398 // Wait until the busy bit is cleared before exiting
399 // This can take up to 400ms according to the datasheet
400 while (w25q16bvGetStatus() & W25Q16BV_STAT1_BUSY);
401
402 return SPIFLASH_ERROR_OK;
403 }
404
405 /**************************************************************************/
406 /*!
407 @brief Erases the entire flash chip
408
409 @section EXAMPLE
410
411 @code
412 spiflashError_e error;
413 error = spiflashEraseChip();
414 if (error)
415 {
416 // Check what went wrong
417 switch (error)
418 {
419 case SPIFLASH_ERROR_PROTECTIONERR:
420 // Couldn't set the write enable bit
421 break;
422 case SPIFLASH_ERROR_TIMEOUT_READY:
423 // Timed out waiting for flash to return ready state
424 break;
425 }
426 }
427 @endcode
428 */
429 /**************************************************************************/
430 spiflashError_e spiflashEraseChip (void)
431 {
432 if (!_w25q16bvInitialised) spiflashInit();
433
434 // Wait until the device is ready or a timeout occurs
435 if (w25q16bvWaitForReady())
436 return SPIFLASH_ERROR_TIMEOUT_READY;
437
438 // Make sure the chip is write enabled
439 spiflashWriteEnable (TRUE);
440
441 // Make sure the write enable latch is actually set
442 uint8_t status;
443 status = w25q16bvGetStatus();
444 if (!(status & W25Q16BV_STAT1_WRTEN))
445 {
446 // Throw a write protection error (write enable latch not set)
447 return SPIFLASH_ERROR_PROTECTIONERR;
448 }
449
450 // Send the erase chip command
451 W25Q16BV_SELECT();
452 w25q16bv_TransferByte(W25Q16BV_CMD_CHIPERASE);
453 W25Q16BV_DESELECT();
454
455 // Wait until the busy bit is cleared before exiting
456 // This can take up to 10 seconds according to the datasheet!
457 while (w25q16bvGetStatus() & W25Q16BV_STAT1_BUSY);
458
459 return SPIFLASH_ERROR_OK;
460 }
461
462 /**************************************************************************/
463 /*!
464 @brief Writes up to 256 bytes of data to the specified page.
465
466 @note Before writing data to a page, make sure that the 4K sector
467 containing the specific page has been erased, otherwise the
468 data will be meaningless.
469
470 @param[in] address
471 The 24-bit address where the write will start.
472 @param[out] *buffer
473 Pointer to the buffer that will store the read results
474 @param[in] len
475 Length of the buffer. Valid values are from 1 to 256,
476 within the limits of the starting address and page length.
477
478 @section EXAMPLE
479
480 @code
481 spiflashError_e error;
482 uint8_t buffer[256];
483
484 buffer[0] = 0x12;
485 buffer[1] = 0x34;
486 buffer[2] = 0x56;
487 buffer[3] = 0x78;
488 buffer[4] = 0xDE;
489 buffer[5] = 0xAD;
490 buffer[6] = 0xC0;
491 buffer[7] = 0xDE;
492
493 error = spiflashWritePage (0, buffer, 8);
494 if (error)
495 {
496 // Check what went wrong
497 switch (error)
498 {
499 case SPIFLASH_ERROR_ADDROUTOFRANGE:
500 // Specified starting address is out of range
501 break;
502 case SPIFLASH_ERROR_DATAEXCEEDSPAGESIZE:
503 // Supplied data exceeds max page size
504 break;
505 case SPIFLASH_ERROR_PAGEWRITEOVERFLOW:
506 // The data length plus the start address offset exceeeds page limits
507 break;
508 case SPIFLASH_ERROR_TIMEOUT_READY:
509 // Timeout waiting for ready status (can be pre or post write)
510 break;
511 case SPIFLASH_ERROR_PROTECTIONERR:
512 // Unable to set write latch
513 break;
514 }
515 }
516 @endcode
517 */
518 /**************************************************************************/
519 spiflashError_e spiflashWritePage (uint32_t address, uint8_t *buffer, uint32_t len)
520 {
521 uint8_t status;
522 uint32_t currentpage, totalpages;
523 uint32_t a, i, timeout;
524 a = i = 0;
525
526 if (!_w25q16bvInitialised) spiflashInit();
527
528 // Make sure the address is valid
529 if (address >= W25Q16BV_MAXADDRESS)
530 {
531 return SPIFLASH_ERROR_ADDROUTOFRANGE;
532 }
533
534 // Make sure that the supplied data is no larger than the page size
535 if (len > W25Q16BV_PAGESIZE)
536 {
537 return SPIFLASH_ERROR_DATAEXCEEDSPAGESIZE;
538 }
539
540 // Make sure that the data won't wrap around to the beginning of the sector
541 if ((address % W25Q16BV_PAGESIZE) + len > W25Q16BV_PAGESIZE)
542 {
543 // If you try to write to a page beyond the last byte, it will
544 // wrap around to the start of the page, almost certainly
545 // messing up your data
546 return SPIFLASH_ERROR_PAGEWRITEOVERFLOW;
547 }
548
549 // Wait until the device is ready or a timeout occurs
550 if (w25q16bvWaitForReady())
551 return SPIFLASH_ERROR_TIMEOUT_READY;
552
553 // Make sure the chip is write enabled
554 spiflashWriteEnable (TRUE);
555
556 // Make sure the write enable latch is actually set
557 status = w25q16bvGetStatus();
558 if (!(status & W25Q16BV_STAT1_WRTEN))
559 {
560 // Throw a write protection error (write enable latch not set)
561 return SPIFLASH_ERROR_PROTECTIONERR;
562 }
563
564 // Send page write command (0x02) plus 24-bit address
565 W25Q16BV_SELECT();
566 w25q16bv_TransferByte(W25Q16BV_CMD_PAGEPROG); // 0x02
567 w25q16bv_TransferByte((address >> 16) & 0xFF); // address upper 8
568 w25q16bv_TransferByte((address >> 8) & 0xFF); // address mid 8
569 if (len == 256)
570 {
571 // If len = 256 bytes, lower 8 bits must be 0 (see datasheet 11.2.17)
572 w25q16bv_TransferByte(0);
573 }
574 else
575 {
576 w25q16bv_TransferByte(address & 0xFF); // address lower 8
577 }
578 // Transfer data
579 for (i = 0; i < len; i++)
580 {
581 w25q16bv_TransferByte(buffer[i]);
582 }
583 // Write only occurs after the CS line is de-asserted
584 W25Q16BV_DESELECT();
585
586 // Wait at least 3ms (max page program time according to datasheet)
587 systickDelay(3);
588
589 // Wait until the device is ready or a timeout occurs
590 if (w25q16bvWaitForReady())
591 return SPIFLASH_ERROR_TIMEOUT_READY;
592
593 return SPIFLASH_ERROR_OK;
594 }
595
This page took 0.068134 seconds and 5 git commands to generate.