1 /* ----------------------------------------------------------------------------
\r
2 * SAM Software Package License
\r
3 * ----------------------------------------------------------------------------
\r
4 * Copyright (c) 2013, Atmel Corporation
\r
6 * All rights reserved.
\r
8 * Redistribution and use in source and binary forms, with or without
\r
9 * modification, are permitted provided that the following conditions are met:
\r
11 * - Redistributions of source code must retain the above copyright notice,
\r
12 * this list of conditions and the disclaimer below.
\r
14 * Atmel's name may not be used to endorse or promote products derived from
\r
15 * this software without specific prior written permission.
\r
17 * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
\r
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
\r
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
\r
20 * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
\r
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
\r
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
\r
23 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
\r
24 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
\r
25 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
\r
26 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\r
27 * ----------------------------------------------------------------------------
\r
31 * \addtogroup at25d_module S25FL1 driver
\r
32 * \ingroup lib_spiflash
\r
33 * The S25FL1 serial dataflash driver is based on the corresponding S25FL1 SPI driver.
\r
34 * A S25FL1 instance has to be initialized using the Dataflash levle function
\r
35 * S25FL1D_Configure(). S25FL1 Dataflash can be automatically detected using
\r
36 * the S25FL1D_FindDevice() function. Then S25FL1 dataflash operations such as
\r
37 * read, write and erase DF can be launched using S25FL1D_SendCommand function
\r
38 * with corresponding S25FL1 command set.
\r
42 * <li> Reads a serial flash device ID using S25FL1D_ReadJedecId().</li>
\r
43 * <li> Reads data from the S25fl1 at the specified address using S25FL1D_Read().</li>
\r
44 * <li> Writes data on the S25fl1 at the specified address using S25FL1D_Write().</li>
\r
45 * <li> Erases all chip using S25FL1D_EraseBlock().</li>
\r
46 * <li> Erases a specified block using S25FL1D_EraseBlock().</li>
\r
47 * <li> Poll until the S25fl1 has completed of corresponding operations using
\r
48 * S25FL1D_IsBusy().</li>
\r
49 * <li> Retrieves and returns the S25fl1 current using S25FL1D_ReadStatus().</li>
\r
62 * Implementation for the S25FL1 Serialflash driver.
\r
66 /*----------------------------------------------------------------------------
\r
68 *----------------------------------------------------------------------------*/
\r
71 //#include <libspiflash.h>
\r
77 static qspiFrame *pDev, *pMem;
\r
79 #define WRITE_DEV 1
\r
80 /*----------------------------------------------------------------------------
\r
82 *----------------------------------------------------------------------------*/
\r
86 static void S25FL1D_DefaultParams(void)
\r
88 pDev->spiMode = QSPI_IFR_WIDTH_SINGLE_BIT_SPI;
\r
89 pDev->ContinuousRead = 0;
\r
91 pDev->DummyCycles = 0;
\r
93 pDev->InstAddrFlag = 0;
\r
99 static uint8_t S25FL1D_SendCommand(uint8_t Instr, AccesType ReadWrite)
\r
102 pDev->Instruction = Instr;
\r
103 QSPI_SendFrame(QSPI, pDev, ReadWrite);
\r
110 * \brief Reads and returns the status register of the serial flash.
\r
112 * \param pS25fl1 Pointer to an S25FL1 driver instance.
\r
114 static uint8_t S25FL1D_ReadStatus(void)
\r
118 pDev->DataSize = 1;
\r
119 S25FL1D_SendCommand(0x05, READ_DEV);
\r
120 status = *(pDev->pData);
\r
125 * \brief Reads and returns the status register of the serial flash.
\r
127 * \param pS25fl1 Pointer to an S25FL1 driver instance.
\r
129 static uint8_t S25FL1D_ReadStatus2(void)
\r
133 pDev->DataSize = 1;
\r
134 S25FL1D_SendCommand(0x35, READ_DEV);
\r
135 status = *(pDev->pData);
\r
140 * \brief Reads and returns the status register of the serial flash.
\r
142 * \param pS25fl1 Pointer to an S25FL1 driver instance.
\r
144 static uint8_t S25FL1D_ReadStatus3(void)
\r
148 pDev->DataSize = 1;
\r
149 S25FL1D_SendCommand(0x33, READ_DEV);
\r
150 status = *(pDev->pData);
\r
154 * \brief Wait for transfer to finish calling the SPI driver ISR. (interrupts are disabled)
\r
156 * \param pS25fl1 Pointer to an S25FL1 driver instance.
\r
158 static void S25FL1D_IsBusy(void)
\r
160 while(S25FL1D_ReadStatus() & STATUS_RDYBSY);
\r
167 static void S25FL1D_EnableWrite(void)
\r
171 status = S25FL1D_ReadStatus();
\r
174 while(status != STATUS_WEL)
\r
176 pDev->DataSize = 0;
\r
177 S25FL1D_SendCommand(WRITE_ENABLE, READ_DEV);
\r
178 status = S25FL1D_ReadStatus();
\r
183 static void S25FL1D_DisableWrite(void)
\r
187 status = S25FL1D_ReadStatus();
\r
189 while( (status & STATUS_WEL) != 0)
\r
191 pDev->DataSize = 0;
\r
192 S25FL1D_SendCommand(WRITE_DISABLE, READ_DEV);
\r
193 status = S25FL1D_ReadStatus();
\r
197 * \brief Writes the given value in the status register of the serial flash device.
\r
199 * \param pS25fl1 Pointer to an S25FL1 driver instance.
\r
200 * \param status Status to write.
\r
202 static void S25FL1D_WriteStatus( uint8_t *pStatus)
\r
204 S25FL1D_EnableWrite();
\r
206 pDev->DataSize = 3;
\r
207 pDev->Instruction = WRITE_STATUS;
\r
208 pDev->pData = pStatus;
\r
209 QSPI_SendFrame(QSPI, pDev, Device_Write);
\r
210 S25FL1D_DisableWrite();
\r
214 * \brief Writes the given value in the status register of the serial flash device.
\r
216 * \param pS25fl1 Pointer to an S25FL1 driver instance.
\r
217 * \param status Status to write.
\r
219 static void S25FL1D_WriteVolatileStatus( uint8_t *pStatus)
\r
223 pDev->DataSize = 0;
\r
224 S25FL1D_SendCommand(0x50, READ_DEV);
\r
226 pDev->DataSize = 3;
\r
227 pDev->Instruction = WRITE_STATUS;
\r
228 pDev->pData = pStatus;
\r
229 QSPI_SendFrame(QSPI, pDev, Device_Write);
\r
230 S25FL1D_DisableWrite();
\r
232 /*----------------------------------------------------------------------------
\r
234 *----------------------------------------------------------------------------*/
\r
237 void S25FL1D_InitFlashInterface(void)
\r
239 pDev = (qspiFrame *)malloc (sizeof(qspiFrame));
\r
240 memset(pDev, 0, sizeof(qspiFrame));
\r
241 pDev->spiMode = QSPI_IFR_WIDTH_SINGLE_BIT_SPI;
\r
242 pDev->pData = (uint8_t *)malloc (sizeof(uint32_t));
\r
245 pMem = (qspiFrame *)malloc (sizeof(qspiFrame));
\r
246 memset(pMem, 0, sizeof(qspiFrame));
\r
247 pMem->spiMode = QSPI_IFR_WIDTH_SINGLE_BIT_SPI;
\r
248 pMem->pData = (uint8_t *)malloc (sizeof(uint8_t));
\r
252 * \brief Reads and returns the serial flash device ID.
\r
254 * \param pS25fl1 Pointer to an S25FL1 driver instance.
\r
256 unsigned int S25FL1D_ReadJedecId(void)
\r
258 unsigned int id = 0;
\r
260 pDev->DataSize = 3;
\r
261 S25FL1D_SendCommand(READ_JEDEC_ID, READ_DEV);
\r
263 id = ( (pDev->pData[0] << 16) || (pDev->pData[1] << 8) || (pDev->pData[2]));
\r
269 * \brief Enables critical writes operation on a serial flash device, such as sector
\r
270 * protection, status register, etc.
\r
272 * \para pS25fl1 Pointer to an S25FL1 driver instance.
\r
274 void S25FL1D_EnableQuadMode(void)
\r
279 status[0] = S25FL1D_ReadStatus();
\r
280 status[1] = S25FL1D_ReadStatus2();
\r
281 status[2] = S25FL1D_ReadStatus3();
\r
283 while(!(status[1] & STATUS_QUAD_ENABLE))
\r
285 status[1] |= STATUS_QUAD_ENABLE;
\r
286 S25FL1D_WriteStatus(status);
\r
287 status[1] = S25FL1D_ReadStatus2();
\r
294 * \brief Enables critical writes operation on a serial flash device, such as sector
\r
295 * protection, status register, etc.
\r
297 * \para pS25fl1 Pointer to an S25FL1 driver instance.
\r
299 void S25FL1D_EnableWrap(uint8_t ByetAlign)
\r
304 status[0] = S25FL1D_ReadStatus();
\r
305 status[1] = S25FL1D_ReadStatus2();
\r
306 status[2] = S25FL1D_ReadStatus3();
\r
308 status[2] = (ByetAlign << 5);
\r
310 pDev->DataSize = 1;
\r
311 *(pDev->pData) = status[2];
\r
312 pDev->DummyCycles = 24;
\r
313 S25FL1D_SendCommand(WRAP_ENABLE, WRITE_DEV);
\r
314 pDev->DummyCycles = 0;
\r
316 S25FL1D_WriteVolatileStatus(status);
\r
317 status[2] = S25FL1D_ReadStatus3();
\r
321 void S25FL1D_SoftReset(void)
\r
324 pDev->DataSize = 0;
\r
325 S25FL1D_SendCommand(SOFT_RESET_ENABLE, READ_DEV);
\r
326 S25FL1D_SendCommand(SOFT_RESET, READ_DEV);
\r
331 * \brief Unprotects the contents of the serial flash device.
\r
333 * \param pS25fl1 Pointer to an S25FL1 driver instance.
\r
335 * \return 0 if the device has been unprotected; otherwise returns
\r
336 * S25FL1D_ERROR_PROTECTED.
\r
338 unsigned char S25FL1D_Unprotect(void)
\r
340 unsigned char status[3];
\r
344 /* Get the status register value to check the current protection */
\r
345 status[0]= S25FL1D_ReadStatus();
\r
346 status[1]= S25FL1D_ReadStatus2();
\r
347 status[2]= S25FL1D_ReadStatus3();
\r
348 if ((status[0] & STATUS_SWP) == STATUS_SWP_PROTNONE) {
\r
350 /* Protection already disabled */
\r
354 status[0] &= (!STATUS_SWP);
\r
355 /* Check if sector protection registers are locked */
\r
356 if ((status[0] & STATUS_SPRL) == STATUS_SPRL_LOCKED) {
\r
357 status[0] &= (!STATUS_SPRL);
\r
358 /* Unprotect sector protection registers by writing the status reg. */
\r
359 S25FL1D_WriteStatus(status);
\r
362 S25FL1D_WriteStatus(status);
\r
364 /* Check the new status */
\r
365 status[0] = S25FL1D_ReadStatus();
\r
366 if ((status[0] & (STATUS_SPRL | STATUS_SWP)) != 0) {
\r
368 return ERROR_PROTECTED;
\r
378 * \brief Unprotects the contents of the serial flash device.
\r
380 * \param pS25fl1 Pointer to an S25FL1 driver instance.
\r
382 * \return 0 if the device has been unprotected; otherwise returns
\r
383 * S25FL1D_ERROR_PROTECTED.
\r
385 unsigned char S25FL1D_Protect(uint32_t StartAddr, uint32_t Size)
\r
387 unsigned char status[3];
\r
391 /* Get the status register value to check the current protection */
\r
392 status[0]= S25FL1D_ReadStatus();
\r
393 status[1]= S25FL1D_ReadStatus2();
\r
394 status[2]= S25FL1D_ReadStatus3();
\r
396 status[0] &= (!STATUS_SWP);
\r
397 /* Check if sector protection registers are locked */
\r
398 if ((status[0] & STATUS_SPRL) == STATUS_SPRL_LOCKED) {
\r
399 status[0] &= (!STATUS_SPRL);
\r
400 /* Unprotect sector protection registers by writing the status reg. */
\r
401 S25FL1D_WriteStatus(status);
\r
404 S25FL1D_WriteStatus(status);
\r
406 /* Check the new status */
\r
407 status[0] = S25FL1D_ReadStatus();
\r
408 if ((status[0] & (STATUS_SPRL | STATUS_SWP)) != 0) {
\r
410 return ERROR_PROTECTED;
\r
420 * \brief Erases all the content of the memory chip.
\r
422 * \param pS25fl1 Pointer to an S25FL1 driver instance.
\r
424 * \return 0 if the device has been unprotected; otherwise returns
\r
427 unsigned char S25FL1D_EraseChip(void)
\r
429 char wait_ch[4] = {'\\','|','/','-' };
\r
432 S25FL1D_EnableWrite();
\r
434 S25FL1D_SendCommand(CHIP_ERASE_2, READ_DEV);
\r
435 S25FL1D_ReadStatus();
\r
437 while(*(pDev->pData) & STATUS_RDYBSY)
\r
439 S25FL1D_ReadStatus();
\r
441 printf("Erasing flash memory %c\r", wait_ch[i]);
\r
446 printf("\rErasing flash memory done..... 100%\n\r");
\r
451 *\brief Erases the specified block of the serial firmware dataflash.
\r
453 * \param pS25fl1 Pointer to an S25FL1 driver instance.
\r
454 * \param address Address of the block to erase.
\r
456 * \return 0 if successful; otherwise returns ERROR_PROTECTED if the
\r
457 * device is protected or ERROR_BUSY if it is busy executing a command.
\r
459 unsigned char S25FL1D_EraseSector(unsigned int address)
\r
462 uint32_t EraseAddr;
\r
464 EraseAddr = address;
\r
466 /* Check that the flash is ready and unprotected */
\r
467 status = S25FL1D_ReadStatus();
\r
468 if ((status & STATUS_RDYBSY) != STATUS_RDYBSY_READY) {
\r
469 TRACE_ERROR("EraseBlock : Flash busy\n\r");
\r
472 else if ((status & STATUS_SWP) != STATUS_SWP_PROTNONE) {
\r
473 TRACE_ERROR("S25FL1D_EraseBlock : Flash protected\n\r");
\r
474 return ERROR_PROTECTED;
\r
478 /* Enable critical write operation */
\r
479 S25FL1D_EnableWrite();
\r
481 pDev->InstAddrFlag = 1;
\r
482 pDev->InstAddr = address;
\r
483 /* Start the block erase command */
\r
484 S25FL1D_SendCommand(BLOCK_ERASE_4K, WRITE_DEV);
\r
485 S25FL1D_DefaultParams();
\r
487 /* Wait for transfer to finish */
\r
495 *\brief Erases the specified 64KB block of the serial firmware dataflash.
\r
497 * \param pS25fl1 Pointer to an S25FL1 driver instance.
\r
498 * \param address Address of the block to erase.
\r
500 * \return 0 if successful; otherwise returns ERROR_PROTECTED if the
\r
501 * device is protected or ERROR_BUSY if it is busy executing a command.
\r
503 unsigned char S25FL1D_Erase64KBlock( unsigned int address)
\r
505 unsigned char status;
\r
507 /* Check that the flash is ready and unprotected */
\r
508 status = S25FL1D_ReadStatus();
\r
509 if ((status & STATUS_RDYBSY) != STATUS_RDYBSY_READY) {
\r
510 TRACE_ERROR("S25FL1D_EraseBlock : Flash busy\n\r");
\r
513 else if ((status & STATUS_SWP) != STATUS_SWP_PROTNONE) {
\r
514 TRACE_ERROR("EraseBlock : Flash protected\n\r");
\r
515 return ERROR_PROTECTED;
\r
518 /* Enable critical write operation */
\r
519 S25FL1D_EnableWrite();
\r
521 pDev->DataSize = 0;
\r
522 pDev->InstAddrFlag = 1;
\r
523 pDev->InstAddr = address;
\r
525 /* Start the block erase command */
\r
526 S25FL1D_SendCommand(BLOCK_ERASE_64K, WRITE_DEV);
\r
527 S25FL1D_DefaultParams();
\r
529 /* Wait for transfer to finish */
\r
537 * \brief Writes data at the specified address on the serial firmware dataflash. The
\r
538 * page(s) to program must have been erased prior to writing. This function
\r
539 * handles page boundary crossing automatically.
\r
541 * \param pS25fl1 Pointer to an S25FL1 driver instance.
\r
542 * \param pData Data buffer.
\r
543 * \param size Number of bytes in buffer.
\r
544 * \param address Write address.
\r
546 * \return 0 if successful; otherwise, returns ERROR_PROGRAM is there has
\r
547 * been an error during the data programming.
\r
549 unsigned char S25FL1D_Write(
\r
554 unsigned int pageSize = 256;
\r
555 unsigned int writeSize;
\r
556 unsigned int i = 0;
\r
559 writeSize = size >> 8;
\r
560 S25FL1D_EnableWrite();
\r
561 pMem->Instruction = 0x02;
\r
562 pMem->InstAddrFlag=1; pMem->InstAddr=address;
\r
563 if(writeSize ==0) // if less than page size
\r
565 pMem->pData = (pData);
\r
566 pMem->DataSize = size;
\r
567 QSPI_SendFrameToMem(QSPI, pMem, Device_Write);
\r
569 else // mulptiple pagesize
\r
571 pMem->DataSize = pageSize;
\r
572 for(i=0; i< writeSize; i++)
\r
574 S25FL1D_EnableWrite();
\r
575 pMem->pData = pData;
\r
576 QSPI_SendFrameToMem(QSPI, pMem, Device_Write);
\r
579 pMem->InstAddr += pageSize;
\r
582 if((writeSize * pageSize) < size)
\r
584 S25FL1D_EnableWrite();
\r
585 pMem->DataSize = (size - (writeSize * pageSize)) ;
\r
586 pMem->pData = pData;
\r
587 QSPI_SendFrameToMem(QSPI, pMem, Device_Write);
\r
592 S25FL1D_DisableWrite();
\r
599 * \brief Reads data from the specified address on the serial flash.
\r
601 * \param pS25fl1 Pointer to an S25FL1 driver instance.
\r
602 * \param pData Data buffer.
\r
603 * \param size Number of bytes to read.
\r
604 * \param address Read address.
\r
606 * \return 0 if successful; otherwise, fail.
\r
608 unsigned char S25FL1D_Read(
\r
613 pMem->Instruction = READ_ARRAY_LF;
\r
614 pMem->InstAddrFlag=1; pMem->InstAddr=address;
\r
615 pMem->pData = pData;
\r
616 pMem->DataSize = size;
\r
617 pMem->DummyCycles = 0;
\r
618 pMem->spiMode = QSPI_IFR_WIDTH_SINGLE_BIT_SPI;
\r
619 QSPI_SendFrameToMem(QSPI, pMem, Device_Read);
\r
626 * \brief Reads data from the specified address on the serial flash.
\r
628 * \param pS25fl1 Pointer to an S25FL1 driver instance.
\r
629 * \param pData Data buffer.
\r
630 * \param size Number of bytes to read.
\r
631 * \param address Read address.
\r
633 * \return 0 if successful; otherwise, fail.
\r
635 unsigned char S25FL1D_ReadDual(
\r
640 pMem->Instruction = READ_ARRAY_DUAL;
\r
641 pMem->InstAddrFlag=1; pMem->InstAddr=address;
\r
642 pMem->pData = pData;
\r
643 pMem->DataSize = size;
\r
644 pMem->DummyCycles = 8;
\r
645 pMem->spiMode = QSPI_IFR_WIDTH_DUAL_OUTPUT;
\r
646 QSPI_SendFrameToMem(QSPI, pMem, Device_Read);
\r
654 * \brief Reads data from the specified address on the serial flash.
\r
656 * \param pS25fl1 Pointer to an S25FL1 driver instance.
\r
657 * \param pData Data buffer.
\r
658 * \param size Number of bytes to read.
\r
659 * \param address Read address.
\r
661 * \return 0 if successful; otherwise, fail.
\r
663 unsigned char S25FL1D_ReadQuad(
\r
669 pMem->Instruction = READ_ARRAY_QUAD;
\r
670 pMem->InstAddrFlag=1; pMem->InstAddr=address;
\r
671 pMem->pData = pData;
\r
672 pMem->DataSize = size;
\r
673 pMem->DummyCycles = 8;
\r
674 pMem->spiMode = QSPI_IFR_WIDTH_QUAD_OUTPUT;
\r
675 QSPI_SendFrameToMem(QSPI, pMem, Device_Read);
\r
682 * \brief Reads data from the specified address on the serial flash.
\r
684 * \param pS25fl1 Pointer to an S25FL1 driver instance.
\r
685 * \param pData Data buffer.
\r
686 * \param size Number of bytes to read.
\r
687 * \param address Read address.
\r
689 * \return 0 if successful; otherwise, fail.
\r
691 unsigned char S25FL1D_ReadQuadIO(
\r
698 pMem->Instruction = READ_ARRAY_QUAD_IO;
\r
699 pMem->InstAddrFlag=1;
\r
700 pMem->InstAddr=address;
\r
701 pMem->pData = pData;
\r
702 pMem->DataSize = size;
\r
703 pMem->DummyCycles = 6;
\r
706 pMem->OptionLen = QSPI_IFR_OPTL_OPTION_4BIT;
\r
707 pMem->Option = 0x2;
\r
708 pMem->ContinuousRead = ContMode;
\r
709 pMem->DummyCycles = 5;
\r
710 pMem->OptionEn = ContMode;
\r
713 pMem->spiMode = QSPI_IFR_WIDTH_QUAD_IO;
\r
714 QSPI_SendFrameToMem(QSPI, pMem, Device_Read);
\r
715 pMem->OptionEn = 0;
\r
716 pMem->ContinuousRead = 0;
\r