diff options
Diffstat (limited to 'memories/spi-flash')
-rw-r--r-- | memories/spi-flash/at26.c | 232 | ||||
-rw-r--r-- | memories/spi-flash/at26.h | 252 | ||||
-rw-r--r-- | memories/spi-flash/at26d.c | 409 | ||||
-rw-r--r-- | memories/spi-flash/at26d.h | 79 | ||||
-rw-r--r-- | memories/spi-flash/at45.c | 257 | ||||
-rw-r--r-- | memories/spi-flash/at45.h | 255 | ||||
-rw-r--r-- | memories/spi-flash/at45d.c | 223 | ||||
-rw-r--r-- | memories/spi-flash/at45d.h | 86 | ||||
-rw-r--r-- | memories/spi-flash/spi-flash.dir | 37 | ||||
-rw-r--r-- | memories/spi-flash/spid.c | 215 | ||||
-rw-r--r-- | memories/spi-flash/spid.h | 212 | ||||
-rw-r--r-- | memories/spi-flash/spid_dma.c | 392 |
12 files changed, 2649 insertions, 0 deletions
diff --git a/memories/spi-flash/at26.c b/memories/spi-flash/at26.c new file mode 100644 index 0000000..4ac80c2 --- /dev/null +++ b/memories/spi-flash/at26.c @@ -0,0 +1,232 @@ +/* ----------------------------------------------------------------------------
+ * 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 <utility/assert.h>
+
+//------------------------------------------------------------------------------
+// Internal definitions
+//------------------------------------------------------------------------------
+
+/// SPI clock frequency used in Hz.
+#if defined (BOARD_AT26F004)
+// SPI runs at a faster frequency for devices with smaller throughput
+#define SPCK 10000000
+#else
+#define SPCK 1000000
+#endif
+
+/// SPI chip select configuration value.
+#define CSR (AT91C_SPI_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},
+ {"AT26F004" , 0x0000041F, 512 * 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;
+
+ SANITY_CHECK(pAt26);
+ SANITY_CHECK(pSpid);
+ SANITY_CHECK(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;
+
+ SANITY_CHECK(pAt26);
+
+ // 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;
+
+ SANITY_CHECK(pAt26);
+
+ // 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;
+}
+
diff --git a/memories/spi-flash/at26.h b/memories/spi-flash/at26.h new file mode 100644 index 0000000..4e3aa6d --- /dev/null +++ b/memories/spi-flash/at26.h @@ -0,0 +1,252 @@ +/* ----------------------------------------------------------------------------
+ * 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 AT26 serial firmware 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 AT26 instance and configures SPI chip select pin
+/// using AT26_Configure().
+/// -# Detect DF and returns DF description corresponding to the device
+/// connected using AT26_FindDevice().This function shall be called by
+/// the application before AT26_SendCommand().
+/// -# Sends a command to the DF through the SPI using AT26_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
+/// // Program page
+/// error = AT26_SendCommand(pAt26, AT26_BYTE_PAGE_PROGRAM, 4,
+/// pData, writeSize, 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
+/// // Start a read operation
+/// error = AT26_SendCommand(pAt26, AT26_READ_ARRAY_LF,
+/// 4, pData, size, address, 0, 0);
+/// \endcode
+/// -# This function does not block; its optional callback will
+/// be invoked when the transfer completes.
+/// -# Check the AT26 driver is ready or not by polling AT26_IsBusy().
+///
+//------------------------------------------------------------------------------
+#ifndef AT26_H
+#define AT26_H
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include "spid.h"
+
+//------------------------------------------------------------------------------
+// Macros
+//------------------------------------------------------------------------------
+
+#define AT26_Size(pAt26) ((pAt26)->pDesc->size)
+#define AT26_PageSize(pAt26) ((pAt26)->pDesc->pageSize)
+#define AT26_BlockSize(pAt26) ((pAt26)->pDesc->blockSize)
+#define AT26_Name(pAt26) ((pAt26)->pDesc->name)
+#define AT26_PageNumber(pAt26) (AT26_Size(pAt26) / AT26_PageSize(pAt26))
+#define AT26_BlockNumber(pAt26) (AT26_Size(pAt26) / AT26_BlockSize(pAt26))
+#define AT26_PagePerBlock(pAt26) (AT26_BlockSize(pAt26) / AT26_PageSize(pAt26))
+#define AT26_BlockEraseCmd(pAt26) ((pAt26)->pDesc->blockEraseCmd)
+
+//------------------------------------------------------------------------------
+// Definitions
+//------------------------------------------------------------------------------
+
+/// Device is protected, operation cannot be carried out.
+#define AT26_ERROR_PROTECTED 1
+/// Device is busy executing a command.
+#define AT26_ERROR_BUSY 2
+/// There was a problem while trying to program page data.
+#define AT26_ERROR_PROGRAM 3
+/// There was an SPI communication error.
+#define AT26_ERROR_SPI 4
+
+/// Device ready/busy status bit.
+#define AT26_STATUS_RDYBSY (1 << 0)
+/// Device is ready.
+#define AT26_STATUS_RDYBSY_READY (0 << 0)
+/// Device is busy with internal operations.
+#define AT26_STATUS_RDYBSY_BUSY (1 << 0)
+/// Write enable latch status bit.
+#define AT26_STATUS_WEL (1 << 1)
+/// Device is not write enabled.
+#define AT26_STATUS_WEL_DISABLED (0 << 1)
+/// Device is write enabled.
+#define AT26_STATUS_WEL_ENABLED (1 << 1)
+/// Software protection status bitfield.
+#define AT26_STATUS_SWP (3 << 2)
+/// All sectors are software protected.
+#define AT26_STATUS_SWP_PROTALL (3 << 2)
+/// Some sectors are software protected.
+#define AT26_STATUS_SWP_PROTSOME (1 << 2)
+/// No sector is software protected.
+#define AT26_STATUS_SWP_PROTNONE (0 << 2)
+/// Write protect pin status bit.
+#define AT26_STATUS_WPP (1 << 4)
+/// Write protect signal is not asserted.
+#define AT26_STATUS_WPP_NOTASSERTED (0 << 4)
+/// Write protect signal is asserted.
+#define AT26_STATUS_WPP_ASSERTED (1 << 4)
+/// Erase/program error bit.
+#define AT26_STATUS_EPE (1 << 5)
+/// Erase or program operation was successful.
+#define AT26_STATUS_EPE_SUCCESS (0 << 5)
+/// Erase or program error detected.
+#define AT26_STATUS_EPE_ERROR (1 << 5)
+/// Sector protection registers locked bit.
+#define AT26_STATUS_SPRL (1 << 7)
+/// Sector protection registers are unlocked.
+#define AT26_STATUS_SPRL_UNLOCKED (0 << 7)
+/// Sector protection registers are locked.
+#define AT26_STATUS_SPRL_LOCKED (1 << 7)
+
+/// Read array command code.
+#define AT26_READ_ARRAY 0x0B
+/// Read array (low frequency) command code.
+#define AT26_READ_ARRAY_LF 0x03
+/// Block erase command code (4K block).
+#define AT26_BLOCK_ERASE_4K 0x20
+/// Block erase command code (32K block).
+#define AT26_BLOCK_ERASE_32K 0x52
+/// Block erase command code (64K block).
+#define AT26_BLOCK_ERASE_64K 0xD8
+/// Chip erase command code 1.
+#define AT26_CHIP_ERASE_1 0x60
+/// Chip erase command code 2.
+#define AT26_CHIP_ERASE_2 0xC7
+/// Byte/page program command code.
+#define AT26_BYTE_PAGE_PROGRAM 0x02
+/// Sequential program mode command code 1.
+#define AT26_SEQUENTIAL_PROGRAM_1 0xAD
+/// Sequential program mode command code 2.
+#define AT26_SEQUENTIAL_PROGRAM_2 0xAF
+/// Write enable command code.
+#define AT26_WRITE_ENABLE 0x06
+/// Write disable command code.
+#define AT26_WRITE_DISABLE 0x04
+/// Protect sector command code.
+#define AT26_PROTECT_SECTOR 0x36
+/// Unprotect sector command code.
+#define AT26_UNPROTECT_SECTOR 0x39
+/// Read sector protection registers command code.
+#define AT26_READ_SECTOR_PROT 0x3C
+/// Read status register command code.
+#define AT26_READ_STATUS 0x05
+/// Write status register command code.
+#define AT26_WRITE_STATUS 0x01
+/// Read manufacturer and device ID command code.
+#define AT26_READ_JEDEC_ID 0x9F
+/// Deep power-down command code.
+#define AT26_DEEP_PDOWN 0xB9
+/// Resume from deep power-down command code.
+#define AT26_RES_DEEP_PDOWN 0xAB
+
+//------------------------------------------------------------------------------
+// Types
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Describes a serial firmware flash device parameters.
+//------------------------------------------------------------------------------
+typedef struct _At26Desc {
+
+ /// Device string name.
+ const char *name;
+ /// JEDEC ID of device.
+ unsigned int jedecId;
+ /// Size of device in bytes.
+ unsigned int size;
+ /// Size of one page in bytes.
+ unsigned int pageSize;
+ /// Block erase size in bytes.
+ unsigned int blockSize;
+ /// Block erase command.
+ unsigned int blockEraseCmd;
+
+} At26Desc;
+
+//------------------------------------------------------------------------------
+/// Serial flash driver structure. Holds the current state of the driver,
+/// including the current command and the descriptor for the underlying device.
+//------------------------------------------------------------------------------
+typedef struct _At26 {
+
+ /// Pointer to the underlying SPI driver.
+ Spid *pSpid;
+ /// Current SPI command sent to the SPI driver.
+ SpidCmd command;
+ /// Pointer to a descriptor for the serial firmware flash device.
+ const At26Desc *pDesc;
+ /// Command buffer.
+ unsigned int pCmdBuffer[2];
+
+} At26;
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+
+extern void AT26_Configure(At26 *pAt26, Spid *pSpid, unsigned char cs);
+
+extern 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);
+
+extern unsigned char AT26_IsBusy(At26 *pAt26);
+
+extern const At26Desc * AT26_FindDevice(
+ At26 *pAt26,
+ unsigned int jedecId);
+
+#endif //#ifndef AT26_H
+
diff --git a/memories/spi-flash/at26d.c b/memories/spi-flash/at26d.c new file mode 100644 index 0000000..123fde1 --- /dev/null +++ b/memories/spi-flash/at26d.c @@ -0,0 +1,409 @@ +/* ----------------------------------------------------------------------------
+ * 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 "at26d.h"
+#include "board.h"
+#include <utility/math.h>
+#include <utility/assert.h>
+
+/*****/
+#include <utility/trace.h>
+/*****/
+
+//------------------------------------------------------------------------------
+// Local functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Wait for transfer to finish calling the SPI driver ISR. (interrupts are disabled)
+/// \param pAt26 Pointer to an AT26 driver instance.
+//------------------------------------------------------------------------------
+static void AT26D_Wait(At26 *pAt26)
+{
+ // Wait for transfer to finish
+ while (AT26_IsBusy(pAt26))
+ SPID_Handler(pAt26->pSpid);
+}
+
+//------------------------------------------------------------------------------
+/// Reads and returns the status register of the serial flash.
+/// \param pAt26 Pointer to an AT26 driver instance.
+//------------------------------------------------------------------------------
+static unsigned char AT26D_ReadStatus(At26 *pAt26)
+{
+ unsigned char error, status;
+
+ SANITY_CHECK(pAt26);
+
+ // Issue a status read command
+ error = AT26_SendCommand(pAt26, AT26_READ_STATUS, 1, &status, 1, 0, 0, 0);
+ ASSERT(!error, "-F- AT26_GetStatus: Failed to issue command.\n\r");
+
+ // Wait for transfer to finish
+ AT26D_Wait(pAt26);
+
+ return status;
+}
+
+//------------------------------------------------------------------------------
+/// Writes the given value in the status register of the serial flash device.
+/// \param pAt26 Pointer to an AT26 driver instance.
+/// \param status Status to write.
+//------------------------------------------------------------------------------
+static void AT26D_WriteStatus(At26 *pAt26, unsigned char status)
+{
+ unsigned char error;
+
+ SANITY_CHECK(pAt26);
+
+ // Issue a write status command
+ error = AT26_SendCommand(pAt26, AT26_WRITE_STATUS, 1, &status, 1, 0, 0, 0);
+ ASSERT(!error, "-F- AT26_WriteStatus: Failed to issue command.\n\r");
+ // Wait for transfer to finish
+ AT26D_Wait(pAt26);
+}
+
+
+//------------------------------------------------------------------------------
+// Global functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Waits for the serial flash device to become ready to accept new commands.
+/// \param pAt26 Pointer to an AT26 driver instance.
+//------------------------------------------------------------------------------
+void AT26D_WaitReady(At26 *pAt26)
+{
+ unsigned char ready = 0;
+
+ SANITY_CHECK(pAt26);
+
+ // Read status register and check busy bit
+ while (!ready) {
+
+ ready = ((AT26D_ReadStatus(pAt26) & AT26_STATUS_RDYBSY) == AT26_STATUS_RDYBSY_READY);
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Reads and returns the serial flash device ID.
+/// \param pAt26 Pointer to an AT26 driver instance.
+//------------------------------------------------------------------------------
+unsigned int AT26D_ReadJedecId(At26 *pAt26)
+{
+ unsigned char error;
+ unsigned int id = 0;
+
+ SANITY_CHECK(pAt26);
+
+ // Issue a read ID command
+ error = AT26_SendCommand(pAt26, AT26_READ_JEDEC_ID, 1,
+ (unsigned char *) &id, 3, 0, 0, 0);
+ ASSERT(!error, "-F- AT26_GetJedecId: Could not issue command.\n\r");
+
+ // Wait for transfer to finish
+ AT26D_Wait(pAt26);
+
+ return id;
+}
+
+//------------------------------------------------------------------------------
+/// Enables critical writes operation on a serial flash device, such as sector
+/// protection, status register, etc.
+/// \para pAt26 Pointer to an AT26 driver instance.
+//------------------------------------------------------------------------------
+void AT26D_EnableWrite(At26 *pAt26)
+{
+ unsigned char error;
+
+ SANITY_CHECK(pAt26);
+
+ // Issue a write enable command
+ error = AT26_SendCommand(pAt26, AT26_WRITE_ENABLE, 1, 0, 0, 0, 0, 0);
+ ASSERT(!error, "-F- AT26_EnableWrite: Could not issue command.\n\r");
+
+ // Wait for transfer to finish
+ AT26D_Wait(pAt26);
+}
+
+#if defined(BOARD_AT26F004)
+
+//------------------------------------------------------------------------------
+// Reads and returns the status register of the serial flash.
+// \param pAt26 Pointer to an AT26 driver instance.
+//------------------------------------------------------------------------------
+unsigned char AT26F004_Unprotect(At26 *pAt26)
+{
+ unsigned char error;
+ unsigned int sector, sectorAddress = 0;
+
+ for (sector = 0 ; sector < 11 ; sector ++)
+ {
+ sectorAddress = 0x0;
+
+ if (sector == 10)
+ sectorAddress = 0x7C000;
+ else if (sector == 9)
+ sectorAddress = 0x7A000;
+ else if (sector == 8)
+ sectorAddress = 0x78000;
+ else if (sector == 7)
+ sectorAddress = 0x70000;
+ else
+ sectorAddress = sectorAddress + (0x10000 * sector);
+
+ // Write Enable
+ AT26D_EnableWrite(pAt26);
+
+ error = AT26_SendCommand(pAt26, AT26_UNPROTECT_SECTOR, 4, 0, 0, sectorAddress, 0, 0);
+ ASSERT(!error, "-F- AT26_SectorUnprotect: Failed to issue command.\n\r");
+
+ // Wait for transfer to finish
+ AT26D_Wait(pAt26);
+ }
+
+ return 0;
+}
+#endif
+
+//------------------------------------------------------------------------------
+/// Unprotects the contents of the serial flash device.
+/// Returns 0 if the device has been unprotected; otherwise returns
+/// SF_PROTECTED.
+/// \param pAt26 Pointer to an AT26 driver instance.
+//------------------------------------------------------------------------------
+unsigned char AT26D_Unprotect(At26 *pAt26)
+{
+ unsigned char status;
+
+ SANITY_CHECK(pAt26);
+
+ // Get the status register value to check the current protection
+ status = AT26D_ReadStatus(pAt26);
+ if ((status & AT26_STATUS_SWP) == AT26_STATUS_SWP_PROTNONE) {
+
+ // Protection already disabled
+ return 0;
+ }
+
+ // Check if sector protection registers are locked
+ if ((status & AT26_STATUS_SPRL) == AT26_STATUS_SPRL_LOCKED) {
+
+ // Unprotect sector protection registers by writing the status reg.
+ AT26D_EnableWrite(pAt26);
+ AT26D_WriteStatus(pAt26, 0);
+ }
+
+ // Perform a global unprotect command
+ AT26D_EnableWrite(pAt26);
+
+ #if defined(BOARD_AT26F004)
+ AT26F004_Unprotect(pAt26);
+ #endif
+
+ AT26D_WriteStatus(pAt26, 0);
+
+ // Check the new status
+ status = AT26D_ReadStatus(pAt26);
+ if ((status & (AT26_STATUS_SPRL | AT26_STATUS_SWP)) != 0) {
+
+ return AT26_ERROR_PROTECTED;
+ }
+ else {
+
+ return 0;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Erases all the content of the memory chip.
+/// \param pAt26 Pointer to an AT26 driver instance.
+//------------------------------------------------------------------------------
+unsigned char AT26D_EraseChip(At26 *pAt26)
+{
+ unsigned char status;
+ unsigned char error;
+
+ SANITY_CHECK(pAt26);
+
+ // Check that the flash is unprotected
+ status = AT26D_ReadStatus(pAt26);
+ if ((status & AT26_STATUS_SWP) != AT26_STATUS_SWP_PROTNONE) {
+ return AT26_ERROR_PROTECTED;
+ }
+
+ // Enable critical write operation
+ AT26D_EnableWrite(pAt26);
+
+ // Erase the chip
+ error = AT26_SendCommand(pAt26, AT26_CHIP_ERASE_2, 1, 0, 0, 0, 0, 0);
+ ASSERT(!error, "-F- AT26_ChipErase: Could not issue command.\n\r");
+ // Wait for transfer to finish
+ AT26D_Wait(pAt26);
+ // Poll the Serial flash status register until the operation is achieved
+ AT26D_WaitReady(pAt26);
+
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// Erases the specified 64KB block of the serial firmware dataflash.
+/// Returns 0 if successful; otherwise returns AT26_ERROR_PROTECTED if the
+/// device is protected or AT26_ERROR_BUSY if it is busy executing a command.
+/// \param pAt26 Pointer to an AT26 driver instance.
+/// \param address Address of the block to erase.
+//------------------------------------------------------------------------------
+unsigned char AT26D_EraseBlock(At26 *pAt26, unsigned int address)
+{
+ unsigned char status;
+ unsigned char error;
+
+ SANITY_CHECK(pAt26);
+
+ // Check that the flash is ready and unprotected
+ status = AT26D_ReadStatus(pAt26);
+ if ((status & AT26_STATUS_RDYBSY) != AT26_STATUS_RDYBSY_READY) {
+ TRACE_ERROR("AT26D_EraseBlock : Flash busy\n\r");
+ return AT26_ERROR_BUSY;
+ }
+ else if ((status & AT26_STATUS_SWP) != AT26_STATUS_SWP_PROTNONE) {
+ TRACE_ERROR("AT26D_EraseBlock : Flash protected\n\r");
+ return AT26_ERROR_PROTECTED;
+ }
+
+ // Enable critical write operation
+ AT26D_EnableWrite(pAt26);
+
+ // Start the block erase command
+ error = AT26_SendCommand(pAt26, AT26_BlockEraseCmd(pAt26), 4, 0, 0, address, 0, 0);
+ ASSERT(!error, "-F- AT26_EraseBlock: Could not issue command.\n\r");
+ // Wait for transfer to finish
+ AT26D_Wait(pAt26);
+ // Poll the Serial flash status register until the operation is achieved
+ AT26D_WaitReady(pAt26);
+
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// Writes data at the specified address on the serial firmware dataflash. The
+/// page(s) to program must have been erased prior to writing. This function
+/// handles page boundary crossing automatically.
+/// Returns 0 if successful; otherwise, returns AT26_ERROR_PROGRAM is there has
+/// been an error during the data programming.
+/// \param pAt26 Pointer to an AT26 driver instance.
+/// \param pData Data buffer.
+/// \param size Number of bytes in buffer.
+/// \param address Write address.
+//------------------------------------------------------------------------------
+unsigned char AT26D_Write(
+ At26 *pAt26,
+ unsigned char *pData,
+ unsigned int size,
+ unsigned int address)
+{
+ unsigned int pageSize;
+ unsigned int writeSize;
+ unsigned char error;
+ #if !defined(BOARD_AT26F004)
+ unsigned char status;
+ #endif
+
+ SANITY_CHECK(pAt26);
+ SANITY_CHECK(pData);
+
+ // Retrieve device page size
+ pageSize = AT26_PageSize(pAt26);
+
+ // Program one page after the other
+ while (size > 0) {
+ // Compute number of bytes to program in page
+ #if defined(BOARD_AT26F004)
+ writeSize = 1;
+ #else
+ writeSize = min(size, pageSize - (address % pageSize));
+ #endif
+
+ // Enable critical write operation
+ AT26D_EnableWrite(pAt26);
+
+ // Program page
+ error = AT26_SendCommand(pAt26, AT26_BYTE_PAGE_PROGRAM, 4,
+ pData, writeSize, address, 0, 0);
+ ASSERT(!error, "-F- AT26_WritePage: Failed to issue command.\n\r");
+ // Wait for transfer to finish
+ AT26D_Wait(pAt26);
+ // Poll the Serial flash status register until the operation is achieved
+ AT26D_WaitReady(pAt26);
+
+ #if !defined(AT26F004)
+ // Make sure that write was without error
+ status = AT26D_ReadStatus(pAt26);
+ if ((status & AT26_STATUS_EPE) == AT26_STATUS_EPE_ERROR) {
+
+ return AT26_ERROR_PROGRAM;
+ }
+ #endif
+
+ pData += writeSize;
+ size -= writeSize;
+ address += writeSize;
+ }
+
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// Reads data from the specified address on the serial flash.
+/// \param pAt26 Pointer to an AT26 driver instance.
+/// \param pData Data buffer.
+/// \param size Number of bytes to read.
+/// \param address Read address.
+//------------------------------------------------------------------------------
+unsigned char AT26D_Read(
+ At26 *pAt26,
+ unsigned char *pData,
+ unsigned int size,
+ unsigned int address)
+{
+ unsigned char error;
+
+ // Start a read operation
+ error = AT26_SendCommand(pAt26, AT26_READ_ARRAY_LF, 4, pData, size, address, 0, 0);
+ ASSERT(!error, "-F- AT26_Read: Could not issue command.\n\r");
+ // Wait for transfer to finish
+ AT26D_Wait(pAt26);
+
+ return error;
+}
diff --git a/memories/spi-flash/at26d.h b/memories/spi-flash/at26d.h new file mode 100644 index 0000000..9bed206 --- /dev/null +++ b/memories/spi-flash/at26d.h @@ -0,0 +1,79 @@ +/* ----------------------------------------------------------------------------
+ * 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 AT26 Serialflash driver.
+///
+/// !Usage
+//------------------------------------------------------------------------------
+
+#ifndef AT26D_H
+#define AT26D_H
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include "at26.h"
+
+
+//------------------------------------------------------------------------------
+// Macros
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+extern void AT26D_WaitReady(At26 *pAt26);
+
+extern unsigned int AT26D_ReadJedecId(At26 *pAt26);
+
+extern unsigned char AT26D_Unprotect(At26 *pAt26);
+
+extern unsigned char AT26D_EraseChip(At26 *pAt26);
+
+extern unsigned char AT26D_EraseBlock(At26 *pAt26, unsigned int address);
+
+extern unsigned char AT26D_Write(
+ At26 *pAt26,
+ unsigned char *pData,
+ unsigned int size,
+ unsigned int address);
+
+extern unsigned char AT26D_Read(
+ At26 *pAt26,
+ unsigned char *pData,
+ unsigned int size,
+ unsigned int address);
+
+#endif // #ifndef AT26D_H
+
diff --git a/memories/spi-flash/at45.c b/memories/spi-flash/at45.c new file mode 100644 index 0000000..142e7ed --- /dev/null +++ b/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/memories/spi-flash/at45.h b/memories/spi-flash/at45.h new file mode 100644 index 0000000..ef7ef26 --- /dev/null +++ b/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
+
diff --git a/memories/spi-flash/at45d.c b/memories/spi-flash/at45d.c new file mode 100644 index 0000000..228a1b6 --- /dev/null +++ b/memories/spi-flash/at45d.c @@ -0,0 +1,223 @@ +/* ----------------------------------------------------------------------------
+ * 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 "at45d.h"
+#include <board.h>
+#include <utility/assert.h>
+
+//------------------------------------------------------------------------------
+// Local functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Wait for transfer to finish calling the SPI driver ISR (interrupts are
+/// disabled).
+/// \param pAt45 Pointer to an AT45 driver instance.
+//------------------------------------------------------------------------------
+static void AT45D_Wait(At45 *pAt45)
+{
+ SANITY_CHECK(pAt45);
+
+ // Wait for transfer to finish
+ while (AT45_IsBusy(pAt45)) {
+
+ SPID_Handler(pAt45->pSpid);
+ }
+}
+
+
+//------------------------------------------------------------------------------
+// Global functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Waits for the At45 to be ready to accept new commands.
+/// \param pAt45 Pointer to a At45 driver instance.
+//------------------------------------------------------------------------------
+void AT45D_WaitReady(At45 *pAt45)
+{
+ unsigned char ready = 0;
+
+ SANITY_CHECK(pAt45);
+
+ // Poll device until it is ready
+ while (!ready) {
+
+ ready = AT45_STATUS_READY(AT45D_GetStatus(pAt45));
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Retrieves and returns the At45 current status, or 0 if an error
+/// happened.
+/// \param pAt45 Pointer to a At45 driver instance.
+//------------------------------------------------------------------------------
+unsigned char AT45D_GetStatus(At45 *pAt45)
+{
+ unsigned char error;
+ unsigned char status;
+
+ SANITY_CHECK(pAt45);
+
+ // Issue a status register read command
+ error = AT45_SendCommand(pAt45, AT45_STATUS_READ, 1, &status, 1, 0, 0, 0);
+ ASSERT(!error, "-F- AT45_GetStatus: Failed to issue command.\n\r");
+
+ // Wait for command to terminate
+ while (AT45_IsBusy(pAt45)) {
+
+ AT45D_Wait(pAt45);
+ }
+
+ return status;
+}
+
+//------------------------------------------------------------------------------
+/// Reads data from the At45 inside the provided buffer. Since a continuous
+/// read command is used, there is no restriction on the buffer size and read
+/// address.
+/// \param pAt45 Pointer to a At45 driver instance.
+/// \param pBuffer Data buffer.
+/// \param size Number of bytes to read.
+/// \param address Address at which data shall be read.
+//------------------------------------------------------------------------------
+void AT45D_Read(
+ At45 *pAt45,
+ unsigned char *pBuffer,
+ unsigned int size,
+ unsigned int address)
+{
+ unsigned char error;
+
+ SANITY_CHECK(pAt45);
+ SANITY_CHECK(pBuffer);
+
+ // Issue a continuous read array command
+ error = AT45_SendCommand(pAt45, AT45_CONTINUOUS_READ_LEG, 8, pBuffer, size, address, 0, 0);
+ ASSERT(!error, "-F- AT45_Read: Failed to issue command\n\r");
+
+ // Wait for the read command to execute
+ while (AT45_IsBusy(pAt45)) {
+
+ AT45D_Wait(pAt45);
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Writes data on the At45 at the specified address. Only one page of
+/// data is written that way; if the address is not at the beginning of the
+/// page, the data is written starting from this address and wraps around to
+/// the beginning of the page.
+/// \param pAt45 Pointer to a At45 driver instance.
+/// \param pBuffer Buffer containing the data to write.
+/// \param size Number of bytes to write.
+/// \param address Destination address on the At45.
+//------------------------------------------------------------------------------
+void AT45D_Write(
+ At45 *pAt45,
+ unsigned char *pBuffer,
+ unsigned int size,
+ unsigned int address)
+{
+ unsigned char error;
+
+ SANITY_CHECK(pAt45);
+ SANITY_CHECK(pBuffer);
+ SANITY_CHECK(size <= pAt45->pDesc->pageSize);
+
+ // Issue a page write through buffer 1 command
+ error = AT45_SendCommand(pAt45, AT45_PAGE_WRITE_BUF1, 4, pBuffer, size, address, 0, 0);
+ ASSERT(!error, "-F- AT45_Write: Could not issue command.\n\r");
+
+ // Wait until the command is sent
+ while (AT45_IsBusy(pAt45)) {
+
+ AT45D_Wait(pAt45);
+ }
+
+ // Wait until the At45 becomes ready again
+ AT45D_WaitReady(pAt45);
+}
+
+//------------------------------------------------------------------------------
+/// Erases a page of data at the given address in the At45.
+/// \param pAt45 Pointer to a At45 driver instance.
+/// \param address Address of page to erase.
+//------------------------------------------------------------------------------
+void AT45D_Erase(At45 *pAt45, unsigned int address)
+{
+ unsigned char error;
+
+ SANITY_CHECK(pAt45);
+
+ // Issue a page erase command.
+ error = AT45_SendCommand(pAt45, AT45_PAGE_ERASE, 4, 0, 0, address, 0, 0);
+ ASSERT(!error, "-F- AT45_Erase: Could not issue command.\n\r");
+
+ // Wait for end of transfer
+ while (AT45_IsBusy(pAt45)) {
+
+ AT45D_Wait(pAt45);
+ }
+
+ // Poll until the At45 has completed the erase operation
+ AT45D_WaitReady(pAt45);
+}
+
+//------------------------------------------------------------------------------
+/// Configure power-of-2 binary page size in the At45.
+/// \param pAt45 Pointer to a At45 driver instance.
+//------------------------------------------------------------------------------
+
+void AT45D_BinaryPage(At45 *pAt45)
+{
+ unsigned char error;
+ unsigned char opcode[3]= {AT45_BINARY_PAGE};
+ SANITY_CHECK(pAt45);
+
+ // Issue a binary page command.
+
+ error = AT45_SendCommand(pAt45, AT45_BINARY_PAGE_FIRST_OPCODE, 1, opcode, 3, 0, 0, 0);
+
+ ASSERT(!error, "-F- AT45_Erase: Could not issue command.\n\r");
+
+ // Wait for end of transfer
+ while (AT45_IsBusy(pAt45)) {
+
+ AT45D_Wait(pAt45);
+ }
+
+ // Wait until the At45 becomes ready again
+ AT45D_WaitReady(pAt45);
+}
diff --git a/memories/spi-flash/at45d.h b/memories/spi-flash/at45d.h new file mode 100644 index 0000000..b512445 --- /dev/null +++ b/memories/spi-flash/at45d.h @@ -0,0 +1,86 @@ +/* ----------------------------------------------------------------------------
+ * 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 AT45 Dataflash driver is based on the corresponding AT45 driver.
+/// A AT45 instance has to be initialized using the Dataflash levle function
+/// AT45_Configure(). AT45 Dataflash can be automatically detected using
+/// the AT45_FindDevice() function. Then AT45 dataflash operations such as
+/// read, write and erase DF can be launched using AT45_SendCommand function
+/// with corresponding AT45 command set.
+///
+/// !!!Usage
+///
+/// -# Reads data from the At45 at the specified address using AT45D_Read().
+/// -# Writes data on the At45 at the specified address using AT45D_Write().
+/// -# Erases a page of data at the given address using AT45D_Erase().
+/// -# Poll until the At45 has completed of corresponding operations using
+/// AT45D_WaitReady().
+/// -# Retrieves and returns the At45 current using AT45D_GetStatus().
+//------------------------------------------------------------------------------
+
+
+#ifndef AT45D_H
+#define AT45D_H
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include "at45.h"
+
+//------------------------------------------------------------------------------
+// Global functions
+//------------------------------------------------------------------------------
+
+extern void AT45D_WaitReady(At45 *pAt45);
+
+extern unsigned char AT45D_GetStatus(At45 *pAt45);
+
+extern void AT45D_Read(
+ At45 *pAt45,
+ unsigned char *pBuffer,
+ unsigned int size,
+ unsigned int address);
+
+extern void AT45D_Write(
+ At45 *pAt45,
+ unsigned char *pBuffer,
+ unsigned int size,
+ unsigned int address);
+
+extern void AT45D_Erase(At45 *pAt45, unsigned int address);
+
+extern void AT45D_BinaryPage(At45 *pAt45);
+
+#endif //#ifndef AT45D_H
+
diff --git a/memories/spi-flash/spi-flash.dir b/memories/spi-flash/spi-flash.dir new file mode 100644 index 0000000..c2f3c2f --- /dev/null +++ b/memories/spi-flash/spi-flash.dir @@ -0,0 +1,37 @@ +/* ----------------------------------------------------------------------------
+ * 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.
+ * ----------------------------------------------------------------------------
+ */
+
+//------------------------------------------------------------------------------
+/// \dir
+///
+/// !!!Purpose
+///
+/// Contains the %spi-flash driver for the SPI compatible Dataflash.
+//------------------------------------------------------------------------------
+
diff --git a/memories/spi-flash/spid.c b/memories/spi-flash/spid.c new file mode 100644 index 0000000..3dd0409 --- /dev/null +++ b/memories/spi-flash/spid.c @@ -0,0 +1,215 @@ +/* ----------------------------------------------------------------------------
+ * 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 "spid.h"
+#include <board.h>
+
+//------------------------------------------------------------------------------
+// Macros
+//------------------------------------------------------------------------------
+
+/// Write PMC register
+#define WRITE_PMC(pPmc, regName, value) pPmc->regName = (value)
+
+/// Write SPI register
+#define WRITE_SPI(pSpi, regName, value) pSpi->regName = (value)
+
+/// Read SPI registers
+#define READ_SPI(pSpi, regName) (pSpi->regName)
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Initializes the Spid structure and the corresponding SPI hardware.
+/// Always returns 0.
+/// \param pSpid Pointer to a Spid instance.
+/// \param pSpiHw Associated SPI peripheral.
+/// \param spiId SPI peripheral identifier.
+//------------------------------------------------------------------------------
+unsigned char SPID_Configure(Spid *pSpid, AT91S_SPI *pSpiHw, unsigned char spiId)
+{
+ // Initialize the SPI structure
+ pSpid->pSpiHw = pSpiHw;
+ pSpid->spiId = spiId;
+ pSpid->semaphore = 1;
+ pSpid->pCurrentCommand = 0;
+
+ // Enable the SPI clock
+ WRITE_PMC(AT91C_BASE_PMC, PMC_PCER, (1 << pSpid->spiId));
+
+ // Execute a software reset of the SPI twice
+ WRITE_SPI(pSpiHw, SPI_CR, AT91C_SPI_SWRST);
+ WRITE_SPI(pSpiHw, SPI_CR, AT91C_SPI_SWRST);
+
+ // Configure SPI in Master Mode with No CS selected !!!
+ WRITE_SPI(pSpiHw, SPI_MR, AT91C_SPI_MSTR | AT91C_SPI_MODFDIS | AT91C_SPI_PCS);
+
+ // Disable the PDC transfer
+ WRITE_SPI(pSpiHw, SPI_PTCR, AT91C_PDC_RXTDIS | AT91C_PDC_TXTDIS);
+
+ // Enable the SPI
+ WRITE_SPI(pSpiHw, SPI_CR, AT91C_SPI_SPIEN);
+
+ // Enable the SPI clock
+ WRITE_PMC(AT91C_BASE_PMC, PMC_PCDR, (1 << pSpid->spiId));
+
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// Configures the parameters for the device corresponding to the cs.
+/// \param pSpid Pointer to a Spid instance.
+/// \param cs number corresponding to the SPI chip select.
+/// \param csr SPI_CSR value to setup.
+//------------------------------------------------------------------------------
+void SPID_ConfigureCS(Spid *pSpid, unsigned char cs, unsigned int csr)
+{
+ AT91S_SPI *pSpiHw = pSpid->pSpiHw;
+ WRITE_SPI(pSpiHw, SPI_CSR[cs], csr);
+}
+
+//------------------------------------------------------------------------------
+/// Starts a SPI master transfer. This is a non blocking function. It will
+/// return as soon as the transfer is started.
+/// Returns 0 if the transfer has been started successfully; otherwise returns
+/// SPID_ERROR_LOCK is the driver is in use, or SPID_ERROR if the command is not
+/// valid.
+/// \param pSpid Pointer to a Spid instance.
+/// \param pCommand Pointer to the SPI command to execute.
+//------------------------------------------------------------------------------
+unsigned char SPID_SendCommand(Spid *pSpid, SpidCmd *pCommand)
+{
+ AT91S_SPI *pSpiHw = pSpid->pSpiHw;
+ unsigned int spiMr;
+
+ // Try to get the dataflash semaphore
+ if (pSpid->semaphore == 0) {
+
+ return SPID_ERROR_LOCK;
+ }
+ pSpid->semaphore--;
+
+ // Enable the SPI clock
+ WRITE_PMC(AT91C_BASE_PMC, PMC_PCER, (1 << pSpid->spiId));
+
+ // Disable transmitter and receiver
+ WRITE_SPI(pSpiHw, SPI_PTCR, AT91C_PDC_RXTDIS | AT91C_PDC_TXTDIS);
+
+ // Write to the MR register
+ spiMr = READ_SPI(pSpiHw, SPI_MR);
+ spiMr |= AT91C_SPI_PCS;
+ spiMr &= ~((1 << pCommand->spiCs) << 16);
+ WRITE_SPI(pSpiHw, SPI_MR, spiMr);
+
+ // Initialize the two SPI PDC buffer
+ WRITE_SPI(pSpiHw, SPI_RPR, (int) pCommand->pCmd);
+ WRITE_SPI(pSpiHw, SPI_RCR, pCommand->cmdSize);
+ WRITE_SPI(pSpiHw, SPI_TPR, (int) pCommand->pCmd);
+ WRITE_SPI(pSpiHw, SPI_TCR, pCommand->cmdSize);
+
+ WRITE_SPI(pSpiHw, SPI_RNPR, (int) pCommand->pData);
+ WRITE_SPI(pSpiHw, SPI_RNCR, pCommand->dataSize);
+ WRITE_SPI(pSpiHw, SPI_TNPR, (int) pCommand->pData);
+ WRITE_SPI(pSpiHw, SPI_TNCR, pCommand->dataSize);
+
+ // Initialize the callback
+ pSpid->pCurrentCommand = pCommand;
+
+ // Enable transmitter and receiver
+ WRITE_SPI(pSpiHw, SPI_PTCR, AT91C_PDC_RXTEN | AT91C_PDC_TXTEN);
+
+ // Enable buffer complete interrupt
+ WRITE_SPI(pSpiHw, SPI_IER, AT91C_SPI_RXBUFF);
+
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// The SPI_Handler must be called by the SPI Interrupt Service Routine with the
+/// corresponding Spi instance.
+/// The SPI_Handler will unlock the Spi semaphore and invoke the upper application
+/// callback.
+/// \param pSpid Pointer to a Spid instance.
+//------------------------------------------------------------------------------
+void SPID_Handler(Spid *pSpid)
+{
+ SpidCmd *pSpidCmd = pSpid->pCurrentCommand;
+ AT91S_SPI *pSpiHw = pSpid->pSpiHw;
+ volatile unsigned int spiSr;
+
+ // Read the status register
+ spiSr = READ_SPI(pSpiHw, SPI_SR);
+ if (spiSr & AT91C_SPI_RXBUFF) {
+
+ // Disable transmitter and receiver
+ WRITE_SPI(pSpiHw, SPI_PTCR, AT91C_PDC_RXTDIS | AT91C_PDC_TXTDIS);
+
+ // Disable the SPI clock
+ WRITE_PMC(AT91C_BASE_PMC, PMC_PCDR, (1 << pSpid->spiId));
+
+ // Disable buffer complete interrupt
+ WRITE_SPI(pSpiHw, SPI_IDR, AT91C_SPI_RXBUFF);
+
+ // Release the dataflash semaphore
+ pSpid->semaphore++;
+
+ // Invoke the callback associated with the current command
+ if (pSpidCmd && pSpidCmd->callback) {
+
+ pSpidCmd->callback(0, pSpidCmd->pArgument);
+ }
+
+ // Nothing must be done after. A new DF operation may have been started
+ // in the callback function.
+ }
+}
+
+//------------------------------------------------------------------------------
+/// Returns 1 if the SPI driver is currently busy executing a command; otherwise
+/// returns 0.
+/// \param pSpid Pointer to a SPI driver instance.
+//------------------------------------------------------------------------------
+unsigned char SPID_IsBusy(const Spid *pSpid)
+{
+ if (pSpid->semaphore == 0) {
+
+ return 1;
+ }
+ else {
+
+ return 0;
+ }
+}
+
diff --git a/memories/spi-flash/spid.h b/memories/spi-flash/spid.h new file mode 100644 index 0000000..654a27e --- /dev/null +++ b/memories/spi-flash/spid.h @@ -0,0 +1,212 @@ +/* ----------------------------------------------------------------------------
+ * 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 Spi driver is a low level spi driver which performs SPI device Initializes,
+/// spi transfer and receive. It can be used by upper SPI driver such as AT45
+/// driver and AT26 driver.
+///
+/// !!!Usage
+///
+/// -# Initializes a SPI instance and the corresponding SPI hardware,
+/// Configure SPI in Master Mode using SPID_Configure().
+/// -# Configures the SPI characteristics (such as Clock Polarity, Phase,
+/// transfers delay and Baud Rate) for the device corresponding to the
+/// chip select using SPID_ConfigureCS().
+/// -# Starts a SPI master transfer using SPID_SendCommand().
+/// The transfer may perform in 2 ways (depending on the implement):
+/// -# The transfer is performed using the PDC channels.
+/// -# It enable the SPI clock.
+/// -# Set the corresponding peripheral chip select.
+/// -# Initialize the two SPI PDC buffers.
+/// - Initialize SPI_TPR and SPI_TCR with SPI command data and size
+/// to send command data first.
+/// - Initialize SPI_RPR and SPI_RCR with SPI command data and size
+/// as dummy value.
+/// - Initialize SPI_TNPR and SPI_TNCR with rest of the data to be
+/// transfered.(if the data specified in cmd structure)
+/// - Initialize SPI_RNPR and SPI_RNCR with rest of the data to be
+/// received.(if the data specified in cmd structure)
+/// -# Initialize the callback function if specified.
+/// -# Enable transmitter and receiver.
+/// -# The transfer is performed using the DMA channels 0 & 1.
+/// -# Enable SPI peripheral.
+/// -# Set the corresponding peripheral chip select.
+/// -# Initialize the two DMA channels.
+/// - Configure channel 0 as RX channel.
+/// - Source DMA interface is SPI RX.
+/// - Source is HW triggerred.
+/// - Configure channel 1 as TX channel
+/// - Destination DMA interface is SPI TX
+/// - Destination is HW triggerred.
+/// - Initialize DMA Link List of two items for RX.
+/// - Source address pointer to SPI_RDR.
+/// - Destination address pointer to command or data position.
+/// - Transfer width always BYTE, size is command or data length.
+/// - Uses Peripheral-to-Memory Flow Control.
+/// - Set DMA channel 0 DMA_DSCR to RX link list.
+/// - Set DMA channel 0 DMA_CTRLB to 0 to load link list.
+/// - Initialize DMA Link List of two items for TX.
+/// - Source address pointer to command or data position.
+/// - Destination address pointer to SPI_TDR.
+/// - Transfer width always BYTE, size is command or data length.
+/// - Uses Memory-to-Peripheral Flow Control.
+/// - Set DMA channel 1 DMA_DSCR to TX link list.
+/// - Set DMA channel 1 DMA_CTRLB to 0 to load link list.
+/// -# Initialize the callback function if specified.
+/// -# Enable transmitter and receiver.
+/// -# Enable two DMA channels at the same time.
+///
+/// - Example for sending a command to the dataflash through the SPI.
+/// \code
+/// /// Build command to be sent.
+/// ...
+/// // Send Command and data through the SPI
+/// if (SPID_SendCommand(pAt45->pSpid, pCommand)) {
+/// return AT45_ERROR_SPI;
+/// }
+/// \endcode
+/// -# The SPID_Handler() must be called by the SPI Interrupt Service Routine
+/// with the corresponding Spi instance. It is invokes to check for pending
+/// interrupts.
+/// - Example for initializing SPI interrupt handler in upper application.
+/// \code
+/// AIC_ConfigureIT(AT91C_ID_SPI, 0, SPI_Handler);
+/// \endcode
+//------------------------------------------------------------------------------
+
+#ifndef SPID_H
+#define SPID_H
+
+//------------------------------------------------------------------------------
+// Headers
+//------------------------------------------------------------------------------
+
+#include <board.h>
+
+//------------------------------------------------------------------------------
+// Definitions
+//------------------------------------------------------------------------------
+
+/// An unspecified error has occured.
+#define SPID_ERROR 1
+
+/// SPI driver is currently in use.
+#define SPID_ERROR_LOCK 2
+
+//------------------------------------------------------------------------------
+// Macros
+//------------------------------------------------------------------------------
+
+/// Calculates the value of the SCBR field of the Chip Select Register given
+/// MCK and SPCK.
+#define SPID_CSR_SCBR(mck, spck) ((((mck) / (spck)) << 8) & AT91C_SPI_SCBR)
+
+/// Calculates the value of the DLYBS field of the Chip Select Register given
+/// the delay in ns and MCK.
+#define SPID_CSR_DLYBS(mck, delay) \
+ ((((((delay) * ((mck) / 1000000)) / 1000) + 1) << 16) & AT91C_SPI_DLYBS)
+
+/// Calculates the value of the DLYBCT field of the Chip Select Register given
+/// the delay in ns and MCK.
+#define SPID_CSR_DLYBCT(mck, delay) \
+ ((((((delay) / 32 * ((mck) / 1000000)) / 1000) + 1) << 24) & AT91C_SPI_DLYBCT)
+
+//------------------------------------------------------------------------------
+// Types
+//------------------------------------------------------------------------------
+
+/// SPI transfer complete callback.
+typedef void (*SpidCallback )(unsigned char, void *);
+
+//------------------------------------------------------------------------------
+/// Spi Transfer Request prepared by the application upper layer. This structure
+/// is sent to the SPI_SendCommand function to start the transfer. At the end of
+/// the transfer, the callback is invoked by the interrupt handler.
+//------------------------------------------------------------------------------
+typedef struct _SpidCmd {
+
+ /// Pointer to the command data.
+ unsigned char *pCmd;
+ /// Command size in bytes.
+ unsigned char cmdSize;
+ /// Pointer to the data to be sent.
+ unsigned char *pData;
+ /// Data size in bytes.
+ unsigned short dataSize;
+ /// SPI chip select.
+ unsigned char spiCs;
+ /// Callback function invoked at the end of transfer.
+ SpidCallback callback;
+ /// Callback arguments.
+ void *pArgument;
+
+} SpidCmd;
+
+//------------------------------------------------------------------------------
+/// Constant structure associated with SPI port. This structure prevents
+/// client applications to have access in the same time.
+//------------------------------------------------------------------------------
+typedef struct {
+
+ /// Pointer to SPI Hardware registers
+ AT91S_SPI *pSpiHw;
+ /// SPI Id as defined in the product datasheet
+ char spiId;
+ /// Current SpiCommand being processed
+ SpidCmd *pCurrentCommand;
+ /// Mutual exclusion semaphore.
+ volatile char semaphore;
+
+} Spid;
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+
+extern unsigned char SPID_Configure(
+ Spid *pSpid,
+ AT91S_SPI *pSpiHw,
+ unsigned char spiId);
+
+extern void SPID_ConfigureCS(Spid *pSpid, unsigned char cs, unsigned int csr);
+
+extern unsigned char SPID_SendCommand(
+ Spid *pSpid,
+ SpidCmd *pCommand);
+
+extern void SPID_Handler(Spid *pSpid);
+
+extern unsigned char SPID_IsBusy(const Spid *pSpid);
+
+#endif // #ifndef SPID_H
+
diff --git a/memories/spi-flash/spid_dma.c b/memories/spi-flash/spid_dma.c new file mode 100644 index 0000000..dc8139d --- /dev/null +++ b/memories/spi-flash/spid_dma.c @@ -0,0 +1,392 @@ +/* ----------------------------------------------------------------------------
+ * 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 "spid.h"
+#include <board.h>
+#include <dma/dma.h>
+#include <drivers/dmad/dmad.h>
+#include <irq/irq.h>
+
+//------------------------------------------------------------------------------
+// Defines
+//------------------------------------------------------------------------------
+
+/// DMA Link List size
+#define SIZE_LL 2
+
+/// DMA Width BYTE
+#define DMA_WIDTH 0
+
+//------------------------------------------------------------------------------
+// Macros
+//------------------------------------------------------------------------------
+
+/// Write PMC register
+#define WRITE_PMC(pPmc, regName, value) pPmc->regName = (value)
+
+/// Write SPI register
+#define WRITE_SPI(pSpi, regName, value) pSpi->regName = (value)
+
+/// Read SPI registers
+#define READ_SPI(pSpi, regName) (pSpi->regName)
+
+/// Enable Peripheral
+#define PERIPH_ENABLE(id) \
+ WRITE_PMC(AT91C_BASE_PMC, PMC_PCER, (1 << (id)))
+/// Disable Peripheral
+#define PERIPH_DISABLE(id) \
+ WRITE_PMC(AT91C_BASE_PMC, PMC_PCDR, (1 << (id)))
+
+
+//------------------------------------------------------------------------------
+// Local Variables
+//------------------------------------------------------------------------------
+
+/// Linked lists for multi transfer buffer chaining structure instance.
+static DmaLinkList dmaTxLinkList[SIZE_LL];
+static DmaLinkList dmaRxLinkList[SIZE_LL];
+
+//------------------------------------------------------------------------------
+// Local functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Configure the DMA Channels: 0 RX, 1 TX.
+/// Channels are disabled after configure.
+//------------------------------------------------------------------------------
+static void configureDmaChannels(void)
+{
+ // Enable DMA Peripheral
+ PERIPH_ENABLE(AT91C_ID_HDMA);
+ // Enable DMA
+ DMA_Enable();
+
+ // Free status
+ DMA_DisableIt(0xFFFFFFFF);
+ DMA_GetChannelStatus();
+ DMA_GetStatus();
+ DMA_DisableChannels((1 << DMA_CHANNEL_0) | (1 << DMA_CHANNEL_1));
+ // RX channel 0
+ DMA_SetConfiguration(DMA_CHANNEL_0,
+ AT91C_HDMA_SRC_PER_2
+ | AT91C_HDMA_DST_PER_2
+ | AT91C_HDMA_SRC_H2SEL_HW
+ | AT91C_HDMA_DST_H2SEL_SW
+ | AT91C_HDMA_SOD_ENABLE
+ | AT91C_HDMA_FIFOCFG_LARGESTBURST
+ );
+
+ // TX channel 1
+ DMA_SetConfiguration(DMA_CHANNEL_1,
+ AT91C_HDMA_SRC_PER_1
+ | AT91C_HDMA_DST_PER_1
+ | AT91C_HDMA_SRC_H2SEL_SW
+ | AT91C_HDMA_DST_H2SEL_HW
+ | AT91C_HDMA_SOD_ENABLE
+ | AT91C_HDMA_FIFOCFG_LARGESTBURST
+ );
+}
+
+//------------------------------------------------------------------------------
+/// Configure the DMA source and destination with Linker List mode.
+/// \param pCommand Pointer to command
+//------------------------------------------------------------------------------
+static void configureLinkList(AT91S_SPI *pSpiHw,
+ SpidCmd *pCommand)
+{
+ // Setup RX Link List
+ dmaRxLinkList[0].sourceAddress = (unsigned int)&pSpiHw->SPI_RDR;
+ dmaRxLinkList[0].destAddress = (unsigned int)pCommand->pCmd;
+ dmaRxLinkList[0].controlA = pCommand->cmdSize
+ | AT91C_HDMA_SRC_WIDTH_BYTE
+ | AT91C_HDMA_DST_WIDTH_BYTE
+ ;
+ dmaRxLinkList[0].controlB = 0
+ //| AT91C_HDMA_SIF_0
+ //| AT91C_HDMA_DIF_0
+ | AT91C_HDMA_SRC_DSCR_FETCH_FROM_MEM
+ | AT91C_HDMA_DST_DSCR_FETCH_FROM_MEM
+ | AT91C_HDMA_FC_PER2MEM
+ | AT91C_HDMA_SRC_ADDRESS_MODE_FIXED
+ | AT91C_HDMA_DST_ADDRESS_MODE_INCR
+ ;
+ dmaTxLinkList[0].sourceAddress = (unsigned int)pCommand->pCmd;
+ dmaTxLinkList[0].destAddress = (unsigned int)&pSpiHw->SPI_TDR;
+ dmaTxLinkList[0].controlA = pCommand->cmdSize
+ | AT91C_HDMA_SRC_WIDTH_BYTE
+ | AT91C_HDMA_DST_WIDTH_BYTE
+ ;
+ dmaTxLinkList[0].controlB = 0
+ //| AT91C_HDMA_SIF_0
+ //| AT91C_HDMA_DIF_0
+ | AT91C_HDMA_SRC_DSCR_FETCH_FROM_MEM
+ | AT91C_HDMA_DST_DSCR_FETCH_FROM_MEM
+ | AT91C_HDMA_FC_MEM2PER
+ | AT91C_HDMA_SRC_ADDRESS_MODE_INCR
+ | AT91C_HDMA_DST_ADDRESS_MODE_FIXED
+ ;
+ // Only command
+ if (pCommand->pData == 0) {
+
+ dmaRxLinkList[0].descriptor = 0;
+ dmaTxLinkList[0].descriptor = 0;
+ }
+ // Command & Data
+ else {
+
+ dmaRxLinkList[0].descriptor = (unsigned int)&dmaRxLinkList[1];
+ dmaRxLinkList[1].sourceAddress = (unsigned int)&pSpiHw->SPI_RDR;
+ dmaRxLinkList[1].destAddress = (unsigned int)pCommand->pData;
+ dmaRxLinkList[1].controlA = pCommand->dataSize
+ | AT91C_HDMA_SRC_WIDTH_BYTE
+ | AT91C_HDMA_DST_WIDTH_BYTE
+ ;
+ dmaRxLinkList[1].controlB = 0
+ //| AT91C_HDMA_SIF_0
+ //| AT91C_HDMA_DIF_0
+ | AT91C_HDMA_SRC_DSCR_FETCH_DISABLE
+ | AT91C_HDMA_DST_DSCR_FETCH_DISABLE
+ | AT91C_HDMA_FC_PER2MEM
+ | AT91C_HDMA_SRC_ADDRESS_MODE_FIXED
+ | AT91C_HDMA_DST_ADDRESS_MODE_INCR
+ ;
+ dmaRxLinkList[1].descriptor = 0;
+
+ dmaTxLinkList[0].descriptor = (unsigned int)&dmaTxLinkList[1];
+ dmaTxLinkList[1].sourceAddress = (unsigned int)pCommand->pData;
+ dmaTxLinkList[1].destAddress = (unsigned int)&pSpiHw->SPI_TDR;
+ dmaTxLinkList[1].controlA = pCommand->dataSize
+ | AT91C_HDMA_SRC_WIDTH_BYTE
+ | AT91C_HDMA_DST_WIDTH_BYTE
+ ;
+ dmaTxLinkList[1].controlB = 0
+ //| AT91C_HDMA_SIF_0
+ //| AT91C_HDMA_DIF_0
+ | AT91C_HDMA_SRC_DSCR_FETCH_DISABLE
+ | AT91C_HDMA_DST_DSCR_FETCH_DISABLE
+ | AT91C_HDMA_FC_MEM2PER
+ | AT91C_HDMA_SRC_ADDRESS_MODE_INCR
+ | AT91C_HDMA_DST_ADDRESS_MODE_FIXED
+ ;
+ dmaTxLinkList[1].descriptor = 0;
+ }
+
+
+ // Setup registers
+ DMA_SetDescriptorAddr(DMA_CHANNEL_0, (unsigned int)&dmaRxLinkList[0]);
+ DMA_SetDescriptorAddr(DMA_CHANNEL_1, (unsigned int)&dmaTxLinkList[0]);
+ AT91C_BASE_HDMA->HDMA_CH[DMA_CHANNEL_0].HDMA_CTRLB = 0
+ | AT91C_HDMA_SRC_DSCR_FETCH_FROM_MEM
+ | AT91C_HDMA_DST_DSCR_FETCH_FROM_MEM
+ ;
+ AT91C_BASE_HDMA->HDMA_CH[DMA_CHANNEL_1].HDMA_CTRLB = 0
+ | AT91C_HDMA_SRC_DSCR_FETCH_FROM_MEM
+ | AT91C_HDMA_DST_DSCR_FETCH_FROM_MEM
+ ;
+}
+
+//------------------------------------------------------------------------------
+// Exported functions
+//------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------
+/// Initializes the Spid structure and the corresponding SPI & DMA hardware.
+/// The driver will uses DMA channel 0 for RX and DMA channel 1 for TX.
+/// The DMA channels are freed automatically when no SPI command processing.
+/// \param pSpid Pointer to a Spid instance.
+/// \param pSpiHw Associated SPI peripheral.
+/// \param spiId SPI peripheral identifier.
+/// \return Always 0.
+//------------------------------------------------------------------------------
+unsigned char SPID_Configure(Spid *pSpid, AT91S_SPI *pSpiHw, unsigned char spiId)
+{
+ // Initialize the SPI structure
+ pSpid->pSpiHw = pSpiHw;
+ pSpid->spiId = spiId;
+ pSpid->semaphore = 1;
+ pSpid->pCurrentCommand = 0;
+
+ // Enable the SPI Peripheral
+ PERIPH_ENABLE(pSpid->spiId);
+
+ // Execute a software reset of the SPI twice
+ WRITE_SPI(pSpiHw, SPI_CR, AT91C_SPI_SWRST);
+ WRITE_SPI(pSpiHw, SPI_CR, AT91C_SPI_SWRST);
+
+ // Configure SPI in Master Mode with No CS selected !!!
+ WRITE_SPI(pSpiHw, SPI_MR, AT91C_SPI_MSTR | AT91C_SPI_MODFDIS | AT91C_SPI_PCS);
+
+ // Disable the PDC transfer
+ #if !defined(at91sam3u)
+ WRITE_SPI(pSpiHw, SPI_PTCR, AT91C_PDC_RXTDIS | AT91C_PDC_TXTDIS);
+ #endif
+
+ // Disable the SPI TX & RX
+ WRITE_SPI(pSpiHw, SPI_CR, AT91C_SPI_SPIDIS);
+
+ // Disable the SPI Peripheral
+ PERIPH_DISABLE(pSpid->spiId);
+
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// Configures the parameters for the device corresponding to the cs.
+/// \param pSpid Pointer to a Spid instance.
+/// \param cs number corresponding to the SPI chip select.
+/// \param csr SPI_CSR value to setup.
+//------------------------------------------------------------------------------
+void SPID_ConfigureCS(Spid *pSpid, unsigned char cs, unsigned int csr)
+{
+ AT91S_SPI *pSpiHw = pSpid->pSpiHw;
+
+ // Enable the SPI Peripheral
+ PERIPH_ENABLE(pSpid->spiId);
+
+ // Write CS
+ WRITE_SPI(pSpiHw, SPI_CSR[cs], csr);
+
+ // Disable the SPI Peripheral
+ PERIPH_DISABLE(pSpid->spiId);
+}
+
+//------------------------------------------------------------------------------
+/// Starts a SPI master transfer. This is a non blocking function. It will
+/// return as soon as the transfer is started.
+/// Returns 0 if the transfer has been started successfully; otherwise returns
+/// SPID_ERROR_LOCK is the driver is in use, or SPID_ERROR if the command is not
+/// valid.
+/// \param pSpid Pointer to a Spid instance.
+/// \param pCommand Pointer to the SPI command to execute.
+//------------------------------------------------------------------------------
+unsigned char SPID_SendCommand(Spid *pSpid, SpidCmd *pCommand)
+{
+ AT91S_SPI *pSpiHw = pSpid->pSpiHw;
+ unsigned int spiMr;
+
+ // Try to get the dataflash semaphore
+ if (pSpid->semaphore == 0) {
+
+ return SPID_ERROR_LOCK;
+ }
+ pSpid->semaphore--;
+
+ // Enable the SPI Peripheral
+ PERIPH_ENABLE(pSpid->spiId);
+
+ // Disable PDC transmitter and receiver
+ #if !defined(at91sam3u)
+ WRITE_SPI(pSpiHw, SPI_PTCR, AT91C_PDC_RXTDIS | AT91C_PDC_TXTDIS);
+ #endif
+
+ // Write to the MR register
+ spiMr = READ_SPI(pSpiHw, SPI_MR);
+ spiMr |= AT91C_SPI_PCS;
+ spiMr &= ~((1 << pCommand->spiCs) << 16);
+ WRITE_SPI(pSpiHw, SPI_MR, spiMr);
+
+ // Initialize DMA controller using channel 0 for RX, 1 for TX.
+ configureDmaChannels();
+ configureLinkList(pSpiHw, pCommand);
+
+ // Initialize the callback
+ pSpid->pCurrentCommand = pCommand;
+
+ // Enable the SPI TX & RX
+ WRITE_SPI(pSpiHw, SPI_CR, AT91C_SPI_SPIEN);
+
+ // Start DMA 0(RX) && 1(TX)
+ DMA_EnableChannels((1 << DMA_CHANNEL_0) | (1 << DMA_CHANNEL_1));
+
+ // Enable DMA Interrupts
+ DMA_EnableIt( (DMA_CBTC << DMA_CHANNEL_0)
+ | (DMA_CBTC << DMA_CHANNEL_1));
+
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+/// SPI DMA transfer ISR, Handle RX complete
+//------------------------------------------------------------------------------
+void SPID_Handler(Spid *pSpid)
+{
+ unsigned int dmaStatus;
+ SpidCmd *pSpidCmd = pSpid->pCurrentCommand;
+ AT91S_SPI *pSpiHw = pSpid->pSpiHw;
+
+ dmaStatus = DMA_GetStatus();
+
+ if ((dmaStatus & AT91C_CBTC) == 0)
+ return;
+
+ if ((dmaStatus & (DMA_CBTC << DMA_CHANNEL_0)) == 0)
+ return;
+
+ // Disable the SPI TX & RX
+ WRITE_SPI(pSpiHw, SPI_CR, AT91C_SPI_SPIDIS);
+ // Disable the SPI Peripheral
+ PERIPH_DISABLE(pSpid->spiId);
+
+ // Disable DMA
+ DMA_Disable();
+ // Disable DMA Peripheral
+ PERIPH_DISABLE(AT91C_ID_HDMA);
+
+ // Release the dataflash semaphore
+ pSpid->semaphore++;
+
+ // Invoke the callback associated with the current command
+ if (pSpidCmd && pSpidCmd->callback) {
+
+ pSpidCmd->callback(0, pSpidCmd->pArgument);
+ }
+
+}
+
+//------------------------------------------------------------------------------
+/// Returns 1 if the SPI driver is currently busy executing a command; otherwise
+/// returns 0.
+/// \param pSpid Pointer to a SPI driver instance.
+//------------------------------------------------------------------------------
+unsigned char SPID_IsBusy(const Spid *pSpid)
+{
+ if (pSpid->semaphore == 0) {
+
+ return 1;
+ }
+ else {
+
+ return 0;
+ }
+}
+
|