/* ---------------------------------------------------------------------------- | |
* ATMEL Microcontroller Software Support | |
* ---------------------------------------------------------------------------- | |
* Copyright (c) 2008, Atmel Corporation | |
* | |
* All rights reserved. | |
* | |
* Redistribution and use in source and binary forms, with or without | |
* modification, are permitted provided that the following conditions are met: | |
* | |
* - Redistributions of source code must retain the above copyright notice, | |
* this list of conditions and the disclaimer below. | |
* | |
* Atmel's name may not be used to endorse or promote products derived from | |
* this software without specific prior written permission. | |
* | |
* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR | |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE | |
* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, | |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, | |
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, | |
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
* ---------------------------------------------------------------------------- | |
*/ | |
//------------------------------------------------------------------------------ | |
// Headers | |
//------------------------------------------------------------------------------ | |
#include "at26.h" | |
#include "board.h" | |
#include <assert.h> | |
//------------------------------------------------------------------------------ | |
// Internal definitions | |
//------------------------------------------------------------------------------ | |
/// SPI clock frequency used in Hz. | |
#define SPCK 1000000 | |
/// SPI chip select configuration value. | |
#define CSR (SPI_CSR_NCPHA | \ | |
SPID_CSR_DLYBCT(BOARD_MCK, 100) | \ | |
SPID_CSR_DLYBS(BOARD_MCK, 5) | \ | |
SPID_CSR_SCBR(BOARD_MCK, SPCK)) | |
/// Number of recognized dataflash. | |
#define NUMDATAFLASH (sizeof(at26Devices) / sizeof(At26Desc)) | |
//------------------------------------------------------------------------------ | |
// Internal variables | |
//------------------------------------------------------------------------------ | |
/// Array of recognized serial firmware dataflash chips. | |
static const At26Desc at26Devices[] = { | |
// name, Jedec ID, size, page size, block size, block erase command | |
{"AT25DF041A" , 0x0001441F, 512 * 1024 , 256, 64 * 1024, AT26_BLOCK_ERASE_64K}, | |
{"AT25DF161" , 0x0002461F, 2 * 1024 * 1024, 256, 64 * 1024, AT26_BLOCK_ERASE_64K}, | |
{"AT26DF081A" , 0x0001451F, 1 * 1024 * 1024, 256, 64 * 1024, AT26_BLOCK_ERASE_64K}, | |
{"AT26DF0161" , 0x0000461F, 2 * 1024 * 1024, 256, 64 * 1024, AT26_BLOCK_ERASE_64K}, | |
{"AT26DF161A" , 0x0001461F, 2 * 1024 * 1024, 256, 64 * 1024, AT26_BLOCK_ERASE_64K}, | |
{"AT26DF321" , 0x0000471F, 4 * 1024 * 1024, 256, 64 * 1024, AT26_BLOCK_ERASE_64K}, | |
{"AT25DF512B" , 0x0001651F, 64 * 1024, 256, 32 * 1024, AT26_BLOCK_ERASE_32K}, | |
{"AT25DF512B" , 0x0000651F, 64 * 1024, 256, 32 * 1024, AT26_BLOCK_ERASE_32K}, | |
{"AT25DF021" , 0x0000431F, 256 * 1024, 256, 64 * 1024, AT26_BLOCK_ERASE_64K}, | |
{"AT26DF641" , 0x0000481F, 8 * 1024 * 1024, 256, 64 * 1024, AT26_BLOCK_ERASE_64K}, | |
// Manufacturer: ST | |
{"M25P05" , 0x00102020, 64 * 1024, 256, 32 * 1024, AT26_BLOCK_ERASE_64K}, | |
{"M25P10" , 0x00112020, 128 * 1024, 256, 32 * 1024, AT26_BLOCK_ERASE_64K}, | |
{"M25P20" , 0x00122020, 256 * 1024, 256, 64 * 1024, AT26_BLOCK_ERASE_64K}, | |
{"M25P40" , 0x00132020, 512 * 1024, 256, 64 * 1024, AT26_BLOCK_ERASE_64K}, | |
{"M25P80" , 0x00142020, 1 * 1024 * 1024, 256, 64 * 1024, AT26_BLOCK_ERASE_64K}, | |
{"M25P16" , 0x00152020, 2 * 1024 * 1024, 256, 64 * 1024, AT26_BLOCK_ERASE_64K}, | |
{"M25P32" , 0x00162020, 4 * 1024 * 1024, 256, 64 * 1024, AT26_BLOCK_ERASE_64K}, | |
{"M25P64" , 0x00172020, 8 * 1024 * 1024, 256, 64 * 1024, AT26_BLOCK_ERASE_64K}, | |
// Manufacturer: Windbond | |
{"W25X10" , 0x001130EF, 128 * 1024, 256, 64 * 1024, AT26_BLOCK_ERASE_64K}, | |
{"W25X20" , 0x001230EF, 256 * 1024, 256, 64 * 1024, AT26_BLOCK_ERASE_64K}, | |
{"W25X40" , 0x001330EF, 512 * 1024, 256, 64 * 1024, AT26_BLOCK_ERASE_64K}, | |
{"W25X80" , 0x001430EF, 1 * 1024 * 1024, 256, 64 * 1024, AT26_BLOCK_ERASE_64K}, | |
// Manufacturer: Macronix | |
{"MX25L512" , 0x001020C2, 64 * 1024, 256, 64 * 1024, AT26_BLOCK_ERASE_64K}, | |
{"MX25L3205" , 0x001620C2, 4 * 1024 * 1024, 256, 64 * 1024, AT26_BLOCK_ERASE_64K}, | |
{"MX25L6405" , 0x001720C2, 8 * 1024 * 1024, 256, 64 * 1024, AT26_BLOCK_ERASE_64K}, | |
// Other | |
{"SST25VF512" , 0x000048BF, 64 * 1024, 256, 32 * 1024, AT26_BLOCK_ERASE_32K} | |
}; | |
//------------------------------------------------------------------------------ | |
// Exported functions | |
//------------------------------------------------------------------------------ | |
//------------------------------------------------------------------------------ | |
/// Initializes an AT26 driver instance with the given SPI driver and chip | |
/// select value. | |
/// \param pAt26 Pointer to an AT26 driver instance. | |
/// \param pSpid Pointer to an SPI driver instance. | |
/// \param cs Chip select value to communicate with the serial flash. | |
//------------------------------------------------------------------------------ | |
void AT26_Configure(At26 *pAt26, Spid *pSpid, unsigned char cs) | |
{ | |
SpidCmd *pCommand; | |
assert(pAt26 != NULL); | |
assert(pSpid != NULL); | |
assert(cs < 4); | |
// Configure the SPI chip select for the serial flash | |
SPID_ConfigureCS(pSpid, cs, CSR); | |
// Initialize the AT26 fields | |
pAt26->pSpid = pSpid; | |
pAt26->pDesc = 0; | |
// Initialize the command structure | |
pCommand = &(pAt26->command); | |
pCommand->pCmd = (unsigned char *) pAt26->pCmdBuffer; | |
pCommand->callback = 0; | |
pCommand->pArgument = 0; | |
pCommand->spiCs = cs; | |
} | |
//------------------------------------------------------------------------------ | |
/// Returns 1 if the serial flash driver is currently busy executing a command; | |
/// otherwise returns 0. | |
/// \param pAt26 Pointer to an At26 driver instance. | |
//------------------------------------------------------------------------------ | |
unsigned char AT26_IsBusy(At26 *pAt26) | |
{ | |
return SPID_IsBusy(pAt26->pSpid); | |
} | |
//------------------------------------------------------------------------------ | |
/// Sends a command to the serial flash through the SPI. The command is made up | |
/// of two parts: the first is used to transmit the command byte and optionally, | |
/// address and dummy bytes. The second part is the data to send or receive. | |
/// This function does not block: it returns as soon as the transfer has been | |
/// started. An optional callback can be invoked to notify the end of transfer. | |
/// Return 0 if successful; otherwise, returns AT26_ERROR_BUSY if the AT26 | |
/// driver is currently executing a command, or AT26_ERROR_SPI if the command | |
/// cannot be sent because of a SPI error. | |
/// \param pAt26 Pointer to an At26 driver instance. | |
/// \param cmd Command byte. | |
/// \param cmdSize Size of command (command byte + address bytes + dummy bytes). | |
/// \param pData Data buffer. | |
/// \param dataSize Number of bytes to send/receive. | |
/// \param address Address to transmit. | |
/// \param callback Optional user-provided callback to invoke at end of transfer. | |
/// \param pArgument Optional argument to the callback function. | |
//------------------------------------------------------------------------------ | |
unsigned char AT26_SendCommand( | |
At26 *pAt26, | |
unsigned char cmd, | |
unsigned char cmdSize, | |
unsigned char *pData, | |
unsigned int dataSize, | |
unsigned int address, | |
SpidCallback callback, | |
void *pArgument) | |
{ | |
SpidCmd *pCommand; | |
assert(pAt26 != NULL); | |
// Check if the SPI driver is available | |
if (AT26_IsBusy(pAt26)) { | |
return AT26_ERROR_BUSY; | |
} | |
// Store command and address in command buffer | |
pAt26->pCmdBuffer[0] = (cmd & 0x000000FF) | |
| ((address & 0x0000FF) << 24) | |
| ((address & 0x00FF00) << 8) | |
| ((address & 0xFF0000) >> 8); | |
// Update the SPI transfer descriptor | |
pCommand = &(pAt26->command); | |
pCommand->cmdSize = cmdSize; | |
pCommand->pData = pData; | |
pCommand->dataSize = dataSize; | |
pCommand->callback = callback; | |
pCommand->pArgument = pArgument; | |
// Start the SPI transfer | |
if (SPID_SendCommand(pAt26->pSpid, pCommand)) { | |
return AT26_ERROR_SPI; | |
} | |
return 0; | |
} | |
//------------------------------------------------------------------------------ | |
/// Tries to detect a serial firmware flash device given its JEDEC identifier. | |
/// The JEDEC id can be retrieved by sending the correct command to the device. | |
/// Returns the corresponding AT26 descriptor if found; otherwise returns 0. | |
/// \param pAt26 Pointer to an AT26 driver instance. | |
/// \param jedecId JEDEC identifier of device. | |
//------------------------------------------------------------------------------ | |
const At26Desc * AT26_FindDevice(At26 *pAt26, unsigned int jedecId) | |
{ | |
unsigned int i = 0; | |
assert(pAt26 != NULL); | |
// Search if device is recognized | |
pAt26->pDesc = 0; | |
while ((i < NUMDATAFLASH) && !(pAt26->pDesc)) { | |
if (jedecId == at26Devices[i].jedecId) { | |
pAt26->pDesc = &(at26Devices[i]); | |
} | |
i++; | |
} | |
return( pAt26->pDesc ); | |
} | |