1
0
Fork 0
mirror of https://github.com/opentx/opentx.git synced 2025-07-23 00:05:17 +03:00

Some ARM SDcard files

This commit is contained in:
bsongis 2012-05-05 14:17:17 +00:00
parent 3708915dc8
commit b9c24d8ac3
5 changed files with 2810 additions and 0 deletions

View file

@ -290,6 +290,7 @@ ifeq ($(PCB), ARM)
BOARDSRC = board_ersky9x.cpp
EXTRABOARDSRC = ersky9x/core_cm3.c ersky9x/board_lowlevel.c ersky9x/crt.c ersky9x/vectors_sam3s.c
# ersky9x/ff.c ersky9x/diskio_sam3s.c ersky9x/Media.c ersky9x/ccsbcs.c ersky9x/sdcard.c ersky9x/MEDSdcard.c
CPPSRC += ersky9x/sdmmc_spi.c ersky9x/sdspi.c
EEPROMSRC = eeprom_arm.cpp
PULSESSRC = pulses_arm.cpp
CPPSRC += ersky9x/audio.cpp haptic.cpp

1410
src/ersky9x/sdmmc_spi.c Normal file

File diff suppressed because it is too large Load diff

443
src/ersky9x/sdmmc_spi.h Normal file
View file

@ -0,0 +1,443 @@
/* ----------------------------------------------------------------------------
* 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.
* ----------------------------------------------------------------------------
*/
//------------------------------------------------------------------------------
/// \page "sdmmc_spi"
///
/// !Purpose
///
/// Implementation for sdcard spi mode physical layer driver. Supply a set of sdcard spi mode's
/// interface.
///
/// !Usage
///
/// -# SD_Init: Run the SDcard initialization sequence
/// -# SD_SPI_Init : Run the SDcard SPI Mode initialization sequence
/// -# SD_Stop: Stop the SDcard by sending Cmd12
/// -# SD_ReadBlock : Read blocks of data
/// -# SD_WriteBlock : Write blocks of data
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
/// \page "sdcard spi mode initialization and identification"
///
/// !Purpose
///
/// sdcard spi mode initialization and identification sequence
///
/// !Description
/// - Host sends Cmd0 to do card reset, card is in "idle state".
/// - Host sends Cmd8 and checks the response of the card, only sdcard supports physical
/// layer version 2.00 will response correctly to Cmd8, and this command is mandatory to be
/// sent before ACmd41 for sdcard which support physical layer version 2.00, to enable new
/// functions or to validate a dual-voltage card.
/// - refer to "If Cmd8 response ok" branch for the initialize of sdcard 2.0.
/// - refer to "If Cmd8 response fail" branch for the initialize of sdcard 1.x, mmc card, sdcard2.0
/// with invalid voltage.
/// - If Cmd8 response ok
/// - Host sends Cmd58 to read OCR register to validate the voltage.
/// - If the response to Cmd58 is fail, initialize ends, the card is put into inactive state.
/// - If the response to Cmd58 is ok, continue to the next step.
/// - Host sends ACmd41* with argument "HCS" equal to "1".
/// - If the response to ACmd41 failed, it means the card does not match the voltage
/// desired by the host, the card will be put into inactive state, initialize ends.
/// - If the response with "CCS" equal to "1", the card is a version 2.0 high capacity sdcard,
/// refer to "Card Initialize" for the succeeding initialize sequence.
/// - If the response with "CCS" equal to "0", the card is a version 2.0 standard capacity sdcard.
/// refer to "Card Initialize" for the succeeding initialize sequence.
/// - If Cmd8 response fail
/// - Host sends Cmd58 to read OCR register to validate the voltage.
/// - If the response to Cmd58 is fail, initialize ends, the card is put into inactive state.
/// - If the response to Cmd58 is ok, continue to the next step.
/// - Host sends ACmd41* argument "HCS" equal to "0".
/// - If the response to ACmd41 ok, the card is a version 1.x sdcard, refer to "Card Initialize" for
/// the succeeding initialize sequence.
/// - If the response to ACmd41 fails
/// - Host sends Cmd0 to reset card.
/// - Host sends Cmd1 to card.
/// - If card has response to Cmd1, the card is a MMC card, refer to "Card Initialize" for the
/// succeeding initialize sequence.
/// - If card has no response to Cmd1, the card is either an unknown card or a card does
/// not match host's voltage, the initialize ends.
/// - Card Initialize
/// - At this stage, the initialization and identification process is over, the following steps are done
/// for the sdcard's succeeding operation.
/// - Host sends Cmd59 to turn sdcard's CRC option off.
/// - Host sends Cmd9 to get the Card Specific Data (CSD).
///
/// \note Send Cmd55 before send ACmd41. \endnote
/// \note sdcard include ver 1.x sdcard, ver2.0 standard capacity sdcard, ver2.0 high capacity sdcard \endnote
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
/// \page "sdcard spi mode write"
///
/// !Purpose
///
/// sdcard spi mode write process
///
/// !Description
/// - Make sure sdcard is under "transfer state", if the sdcard is under other state, host will send
/// Cmd12 or use stop transmission token to stop multiple block write, and to transit sdcard to
/// "stand-by state".
/// - Host sends Cmd13 to check sdcard's status, to make sure sdcard is "ready-for-data".
/// - Host sends Cmd25 to do multiple blocks write, the address here is different between high capacity
/// sdcard and normal sdcard, the address of SDHC is equal to the block number, while normal sdcard's
/// address is equal to block number times 512.
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
/// \page "sdcard spi mode read"
///
/// !Purpose
///
/// sdcard spi mode read process
///
/// !Description
/// - Make sure sdcard is under "transfer state", if the sdcard is under other state, host will send
/// Cmd12 or use stop transmission token to stop multiple block read and to transit sdcard to
/// "stand-by state".
/// - Host sends Cmd13 to check sdcard's status, to make sure sdcard is "ready-for-data".
/// - Host sends Cmd18 to do multiple blocks read, the address here is different between high capacity
/// sdcard and normal sdcard, the address of SDHC is equal to the block number, while normal sdcard's
/// address is equal to block number times 512.
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
/// \page "sdhc"
///
/// !Purpose
///
/// highlight of sdhc
///
/// !Sdhc initialization and identification
///
/// - Refer to page "sdcard spi mode initialization and identification" for the initialization and identification
/// sequence of a sdhc.
///
/// !Functional difference between sdhc and standard capacity sdcard
///
/// - Command argument is different:
/// - Sdhc uses block address format in memory access commands*, block length is fixed to 512 bytes.
/// - Standard capacity sdcard uses byte address format in memory access commands, block length
/// is defined in Cmd16.
/// - Partial access and misalign access are disabled in sdhc as the block address is used.
/// - Sdhc does not support write-protected commands (Cmd28, Cmd29, Cmd30).
///
/// \note Memory access commands means block read commands (CMD17, CMD18), block write commands
/// (CMD24, CMD25), and block erase commands (CMD32, CMD33).
///
//------------------------------------------------------------------------------
#ifndef SDCARD_H
#define SDCARD_H
//------------------------------------------------------------------------------
// Constants
//------------------------------------------------------------------------------
/// There was an error with the SD driver.
#define SD_ERROR_DRIVER 1
/// The SD card did not answer the command.
#define SD_ERROR_NORESPONSE 2
/// The SD card did not answer the command.
#define SD_ERROR_NOT_INITIALIZED 3
/// The SD card is busy
#define SD_ERROR_BUSY 4
/// The operation is not supported
#define SD_ERROR_NOT_SUPPORT 5
/// SD card block size in bytes.
#define SD_BLOCK_SIZE 512
/// SD card block size binary shift value
#define SD_BLOCK_SIZE_BIT 9
//- MMC Card Command Types
/// Broadcast commands (bc), no response
#define MMC_CCT_BC 0
/// Broadcase commands with response (bcr)
#define MMC_CCT_BCR 1
/// Addressed commands (ac), no data transfer on DAT lines
#define MMC_CCT_AC 2
/// Addressed data transfer commands (adtc), data transfer on DAT lines
#define MMC_CCT_ADTC 3
//- MMC Card Command Classes (CCC)
/// Class 0: basic
#define MMC_CCC_BASIC 0
/// Class 1: stream read
#define MMC_CCC_STREAM_READ 1
/// Class 2: block read
#define MMC_CCC_BLOCK_READ 2
/// Class 3: stream write
#define MMC_CCC_STREAM_WRITE 3
/// Class 4: block write
#define MMC_CCC_BLOCK_WRITE 4
/// Class 5: erase
#define MMC_CCC_ERASE 5
/// Class 6: write protection
#define MMC_CCC_WRITE_PROTECTION 6
/// Class 7: lock card
#define MMC_CCC_LOCK_CARD 7
/// Class 8: application specific
#define MMC_CCC_APP_SPEC 8
/// Class 9: I/O mode
#define MMC_CCC_IO_MODE 9
//- MMC/SD Card Command Response Type
/// R1 (normal response command), 48bits
#define MMC_RESP_R1 1
#define SD_RESP_R1 MMC_RESP_R1
/// R1b: busy signal transmitted on the data line DAT0
#define MMC_RESP_R1b 1
#define SD_RESP_R1b MMC_RESP_R1b
/// R2: 136bits, CID, CSD register
#define MMC_RESP_R2 2
#define SD_RESP_R2 MMC_RESP_R2
/// R3: 48bits, OCR
#define MMC_RESP_R3 3
#define SD_RESP_R3 MMC_RESP_R3
/// R4 (Fast I/O), 48bits
#define MMC_RESP_R4 4
/// R5 (Interrupt request), 48bits
#define MMC_RESP_R5 5
/// R6 (Published RCA response), 48bits
#define SD_RESP_R6 6
/// R7 (Card interface condition), 48bits
#define SD_RESP_R7 7
//- MMC Card CMD6 access mode
#define MMC_SWITCH_CMDSET 0
#define MMC_SWITCH_SETBITS 1
#define MMC_SWITCH_CLRBITS 2
#define MMC_SWITCH_WRITE 3
//-MMC Boot partition enable
/// Boot partition 1 enabled for boot
#define MMC_BOOT_PART_1 1
/// Boot partition 2 enabled for boot
#define MMC_BOOT_PART_2 2
/// User area enabled for boot
#define MMC_BOOT_PART_USER 7
//-MMC Boot partition access
/// R/W boot partition 1
#define MMC_BOOT_ACC_PART1 1
/// R/W boot partition 2
#define MMC_BOOT_ACC_PART2 2
//------------------------------------------------------------------------------
// Macros
//------------------------------------------------------------------------------
// CID register access macros.
#define SD_CID(pSd, bitfield, bits) ( (pSd->cid[3-(bitfield)/32] >> ((bitfield)%32)) & ((1 << (bits)) - 1))
#define SD_CID_MID(pSd) SD_CID(pSd, 120, 8) ///< Manufacturer ID
#define SD_CID_BGA(pSd) SD_CID(pSd, 112, 2) ///< Card/BGA(eMMC)
#define SD_CID_CBS(pSd) SD_CID(pSd, 112, 2) ///< Card/BGA(eMMC)
#define SD_CID_OID_BYTE_1(pSd) SD_CID(pSd, 112, 8) ///< OEM/Application ID byte 1
#define SD_CID_OID_BYTE_0(pSd) SD_CID(pSd, 104, 8) ///< OEM/Application ID byte 0
#define SD_CID_PNM_BYTE_4(pSd) SD_CID(pSd, 96, 8) ///< Product revision byte 4
#define SD_CID_PNM_BYTE_3(pSd) SD_CID(pSd, 88, 8) ///< Product revision byte 3
#define SD_CID_PNM_BYTE_2(pSd) SD_CID(pSd, 80, 8) ///< Product revision byte 2
#define SD_CID_PNM_BYTE_1(pSd) SD_CID(pSd, 72, 8) ///< Product revision byte 1
#define SD_CID_PNM_BYTE_0(pSd) SD_CID(pSd, 64, 8) ///< Product revision byte 0
#define SD_CID_PRV_1(pSd) SD_CID(pSd, 24, 8) ///< Product serial number 1
#define SD_CID_PRV_2(pSd) SD_CID(pSd, 32,24) ///< Product serial number 2
#define SD_CID_MDT_YEAR(pSd) (SD_CID(pSd, 12, 8))+2000///< Manufacturing date year
#define SD_CID_MDT_MONTH(pSd) SD_CID(pSd, 8, 4) ///< Manufacturing date month
#define SD_CID_CRC(pSd) SD_CID(pSd, 1, 7) ///< CRC7 checksum
// CSD register access macros.
#define SD_CSD(pSd, bitfield, bits) ((((pSd)->csd)[3-(bitfield)/32] >> ((bitfield)%32)) & ((1 << (bits)) - 1))
#define SD_CSD_STRUCTURE(pSd) SD_CSD(pSd, 126, 2) ///< CSD structure 00b Version 1.0 01b version 2.0 High Cap
#define SD_CSD_SPEC_VERS(pSd) SD_CSD(pSd, 122, 4) ///< System Specification Version Number
#define SD_CSD_TAAC(pSd) SD_CSD(pSd, 112, 8) ///< Data read-access-time-1
#define SD_CSD_NSAC(pSd) SD_CSD(pSd, 104, 8) ///< Data read access-time-2 in CLK cycles
#define SD_CSD_TRAN_SPEED(pSd) SD_CSD(pSd, 96, 8) ///< Max. data transfer rate
#define SD_CSD_CCC(pSd) SD_CSD(pSd, 84, 12) ///< Card command class
#define SD_CSD_READ_BL_LEN(pSd) SD_CSD(pSd, 80, 4) ///< Max. read data block length
#define SD_CSD_READ_BL_PARTIAL(pSd) SD_CSD(pSd, 79, 1) ///< Bartial blocks for read allowed
#define SD_CSD_WRITE_BLK_MISALIGN(pSd) SD_CSD(pSd, 78, 1) ///< Write block misalignment
#define SD_CSD_READ_BLK_MISALIGN(pSd) SD_CSD(pSd, 77, 1) ///< Read block misalignment
#define SD_CSD_DSR_IMP(pSd) SD_CSD(pSd, 76, 1) ///< DSP implemented
#define SD_CSD_C_SIZE(pSd) ((SD_CSD(pSd, 72, 2) << 10) + \
(SD_CSD(pSd, 64, 8) << 2) + \
SD_CSD(pSd, 62, 2)) ///< Device size
#define SD_CSD_C_SIZE_HC(pSd) ((SD_CSD(pSd, 64, 6) << 16) + \
(SD_CSD(pSd, 56, 8) << 8) + \
SD_CSD(pSd, 48, 8)) ///< Device size v2.0 High Capacity
#define SD_CSD_VDD_R_CURR_MIN(pSd) SD_CSD(pSd, 59, 3) ///< Max. read current @VDD min
#define SD_CSD_VDD_R_CURR_MAX(pSd) SD_CSD(pSd, 56, 3) ///< Max. read current @VDD max
#define SD_CSD_VDD_W_CURR_MIN(pSd) SD_CSD(pSd, 53, 3) ///< Max. write current @VDD min
#define SD_CSD_VDD_W_CURR_MAX(pSd) SD_CSD(pSd, 50, 3) ///< Max. write current @VDD max
#define SD_CSD_C_SIZE_MULT(pSd) SD_CSD(pSd, 47, 3) ///< Device size multiplier
#define SD_CSD_ERASE_BLK_EN(pSd) SD_CSD(pSd, 46, 1) ///< Erase single block enable
#define SD_CSD_SECTOR_SIZE(pSd) ((SD_CSD(pSd, 40, 6) << 1) + SD_CSD(pSd, 39, 1)) ///< Erase sector size
#define SD_CSD_WP_GRP_SIZE(pSd) SD_CSD(pSd, 32, 7) ///< Write protect group size
#define SD_CSD_WP_GRP_ENABLE(pSd) SD_CSD(pSd, 31, 1) ///< write protect group enable
#define SD_CSD_R2W_FACTOR(pSd) SD_CSD(pSd, 26, 3) ///< Write speed factor
#define SD_CSD_WRITE_BL_LEN(pSd) ((SD_CSD(pSd, 24, 2) << 2) + SD_CSD(pSd, 22, 2)) ///< Max write block length
#define SD_CSD_WRITE_BL_PARTIAL(pSd) SD_CSD(pSd, 21, 1) ///< Partial blocks for write allowed
#define SD_CSD_CONTENT_PROT_APP(pSd) SD_CSD(pSd, 16, 1) ///< File format group
#define SD_CSD_FILE_FORMAT_GRP(pSd) SD_CSD(pSd, 15, 1) ///< File format group
#define SD_CSD_COPY(pSd) SD_CSD(pSd, 14, 1) ///< Copy flag (OTP)
#define SD_CSD_PERM_WRITE_PROTECT(pSd) SD_CSD(pSd, 13, 1) ///< Permanent write protect
#define SD_CSD_TMP_WRITE_PROTECT(pSd) SD_CSD(pSd, 12, 1) ///< Temporary write protection
#define SD_CSD_FILE_FORMAT(pSd) SD_CSD(pSd, 11, 2) ///< File format
#define SD_CSD_ECC(pSd) SD_CSD(pSd, 8, 2) ///< CRC
#define SD_CSD_CRC(pSd) SD_CSD(pSd, 1, 7) ///< CRC
#define SD_CSD_MULT(pSd) (1 << (SD_CSD_C_SIZE_MULT(pSd) + 2))
#define SD_CSD_BLOCKNR(pSd) ((SD_CSD_C_SIZE(pSd) + 1) * SD_CSD_MULT(pSd))
#define SD_CSD_BLOCKNR_HC(pSd) ((SD_CSD_C_SIZE_HC(pSd) + 1) * 1024)
#define SD_CSD_BLOCK_LEN(pSd) (1 << SD_CSD_READ_BL_LEN(pSd))
#define SD_CSD_TOTAL_SIZE(pSd) (SD_CSD_BLOCKNR(pSd) * SD_CSD_BLOCK_LEN(pSd))
#define SD_CSD_TOTAL_SIZE_HC(pSd) ((SD_CSD_C_SIZE_HC(pSd) + 1) * 512* 1024)
#define SD_TOTAL_SIZE(pSd) ((pSd)->totalSize)
#define SD_TOTAL_BLOCK(pSd) ((pSd)->blockNr)
// SCR register access macros.
#define SD_SCR_BUS_WIDTHS(pScr) ((pScr[1] >> 16) & 0xF) ///< Describes all the DAT bus that are supported by this card
#define SD_SCR_BUS_WIDTH_4BITS (1 << 1) ///< 4bit Bus Width is supported
#define SD_SCR_BUS_WIDTH_1BIT (1 << 0) ///< 1bit Bus Width is supported
//------------------------------------------------------------------------------
// Types
//------------------------------------------------------------------------------
/// SD end-of-transfer callback function.
typedef void (*SdCallback)(unsigned char status, void *pCommand);
//------------------------------------------------------------------------------
/// SD Transfer Request prepared by the application upper layer. This structure
/// is sent to the SD_SendCommand function to start the transfer. At the end of
/// the transfer, the callback is invoked by the interrupt handler.
//------------------------------------------------------------------------------
typedef struct _SdCmd {
/// Command status.
volatile char status;
/// Command code.
unsigned int cmd;
/// Command argument.
unsigned int arg;
/// Data buffer.
unsigned char *pData;
/// Size of data buffer in bytes.
unsigned short blockSize;
/// Number of blocks to be transfered
unsigned short nbBlock;
/// Indicate if continue to transfer data
unsigned char conTrans;
/// Indicates if the command is a read operation.
unsigned char isRead;
/// Response buffer.
unsigned int *pResp;
/// SD card response type.
unsigned char resType;
/// Optional user-provided callback function.
SdCallback callback;
/// Optional argument to the callback function.
void *pArg;
} SdCmd;
//------------------------------------------------------------------------------
/// SD driver structure. Holds the internal state of the SD driver and
/// prevents parallel access to a SPI peripheral.
//------------------------------------------------------------------------------
typedef struct {
/// Pointer to a SPI peripheral.
//AT91S_MCI *pSdHw;
/// SPI peripheral identifier.
unsigned char spiId;
/// MCI HW mode
unsigned char mciMode;
/// Pointer to currently executing command.
SdCmd *pCommand;
/// Mutex.
volatile char semaphore;
} SdDriver;
//------------------------------------------------------------------------------
/// Sdcard driver structure. It holds the current command being processed and
/// the SD card address.
//------------------------------------------------------------------------------
typedef struct _SdCard {
/// Pointer to the underlying MCI driver.
SdDriver *pSdDriver;
/// Current MCI command being processed.
SdCmd command;
/// SD card current address.
unsigned short cardAddress;
/// Card-specific data.
unsigned int csd[4];
/// Previous access block number.
unsigned int preBlock;
/// State after sd command complete
unsigned char state;
/// Card type
unsigned char cardType;
/// Card total size
unsigned int totalSize;
/// Card block number
unsigned int blockNr;
/// Card access mode
unsigned char mode;
} SdCard;
//------------------------------------------------------------------------------
// Global functions
//------------------------------------------------------------------------------
extern unsigned char SD_Init(SdCard *pSd,
SdDriver *pSdDriver);
extern unsigned char SD_ReadBlock(
SdCard *pSd,
unsigned int address,
unsigned short nbBlocks,
unsigned char *pData);
extern unsigned char SD_WriteBlock(
SdCard *pSd,
unsigned int address,
unsigned short nbBlocks,
const unsigned char *pData);
extern unsigned char SD_Stop(SdCard *pSd, SdDriver *pSdDriver);
#endif //#ifndef SDCARD_H

