diff options
| author | Harald Welte <laforge@gnumonks.org> | 2011-07-24 10:59:32 +0200 | 
|---|---|---|
| committer | Harald Welte <laforge@gnumonks.org> | 2011-07-24 10:59:32 +0200 | 
| commit | 7268260e100caf8efb12193b12442574c5d4b193 (patch) | |
| tree | d8315c9f66a8b894dda8ca6c6c590d5cb7e9b50d | |
| parent | 7dd5963915d405866595439aef4c47b8eee83edf (diff) | |
import 'memories' part of at91lib from serialflash-example
| -rw-r--r-- | at91lib/memories/spi-flash/at26.c | 222 | ||||
| -rw-r--r-- | at91lib/memories/spi-flash/at26.h | 252 | ||||
| -rw-r--r-- | at91lib/memories/spi-flash/spid.c | 215 | ||||
| -rw-r--r-- | at91lib/memories/spi-flash/spid.h | 183 | 
4 files changed, 872 insertions, 0 deletions
| diff --git a/at91lib/memories/spi-flash/at26.c b/at91lib/memories/spi-flash/at26.c new file mode 100644 index 0000000..d7934c9 --- /dev/null +++ b/at91lib/memories/spi-flash/at26.c @@ -0,0 +1,222 @@ +/* ----------------------------------------------------------------------------
 + *         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.
 +#define SPCK            1000000
 +
 +/// 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, 1 * 1024 * 1024, 256, 64 * 1024, AT26_BLOCK_ERASE_64K},
 +    {"AT25DF161"  , 0x0002461F, 2 * 1024 * 1024, 256, 64 * 1024, AT26_BLOCK_ERASE_64K},
 +    {"AT26DF081A" , 0x0001451F, 1 * 1024 * 1024, 256, 64 * 1024, AT26_BLOCK_ERASE_64K},
 +    {"AT26DF0161" , 0x0000461F, 2 * 1024 * 1024, 256, 64 * 1024, AT26_BLOCK_ERASE_64K},
 +    {"AT26DF161A" , 0x0001461F, 2 * 1024 * 1024, 256, 64 * 1024, AT26_BLOCK_ERASE_64K},
 +    {"AT26DF321 " , 0x0000471F, 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/at91lib/memories/spi-flash/at26.h b/at91lib/memories/spi-flash/at26.h new file mode 100644 index 0000000..4e3aa6d --- /dev/null +++ b/at91lib/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/at91lib/memories/spi-flash/spid.c b/at91lib/memories/spi-flash/spid.c new file mode 100644 index 0000000..3dd0409 --- /dev/null +++ b/at91lib/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/at91lib/memories/spi-flash/spid.h b/at91lib/memories/spi-flash/spid.h new file mode 100644 index 0000000..5852c1c --- /dev/null +++ b/at91lib/memories/spi-flash/spid.h @@ -0,0 +1,183 @@ +/* ----------------------------------------------------------------------------
 + *         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 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.
 +///    -# 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 SPI_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
 +
 | 
