diff options
Diffstat (limited to 'at91lib/memories')
-rw-r--r-- | at91lib/memories/spi-flash/at45.c | 257 | ||||
-rw-r--r-- | at91lib/memories/spi-flash/at45.h | 255 |
2 files changed, 512 insertions, 0 deletions
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 <board.h>
+#include <utility/assert.h>
+
+#include <string.h>
+
+//------------------------------------------------------------------------------
+// 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
+
|