781
src/ersky9x/sdspi.c Normal file
View file

@ -0,0 +1,781 @@
/* ----------------------------------------------------------------------------
* 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 "sdspi.h"
//#include <utility/assert.h>
//#include <utility/trace.h>
//#include <board.h>
//#include <crc7.h>
//#include <crc-itu-t.h>
//#include <crc16.h>
//#include <crc-ccitt.h>
#include <string.h>
//------------------------------------------------------------------------------
// Macros
//------------------------------------------------------------------------------
/// Transfer is pending.
#define SDSPI_STATUS_PENDING 1
/// Transfer has been aborted because an error occured.
#define SDSPI_STATUS_ERROR 2
/// SPI driver is currently in use.
#define SDSPI_ERROR_LOCK 1
// Data Tokens
#define SDSPI_START_BLOCK_1 0xFE // Single/Multiple read, single write
#define SDSPI_START_BLOCK_2 0xFC // Multiple block write
#define SDSPI_STOP_TRAN 0xFD // Cmd12
//------------------------------------------------------------------------------
// Exported functions
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
/// Initializes the SD Spi structure and the corresponding SPI hardware.
/// \param pSpid Pointer to a Spid instance.
/// \param pSpiHw Associated SPI peripheral.
/// \param spiId SPI peripheral identifier.
//------------------------------------------------------------------------------
void SDSPI_Configure(SdSpi *pSdSpi,
AT91PS_SPI pSpiHw,
unsigned char spiId)
{
// Initialize the SPI structure
pSdSpi->pSpiHw = pSpiHw;
pSdSpi->spiId = spiId;
pSdSpi->semaphore = 1;
// Enable the SPI clock
// BSS replaced by below AT91C_BASE_PMC->PMC_PCER = (1 << pSdSpi->spiId);
PMC->PMC_PCER0 = (1 << pSdSpi->spiId);
// Execute a software reset of the SPI twice
pSpiHw->SPI_CR = SPI_CR_SWRST; // BSS AT91C_SPI_SWRST;
pSpiHw->SPI_CR = SPI_CR_SWRST; // BSS AT91C_SPI_SWRST;
// Configure SPI in Master Mode with No CS selected !!!
pSpiHw->SPI_MR = SPI_MR_MSTR | SPI_MR_MODFDIS | SPI_MR_PCS; // BSS AT91C_SPI_MSTR | AT91C_SPI_MODFDIS | AT91C_SPI_PCS;
// Disables the receiver PDC transfer requests
// Disables the transmitter PDC transfer requests.
pSpiHw->SPI_PTCR = SPI_PTCR_RXTDIS | SPI_PTCR_TXTDIS; // BSS AT91C_PDC_RXTDIS | AT91C_PDC_TXTDIS;
// Enable the SPI
pSpiHw->SPI_CR = SPI_CR_SPIEN; // BSS AT91C_SPI_SPIEN;
// Disable the SPI clock
// BSS replaced by below AT91C_BASE_PMC->PMC_PCDR = (1 << pSdSpi->spiId);
PMC->PMC_PCDR0 = (1 << pSdSpi->spiId);
}
//------------------------------------------------------------------------------
/// Configures the parameters for the device corresponding to the cs.
/// \param pSdSpi Pointer to a SdSpi instance.
/// \param cs number corresponding to the SPI chip select.
/// \param csr SPI_CSR value to setup.
//------------------------------------------------------------------------------
void SDSPI_ConfigureCS(SdSpi *pSdSpi, unsigned char cs, unsigned int csr)
{
unsigned int spiMr;
AT91S_SPI *pSpiHw = pSdSpi->pSpiHw;
// Enable the SPI clock
// BSS below AT91C_BASE_PMC->PMC_PCER = (1 << pSdSpi->spiId);
PMC->PMC_PCER0 = (1 << pSdSpi->spiId);
//TRACE_DEBUG("CSR[%d]=0x%8X\n\r", cs, csr);
pSpiHw->SPI_CSR[cs] = csr;
//jcb to put in sendcommand
// Write to the MR register
spiMr = pSpiHw->SPI_MR;
spiMr |= SPI_MR_PCS; // TODO AT91C_SPI_PCS;
spiMr &= ~((1 << cs) << 16);
pSpiHw->SPI_MR = spiMr;
// Disable the SPI clock
// BSS below AT91C_BASE_PMC->PMC_PCDR = (1 << pSdSpi->spiId);
PMC->PMC_PCDR0 = (1 << pSdSpi->spiId);
}
//------------------------------------------------------------------------------
/// Use PDC for SPI data transfer.
/// Return 0 if no error, otherwise return error status.
/// \param pSdSpi Pointer to a SdSpi instance.
/// \param pData Data pointer.
/// \param size Data transfer byte count.
//------------------------------------------------------------------------------
unsigned char SDSPI_PDC(SdSpi *pSdSpi, unsigned char *pData, unsigned int size)
{
AT91PS_SPI pSpiHw = pSdSpi->pSpiHw;
unsigned int spiIer;
if (pSdSpi->semaphore == 0) {
TRACE_DEBUG("No semaphore\n\r");
return SDSPI_ERROR_LOCK;
}
pSdSpi->semaphore--;
// Enable the SPI clock
// BSS below AT91C_BASE_PMC->PMC_PCER = (1 << pSdSpi->spiId);
PMC->PMC_PCER0 = (1 << pSdSpi->spiId);
// Disable transmitter and receiver
pSpiHw->SPI_PTCR = SPI_PTCR_RXTDIS | SPI_PTCR_TXTDIS; // BSS AT91C_PDC_RXTDIS | AT91C_PDC_TXTDIS;
// Receive Pointer Register
pSpiHw->SPI_RPR = (int)pData;
// Receive Counter Register
pSpiHw->SPI_RCR = size;
// Transmit Pointer Register
pSpiHw->SPI_TPR = (int) pData;
// Transmit Counter Register
pSpiHw->SPI_TCR = size;
spiIer = SPI_IER_RXBUFF; // TODO AT91C_SPI_RXBUFF;
// Enable transmitter and receiver
pSpiHw->SPI_PTCR = SPI_PTCR_RXTEN | SPI_PTCR_TXTEN; // BSS AT91C_PDC_RXTEN | AT91C_PDC_TXTEN;
// Interrupt enable shall be done after PDC TXTEN and RXTEN
pSpiHw->SPI_IER = spiIer;
return 0;
}
//! Should be moved to a new file
//------------------------------------------------------------------------------
/// Read data on SPI data bus;
/// Returns 1 if read fails, returns 0 if no error.
/// \param pSdSpi Pointer to a SD SPI driver instance.
/// \param pData Data pointer.
/// \param size Data size.
//------------------------------------------------------------------------------
unsigned char SDSPI_Read(SdSpi *pSdSpi, unsigned char *pData, unsigned int size)
{
unsigned char error;
// MOSI should hold high during read, or there will be wrong data in received data.
memset(pData, 0xff, size);
error = SDSPI_PDC(pSdSpi, pData, size);
while(SDSPI_IsBusy(pSdSpi) == 1);
if( error == 0 ) {
return 0;
}
else {
TRACE_DEBUG("PB SDSPI_Read\n\r");
return 1;
}
}
//------------------------------------------------------------------------------
/// Write data on SPI data bus;
/// Returns 1 if write fails, returns 0 if no error.
/// \param pSdSpi Pointer to a SD SPI driver instance.
/// \param pData Data pointer.
/// \param size Data size.
//------------------------------------------------------------------------------
unsigned char SDSPI_Write(SdSpi *pSdSpi, unsigned char *pData, unsigned int size)
{
unsigned char error;
error = SDSPI_PDC(pSdSpi, pData, size);
while(SDSPI_IsBusy(pSdSpi) == 1);
if( error == 0 ) {
return 0;
}
else {
TRACE_DEBUG("PB SDSPI_Write\n\r");
return 1;
}
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
unsigned char SDSPI_WaitDataBusy(SdSpi *pSdSpi)
{
unsigned char busyData;
SDSPI_Read(pSdSpi, &busyData, 1);
if (busyData != 0xff) {
return 1;
}
else {
return 0;
}
}
/* Table for CRC-7 (polynomial x^7 + x^3 + 1) */
const uint8_t crc7_syndrome_table[256] = {
0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f,
0x48, 0x41, 0x5a, 0x53, 0x6c, 0x65, 0x7e, 0x77,
0x19, 0x10, 0x0b, 0x02, 0x3d, 0x34, 0x2f, 0x26,
0x51, 0x58, 0x43, 0x4a, 0x75, 0x7c, 0x67, 0x6e,
0x32, 0x3b, 0x20, 0x29, 0x16, 0x1f, 0x04, 0x0d,
0x7a, 0x73, 0x68, 0x61, 0x5e, 0x57, 0x4c, 0x45,
0x2b, 0x22, 0x39, 0x30, 0x0f, 0x06, 0x1d, 0x14,
0x63, 0x6a, 0x71, 0x78, 0x47, 0x4e, 0x55, 0x5c,
0x64, 0x6d, 0x76, 0x7f, 0x40, 0x49, 0x52, 0x5b,
0x2c, 0x25, 0x3e, 0x37, 0x08, 0x01, 0x1a, 0x13,
0x7d, 0x74, 0x6f, 0x66, 0x59, 0x50, 0x4b, 0x42,
0x35, 0x3c, 0x27, 0x2e, 0x11, 0x18, 0x03, 0x0a,
0x56, 0x5f, 0x44, 0x4d, 0x72, 0x7b, 0x60, 0x69,
0x1e, 0x17, 0x0c, 0x05, 0x3a, 0x33, 0x28, 0x21,
0x4f, 0x46, 0x5d, 0x54, 0x6b, 0x62, 0x79, 0x70,
0x07, 0x0e, 0x15, 0x1c, 0x23, 0x2a, 0x31, 0x38,
0x41, 0x48, 0x53, 0x5a, 0x65, 0x6c, 0x77, 0x7e,
0x09, 0x00, 0x1b, 0x12, 0x2d, 0x24, 0x3f, 0x36,
0x58, 0x51, 0x4a, 0x43, 0x7c, 0x75, 0x6e, 0x67,
0x10, 0x19, 0x02, 0x0b, 0x34, 0x3d, 0x26, 0x2f,
0x73, 0x7a, 0x61, 0x68, 0x57, 0x5e, 0x45, 0x4c,
0x3b, 0x32, 0x29, 0x20, 0x1f, 0x16, 0x0d, 0x04,
0x6a, 0x63, 0x78, 0x71, 0x4e, 0x47, 0x5c, 0x55,
0x22, 0x2b, 0x30, 0x39, 0x06, 0x0f, 0x14, 0x1d,
0x25, 0x2c, 0x37, 0x3e, 0x01, 0x08, 0x13, 0x1a,
0x6d, 0x64, 0x7f, 0x76, 0x49, 0x40, 0x5b, 0x52,
0x3c, 0x35, 0x2e, 0x27, 0x18, 0x11, 0x0a, 0x03,
0x74, 0x7d, 0x66, 0x6f, 0x50, 0x59, 0x42, 0x4b,
0x17, 0x1e, 0x05, 0x0c, 0x33, 0x3a, 0x21, 0x28,
0x5f, 0x56, 0x4d, 0x44, 0x7b, 0x72, 0x69, 0x60,
0x0e, 0x07, 0x1c, 0x15, 0x2a, 0x23, 0x38, 0x31,
0x46, 0x4f, 0x54, 0x5d, 0x62, 0x6b, 0x70, 0x79
};
// BSS crc functions added
static inline uint8_t crc7_byte(uint8_t crc, uint8_t data)
{
return crc7_syndrome_table[(crc << 1) ^ data];
}
uint8_t crc7(uint8_t crc, const uint8_t *buffer, size_t len)
{
while (len--)
crc = crc7_byte(crc, *buffer++);
return crc;
}
//------------------------------------------------------------------------------
/// Convert SD MCI command to a SPI mode command token.
/// \param pCmdToken Pointer to the SD command token.
/// \param arg SD command argument
//------------------------------------------------------------------------------
void SDSPI_MakeCmd(unsigned char *pCmdToken, unsigned int arg)
{
unsigned char sdCmdNum;
unsigned char crc = 0;
unsigned char crcPrev = 0;
sdCmdNum = 0x3f & *pCmdToken;
*pCmdToken = sdCmdNum | 0x40;
*(pCmdToken+1) = (arg >> 24) & 0xff;
*(pCmdToken+2) = (arg >> 16) & 0xff;
*(pCmdToken+3) = (arg >> 8) & 0xff;
*(pCmdToken+4) = arg & 0xff;
crc = crc7(crcPrev, (unsigned char *)(pCmdToken), 5);
*(pCmdToken+5) = (crc << 1) | 1;
}
//------------------------------------------------------------------------------
/// Get response after send SD command.
/// Return 0 if no error, otherwise indicate an error.
/// \param pSdSpi Pointer to the SD SPI instance.
/// \param pCommand Pointer to the SD command
//------------------------------------------------------------------------------
unsigned char SDSPI_GetCmdResp(SdSpi *pSdSpi, SdSpiCmd *pCommand)
{
unsigned char resp[8]; // response
unsigned char error;
unsigned int respRetry = 8; //NCR max 8, refer to card datasheet
memset(resp, 0, 8);
// Wait for response start bit.
do {
error = SDSPI_Read(pSdSpi, &resp[0], 1);
if (error) {
TRACE_DEBUG("\n\rpb SDSPI_GetCmdResp: 0x%X\n\r", error);
return error;
}
if ((resp[0]&0x80) == 0) {
break;
}
respRetry--;
} while(respRetry > 0);
switch (pCommand->resType) {
case 1:
*(pCommand->pResp) = resp[0];
break;
case 2:
error = SDSPI_Read(pSdSpi, &resp[1], 1);
if (error) {
return error;
}
*(pCommand->pResp) = resp[0]
| (resp[1] << 8);
break;
// Response 3, get OCR
case 3:
error = SDSPI_Read(pSdSpi, &resp[1], 4);
if (error) {
return error;
}
*(pCommand->pResp) = resp[0]
| (resp[1] << 8)
| (resp[2] << 16)
| (resp[3] << 24);
*(pCommand->pResp+1) = resp[4];
break;
case 7:
TRACE_DEBUG("case 7\n\r");
error = SDSPI_Read(pSdSpi, &resp[1], 4);
if (error) {
return error;
}
*(pCommand->pResp) = resp[0]
| (resp[1] << 8)
| (resp[2] << 16)
| (resp[3] << 24);
*(pCommand->pResp+1) = resp[4];
break;
default:
TRACE_DEBUG("PB default\n\r");
break;
}
return 0;
}
//------------------------------------------------------------------------------
/// Get response after send data.
/// Return 0 if no error, otherwise indicate an error.
/// \param pSdSpi Pointer to the SD SPI instance.
/// \param pCommand Pointer to the SD command
//------------------------------------------------------------------------------
unsigned char SDSPI_GetDataResp(SdSpi *pSdSpi, SdSpiCmd *pCommand)
{
unsigned char resp = 0; // response
unsigned char error;
unsigned int respRetry = 18; //NCR max 8, refer to card datasheet
// Wait for response start bit.
do {
error = SDSPI_Read(pSdSpi, &resp, 1);
if (error) {
return error;
}
if (((resp & 0x11) == 0x1) || ((resp & 0xf0) == 0))
break;
respRetry--;
} while(respRetry > 0);
//TRACE_DEBUG("SDSPI_GetDataResp 0x%X\n\r",resp);
return resp;
}
// BSS crc16 function added
const uint16_t crc_itu_t_table[256] = {
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
};
static inline uint16_t crc_itu_t_byte(uint16_t crc, const uint8_t data)
{
return (crc << 8) ^ crc_itu_t_table[((crc >> 8) ^ data) & 0xff];
}
uint16_t crc_itu_t(uint16_t crc, const uint8_t *buffer, size_t len)
{
while (len--)
crc = crc_itu_t_byte(crc, *buffer++);
return crc;
}
//------------------------------------------------------------------------------
/// 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
/// error.
/// \param pSdSpi Pointer to a SdSpi instance.
/// \param pCommand Pointer to the SPI command to execute.
//------------------------------------------------------------------------------
unsigned char SDSPI_SendCommand(SdSpi *pSdSpi, SdSpiCmd *pCommand)
{
// BSS AT91S_SPI *pSpiHw = pSdSpi->pSpiHw;
unsigned char CmdToken[6];
unsigned char *pData;
unsigned int blockSize;
unsigned int i;
unsigned char error;
unsigned char dataHeader;
unsigned int dataRetry1 = 100;
unsigned int dataRetry2 = 100;
unsigned char crc[2];
unsigned char crcPrev = 0;
unsigned char crcPrev2 = 0;
SANITY_CHECK(pSdSpi);
// BSS SANITY_CHECK(pSpiHw);
SANITY_CHECK(pCommand);
CmdToken[0] = pCommand->cmd & 0x3F;
pData = pCommand->pData;
blockSize = pCommand->blockSize;
SDSPI_MakeCmd((unsigned char *)&CmdToken, pCommand->arg);
// Command is now being executed
pSdSpi->pCommand = pCommand;
pCommand->status = SDSPI_STATUS_PENDING;
// Send the command
if((pCommand->conTrans == SPI_NEW_TRANSFER) || (blockSize == 0)) {
for(i = 0; i < 6; i++) {
error = SDSPI_Write(pSdSpi, &CmdToken[i], 1);
if (error) {
TRACE_DEBUG("Error: %d\n\r", error);
return error;
}
}
// Specific for Cmd12()
if ((pCommand->cmd & 0x3F) == 12) {
if( 1 == SDSPI_Wait(pSdSpi, 2) ) {
TRACE_DEBUG("Pb Send command 12\n\r");
}
}
if (pCommand->pResp) {
error = SDSPI_GetCmdResp(pSdSpi, pCommand);
if (error) {
TRACE_DEBUG("Error: %d\n\r", error);
return error;
}
}
}
if( (blockSize > 0) && (pCommand->nbBlock == 0) ) {
pCommand->nbBlock = 1;
}
// For data block operations
while (pCommand->nbBlock > 0) {
// If data block size is invalid, return error
if (blockSize == 0) {
TRACE_DEBUG("Block Size = 0\n\r");
return 1;
}
// DATA transfer from card to host
if (pCommand->isRead) {
do {
SDSPI_Read(pSdSpi, &dataHeader, 1);
dataRetry1 --;
if (dataHeader == SDSPI_START_BLOCK_1) {
break;
}
else if((dataHeader & 0xf0) == 0x00) {
pCommand->status = SDSPI_STATUS_ERROR;
TRACE_DEBUG("Data Error 0x%X!\n\r", dataHeader);
return 1;
}
} while(dataRetry1 > 0);
if (dataRetry1 == 0) {
TRACE_DEBUG("Timeout dataretry1\n\r");
return 1;
}
SDSPI_Read(pSdSpi, pData, blockSize);
// Specific for Cmd9()
if ((pCommand->cmd & 0x3f) != 0x9) {
SDSPI_Read(pSdSpi, crc, 2);
#ifdef SDSPI_CRC_ON
// Check data CRC
TRACE_DEBUG("Check Data CRC\n\r");
crcPrev = 0;
crcPrev2 = 0;
if (crc[0] != ((crc_itu_t(crcPrev, pData, blockSize) & 0xff00) >> 8 )
|| crc[1] != (crc_itu_t(crcPrev2, pData, blockSize) & 0xff)) {
TRACE_ERROR("CRC error 0x%X 0x%X 0x%X\n\r", \
crc[0], crc[1], crc_itu_t(pData, blockSize));
return 1;
}
#endif
}
}
// DATA transfer from host to card
else {
SDSPI_NCS(pSdSpi);
if ((pCommand->conTrans == SPI_CONTINUE_TRANSFER) || ((pCommand->cmd & 0x3f) == 25)) {
dataHeader = SDSPI_START_BLOCK_2;
}
else {
dataHeader = SDSPI_START_BLOCK_1;
}
crcPrev = 0;
crc[0] = (crc_itu_t(crcPrev, pData, blockSize) & 0xff00) >> 8;
crcPrev2 = 0;
crc[1] = (crc_itu_t(crcPrev2, pData, blockSize) & 0xff);
SDSPI_Write(pSdSpi, &dataHeader, 1);
SDSPI_Write(pSdSpi, pData, blockSize);
SDSPI_Write(pSdSpi, crc, 2);
// If status bits in data response is not "data accepted", return error
if ((SDSPI_GetDataResp(pSdSpi, pCommand) & 0xe) != 0x4) {
TRACE_ERROR("Write resp error!\n\r");
return 1;
}
do {
if (SDSPI_WaitDataBusy(pSdSpi) == 0) {
break;
}
dataRetry2--;
} while(dataRetry2 > 0);
}
pData += blockSize;
pCommand->nbBlock--;
}
if (pCommand->status == SDSPI_STATUS_PENDING) {
pCommand->status = 0;
}
//TRACE_DEBUG("end SDSPI_SendCommand\n\r");
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 pSdSpi Pointer to a SdSpi instance.
//------------------------------------------------------------------------------
void SDSPI_Handler(SdSpi *pSdSpi)
{
SdSpiCmd *pCommand = pSdSpi->pCommand;
AT91S_SPI *pSpiHw = pSdSpi->pSpiHw;
volatile unsigned int spiSr;
// Read the status register
spiSr = pSpiHw->SPI_SR;
if(spiSr & SPI_SR_RXBUFF/*BSS AT91C_SPI_RXBUFF*/) {
if (pCommand->status == SDSPI_STATUS_PENDING) {
pCommand->status = 0;
}
// Disable transmitter and receiver
pSpiHw->SPI_PTCR = SPI_PTCR_RXTDIS | SPI_PTCR_TXTDIS; // BSS AT91C_PDC_RXTDIS | AT91C_PDC_TXTDIS;
// Disable the SPI clock
// BSS below AT91C_BASE_PMC->PMC_PCDR = (1 << pSdSpi->spiId);
PMC->PMC_PCDR0 = (1 << pSdSpi->spiId);
// Disable buffer complete interrupt
pSpiHw->SPI_IDR = SPI_IDR_RXBUFF | SPI_IDR_ENDTX; // BSS AT91C_SPI_RXBUFF | AT91C_SPI_ENDTX;
// Release the SPI semaphore
pSdSpi->semaphore++;
}
// Invoke the callback associated with the current command
if (pCommand && pCommand->callback) {
pCommand->callback(0, pCommand);
}
}
//------------------------------------------------------------------------------
/// Returns 1 if the given SPI transfer is complete; otherwise returns 0.
/// \param pCommand Pointer to a SdSpiCmd instance.
//------------------------------------------------------------------------------
unsigned char SDSPI_IsTxComplete(SdSpiCmd *pCommand)
{
if (pCommand->status != SDSPI_STATUS_PENDING) {
if (pCommand->status != 0){
TRACE_DEBUG("SPI_IsTxComplete %d\n\r", pCommand->status);
}
return 1;
}
else {
return 0;
}
}
//------------------------------------------------------------------------------
/// Close a SPI driver instance and the underlying peripheral.
/// \param pSdSpi Pointer to a SD SPI driver instance.
//------------------------------------------------------------------------------
void SDSPI_Close(SdSpi *pSdSpi)
{
AT91S_SPI *pSpiHw = pSdSpi->pSpiHw;
SANITY_CHECK(pSdSpi);
SANITY_CHECK(pSpiHw);
// Enable the SPI clock
// BSS below AT91C_BASE_PMC->PMC_PCER = (1 << pSdSpi->spiId);
PMC->PMC_PCER0 = (1 << pSdSpi->spiId);
// Disable the PDC transfer
pSpiHw->SPI_PTCR = SPI_PTCR_RXTDIS | SPI_PTCR_TXTDIS; // BSS AT91C_PDC_RXTDIS | AT91C_PDC_TXTDIS;
// Enable the SPI
pSpiHw->SPI_CR = SPI_CR_SPIDIS; // BSS AT91C_SPI_SPIDIS;
// Disable the SPI clock
// BSS below AT91C_BASE_PMC->PMC_PCDR = (1 << pSdSpi->spiId);
PMC->PMC_PCDR0 = (1 << pSdSpi->spiId);
// Disable all the interrupts
pSpiHw->SPI_IDR = 0xFFFFFFFF;
}
//------------------------------------------------------------------------------
/// Returns 1 if the SPI driver is currently busy programming;
/// otherwise returns 0.
/// \param pSdSpi Pointer to a SD SPI driver instance.
//------------------------------------------------------------------------------
unsigned char SDSPI_IsBusy(SdSpi *pSdSpi)
{
if (pSdSpi->semaphore == 0) {
return 1;
}
else {
return 0;
}
}
//------------------------------------------------------------------------------
/// Wait several cycles on SPI bus;
/// Returns 0 to indicates no error, otherwise return 1.
/// \param pSdSpi Pointer to a SD SPI driver instance.
/// \param cycles Wait data cycles.
//------------------------------------------------------------------------------
unsigned char SDSPI_Wait(SdSpi *pSdSpi, unsigned int cycles)
{
unsigned int i = cycles;
unsigned char data = 0xff;
for (; i > 0; i--) {
if (SDSPI_Read(pSdSpi, &data, 1)) {
return 1;
}
}
return 0;
}
//------------------------------------------------------------------------------
/// Send stop transfer data token;
/// Returns 0 to indicates no error, otherwise return 1.
/// \param pSdSpi Pointer to a SD SPI driver instance.
//------------------------------------------------------------------------------
unsigned char SDSPI_StopTranToken(SdSpi *pSdSpi)
{
unsigned char stopToken = SDSPI_STOP_TRAN;
TRACE_DEBUG("SDSPI_StopTranToken\n\r");
return SDSPI_Write(pSdSpi, &stopToken, 1);
}
//------------------------------------------------------------------------------
/// Wait, SD card Ncs cycles;
/// Returns 0 to indicates no error, otherwise return 1.
/// \param pSdSpi Pointer to a SD SPI driver instance.
//------------------------------------------------------------------------------
unsigned char SDSPI_NCS(SdSpi *pSdSpi)
{
unsigned int i;
unsigned char ncs;
for(i = 0; i < 15; i++) {
ncs = 0xff;
if (SDSPI_Write(pSdSpi, &ncs, 1)) {
return 1;
}
}
return 0;
}

175
src/ersky9x/sdspi.h Normal file
View file

@ -0,0 +1,175 @@
/* ----------------------------------------------------------------------------
* 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.
* ----------------------------------------------------------------------------
*/
//------------------------------------------------------------------------------
/// \page "sdspi"
///
/// !Purpose
///
/// sdcard spi-bus driver
///
/// !Usage
///
/// -# SDSPI_Configure: Initializes the SD Spi structure and the corresponding SPI hardware
/// -# SDSPI_ConfigureCS : Configures the parameters for the device corresponding to the cs
/// -# SDSPI_Read: Read data on SPI data bus
/// -# SDSPI_Write : Write data on SPI data bus
/// -# SDSPI_SendCommand : Starts a SPI master transfer
/// -# SDSPI_StopTranToken : Send stop transfer data token
//------------------------------------------------------------------------------
#ifndef SDSPI_H
#define SDSPI_H
//------------------------------------------------------------------------------
// Headers
//------------------------------------------------------------------------------
#ifdef REVA
#include "AT91SAM3S2.h"
#else
#include "AT91SAM3S4.h"
#endif
//#include <board.h>
//#include <spi/spi.h>
/// SPI CSR value
#define SDSPI_CSR(scbr) ( AT91C_SPI_CPOL \
| AT91C_SPI_BITS_8 \
| (((scbr)<< 8) & AT91C_SPI_SCBR) \
| ( (0x08 << 16) & AT91C_SPI_DLYBS)\
| ( (0x01 << 24) & AT91C_SPI_DLYBCT) )
/// 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)
#define AT45_CSR(mck, spck) \
(AT91C_SPI_NCPHA | SPID_CSR_DLYBCT(mck, 250) \
| SPID_CSR_DLYBS(mck, 250) | SPID_CSR_SCBR(mck, spck))
/// Start new data transfer
#define SPI_NEW_TRANSFER 0
/// Continue data transfer
#define SPI_CONTINUE_TRANSFER 1
/// SD end-of-transfer callback function.
typedef void (*SdSpiCallback)(unsigned char status, void *pCommand);
//------------------------------------------------------------------------------
/// SPI Transfer Request prepared by the application upper layer. This structure
/// is sent to the SDSPI_SendCommand function to start the transfer. At the end of
/// the transfer, the callback is invoked by the interrupt handler.
//------------------------------------------------------------------------------
typedef struct _SdSpiCmd {
/// Command status.
volatile char status;
/// Command code.
unsigned int cmd;
/// Command argument.
unsigned int arg;
/// Data buffer.
unsigned char *pData;
/// Size of data buffer in bytes.
unsigned short blockSize;
/// Number of blocks to be transfered
unsigned short nbBlock;
/// Indicate if continue to transfer data
unsigned char conTrans;
/// Indicates if the command is a read operation.
unsigned char isRead;
/// Response buffer.
unsigned int *pResp;
/// Size of SD card response in bytes.
unsigned char resType;
/// Optional user-provided callback function.
SdSpiCallback callback;
/// Optional argument to the callback function.
void *pArg;
} SdSpiCmd;
/// Above should be put into SD card header file.
//------------------------------------------------------------------------------
/// SPI driver structure. Holds the internal state of the SPI driver and
/// prevents parallel access to a SPI peripheral.
//------------------------------------------------------------------------------
typedef struct {
/// Pointer to a SPI peripheral.
AT91S_SPI *pSpiHw;
/// SPI peripheral identifier.
unsigned char spiId;
/// Pointer to currently executing command.
SdSpiCmd *pCommand;
/// Mutex.
volatile char semaphore;
} SdSpi;
extern void SDSPI_Configure(SdSpi *pSdSpi,AT91PS_SPI pSpiHw,unsigned char spiId);
extern void SDSPI_SetSpeed(SdSpi *pSdSpi, unsigned int spiSpeed);
extern unsigned char SDSPI_SendCommand(SdSpi *pSdSpi, SdSpiCmd *pSdSpiCmd);
extern void SDSPI_Handler(SdSpi *pSdSpi);
extern unsigned char SDSPI_IsTxComplete(SdSpiCmd *pSdSpiCmd);
extern unsigned char SDSPI_IsBusy(SdSpi *pSdSpi);
extern unsigned char SDSPI_NCS(SdSpi *pSdSpi);
extern void SDSPI_Close(SdSpi *pSdSpi);
extern void SDSPI_ConfigureCS(SdSpi *pSdSpi, unsigned char cs, unsigned int csr);
extern unsigned char SDSPI_StopTranToken(SdSpi *pSdSpi);
extern unsigned char SDSPI_Wait(SdSpi *pSdSpi, unsigned int cycles);
extern unsigned char SDSPI_WaitDataBusy(SdSpi *pSdSpi);
#endif