From adaa3fd67c225d5303b53044d8acc609b3100a12 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 30 Jul 2011 19:28:45 +0200 Subject: at91lib: add dataflash (at45) from basic-dataflash-project --- at91lib/memories/spi-flash/at45.c | 257 ++++++++++++++++++++++++++++++++++++++ at91lib/memories/spi-flash/at45.h | 255 +++++++++++++++++++++++++++++++++++++ 2 files changed, 512 insertions(+) create mode 100644 at91lib/memories/spi-flash/at45.c create mode 100644 at91lib/memories/spi-flash/at45.h (limited to 'at91lib/memories') diff --git a/at91lib/memories/spi-flash/at45.c b/at91lib/memories/spi-flash/at45.c new file mode 100644 index 0000000..142e7ed --- /dev/null +++ b/at91lib/memories/spi-flash/at45.c @@ -0,0 +1,257 @@ +/* ---------------------------------------------------------------------------- + * 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 "at45.h" +#include +#include + +#include + +//------------------------------------------------------------------------------ +// Internal definitions +//------------------------------------------------------------------------------ + +/// Number of dataflash which can be recognized. +#define NUMDATAFLASH (sizeof(at45Devices) / sizeof(At45Desc)) + +//------------------------------------------------------------------------------ +// Local variables +//------------------------------------------------------------------------------ + +/// indicate if the device is configured as binary page or not. +static unsigned char configuredBinaryPage; + +//------------------------------------------------------------------------------ +// Internal variables +//------------------------------------------------------------------------------ + +static const At45Desc at45Devices[] = { + { 512, 1, 264, 9, 0x0C, "AT45DB011D"}, + { 1024, 1, 264, 9, 0x14, "AT45DB021D"}, + { 2048, 1, 264, 9, 0x1C, "AT45DB041D"}, + { 4096, 1, 264, 9, 0x24, "AT45DB081D"}, + { 4096, 1, 528, 10, 0x2C, "AT45DB161D"}, + { 8192, 1, 528, 10, 0x34, "AT45DB321D"}, + { 8192, 1, 1056, 11, 0x3C, "AT45DB642D"}, + {16384, 1, 1056, 11, 0x10, "AT45DB1282"}, + {16384, 1, 2112, 12, 0x18, "AT45DB2562"}, + {32768, 1, 2112, 12, 0x20, "AT45DB5122"} +}; + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Initializes an AT45 instance and configures SPI chip select register. +/// Always returns 0. +/// \param pAt45 Pointer to the At45 instance to initialize. +/// \param pSpid Pointer to the underlying SPI driver. +/// \param spiCs Chip select value to connect to the At45. +//------------------------------------------------------------------------------ +unsigned char AT45_Configure(At45 *pAt45, Spid *pSpid, unsigned char spiCs) +{ + SpidCmd *pCommand; + + // Sanity checks + ASSERT(pSpid, "AT45_Configure: pSpid is 0.\n\r"); + ASSERT(pAt45, "AT45_Configure: pAt45 is 0.\n\r"); + + // Initialize the At45 instance + pAt45->pSpid = pSpid; + pAt45->pDesc = 0; + memset(pAt45->pCmdBuffer, 0, 8); + + // Initialize the spidCmd structure + pCommand = &(pAt45->command); + pCommand->pCmd = pAt45->pCmdBuffer; + pCommand->callback = 0; + pCommand->pArgument = 0; + pCommand->spiCs = spiCs; + + return 0; +} + +//------------------------------------------------------------------------------ +/// This function returns 1 if the At45 driver is not executing any command; +/// otherwise it returns 0. +/// \param pAt45 Pointer to an At45 instance. +//------------------------------------------------------------------------------ +unsigned char AT45_IsBusy(At45 *pAt45) +{ + return SPID_IsBusy(pAt45->pSpid); +} + +//------------------------------------------------------------------------------ +/// Sends a command to the dataflash through the SPI. The command is identified +/// by its command code and the number of bytes to transfer (1 + number of +/// address bytes + number of dummy bytes). If data needs to be received, then +/// a data buffer must be provided. +/// This function does not block; its optional callback will be invoked when +/// the transfer completes. +/// \param pAt45 Pointer to an At45 driver instance. +/// \param cmd Command code. +/// \param cmdSize Size of command code + address bytes + dummy bytes. +/// \param pData Data buffer. +/// \param dataSize Number of data bytes to send/receive. +/// \param address Address at which the command is performed if meaningful. +/// \param callback Optional callback to invoke at end of transfer. +/// \param pArgument Optional parameter to the callback function. +//------------------------------------------------------------------------------ +unsigned char AT45_SendCommand( + At45 *pAt45, + unsigned char cmd, + unsigned char cmdSize, + unsigned char *pData, + unsigned int dataSize, + unsigned int address, + SpidCallback callback, + void *pArgument) +{ + SpidCmd *pCommand; + const At45Desc *pDesc = pAt45->pDesc; + unsigned int dfAddress = 0; + + // Sanity checks + ASSERT(pAt45, "AT45_Command: pAt45 is 0.\n\r"); + ASSERT(pDesc || (cmd == AT45_STATUS_READ), + "AT45_Command: Device has no descriptor, only STATUS_READ command allowed\n\r"); + + // Check if the SPI driver is available + if (AT45_IsBusy(pAt45)) { + + return AT45_ERROR_LOCK; + } + + // Compute command pattern + pAt45->pCmdBuffer[0] = cmd; + + // Add address bytes if necessary + if (cmdSize > 1) { + + ASSERT(pDesc, "AT45_Command: No descriptor for dataflash.\n\r"); + if (!configuredBinaryPage) { + dfAddress = + ((address / (pDesc->pageSize)) << pDesc->pageOffset) + + (address % (pDesc->pageSize)); + } + else { + dfAddress = address; + } + // Write address bytes + if (pDesc->pageNumber >= 16384) { + + pAt45->pCmdBuffer[1] = ((dfAddress & 0x0F000000) >> 24); + pAt45->pCmdBuffer[2] = ((dfAddress & 0x00FF0000) >> 16); + pAt45->pCmdBuffer[3] = ((dfAddress & 0x0000FF00) >> 8); + pAt45->pCmdBuffer[4] = ((dfAddress & 0x000000FF) >> 0); + + if ((cmd != AT45_CONTINUOUS_READ) && (cmd != AT45_PAGE_READ)) { + + cmdSize++; + } + } + else { + + pAt45->pCmdBuffer[1] = ((dfAddress & 0x00FF0000) >> 16); + pAt45->pCmdBuffer[2] = ((dfAddress & 0x0000FF00) >> 8); + pAt45->pCmdBuffer[3] = ((dfAddress & 0x000000FF) >> 0); + } + } + + // Update the SPI Transfer descriptors + pCommand = &(pAt45->command); + pCommand->cmdSize = cmdSize; + pCommand->pData = pData; + pCommand->dataSize = dataSize; + pCommand->callback = callback; + pCommand->pArgument = pArgument; + + // Send Command and data through the SPI + if (SPID_SendCommand(pAt45->pSpid, pCommand)) { + + return AT45_ERROR_SPI; + } + + return 0; +} + +//------------------------------------------------------------------------------ +/// This function returns the At45Desc structure corresponding to the device +/// connected +/// It automatically initializes pAt45->pDesc field structure. +/// This function shall be called by the application before AT45_SendCommand. +/// Returns 0 if successful; Otherwise, returns AT45_ERROR_LOCK if the At45 +/// driver is in use or AT45_ERROR_SPI if there was an error with the SPI driver. +/// \param pAt45 Pointer to an AT45 driver instance. +/// \param status Device status register value. +//------------------------------------------------------------------------------ +const At45Desc * AT45_FindDevice(At45 *pAt45, unsigned char status) +{ + unsigned int i; + unsigned char id = AT45_STATUS_ID(status); + + // Check if status is all one; in which case, it is assumed that no device + // is connected + if (status == 0xFF) { + + return 0; + } + + // Look in device array + i = 0; + pAt45->pDesc = 0; + while ((i < NUMDATAFLASH) && !(pAt45->pDesc)) { + + if (at45Devices[i].id == id) { + + pAt45->pDesc = &(at45Devices[i]); + } + i++; + } + configuredBinaryPage = AT45_STATUS_BINARY(status); + return pAt45->pDesc; +} + +//------------------------------------------------------------------------------ +/// This function returns the pagesize corresponding to the device connected +/// \param pAt45 Pointer to an AT45 driver instance. +//------------------------------------------------------------------------------ +unsigned int AT45_PageSize(At45 *pAt45) +{ + unsigned int pagesize = pAt45->pDesc->pageSize; + if(((pAt45->pDesc->hasBinaryPage) == 0) || !configuredBinaryPage){ + return pagesize; + } + return ((pagesize >> 8) << 8); +} diff --git a/at91lib/memories/spi-flash/at45.h b/at91lib/memories/spi-flash/at45.h new file mode 100644 index 0000000..ef7ef26 --- /dev/null +++ b/at91lib/memories/spi-flash/at45.h @@ -0,0 +1,255 @@ +/* ---------------------------------------------------------------------------- + * 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. + * ---------------------------------------------------------------------------- + */ +//------------------------------------------------------------------------------ +/// \unit +/// +/// !!!Purpose +/// +/// The Dataflash driver is based on top of the corresponding Spi driver. +/// A Dataflash structure instance has to be initialized using the DF_Init +/// function. Then basic dataflash operations can be launched using macros such +/// as DF_continuous_read. These macros invoke the DF_Command() function which +/// invokes the DPI low driver using the SPI_SendCommand() function. +/// Beware to compute the dataflash internal address, the dataflash sector +/// description must be known (DataflashDesc). Dataflash can be automatically +/// detected using the DF_Scan() function. +/// !!!Usage +/// +/// -# Initializes an AT45 instance and configures SPI chip select pin +/// using AT45_Configure(). +/// -# Detect DF and returns DF description corresponding to the device +/// connected using AT45_FindDevice().This function shall be called by +/// the application before AT45_SendCommand. +/// -# Sends a command to the DF through the SPI using AT45_SendCommand(). +/// The command is identified by its command code and the number of +/// bytes to transfer. +/// -# Example code for sending command to write a page to DF. +/// \code +/// // Issue a page write through buffer 1 command +/// error = AT45_SendCommand(pAt45, AT45_PAGE_WRITE_BUF1, 4, +/// pBuffer, size, address, 0, 0); +/// \endcode +/// -# Example code for sending command to read a page from DF. +/// If data needs to be received, then a data buffer must be +/// provided. +/// \code +/// // Issue a continuous read array command +/// error = AT45_SendCommand(pAt45, AT45_CONTINUOUS_READ_LEG, 8, +/// pBuffer, size, address, 0, 0); +/// \endcode +/// -# This function does not block; its optional callback will +/// be invoked when the transfer completes. +/// -# Check the AT45 driver is ready or not by polling AT45_IsBusy(). +/// +//------------------------------------------------------------------------------ + +#ifndef AT45_H +#define AT45_H + +//------------------------------------------------------------------------------ +// Headers +//------------------------------------------------------------------------------ + +#include "spid.h" + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +/// The dataflash driver is currently in use. +#define AT45_ERROR_LOCK 1 +/// There was an error with the SPI driver. +#define AT45_ERROR_SPI 2 + +/// AT45 dataflash SPI CSR settings given MCK and SPCK. +#define AT45_CSR(mck, spck) \ + (AT91C_SPI_NCPHA | SPID_CSR_DLYBCT(mck, 250) \ + | SPID_CSR_DLYBS(mck, 250) | SPID_CSR_SCBR(mck, spck)) + +//------------------------------------------------------------------------------ +// Macros +//------------------------------------------------------------------------------ + +#define AT45_PageOffset(pAt45) ((pAt45)->pDesc->pageOffset) +#define AT45_PageNumber(pAt45) ((pAt45)->pDesc->pageNumber) + +/// Returns 1 if the device is ready; otherwise 0. +#define AT45_STATUS_READY(status) (status & 0x80) +/// Returns the device ID code. +#define AT45_STATUS_ID(status) (status & 0x3c) +/// Returns 1 if the device is configured in binary page mode; otherwise 0. +#define AT45_STATUS_BINARY(status) (status & 0x01) + +//------------------------------------------------------------------------------ +// Definitions +//------------------------------------------------------------------------------ + +/// Main memory page read command code. +#define AT45_PAGE_READ 0xD2 +/// Continous array read (legacy) command code. +#define AT45_CONTINUOUS_READ_LEG 0xE8 +/// Continous array read (low frequency) command code. +#define AT45_CONTINUOUS_READ_LF 0x03 +/// Continous array read command code. +#define AT45_CONTINUOUS_READ 0x0B +/// Buffer 1 read (low frequency) command code. +#define AT45_BUF1_READ_LF 0xD1 +/// Buffer 2 read (low frequency) command code. +#define AT45_BUF2_READ_LF 0xD3 +/// Buffer 1 read (serial) command code. +#define AT45_BUF1_READ_SER 0xD4 +/// Buffer 2 read (serial) command code. +#define AT45_BUF2_READ_SER 0xD6 +/// Buffer 1 read (8-bit) command code. +#define AT45_BUF1_READ_8B 0x54 +/// Buffer 2 read (8-bit) command code. +#define AT45_BUF2_READ_8B 0x56 + +/// Buffer 1 write command code. +#define AT45_BUF1_WRITE 0x84 +/// Buffer 2 write command code. +#define AT45_BUF2_WRITE 0x87 +/// Buffer 1 to main memory page program with erase command code. +#define AT45_BUF1_MEM_ERASE 0x83 +/// Buffer 2 to main memory page program with erase command code. +#define AT45_BUF2_MEM_ERASE 0x86 +/// Buffer 1 to main memory page program without erase command code. +#define AT45_BUF1_MEM_NOERASE 0x88 +/// Buffer 2 to main memory page program without erase command code. +#define AT45_BUF2_MEM_NOERASE 0x89 +/// Page erase command code. +#define AT45_PAGE_ERASE 0x81 +/// Block erase command code. +#define AT45_BLOCK_ERASE 0x50 +/// Sector erase command code. +#define AT45_SECTOR_ERASE 0x7C +/// Chip erase command code. +#define AT45_CHIP_ERASE 0xC7, 0x94, 0x80, 0x9A +/// Main memory page program through buffer 1 command code. +#define AT45_PAGE_WRITE_BUF1 0x82 +/// Main memory page program through buffer 2 command code. +#define AT45_PAGE_WRITE_BUF2 0x85 + +/// Main memory page to buffer 1 transfer command code. +#define AT45_PAGE_BUF1_TX 0x53 +/// Main memory page to buffer 2 transfer command code. +#define AT45_PAGE_BUF2_TX 0x55 +/// Main memory page to buffer 1 compare command code. +#define AT45_PAGE_BUF1_CMP 0x60 +/// Main memory page to buffer 2 compare command code. +#define AT45_PAGE_BUF2_CMP 0x61 +/// Auto page rewrite through buffer 1 command code. +#define AT45_AUTO_REWRITE_BUF1 0x58 +/// Auto page rewrite through buffer 2 command code. +#define AT45_AUTO_REWRITE_BUF2 0x59 +/// Deep power-down command code. +#define AT45_DEEP_PDOWN 0xB9 +/// Resume from deep power-down command code. +#define AT45_RES_DEEP_PDOWN 0xAB +/// Status register read command code. +#define AT45_STATUS_READ 0xD7 +/// Manufacturer and device ID read command code. +#define AT45_ID_READ 0x9F + +/// Power-of-2 binary page size configuration command code. +#define AT45_BINARY_PAGE_FIRST_OPCODE 0x3D +#define AT45_BINARY_PAGE 0x2A, 0x80, 0xA6 + +//------------------------------------------------------------------------------ +// Types +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +/// Dataflash description. A constant array of DataflashDesc instance is defined +/// in at45.c. The DF_Scan() function returns the corresponding descriptor +/// according to the dataflash ID detected. +/// This description (page_size, page_offset) is used to compute the internal +/// dataflash address by the DF_Command() function. +//------------------------------------------------------------------------------ +typedef struct { + + /// dataflash page number. + unsigned int pageNumber; + // indicate if power-of-2 binary page supported. + unsigned int hasBinaryPage; + /// dataflash page size. + unsigned int pageSize; + /// page offset in command. + unsigned int pageOffset; + /// Dataflash ID. + unsigned char id; + /// Identifier. + const char *name; + +} At45Desc; + +//------------------------------------------------------------------------------ +/// Dataflash driver structure. It holds the current command being processed. +/// This structure is initialized by the DF_Init() command. +/// pDfDesc field can be initialized by the DF_Scan() function. +/// cmdBuffer is a private driver area used to compute the dataflash address to +/// be sent to the dataflash. +/// Beware the PDC master must have access to this area. +//------------------------------------------------------------------------------ +typedef struct _Dataflash { + + /// Pointer to Spi Structure (SPI low level driver). + Spid *pSpid; + /// Current SPI command sent to the SPI low level driver. + SpidCmd command; + /// Pointer to the dataflash description. + const At45Desc *pDesc; + /// Buffer to store the current command (opcode + dataflash address. + unsigned char pCmdBuffer[8]; + +} At45; + +//------------------------------------------------------------------------------ +// Exported functions +//------------------------------------------------------------------------------ + +extern unsigned char AT45_Configure(At45 *pAt45, Spid *pSpid, unsigned char spiCs); + +extern unsigned char AT45_IsBusy(At45 *pAt45); + +extern unsigned char AT45_SendCommand( + At45 *pAt45, + unsigned char cmd, + unsigned char cmdSize, + unsigned char *pData, + unsigned int dataSize, + unsigned int address, + SpidCallback callback, + void *pArgument); + +extern const At45Desc * AT45_FindDevice(At45 *pAt45, unsigned char status); + +extern unsigned int AT45_PageSize(At45 *pAt45); +#endif // #ifndef AT45_H + -- cgit v1.2.3