First commit
[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
46 // Macros to toggle the CS/SSEL line on the SPI bus
47 #define W25Q16BV_SELECT() gpioSetValue(0, 2, 0)
48 #define W25Q16BV_DESELECT() gpioSetValue(0, 2, 1)
49
50 // Flag to indicate whether the SPI flash has been initialised or not
51 static bool _w25q16bvInitialised = false;
52
53 /**************************************************************************/
54 /* HW Specific Functions */
55 /* ------------------------------------------------------------------- */
56 /* These functions are specific to the chip being used, and are */
57 /* seperate from the 'generic' functions defined in spiflash.h */
58 /* */
59 /**************************************************************************/
60
61 /**************************************************************************/
62 /*!
63 This function both reads and writes data. For write operations, include data
64 to be written as argument. For read ops, use dummy data as arg. Returned
65 data is read byte val.
66 */
67 /**************************************************************************/
68 uint8_t w25q16bv_TransferByte(uint8_t data)
69 {
70 /* Move on only if NOT busy and TX FIFO not full */
71 while ((SSP_SSP0SR & (SSP_SSP0SR_TNF_MASK | SSP_SSP0SR_BSY_MASK)) != SSP_SSP0SR_TNF_NOTFULL);
72 SSP_SSP0DR = data;
73
74 /* Wait until the busy bit is cleared and receive buffer is not empty */
75 while ((SSP_SSP0SR & (SSP_SSP0SR_BSY_MASK | SSP_SSP0SR_RNE_MASK)) != SSP_SSP0SR_RNE_NOTEMPTY);
76
77 // Read the queue
78 return SSP_SSP0DR;
79 }
80
81 /**************************************************************************/
82 /*!
83 @brief Gets the value of the Read Status Register (0x05)
84
85 @return The 8-bit value returned by the Read Status Register
86 */
87 /**************************************************************************/
88 uint8_t w25q16bvGetStatus()
89 {
90 uint8_t status;
91
92 W25Q16BV_SELECT();
93 w25q16bv_TransferByte(W25Q16BV_CMD_READSTAT1); // Send read status 1 cmd
94 status = w25q16bv_TransferByte(0xFF); // Dummy write
95 W25Q16BV_DESELECT();
96
97 return status & (W25Q16BV_STAT1_BUSY | W25Q16BV_STAT1_WRTEN);
98 }
99
100 /**************************************************************************/
101 /*!
102 @brief Waits for the SPI flash to indicate that it is ready (not
103 busy) or until a timeout occurs.
104
105 @return An error message indicating that a timeoout occured
106 (SPIFLASH_ERROR_TIMEOUT_READY) or an OK signal to indicate that
107 the SPI flash is ready (SPIFLASH_ERROR_OK)
108 */
109 /**************************************************************************/
110 spiflashError_e w25q16bvWaitForReady()
111 {
112 uint32_t timeout = 0;
113 uint8_t status;
114
115 while ( timeout < SSP_MAX_TIMEOUT )
116 {
117 status = w25q16bvGetStatus() & W25Q16BV_STAT1_BUSY;
118 if (status == 0)
119 {
120 break;
121 }
122 timeout++;
123 }
124 if ( timeout == SSP_MAX_TIMEOUT )
125 {
126 return SPIFLASH_ERROR_TIMEOUT_READY;
127 }
128
129 return SPIFLASH_ERROR_OK;
130 }
131
132 /**************************************************************************/
133 /*!
134 @brief Gets the unique 64-bit ID assigned to this IC (useful for
135 security purposes to detect if the flash was changed, etc.)
136
137 @param[out] *buffer
138 Pointer to the uint8_t buffer that will store the 8 byte
139 long unique ID
140
141 @note The unique ID is return in bit order 63..0
142 */
143 /**************************************************************************/
144 void w25q16bvGetUniqueID(uint8_t *buffer)
145 {
146 uint8_t i;
147
148 W25Q16BV_SELECT();
149 w25q16bv_TransferByte(W25Q16BV_CMD_READUNIQUEID); // Unique ID cmd
150 w25q16bv_TransferByte(0xFF); // Dummy write
151 w25q16bv_TransferByte(0xFF); // Dummy write
152 w25q16bv_TransferByte(0xFF); // Dummy write
153 w25q16bv_TransferByte(0xFF); // Dummy write
154 // Read 8 bytes worth of data
155 for (i = 0; i < 8; i++)
156 {
157 buffer[i] = w25q16bv_TransferByte(0xFF);
158 }
159 W25Q16BV_DESELECT();
160 }
161
162 /**************************************************************************/
163 /* Generic spiflash.h Functions */
164 /* ------------------------------------------------------------------- */
165 /* These functions are part of the common interface defined in */
166 /* spiflash.h and must be implemented by any spi flash device */
167 /* */
168 /**************************************************************************/
169
170 /**************************************************************************/
171 /*!
172 @brief Tries to initialise the flash device, and setups any HW
173 required by the SPI flash
174 */
175 /**************************************************************************/
176 void spiflashInit (void)
177 {
178 // Initialise the SPI bus
179 sspInit(0, sspClockPolarity_Low, sspClockPhase_RisingEdge);
180
181 // ToDo: Set the WP, Hold, etc. pins to an appropriate state
182
183 _w25q16bvInitialised = TRUE;
184 }
185
186 /**************************************************************************/
187 /*!
188 @brief Gets an instance of spiflashSizeInfo_t that describes the
189 storage limits of the SPI flash like page size (minimum write
190 size) and sector size (minimum erase size).
191 */
192 /**************************************************************************/
193 spiflashSizeInfo_t spiflashGetSizeInfo(void)
194 {
195 spiflashSizeInfo_t size;
196 size.pageSize = W25Q16BV_PAGESIZE;
197 size.pageCount = W25Q16BV_PAGES;
198 size.sectorSize = W25Q16BV_SECTORSIZE;
199 size.sectorCount = W25Q16BV_SECTORS;
200 return size;
201 }
202
203 /**************************************************************************/
204 /*!
205 @brief Gets the 8-bit manufacturer ID and device ID for the flash
206
207 @param[out] *manufID
208 Pointer to the uint8_t that will store the manufacturer ID
209 @param[out] *deviceID
210 Pointer to the uint8_t that will store the device ID
211 */
212 /**************************************************************************/
213 void spiflashGetManufacturerInfo (uint8_t *manufID, uint8_t *deviceID)
214 {
215 if (!_w25q16bvInitialised) spiflashInit();
216
217 // W25Q16BV_CMD_MANUFDEVID (0x90) provides both the JEDEC manufacturer
218 // ID and the device ID
219
220 W25Q16BV_SELECT();
221 w25q16bv_TransferByte(W25Q16BV_CMD_MANUFDEVID);
222 w25q16bv_TransferByte(0x00); // Dummy write
223 w25q16bv_TransferByte(0x00); // Dummy write
224 w25q16bv_TransferByte(0x00); // Dummy write
225 *manufID = w25q16bv_TransferByte(0xFF);
226 *deviceID = w25q16bv_TransferByte(0xFF);
227 W25Q16BV_DESELECT();
228 }
229
230 /**************************************************************************/
231 /*!
232 @brief Sets the write flag on the SPI flash, and if required puts the
233 WP pin in an appropriate state
234
235 @param[in] enable
236 True (1) to enable writing, false (0) to disable it
237 */
238 /**************************************************************************/
239 void spiflashWriteEnable (bool enable)
240 {
241 if (!_w25q16bvInitialised) spiflashInit();
242
243 uint32_t i;
244
245 // ToDo: Put the WP pin in an appropriate state if required
246
247 W25Q16BV_SELECT();
248 w25q16bv_TransferByte(enable ? W25Q16BV_CMD_WRITEENABLE : W25Q16BV_CMD_WRITEDISABLE);
249 W25Q16BV_DESELECT();
250 }
251
252 /**************************************************************************/
253 /*!
254 @brief Reads the specified number of bytes from the supplied address.
255
256 This function will read one or more bytes starting at the supplied
257 address. Please note that bufferLength is zero-based, meaning you
258 should supply '0' to read a single byte, '3' to read 4 bytes of data,
259 etc.
260
261 @param[in] address
262 The 24-bit address where the read will start.
263 @param[out] *buffer
264 Pointer to the buffer that will store the read results
265 @param[in] len
266 Length of the buffer (zero-based).
267
268 @section EXAMPLE
269
270 @code
271 uint8_t buffer[64];
272 spiflashError_e error;
273 error = spiflashReadBuffer (0, buffer, 64);
274 if (error)
275 {
276 // Check what went wrong
277 switch (error)
278 {
279 case SPIFLASH_ERROR_ADDROUTOFRANGE:
280 // Specified starting address is out of range
281 break;
282 case SPIFLASH_ERROR_TIMEOUT_READY:
283 // Timed out waiting for flash to return ready state
284 break;
285 case SPIFLASH_ERROR_ADDROVERFLOW:
286 // Ran over the upper address during read
287 break;
288 }
289 }
290 @endcode
291 */
292 /**************************************************************************/
293 spiflashError_e spiflashReadBuffer (uint32_t address, uint8_t *buffer, uint32_t len)
294 {
295 if (!_w25q16bvInitialised) spiflashInit();
296
297 uint32_t a, i;
298 a = i = 0;
299
300 // Make sure the address is valid
301 if (address >= W25Q16BV_MAXADDRESS)
302 {
303 return SPIFLASH_ERROR_ADDROUTOFRANGE;
304 }
305
306 // Wait until the device is ready or a timeout occurs
307 if (w25q16bvWaitForReady())
308 return SPIFLASH_ERROR_TIMEOUT_READY;
309
310 // Send the read data command
311 W25Q16BV_SELECT();
312 w25q16bv_TransferByte(W25Q16BV_CMD_READDATA); // 0x03
313 w25q16bv_TransferByte((address >> 16) & 0xFF); // address upper 8
314 w25q16bv_TransferByte((address >> 8) & 0xFF); // address mid 8
315 w25q16bv_TransferByte(address & 0xFF); // address lower 8
316 // Fill response buffer
317 for (a = address; a < address + len; a++, i++)
318 {
319 if (a > W25Q16BV_MAXADDRESS)
320 {
321 // Oops ... we're at the end of the flash memory
322 return SPIFLASH_ERROR_ADDROVERFLOW;
323 }
324 buffer[i] = w25q16bv_TransferByte(0xFF);
325 }
326 W25Q16BV_DESELECT();
327
328 return SPIFLASH_ERROR_OK;
329 }
330
331 /**************************************************************************/
332 /*!
333 @brief Erases the contents of a single sector
334
335 @param[in] sectorNumber
336 The sector number to erase (zero-based).
337
338 @section EXAMPLE
339
340 @code
341 spiflashError_e error;
342 error = spiflashEraseSector(0);
343 if (error)
344 {
345 // Check what went wrong
346 switch (error)
347 {
348 case SPIFLASH_ERROR_ADDROUTOFRANGE:
349 // Specified starting address is out of range
350 break;
351 case SPIFLASH_ERROR_PROTECTIONERR:
352 // Couldn't set the write enable bit
353 break;
354 case SPIFLASH_ERROR_TIMEOUT_READY:
355 // Timed out waiting for flash to return ready state
356 break;
357 }
358 }
359 @endcode
360 */
361 /**************************************************************************/
362 spiflashError_e spiflashEraseSector (uint32_t sectorNumber)
363 {
364 if (!_w25q16bvInitialised) spiflashInit();
365
366 // Make sure the address is valid
367 if (sectorNumber >= W25Q16BV_SECTORS)
368 {
369 return SPIFLASH_ERROR_ADDROUTOFRANGE;
370 }
371
372 // Wait until the device is ready or a timeout occurs
373 if (w25q16bvWaitForReady())
374 return SPIFLASH_ERROR_TIMEOUT_READY;
375
376 // Make sure the chip is write enabled
377 spiflashWriteEnable (TRUE);
378
379 // Make sure the write enable latch is actually set
380 uint8_t status;
381 status = w25q16bvGetStatus();
382 if (!(status & W25Q16BV_STAT1_WRTEN))
383 {
384 // Throw a write protection error (write enable latch not set)
385 return SPIFLASH_ERROR_PROTECTIONERR;
386 }
387
388 // Send the erase sector command
389 uint32_t address = sectorNumber * W25Q16BV_SECTORSIZE;
390 W25Q16BV_SELECT();
391 w25q16bv_TransferByte(W25Q16BV_CMD_SECTERASE4);
392 w25q16bv_TransferByte((address >> 16) & 0xFF); // address upper 8
393 w25q16bv_TransferByte((address >> 8) & 0xFF); // address mid 8
394 w25q16bv_TransferByte(address & 0xFF); // address lower 8
395 W25Q16BV_DESELECT();
396
397 // Wait until the busy bit is cleared before exiting
398 // This can take up to 10 seconds according to the datasheet!
399 while (w25q16bvGetStatus() & W25Q16BV_STAT1_BUSY);
400
401 return SPIFLASH_ERROR_OK;
402 }
403
404 /**************************************************************************/
405 /*!
406 @brief Erases the entire flash chip
407
408 @section EXAMPLE
409
410 @code
411 spiflashError_e error;
412 error = spiflashEraseChip();
413 if (error)
414 {
415 // Check what went wrong
416 switch (error)
417 {
418 case SPIFLASH_ERROR_PROTECTIONERR:
419 // Couldn't set the write enable bit
420 break;
421 case SPIFLASH_ERROR_TIMEOUT_READY:
422 // Timed out waiting for flash to return ready state
423 break;
424 }
425 }
426 @endcode
427 */
428 /**************************************************************************/
429 spiflashError_e spiflashEraseChip (void)
430 {
431 if (!_w25q16bvInitialised) spiflashInit();
432
433 // Wait until the device is ready or a timeout occurs
434 if (w25q16bvWaitForReady())
435 return SPIFLASH_ERROR_TIMEOUT_READY;
436
437 // Make sure the chip is write enabled
438 spiflashWriteEnable (TRUE);
439
440 // Make sure the write enable latch is actually set
441 uint8_t status;
442 status = w25q16bvGetStatus();
443 if (!(status & W25Q16BV_STAT1_WRTEN))
444 {
445 // Throw a write protection error (write enable latch not set)
446 return SPIFLASH_ERROR_PROTECTIONERR;
447 }
448
449 // Send the erase chip command
450 W25Q16BV_SELECT();
451 w25q16bv_TransferByte(W25Q16BV_CMD_CHIPERASE);
452 W25Q16BV_DESELECT();
453
454 // Wait until the busy bit is cleared before exiting
455 // This can take up to 10 seconds according to the datasheet!
456 while (w25q16bvGetStatus() & W25Q16BV_STAT1_BUSY);
457
458 return SPIFLASH_ERROR_OK;
459 }
460
461 ///**************************************************************************/
462 ///*!
463 // @brief Writes the supplied bytes at a specified address.
464 //
465 // This function will write one or more bytes starting at the supplied
466 // address.
467 //
468 // @param[in] address
469 // The 16-bit address where the write will start. The
470 // maximum value for the address depends on the size of the
471 // EEPROM
472 // @param[in] *buffer
473 // Pointer to the buffer that contains the values to write.
474 // @param[in] bufferLength
475 // Length of the buffer
476 //*/
477 ///**************************************************************************/
478 //at25Error_e at25Write (uint16_t address, uint8_t *buffer, uint32_t bufferLength)
479 //{
480 // if (address >= AT25_MAXADDRESS)
481 // {
482 // return AT25_ERROR_ADDRERR;
483 // }
484 //
485 // if (bufferLength > 6)
486 // {
487 // return AT25_ERROR_BUFFEROVERFLOW;
488 // }
489 //
490 // // Set write enable latch
491 // at25WriteEnable();
492 //
493 // timeout = 0;
494 // while ( timeout < SSP_MAX_TIMEOUT )
495 // {
496 // // Wait until the device is write enabled
497 // if (at25GetRSR() == AT25_RDSR_WEN)
498 // {
499 // break;
500 // }
501 // timeout++;
502 // }
503 // if ( timeout == SSP_MAX_TIMEOUT )
504 // {
505 // return AT25_ERROR_TIMEOUT_WE;
506 // }
507 //
508 // for (i = 0; i < bufferLength; i++) // Init RD and WR buffer
509 // {
510 // src_addr[i+2] = buffer[i]; // leave two bytes for cmd and offset(8 bits)
511 // dest_addr[i] = 0;
512 // }
513 //
514 // W25Q16BV_SELECT();
515 // // Write command (0x02), append A8 if addr > 256 bytes
516 // src_addr[0] = address > 0xFF ? AT25_WRITE | AT25_A8 : AT25_WRITE;
517 // src_addr[1] = (address);
518 // sspSend(0, (uint8_t *)src_addr, bufferLength + 2);
519 // W25Q16BV_DESELECT();
520 //
521 // // Wait at least 3ms
522 // for (i = 0; i < ((CFG_CPU_CCLK / 1000) * 3); i++);
523 //
524 // timeout = 0;
525 // while ( timeout < SSP_MAX_TIMEOUT )
526 // {
527 // // Check status to see if write cycle is done or not
528 // W25Q16BV_SELECT();
529 // src_addr[0] = AT25_RDSR;
530 // sspSend(0, (uint8_t *)src_addr, 1);
531 // sspReceive(0, (uint8_t *)dest_addr, 1);
532 // W25Q16BV_DESELECT();
533 // // Wait until device is ready
534 // if ((dest_addr[0] & AT25_RDSR_RDY) == 0x00)
535 // {
536 // break;
537 // }
538 // timeout++;
539 // }
540 // if ( timeout == SSP_MAX_TIMEOUT )
541 // {
542 // return AT25_ERROR_TIMEOUT_WFINISH;
543 // }
544 //
545 // for (i = 0; i < 300; i++); // Wait at least 250ns
546 //
547 // return AT25_ERROR_OK;
548 //}
This page took 0.090061 seconds and 5 git commands to generate.