1 /* ----------------------------------------------------------------------------
\r
2 * ATMEL Microcontroller Software Support
\r
3 * ----------------------------------------------------------------------------
\r
4 * Copyright (c) 2010, 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 external_component External Component
\r
33 * \addtogroup at25d_module AT25 driver
\r
34 * \ingroup external_component
\r
35 * The AT25 serial dataflash driver is based on the corresponding AT25 SPI driver.
\r
36 * A AT25 instance has to be initialized using the Dataflash levle function
\r
37 * AT25_Configure(). AT25 Dataflash can be automatically detected using
\r
38 * the AT25_FindDevice() function. Then AT25 dataflash operations such as
\r
39 * read, write and erase DF can be launched using AT25_SendCommand function
\r
40 * with corresponding AT25 command set.
\r
44 * <li> Reads a serial flash device ID using AT25D_ReadJedecId().</li>
\r
45 * <li> Reads data from the At25 at the specified address using AT25D_Read().</li>
\r
46 * <li> Writes data on the At25 at the specified address using AT25D_Write().</li>
\r
47 * <li> Erases all chip using AT25D_EraseBlock().</li>
\r
48 * <li> Erases a specified block using AT25D_EraseBlock().</li>
\r
49 * <li> Poll until the At25 has completed of corresponding operations using
\r
50 * AT25D_WaitReady().</li>
\r
51 * <li> Retrieves and returns the At25 current using AT25D_ReadStatus().</li>
\r
64 * Implementation for the AT25 Serialflash driver.
\r
68 /*----------------------------------------------------------------------------
\r
70 *----------------------------------------------------------------------------*/
\r
76 /*----------------------------------------------------------------------------
\r
78 *----------------------------------------------------------------------------*/
\r
81 * \brief Wait for transfer to finish calling the SPI driver ISR. (interrupts are disabled)
\r
83 * \param pAt25 Pointer to an AT25 driver instance.
\r
85 static void AT25D_Wait(At25 *pAt25)
\r
87 /* Wait for transfer to finish */
\r
88 while (AT25_IsBusy(pAt25))
\r
89 SPID_Handler(pAt25->pSpid);
\r
93 * \brief Reads and returns the status register of the serial flash.
\r
95 * \param pAt25 Pointer to an AT25 driver instance.
\r
97 static unsigned char AT25D_ReadStatus(At25 *pAt25)
\r
99 unsigned char error, status;
\r
103 /* Issue a status read command */
\r
104 error = AT25_SendCommand(pAt25, AT25_READ_STATUS, 1, &status, 1, 0, 0, 0);
\r
107 /* Wait for transfer to finish */
\r
114 * \brief Writes the given value in the status register of the serial flash device.
\r
116 * \param pAt25 Pointer to an AT25 driver instance.
\r
117 * \param status Status to write.
\r
119 static void AT25D_WriteStatus(At25 *pAt25, unsigned char status)
\r
121 unsigned char error;
\r
125 /* Issue a write status command */
\r
126 error = AT25_SendCommand(pAt25, AT25_WRITE_STATUS, 1, &status, 1, 0, 0, 0);
\r
129 /* Wait for transfer to finish */
\r
133 /*----------------------------------------------------------------------------
\r
135 *----------------------------------------------------------------------------*/
\r
138 * \brief Waits for the serial flash device to become ready to accept new commands.
\r
140 * \param pAt25 Pointer to an AT25 driver instance.
\r
142 void AT25D_WaitReady(At25 *pAt25)
\r
144 unsigned char ready = 0;
\r
148 /* Read status register and check busy bit */
\r
151 ready = ((AT25D_ReadStatus(pAt25) & AT25_STATUS_RDYBSY) == AT25_STATUS_RDYBSY_READY);
\r
156 * \brief Reads and returns the serial flash device ID.
\r
158 * \param pAt25 Pointer to an AT25 driver instance.
\r
160 unsigned int AT25D_ReadJedecId(At25 *pAt25)
\r
162 unsigned char error;
\r
163 unsigned int id = 0;
\r
167 /* Issue a read ID command */
\r
168 error = AT25_SendCommand(pAt25, AT25_READ_JEDEC_ID, 1,
\r
169 (unsigned char *) &id, 3, 0, 0, 0);
\r
172 /* Wait for transfer to finish */
\r
179 * \brief Enables critical writes operation on a serial flash device, such as sector
\r
180 * protection, status register, etc.
\r
182 * \para pAt25 Pointer to an AT25 driver instance.
\r
184 void AT25D_EnableWrite(At25 *pAt25)
\r
186 unsigned char error;
\r
190 /* Issue a write enable command */
\r
191 error = AT25_SendCommand(pAt25, AT25_WRITE_ENABLE, 1, 0, 0, 0, 0, 0);
\r
194 /* Wait for transfer to finish */
\r
199 * \brief Disables write operation on a serial flash device.
\r
201 * \para pAt25 Pointer to an AT25 driver instance.
\r
203 void AT25D_DisableWrite(At25 *pAt25)
\r
205 unsigned char error;
\r
209 /* Issue a write enable command */
\r
210 error = AT25_SendCommand(pAt25, AT25_WRITE_DISABLE, 1, 0, 0, 0, 0, 0);
\r
213 /* Wait for transfer to finish */
\r
218 * \brief Unprotects the contents of the serial flash device.
\r
220 * \param pAt25 Pointer to an AT25 driver instance.
\r
222 * \return 0 if the device has been unprotected; otherwise returns
\r
223 * AT25_ERROR_PROTECTED.
\r
225 unsigned char AT25D_Unprotect(At25 *pAt25)
\r
227 unsigned char status;
\r
231 /* Get the status register value to check the current protection */
\r
232 status = AT25D_ReadStatus(pAt25);
\r
233 if ((status & AT25_STATUS_SWP) == AT25_STATUS_SWP_PROTNONE) {
\r
235 /* Protection already disabled */
\r
239 /* Check if sector protection registers are locked */
\r
240 if ((status & AT25_STATUS_SPRL) == AT25_STATUS_SPRL_LOCKED) {
\r
242 /* Unprotect sector protection registers by writing the status reg. */
\r
243 AT25D_EnableWrite(pAt25);
\r
244 AT25D_WriteStatus(pAt25, 0);
\r
247 /* Perform a global unprotect command */
\r
248 AT25D_EnableWrite(pAt25);
\r
250 AT25D_WriteStatus(pAt25, 0);
\r
252 /* Check the new status */
\r
253 status = AT25D_ReadStatus(pAt25);
\r
254 if ((status & (AT25_STATUS_SPRL | AT25_STATUS_SWP)) != 0) {
\r
256 return AT25_ERROR_PROTECTED;
\r
265 * \brief Erases all the content of the memory chip.
\r
267 * \param pAt25 Pointer to an AT25 driver instance.
\r
269 * \return 0 if the device has been unprotected; otherwise returns
\r
270 * AT25_ERROR_PROTECTED.
\r
272 unsigned char AT25D_EraseChip(At25 *pAt25)
\r
274 unsigned char status;
\r
275 unsigned char error;
\r
279 /* Check that the flash is unprotected */
\r
280 status = AT25D_ReadStatus(pAt25);
\r
281 if ((status & AT25_STATUS_SWP) != AT25_STATUS_SWP_PROTNONE) {
\r
282 return AT25_ERROR_PROTECTED;
\r
285 /* Enable critical write operation */
\r
286 AT25D_EnableWrite(pAt25);
\r
288 /* Erase the chip */
\r
289 error = AT25_SendCommand(pAt25, AT25_CHIP_ERASE_2, 1, 0, 0, 0, 0, 0);
\r
292 /* Wait for transfer to finish */
\r
294 /* Poll the Serial flash status register until the operation is achieved */
\r
295 AT25D_WaitReady(pAt25);
\r
301 *\brief Erases the specified block of the serial firmware dataflash.
\r
303 * \param pAt25 Pointer to an AT25 driver instance.
\r
304 * \param address Address of the block to erase.
\r
306 * \return 0 if successful; otherwise returns AT25_ERROR_PROTECTED if the
\r
307 * device is protected or AT25_ERROR_BUSY if it is busy executing a command.
\r
309 unsigned char AT25D_EraseBlock(At25 *pAt25, unsigned int address)
\r
311 unsigned char status;
\r
312 unsigned char error;
\r
316 /* Check that the flash is ready and unprotected */
\r
317 status = AT25D_ReadStatus(pAt25);
\r
318 if ((status & AT25_STATUS_RDYBSY) != AT25_STATUS_RDYBSY_READY) {
\r
319 TRACE_ERROR("AT25D_EraseBlock : Flash busy\n\r");
\r
320 return AT25_ERROR_BUSY;
\r
322 else if ((status & AT25_STATUS_SWP) != AT25_STATUS_SWP_PROTNONE) {
\r
323 TRACE_ERROR("AT25D_EraseBlock : Flash protected\n\r");
\r
324 return AT25_ERROR_PROTECTED;
\r
327 /* Enable critical write operation */
\r
328 AT25D_EnableWrite(pAt25);
\r
330 /* Start the block erase command */
\r
331 error = AT25_SendCommand(pAt25, AT25_BlockEraseCmd(pAt25), 4, 0, 0, address, 0, 0);
\r
334 /* Wait for transfer to finish */
\r
336 /* Poll the Serial flash status register until the operation is achieved */
\r
337 AT25D_WaitReady(pAt25);
\r
344 *\brief Erases the specified 64KB block of the serial firmware dataflash.
\r
346 * \param pAt25 Pointer to an AT25 driver instance.
\r
347 * \param address Address of the block to erase.
\r
349 * \return 0 if successful; otherwise returns AT25_ERROR_PROTECTED if the
\r
350 * device is protected or AT25_ERROR_BUSY if it is busy executing a command.
\r
352 unsigned char AT25D_Erase64KBlock(At25 *pAt25, unsigned int address)
\r
354 unsigned char status;
\r
355 unsigned char error;
\r
359 /* Check that the flash is ready and unprotected */
\r
360 status = AT25D_ReadStatus(pAt25);
\r
361 if ((status & AT25_STATUS_RDYBSY) != AT25_STATUS_RDYBSY_READY) {
\r
362 TRACE_ERROR("AT25D_EraseBlock : Flash busy\n\r");
\r
363 return AT25_ERROR_BUSY;
\r
365 else if ((status & AT25_STATUS_SWP) != AT25_STATUS_SWP_PROTNONE) {
\r
366 TRACE_ERROR("AT25D_EraseBlock : Flash protected\n\r");
\r
367 return AT25_ERROR_PROTECTED;
\r
370 /* Enable critical write operation */
\r
371 AT25D_EnableWrite(pAt25);
\r
373 /* Start the block erase command */
\r
374 error = AT25_SendCommand(pAt25, AT25_BLOCK_ERASE_64K, 4, 0, 0, address, 0, 0);
\r
377 /* Wait for transfer to finish */
\r
379 /* Poll the Serial flash status register until the operation is achieved */
\r
380 AT25D_WaitReady(pAt25);
\r
387 * \brief Writes data at the specified address on the serial firmware dataflash. The
\r
388 * page(s) to program must have been erased prior to writing. This function
\r
389 * handles page boundary crossing automatically.
\r
391 * \param pAt25 Pointer to an AT25 driver instance.
\r
392 * \param pData Data buffer.
\r
393 * \param size Number of bytes in buffer.
\r
394 * \param address Write address.
\r
396 * \return 0 if successful; otherwise, returns AT25_ERROR_PROGRAM is there has
\r
397 * been an error during the data programming.
\r
399 unsigned char AT25D_Write(
\r
401 unsigned char *pData,
\r
403 unsigned int address)
\r
405 unsigned int pageSize;
\r
406 unsigned int writeSize;
\r
407 unsigned char error;
\r
408 unsigned char status;
\r
409 unsigned int i = 0;
\r
414 /* Retrieve device page size */
\r
415 pageSize = AT25_PageSize(pAt25);
\r
417 /* Program one page after the other */
\r
419 /* Compute number of bytes to program in page */
\r
420 writeSize = min(size, pageSize - (address % pageSize));
\r
422 /* Enable critical write operation */
\r
423 AT25D_EnableWrite(pAt25);
\r
426 if (AT25_ManId(pAt25) == SST_SPI_FLASH) {
\r
428 error = AT25_SendCommand(pAt25, AT25_SEQUENTIAL_PROGRAM_1, 4,
\r
429 pData, 2, address, 0, 0);
\r
433 /* Wait for transfer to finish */
\r
435 /* Poll the Serial flash status register until the operation is achieved */
\r
436 AT25D_WaitReady(pAt25);
\r
438 for (i = 2; i < pageSize; i += 2) {
\r
439 error = AT25_SendCommand(pAt25, AT25_SEQUENTIAL_PROGRAM_1, 1,
\r
440 pData + i, 2, 0, 0, 0);
\r
444 /* Wait for transfer to finish */
\r
446 /* Poll the Serial flash status register until the operation is achieved */
\r
447 AT25D_WaitReady(pAt25);
\r
452 error = AT25_SendCommand(pAt25, AT25_BYTE_PAGE_PROGRAM, 4,
\r
453 pData, writeSize, address, 0, 0);
\r
457 /* Wait for transfer to finish */
\r
459 /* Poll the Serial flash status register until the operation is achieved */
\r
460 AT25D_WaitReady(pAt25);
\r
464 /* Make sure that write was without error */
\r
465 status = AT25D_ReadStatus(pAt25);
\r
466 if ((status & AT25_STATUS_EPE) == AT25_STATUS_EPE_ERROR) {
\r
468 return AT25_ERROR_PROGRAM;
\r
471 pData += writeSize;
\r
473 address += writeSize;
\r
476 /* Enable critical write operation */
\r
477 AT25D_DisableWrite(pAt25);
\r
483 * \brief Reads data from the specified address on the serial flash.
\r
485 * \param pAt25 Pointer to an AT25 driver instance.
\r
486 * \param pData Data buffer.
\r
487 * \param size Number of bytes to read.
\r
488 * \param address Read address.
\r
490 * \return 0 if successful; otherwise, fail.
\r
492 unsigned char AT25D_Read(
\r
494 unsigned char *pData,
\r
496 unsigned int address)
\r
498 unsigned char error;
\r
500 /* Start a read operation */
\r
501 error = AT25_SendCommand(pAt25, AT25_READ_ARRAY_LF, 4, pData, size, address, 0, 0);
\r
504 /* Wait for transfer to finish */
\r