Files
edgetx-gx12/src/sky9x/diskio.cpp
T
bsongis 313a74bc7c [Vario] Now ID 0x38 instead of 0x3F for vario (home made sensors)
[Jeti] Code cleaning
[sky9x] No more SD mount polling
2013-01-31 20:16:30 +00:00

1451 lines
44 KiB
C++

/*
* Authors (alphabetical order)
* - Andre Bernet <bernet.andre@gmail.com>
* - Bertrand Songis <bsongis@gmail.com>
* - Bryan J. Rentoul (Gruvin) <gruvin@gmail.com>
* - Cameron Weeks <th9xer@gmail.com>
* - Erez Raviv
* - Jean-Pierre Parisy
* - Karl Szmutny <shadow@privy.de>
* - Michael Blandford
* - Michal Hlavinka
* - Pat Mackenzie
* - Philip Moss
* - Rob Thomson
* - Romolo Manfredini <romolo.manfredini@gmail.com>
* - Thomas Husterer
*
* open9x is based on code named
* gruvin9x by Bryan J. Rentoul: http://code.google.com/p/gruvin9x/,
* er9x by Erez Raviv: http://code.google.com/p/er9x/,
* and the original (and ongoing) project by
* Thomas Husterer, th9x: http://code.google.com/p/th9x/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
/*-----------------------------------------------------------------------*/
/* MMCv3/SDv1/SDv2 (in SPI mode) control module (C)ChaN, 2010 */
/*-----------------------------------------------------------------------*/
/* Only rcvr_spi(), xmit_spi(), sdPoll10ms() and some macros */
/* are platform dependent. */
/*-----------------------------------------------------------------------*/
#include <string.h>
#include "board.h"
#include "debug.h"
#include "../FatFs/diskio.h"
#include "../FatFs/ff.h"
#include "../CoOS/kernel/CoOS.h"
#define CARD_TYPE_bmHC (1 << 0) /**< Bit for High-Capacity(Density) */
#define CARD_TYPE_bmSDMMC (0x3 << 1) /**< Bits mask for SD/MMC */
#define CARD_TYPE_bmUNKNOWN (0x0 << 1) /**< Bits for Unknown card */
#define CARD_TYPE_bmSD (0x1 << 1) /**< Bits for SD */
#define CARD_TYPE_bmMMC (0x2 << 1) /**< Bits for MMC */
#define CARD_TYPE_bmSDIO (1 << 3) /**< Bit for SDIO */
/** Card can not be identified */
#define CARD_UNKNOWN (0)
/** SD Card (0x2) */
#define CARD_SD (CARD_TYPE_bmSD)
/** SD High Capacity Card (0x3) */
#define CARD_SDHC (CARD_TYPE_bmSD|CARD_TYPE_bmHC)
/** MMC Card (0x4) */
#define CARD_MMC (CARD_TYPE_bmMMC)
/** MMC High-Density Card (0x5) */
#define CARD_MMCHD (CARD_TYPE_bmMMC|CARD_TYPE_bmHC)
/** SDIO only card (0x8) */
#define CARD_SDIO (CARD_TYPE_bmSDIO)
/** SDIO Combo, with SD embedded (0xA) */
#define CARD_SDCOMBO (CARD_TYPE_bmSDIO|CARD_SD)
/** SDIO Combo, with SDHC embedded (0xB) */
#define CARD_SDHCCOMBO (CARD_TYPE_bmSDIO|CARD_SDHC)
#define STATUS_READY_FOR_DATA (1UL << 8)
#define STATUS_TRAN (4UL << 9)
#define STATUS_STATE (0xFUL << 9)
/** Bit mask for data errors */
#define STATUS_ERRORS_DATA ((uint32_t)(HSMCI_SR_UNRE \
| HSMCI_SR_OVRE \
/*| HSMCI_SR_BLKOVRE*/ \
/*| HSMCI_SR_CSTOE*/ \
| HSMCI_SR_DTOE \
| HSMCI_SR_DCRCE))
uint32_t Card_ID[4] ;
uint32_t Card_SCR[2] ;
uint32_t Card_CSD[4] ;
int32_t Card_state = SD_ST_STARTUP ;
volatile uint32_t Card_initialized = 0;
uint32_t Sd_rca ;
uint32_t Cmd_A41_resp ;
uint8_t cardType;
uint32_t transSpeed;
/*-----------------------------------------------------------------------*/
/* Lock / unlock functions */
/*-----------------------------------------------------------------------*/
int ff_cre_syncobj (BYTE vol, _SYNC_t *mutex)
{
*mutex = CoCreateMutex();
return 1;
}
int ff_req_grant (_SYNC_t mutex)
{
CoEnterMutexSection(mutex);
return 1;
}
void ff_rel_grant (_SYNC_t mutex)
{
CoLeaveMutexSection(mutex);
}
int ff_del_syncobj (_SYNC_t mutex)
{
return 1;
}
//------------------------------------------------------------------------------
/// Get Trans Speed Value (Kbit/s)
/// \param tranSpeed The TRAN_SPEED value from SD(IO)/MMC enum information.
/// \param unitList Transfer rate units (Kbit/s), 4 units listed.
/// \param nbUnits Transfer rate units list size.
/// \param codeList Time value codes list, 16 codes listed.
//------------------------------------------------------------------------------
static unsigned int MmcGetTranSpeed(unsigned int tranSpeed,
const unsigned int* unitList, unsigned int nbUnits,
const unsigned int* codeList)
{
unsigned int unit, value;
unit = tranSpeed & 0x7;
if (unit < nbUnits) unit = unitList[unit];
else return 0;
value = (tranSpeed >> 3) & 0xF;
if (value < 16) value = codeList[value];
else return 0;
return (unit * value);
}
//------------------------------------------------------------------------------
/// Get Trans Speed Value
/// \param pSd
//------------------------------------------------------------------------------
uint32_t GetTransSpeedValue()
{
// CSD register, TRANS_SPEED bit
const unsigned int units[4] = {10, 100, 1000, 10000 }; // *Kbit/s
/* const unsigned int values_emmc[16] = {0, 10, 12, 13, 15, 20,
26, 30, 35, 40, 45, 52,
55, 60, 70, 80}; */
const unsigned int values_sdmmc[16] = {0, 10, 12, 13, 15, 20,
25, 30, 35, 40, 45, 50,
55, 60, 70, 80};
#if 0
unsigned int unit, value;
unit = (SD_CSD_TRAN_SPEED(pSd) & 0x7);
if(unit < 4) unit = units[unit];
else return;
value = (SD_CSD_TRAN_SPEED(pSd) >> 3) & 0xF;
if (value < 16) {
if (pSd->cardType >= CARD_MMC && SD_CID_BGA(pSd) == 1) {
value = values_emmc[value];
}
else
value = values_sdmmc[value];
}
else return;
pSd->transSpeed = (unit * value);
#else
transSpeed = MmcGetTranSpeed(SD_CSD_TRAN_SPEED(Card_CSD),
units, 4,
values_sdmmc);
#endif
/*if (pSd->cardType >= CARD_MMC && SD_EXTCSD_HS_TIMING(pSd)) {
pSd->transSpeed *= 2;
}*/
TRACE_ERROR("-I- SD/MMC TRANS SPEED %d KBit/s\r\n", transSpeed);
transSpeed *= 1000;
return transSpeed;
}
/**
* Configure the MCI CLKDIV in the MCI_MR register. The max. for MCI clock is
* MCK/2 and corresponds to CLKDIV = 0
* \param mciSpeed MCI clock speed in Hz, 0 will not change current speed.
* \return The actual speed used, 0 for fail.
*/
uint32_t sdSetSpeed(uint32_t mciSpeed )
{
uint32_t mciMr;
uint32_t clkdiv, divLimit;
mciMr = HSMCI->HSMCI_MR & (~(uint32_t)HSMCI_MR_CLKDIV_Msk);
/* Multimedia Card Interface clock (MCCK or MCI_CK) is Master Clock (MCK)
* divided by (2*(CLKDIV+1))
* mciSpeed = MCK / (2*(CLKDIV+1)) */
if (mciSpeed > 0) {
#if 1
divLimit = (Master_frequency / 2 / mciSpeed);
if ((Master_frequency / 2) % mciSpeed) divLimit ++;
clkdiv = (Master_frequency / 2 / mciSpeed);
if (mciSpeed && clkdiv < divLimit)
clkdiv = divLimit;
if (clkdiv > 0)
clkdiv -= 1;
#else
clkdiv = (Master_frequency / 2 / mciSpeed);
/* Speed should not bigger than expired one */
if (mciSpeed < Master_frequency / 2 / clkdiv) {
clkdiv++;
}
if (clkdiv > 0) {
clkdiv -= 1;
}
#endif
}
else {
clkdiv = 0;
}
/* Actual MCI speed */
mciSpeed = Master_frequency / 2 / (clkdiv + 1);
/* Modify MR */
HSMCI->HSMCI_MR = mciMr | clkdiv;
return mciSpeed;
}
#if 0
void SD_SetBlklen( uint32_t blklen )
{
uint32_t mciMr;
uint32_t clkdiv;
mciMr = HSMCI->HSMCI_MR & (~(uint32_t)HSMCI_MR_BLKLEN);
/* Modify MR */
HSMCI->HSMCI_MR = mciMr | blklen << 16 ;
}
#endif
#if 0
/**
* Reset MCI HW interface and disable it.
* \param keepSettings Keep old register settings, including
* _MR, _SDCR, _DTOR, _CSTOR, _DMA and _CFG.
*/
void SD_Reset( uint8_t keepSettings)
{
Hsmci *pMciHw = HSMCI ;
if (keepSettings)
{
uint32_t mr, sdcr, dtor, cstor;
uint32_t cfg;
mr = pMciHw->HSMCI_MR;
sdcr = pMciHw->HSMCI_SDCR;
dtor = pMciHw->HSMCI_DTOR;
cstor = pMciHw->HSMCI_CSTOR;
cfg = pMciHw->HSMCI_CFG;
pMciHw->HSMCI_CR = HSMCI_CR_SWRST ; // Reset
pMciHw->HSMCI_CR = HSMCI_CR_MCIDIS; // Disable
pMciHw->HSMCI_MR = mr;
pMciHw->HSMCI_SDCR = sdcr;
pMciHw->HSMCI_DTOR = dtor;
pMciHw->HSMCI_CSTOR = cstor;
pMciHw->HSMCI_CFG = cfg;
}
else
{
pMciHw->HSMCI_CR = HSMCI_CR_SWRST ; // Reset
pMciHw->HSMCI_CR = HSMCI_CR_MCIDIS; // Disable
}
}
#endif
const char SD_NORESPONSE[] = "No response";
const char * sdCommand(uint32_t cmd, uint32_t arg)
{
uint32_t i;
Hsmci *phsmci = HSMCI;
if (CardIsConnected()) {
phsmci->HSMCI_ARGR = arg;
phsmci->HSMCI_CMDR = cmd;
for (i = 0; i < 50000; i += 1) {
if (phsmci->HSMCI_SR & HSMCI_SR_CMDRDY) {
return 0;
}
}
return SD_NORESPONSE;
}
else {
return "No Sdcard";
}
}
#define SDMMC_POWER_ON_INIT (0 | HSMCI_CMDR_TRCMD_NO_DATA \
| HSMCI_CMDR_SPCMD_INIT \
| HSMCI_CMDR_OPDCMD )
const char * sdPowerOn()
{
return sdCommand(SDMMC_POWER_ON_INIT, 0);
}
#define SDMMC_GO_IDLE_STATE (0 | HSMCI_CMDR_TRCMD_NO_DATA \
| HSMCI_CMDR_SPCMD_STD )
const char * sdCmd0()
{
return sdCommand(SDMMC_GO_IDLE_STATE, 0);
}
#if 0
#define SDIO_SEND_OP_COND (5 | HSMCI_CMDR_SPCMD_STD \
| HSMCI_CMDR_TRCMD_NO_DATA \
| HSMCI_CMDR_RSPTYP_48_BIT \
| HSMCI_CMDR_OPDCMD )
const char * sdCmd5(uint32_t *pIo)
{
const char * result = sdCommand(SDIO_SEND_OP_COND, *pIo);
if (result)
return result;
*pIo = HSMCI->HSMCI_RSPR[0];
return 0;
}
#endif
#define SD_SEND_IF_COND (8 | HSMCI_CMDR_TRCMD_NO_DATA \
| HSMCI_CMDR_SPCMD_STD \
| HSMCI_CMDR_RSPTYP_48_BIT \
| HSMCI_CMDR_OPDCMD /* BSS difference */ \
| HSMCI_CMDR_MAXLAT )
const char * sdCmd8(uint8_t supplyVoltage)
{
return sdCommand(SD_SEND_IF_COND, (supplyVoltage << 8) | (0xAA));
}
#define SDMMC_APP_CMD (55| HSMCI_CMDR_SPCMD_STD \
| HSMCI_CMDR_RSPTYP_48_BIT \
| HSMCI_CMDR_TRCMD_NO_DATA \
| HSMCI_CMDR_MAXLAT)
const char * sdCmd55()
{
return sdCommand(SDMMC_APP_CMD, Sd_rca);
}
#define SDMMC_SEND_STATUS_CMD (13 | HSMCI_CMDR_TRCMD_NO_DATA \
| HSMCI_CMDR_SPCMD_STD \
| HSMCI_CMDR_RSPTYP_48_BIT \
| HSMCI_CMDR_MAXLAT )
const char * sdCmd13(unsigned int *status)
{
const char *result = sdCommand(SDMMC_SEND_STATUS_CMD, Sd_rca);
if (result)
return result;
*status = HSMCI->HSMCI_RSPR[0];
return 0;
}
#define SDMMC_SET_BLOCKLEN (16 | HSMCI_CMDR_TRCMD_NO_DATA \
| HSMCI_CMDR_SPCMD_STD \
| HSMCI_CMDR_RSPTYP_48_BIT \
| HSMCI_CMDR_MAXLAT_64 )
uint32_t sdCmd16()
{
Hsmci *phsmci = HSMCI;
if (CardIsConnected()) {
phsmci->HSMCI_BLKR = ( ( 512 ) << 16 ) | 1 ;
phsmci->HSMCI_ARGR = 512;
phsmci->HSMCI_CMDR = SDMMC_SET_BLOCKLEN;
while(1) {
if (phsmci->HSMCI_SR & HSMCI_SR_CMDRDY) {
break;
}
}
return phsmci->HSMCI_RSPR[0];
}
else {
return 0;
}
}
#define SD_SD_SEND_OP_COND (41| HSMCI_CMDR_SPCMD_STD \
| HSMCI_CMDR_RSPTYP_48_BIT \
| HSMCI_CMDR_TRCMD_NO_DATA \
/*| HSMCI_CMDR_OPDCMD_OPENDRAIN */ )
const char * sdCmd41(uint32_t arg, uint32_t * status)
{
const char * result = sdCommand(SD_SD_SEND_OP_COND, arg);
if (result)
return result;
*status = HSMCI->HSMCI_RSPR[0];
return 0;
}
#define OCR_VDD_27_28 ((uint32_t)(1 << 15))
#define OCR_VDD_28_29 ((uint32_t)(1 << 16))
#define OCR_VDD_29_30 ((uint32_t)(1 << 17))
#define OCR_VDD_30_31 ((uint32_t)(1 << 18))
#define OCR_VDD_31_32 ((uint32_t)(1 << 19))
#define OCR_VDD_32_33 ((uint32_t)(1 << 20))
#define OCR_VDD_33_34 ((uint32_t)(1 << 21))
#define SDMMC_HOST_VOLTAGE_RANGE (OCR_VDD_27_28 +\
OCR_VDD_28_29 +\
OCR_VDD_29_30 +\
OCR_VDD_30_31 +\
OCR_VDD_31_32 +\
OCR_VDD_32_33 +\
OCR_VDD_32_33) /* not in SAM3S reference code */
#define OCR_POWER_UP_BUSY (1UL << 31)
const char * sdMemInit(uint8_t hcs, uint32_t *pCCS)
{
const char * result;
uint32_t arg;
uint32_t status;
do {
result = sdCmd55();
if (result)
return result;
arg = SDMMC_HOST_VOLTAGE_RANGE;
if (hcs) arg |= OCR_SD_CCS;
result = sdCmd41(arg, &status);
if (result)
return result;
*pCCS = (status & OCR_SD_CCS);
} while ((status & OCR_POWER_UP_BUSY) != OCR_POWER_UP_BUSY);
return 0;
}
// Get Card ID
const char * sdCmd2()
{
const char * result = sdCommand(0x00001082, 0);
if (result)
return result;
Hsmci *phsmci = HSMCI ;
Card_ID[0] = phsmci->HSMCI_RSPR[0] ;
Card_ID[1] = phsmci->HSMCI_RSPR[1] ;
Card_ID[2] = phsmci->HSMCI_RSPR[2] ;
Card_ID[3] = phsmci->HSMCI_RSPR[3] ;
return 0;
}
// Get new RCA
const char * sdCmd3()
{
const char * result = sdCommand(0x00001043, 0);
if (result)
return result;
Sd_rca = HSMCI->HSMCI_RSPR[0];
return 0;
}
// Get CSD
const char * sdCmd9()
{
const char * result = sdCommand(0x00001089, Sd_rca);
if (result)
return result;
Hsmci *phsmci = HSMCI ;
Card_CSD[0] = phsmci->HSMCI_RSPR[0] ;
Card_CSD[1] = phsmci->HSMCI_RSPR[1] ;
Card_CSD[2] = phsmci->HSMCI_RSPR[2] ;
Card_CSD[3] = phsmci->HSMCI_RSPR[3] ;
return 0;
}
/** Cmd7 MCI, ac, R1/R1b */
#define SDMMC_SELECT_CARD (7 | HSMCI_CMDR_TRCMD_NO_DATA \
| HSMCI_CMDR_SPCMD_STD \
| HSMCI_CMDR_RSPTYP_R1B \
| HSMCI_CMDR_MAXLAT )
const char * sdCmd7()
{
return sdCommand(SDMMC_SELECT_CARD, Sd_rca);
}
#define SD_SEND_SCR (51 | HSMCI_CMDR_SPCMD_STD | HSMCI_CMDR_RSPTYP_48_BIT \
| HSMCI_CMDR_TRCMD_START_DATA | HSMCI_CMDR_TRDIR_READ \
| HSMCI_CMDR_TRTYP_SINGLE | HSMCI_CMDR_MAXLAT)
#define SD_READ_SINGLE_BLOCK (17 | HSMCI_CMDR_SPCMD_STD | HSMCI_CMDR_RSPTYP_48_BIT \
| HSMCI_CMDR_TRCMD_START_DATA | HSMCI_CMDR_TRDIR_READ \
| HSMCI_CMDR_TRTYP_SINGLE | HSMCI_CMDR_MAXLAT)
#define SD_WRITE_SINGLE_BLOCK (24 | HSMCI_CMDR_SPCMD_STD \
| HSMCI_CMDR_RSPTYP_48_BIT \
| HSMCI_CMDR_TRCMD_START_DATA \
| HSMCI_CMDR_TRDIR_WRITE \
| HSMCI_CMDR_TRTYP_SINGLE \
| HSMCI_CMDR_MAXLAT)
// Get SCR
const char * sdAcmd51()
{
const char * result;
result = sdCmd55();
if (result)
return result;
Hsmci *phsmci = HSMCI ;
// Block size = 64/ 8, nblocks = 1
phsmci->HSMCI_BLKR = ( ( 64 / 8 ) << 16 ) | 1 ;
phsmci->HSMCI_ARGR = 0 ;
phsmci->HSMCI_CMDR = SD_SEND_SCR ;
uint8_t scrLen = 0;
uint32_t i;
for ( i = 0 ; i < 50000 ; i += 1 ) {
if ( phsmci->HSMCI_SR & HSMCI_SR_RXRDY )
Card_SCR[scrLen++] = __REV(phsmci->HSMCI_RDR) ;
if ( ( phsmci->HSMCI_SR & ( HSMCI_SR_CMDRDY | HSMCI_SR_XFRDONE ) ) == ( HSMCI_SR_CMDRDY | HSMCI_SR_XFRDONE ) )
return 0;
}
return "No response";
}
#define SD_SET_BUS_WIDTH (6 | HSMCI_CMDR_SPCMD_STD | HSMCI_CMDR_RSPTYP_48_BIT \
| HSMCI_CMDR_MAXLAT)
void sdEnableHsMode(uint8_t enable)
{
Hsmci *phsmci = HSMCI;
if (enable)
phsmci->HSMCI_CFG |= HSMCI_CFG_HSMODE;
else
phsmci->HSMCI_CFG &= ~HSMCI_CFG_HSMODE;
}
void sdSetBusWidth(uint32_t busWidth)
{
Hsmci *phsmci = HSMCI;
phsmci->HSMCI_SDCR = (HSMCI->HSMCI_SDCR & ~HSMCI_SDCR_SDCBUS_Msk) | busWidth;
}
// Set bus width to 4 bits, set speed to 9 MHz
const char * sdAcmd6()
{
const char * result;
result = sdCmd55() ;
if (result)
return result;
result = sdCommand(SD_SET_BUS_WIDTH, 2);
if (result)
return result;
sdSetBusWidth( HSMCI_SDCR_SDCBUS_4 ) ;
GetTransSpeedValue();
sdSetSpeed(transSpeed/*9000000*/);
// TODO + Cmd6? sdEnableHsMode(1);
if (Cmd_A41_resp & OCR_SD_CCS)
sdCmd16();
return 0;
}
#if 0
/** SDIO CMD52, R5 */
#define SDIO_IO_RW_DIRECT (52| HSMCI_CMDR_SPCMD_STD \
| HSMCI_CMDR_TRCMD_NO_DATA \
| HSMCI_CMDR_RSPTYP_48_BIT \
| HSMCI_CMDR_MAXLAT)
static const char * sdCmd52(uint8_t wrFlag,
uint8_t funcNb,
uint8_t rdAfterWr,
uint32_t addr,
uint32_t *status)
{
typedef struct
{
uint32_t data:8, /**< [ 7: 0] data for writing */
stuff0:1, /**< [ 8] reserved */
regAddress:17, /**< [25: 9] register address */
stuff1:1, /**< [ 26] reserved */
rawFlag:1, /**< [ 27] Read after Write flag */
functionNum:3, /**< [30:28] Number of the function */
rwFlag:1; /**< [ 31] Direction, 1:write, 0:read. */
} SdioCmd52Arg;
SdioCmd52Arg pArg52;
pArg52.rwFlag = wrFlag;
pArg52.functionNum = funcNb;
pArg52.rawFlag = rdAfterWr;
pArg52.regAddress = addr;
const char * result = sdCommand(SDIO_IO_RW_DIRECT, *(uint32_t*)&pArg52);
if (result)
return result;
*status = HSMCI->HSMCI_RSPR[0];
return 0;
}
const char * sdSwReset(uint32_t retry)
{
uint32_t i;
const char * result = 0;
for (i = 0; i < retry; i++) {
result = sdCmd0(0);
if (result != SD_NORESPONSE)
break;
}
return result;
}
#endif
/**
* \brief Run the SD/MMC/SDIO Mode initialization sequence.
* This function runs the initialization procedure and the identification
* process. Then it leaves the card in ready state. The following procedure must
* check the card type and continue to put the card into tran(for memory card)
* or cmd(for io card) state for data exchange.
* \param pSd Pointer to a SD card driver instance.
* \return 0 if successful; otherwise returns an \ref sdmmc_rc "SD_ERROR code".
*/
#define SDIO_CIA 0 /**< SDIO Function 0 (CIA) */
#define SDIO_IOA_REG 0x06 /**< I/O Abort */
/** SDIO state (in R5) */
#define SDIO_R5_ERROR (1UL << 11)/**< General error */
#define SDIO_R5_FUNC_NUM (1UL << 10)/**< Invalid function number */
#define SDIO_R5_OUT_OF_RANGE (1UL << 9) /**< Argument out of range */
/** Status bits mask for SDIO R5 */
#define STATUS_SDIO_R5 (0/*SDIO_R5_STATE*/ \
| SDIO_R5_ERROR \
| SDIO_R5_FUNC_NUM \
| SDIO_R5_OUT_OF_RANGE)
#define OCR_SDIO_MP (1UL << 27)
#define OCR_SDIO_NF (7UL << 28)
#if 0
const char * sdIdentify()
{
uint8_t mem = 0, io = 0, f8 = 0, mp = 1;
uint32_t status, ccs=0;
const char * result;
/* Reset HC to default HS and BusMode */
sdEnableHsMode(0);
sdSetBusWidth(HSMCI_SDCR_SDCBUS_1);
#if 0
/* Reset SDIO: CMD52, write 1 to RES bit in CCCR (bit 3 of register 6) */
result = sdCmd52(1, SDIO_CIA, 0, SDIO_IOA_REG, &status);
if (result)
return result;
if (status & STATUS_SDIO_R5)
return "Identify.52 error";
#endif
/* Reset MEM: CMD0 */
result = sdSwReset(1);
if (result)
return result;
/* CMD8 is newly added in the Physical Layer Specification Version 2.00 to
* support multiple voltage ranges and used to check whether the card
* supports supplied voltage. The version 2.00 host shall issue CMD8 and
* verify voltage before card initialization.
* The host that does not support CMD8 shall supply high voltage range... */
result = sdCmd8(1);
if (result == 0) f8 = 1;
else if (result == SD_NORESPONSE) CoTickDelay(1); /* 2ms delay after "no response" */
else return "Identify.8 error";
#if 0
/* CMD5 is newly added for SDIO initialize & power on */
status = 0;
result = sdCmd5(&status);
if (!result && (status & OCR_SDIO_NF) > 0) {
unsigned int cmd5Retries = 10000;
do {
status &= SDMMC_HOST_VOLTAGE_RANGE;
result = sdCmd5(&status);
if (status & OCR_POWER_UP_BUSY) break;
} while(!result && cmd5Retries --);
if (result)
return "Identify.5 error";
io = 1;
/* IO only ?*/
mp = ((status & OCR_SDIO_MP) > 0);
}
#endif
/* Has memory: SD/MMC/COMBO */
/*if (mp) */
{
/* Try SD memory initialize */
result = sdMemInit(f8, &ccs);
if (result) {
//unsigned int cmd1Retries = 10000;
/* Try MMC initialize */
result = sdSwReset(10);
if (result)
return "Reset error";
/* TODO ccs = 1;
do { result = sdCmd1(&ccs); } while(result && cmd1Retries -- > 0);
if (error) {
TRACE_ERROR("SdMmcIdentify.Cmd1: %u\n\r", error);
return SDMMC_ERROR;
}
else if (ccs) cardType = CARD_MMCHD;
else cardType = CARD_MMC;
*/
return "TODO error";
/* MMC card identification OK */
return 0;
}
// mem = 1;
}
/* SD(IO) + MEM ? */
/* if (!mem) {
if (io) cardType = CARD_SDIO;
else
return "Unknown SD";
} */
/* SD(HC) combo */
/*else if (io)
cardType = ccs ? CARD_SDHCCOMBO : CARD_SDCOMBO;*/
/* SD(HC) */
//else
cardType = ccs ? CARD_SDHC : CARD_SD;
return 0;
}
const char * sdEnum()
{
uint8_t mem , io;
const char * result;
uint32_t ioSpeed = 0, memSpeed = 0;
uint8_t hsExec = 0, bwExec = 0;
/* - has Memory/IO/High-Capacity - */
mem = ((cardType & CARD_TYPE_bmSDMMC) > 0);
io = ((cardType & CARD_TYPE_bmSDIO) > 0);
/* For MEMORY cards:
* The host then issues the command ALL_SEND_CID (CMD2) to the card to get
* its unique card identification (CID) number.
* Card that is unidentified (i.e. which is in Ready State) sends its CID
* number as the response (on the CMD line). */
if (mem) {
result = sdCmd2();
if (result)
return result;
}
/* For MEMORY and SDIO cards:
* Thereafter, the host issues CMD3 (SEND_RELATIVE_ADDR) asks the
* card to publish a new relative card address (RCA), which is shorter than
* CID and which is used to address the card in the future data transfer
* mode. Once the RCA is received the card state changes to the Stand-by
* State. At this point, if the host wants to assign another RCA number, it
* can ask the card to publish a new number by sending another CMD3 command
* to the card. The last published RCA is the actual RCA number of the
* card. */
result = sdCmd3();
if (result)
return result;
/* For MEMORY cards:
* SEND_CSD (CMD9) to obtain the Card Specific Data (CSD register),
* e.g. block length, card storage capacity, etc... */
if (mem) {
result = sdCmd9();
if (result)
return result;
}
/* Now select the card, to TRAN state */
error = MmcSelectCard(pSd, pSd->cardAddress, 0);
if (error) {
TRACE_ERROR("SdMmcInit.SelCard(%d)\n\r", error);
return error;
}
/* - Now in TRAN, obtain extended setup information - */
/* If the card support EXT_CSD, read it! */
TRACE_INFO("Card Type %d, CSD_STRUCTURE %d\n\r",
pSd->cardType, SD_CSD_STRUCTURE(pSd));
/* Get extended information of the card */
SdMmcUpdateInformation(pSd, 0, 1);
/* Calculate transfer speed */
if (io) ioSpeed = SdioGetMaxSpeed(pSd);
if (mem) memSpeed = SdmmcGetMaxSpeed(pSd);
/* Combo, min speed */
if (io && mem) {
pSd->transSpeed = (ioSpeed > memSpeed) ? memSpeed : ioSpeed;
}
/* SDIO only */
else if (io) {
pSd->transSpeed = ioSpeed;
}
/* Memory card only */
else if (mem) {
pSd->transSpeed = memSpeed;
}
pSd->transSpeed *= 1000;
/* Enable more bus width Mode */
error = SdMmcDesideBuswidth(pSd);
if (!error) bwExec = 1;
else if (error != SDMMC_ERROR_NOT_SUPPORT) {
TRACE_ERROR("SdmmcEnum.DesideBusWidth: %u\n\r", error);
return SDMMC_ERROR;
}
/* Enable High-Speed Mode */
error = SdMmcEnableHighSpeed(pSd);
if (!error) hsExec = 1;
else if (error != SDMMC_ERROR_NOT_SUPPORT) {
TRACE_ERROR("SdmmcEnum.EnableHS: %u\n\r", error);
return SDMMC_ERROR;
}
/* In HS mode transfer speed *2 */
if (hsExec) pSd->transSpeed *= 2;
/* Update card information since status changed */
if (bwExec || hsExec) SdMmcUpdateInformation(pSd, hsExec, 1);
return 0;
}
void sdInit()
{
const char * result;
uint8_t i;
/* Clear CID, CSD, EXT_CSD data */
for (i = 0; i < 4; i++) Card_ID[i] = 0;
for (i = 0; i < 4; i++) Card_CSD[i] = 0;
// TODO for (i = 0; i < 512/4; i++) pSd->extData[i] = 0;
/* Set low speed for device identification (LS device max speed) */
sdSetSpeed(400000);
/* Initialization delay: The maximum of 1 msec, 74 clock cycles and supply
* ramp up time. Supply ramp up time provides the time that the power is
* built up to the operating level (the bus master supply voltage) and the
* time to wait until the SD card can accept the first command.
*/
/* Power On Init Special Command */
result = sdPowerOn();
if (result)
return;
/* After power-on or CMD0, all cards?
* CMD lines are in input mode, waiting for start bit of the next command.
* The cards are initialized with a default relative card address
* (RCA=0x0000) and with a default driver stage register setting
* (lowest speed, highest driving current capability).
*/
result = sdIdentify();
if (result) {
return;
}
#if 0
result = sdEnum();
if (result) {
return;
}
/* In the case of a Standard Capacity SD Memory Card, this command sets the
* block length (in bytes) for all following block commands
* (read, write, lock).
* Default block length is fixed to 512 Bytes.
* Set length is valid for memory access commands only if partial block read
* operation are allowed in CSD.
* In the case of a High Capacity SD Memory Card, block length set by CMD16
* command does not affect the memory read and write commands. Always 512
* Bytes fixed block length is used. This command is effective for
* LOCK_UNLOCK command.
* In both cases, if block length is set larger than 512Bytes, the card sets
* the BLOCK_LEN_ERROR bit. */
if (pSd->cardType == CARD_SD) {
error = Cmd16(pSd, SDMMC_BLOCK_SIZE);
if (error) {
pSd->optCmdBitMap &= ~SD_CMD16_SUPPORT;
TRACE_INFO("SD_Init.Cmd16 (%d)\n\r", error);
TRACE_INFO("Fail to set BLK_LEN, default is 512\n\r");
}
}
/* Reset status for R/W */
pSd->state = SD_STATE_READY;
/* If MMC Card & get size from EXT_CSD */
if ((pSd->cardType & CARD_TYPE_bmSDMMC) == CARD_TYPE_bmMMC
&& SD_CSD_C_SIZE(pSd) == 0xFFF) {
pSd->blockNr = SD_EXTCSD_BLOCKNR(pSd);
/* Block number less than 0x100000000/512 */
if (pSd->blockNr > 0x800000)
pSd->totalSize = 0xFFFFFFFF;
else
pSd->totalSize = SD_EXTCSD_TOTAL_SIZE(pSd);
}
/* If SD CSD v2.0 */
else if((pSd->cardType & CARD_TYPE_bmSDMMC) == CARD_TYPE_bmSD
&& SD_CSD_STRUCTURE(pSd) >= 1) {
pSd->blockNr = SD_CSD_BLOCKNR_HC(pSd);
pSd->totalSize = 0xFFFFFFFF;
}
/* Normal SD/MMC card */
else if (pSd->cardType & CARD_TYPE_bmSDMMC) {
pSd->totalSize = SD_CSD_TOTAL_SIZE(pSd);
pSd->blockNr = SD_CSD_BLOCKNR(pSd);
}
if (pSd->cardType == CARD_UNKNOWN) {
return SDMMC_ERROR_NOT_INITIALIZED;
}
/* Automatically select the max clock */
clock = SdmmcSetSpeed(pSd, pSd->transSpeed);
TRACE_WARNING_WP("-I- Set SD/MMC clock to %dK\n\r", clock/1000);
pSd->accSpeed = clock;
#endif
}
#endif
uint8_t sdErrorCount = 0;
FATFS g_FATFS_Obj = { 0 };
void sdMountPoll()
{
#if 0
if (!Card_initialized)
return;
if (!CardIsConnected()) {
Card_state = SD_ST_EMPTY;
Sd_rca = 0;
sdErrorCount = 0;
}
switch (Card_state) {
case SD_ST_EMPTY:
if (CardIsConnected()) {
Card_state = SD_ST_INIT1;
}
break;
case SD_ST_INIT1:
sdCmd0();
Card_state = SD_ST_INIT2;
break;
case SD_ST_INIT2:
sdCmd8(1);
Card_state = SD_ST_IDLE;
break;
case SD_ST_IDLE:
sdMemInit(1, &Cmd_A41_resp);
Card_state = SD_ST_READY;
break;
case SD_ST_READY:
if (!sdCmd2()) Card_state = SD_ST_IDENT;
break;
case SD_ST_IDENT:
if (!sdCmd3()) Card_state = SD_ST_STBY;
break;
case SD_ST_STBY:
sdCmd9();
sdCmd7(); // Select Card
Card_state = SD_ST_TRAN;
break;
case SD_ST_TRAN:
sdAcmd51();
sdAcmd6(); // Set bus width to 4 bits, and speed to 9 MHz
// Should check the card can do this ****
Card_state = SD_ST_DATA;
break;
case SD_ST_DATA:
if (!usbPlugged() && f_mount(0, &g_FATFS_Obj) == FR_OK) {
refreshSystemAudioFiles();
Card_state = SD_ST_MOUNTED;
}
break;
case SD_ST_ERR:
break;
}
#endif
}
void sdInit()
{
Sd_rca = 0;
sdErrorCount = 0;
if (!CardIsConnected()) {
Card_state = SD_ST_EMPTY;
Card_initialized = 1;
return;
}
sdCmd0();
CoTickDelay(5); // 10ms
sdCmd8(1);
#if 0
uint8_t i;
uint32_t status;
for (i=0; i<100; i++)
sdCmd5(&status);
#endif
sdMemInit(1, &Cmd_A41_resp);
uint8_t retry;
for (retry=0; retry<10; retry++) {
if (!sdCmd2()) break;
CoTickDelay(1); // 2ms
}
if (retry == 10) {
Card_state = SD_ST_READY;
Card_initialized = 1;
return;
}
for (retry=0; retry<10; retry++) {
if (!sdCmd3()) break;
CoTickDelay(1); // 2ms
}
if (retry == 10) {
Card_state = SD_ST_IDENT;
Card_initialized = 1;
return;
}
sdCmd9();
sdCmd7(); // Select Card
sdAcmd51();
sdAcmd6(); // Set bus width to 4 bits, and speed to 9 MHz
// Should check the card can do this ****
Card_state = SD_ST_DATA;
if (f_mount(0, &g_FATFS_Obj) == FR_OK) {
refreshSystemAudioFiles();
Card_state = SD_ST_MOUNTED;
}
Card_initialized = 1;
}
// Checks for card ready for read/write
// returns 1 for YES, 0 for NO
uint32_t sd_card_ready( void )
{
return CardIsConnected() && Card_state >= SD_ST_DATA;
}
uint32_t sdMounted( void )
{
return CardIsConnected() && Card_state == SD_ST_MOUNTED;
}
uint32_t sd_read_block(uint32_t block_no, uint32_t *data)
{
unsigned int status = 0;
// TRACE_ERROR("read block %d", block_no);
if (sd_card_ready()) {
// Wait for card to be ready for data transfers
do {
sdCmd13(&status);
}
while (((status & STATUS_READY_FOR_DATA) == 0)
|| ((status & STATUS_STATE) != STATUS_TRAN) );
// Block size = 512, nblocks = 1
HSMCI->HSMCI_BLKR = ((512) << 16) | 1;
HSMCI->HSMCI_MR = (HSMCI->HSMCI_MR & (~(HSMCI_MR_BLKLEN_Msk|HSMCI_MR_FBYTE))) | (HSMCI_MR_PDCMODE|HSMCI_MR_WRPROOF|HSMCI_MR_RDPROOF) | (512 << 16);
HSMCI->HSMCI_ARGR = (Cmd_A41_resp & OCR_SD_CCS ? block_no : (block_no << 9));
HSMCI->HSMCI_RPR = (uint32_t)data;
HSMCI->HSMCI_RCR = 512 / 4;
HSMCI->HSMCI_PTCR = HSMCI_PTCR_RXTEN;
HSMCI->HSMCI_CMDR = SD_READ_SINGLE_BLOCK;
while (!(HSMCI->HSMCI_SR & HSMCI_SR_CMDRDY));
(void) HSMCI->HSMCI_RSPR[0];
while (1) {
if ((HSMCI->HSMCI_SR & (HSMCI_SR_ENDRX|HSMCI_SR_XFRDONE)) == (HSMCI_SR_ENDRX|HSMCI_SR_XFRDONE)) {
break;
}
}
/* Disable PDC */
HSMCI->HSMCI_MR &= ~(uint32_t)HSMCI_MR_PDCMODE;
HSMCI->HSMCI_PTCR = HSMCI_PTCR_RXTDIS | HSMCI_PTCR_TXTDIS;
return 1;
}
// TRACE_ERROR("ok %.2X %.4Xd\n\r", HSMCI->HSMCI_SR, HSMCI->HSMCI_RSPR[0]);
return 0;
}
uint32_t sd_write_block( uint32_t block_no, uint32_t *data )
{
unsigned int status = 0;
if (sd_card_ready()) {
// TRACE_ERROR("write block %d", block_no);
// Wait for card to be ready for data transfers
do {
sdCmd13(&status);
} while ((status & STATUS_READY_FOR_DATA) == 0);
// Block size = 512, nblocks = 1
HSMCI->HSMCI_BLKR = ((512) << 16) | 1;
HSMCI->HSMCI_MR = (HSMCI->HSMCI_MR & (~(HSMCI_MR_BLKLEN_Msk|HSMCI_MR_FBYTE))) | (HSMCI_MR_PDCMODE|HSMCI_MR_WRPROOF) | (512 << 16);
HSMCI->HSMCI_ARGR = (Cmd_A41_resp & OCR_SD_CCS ? block_no : (block_no << 9));
HSMCI->HSMCI_TPR = (uint32_t)data;
HSMCI->HSMCI_TCR = 512 / 4;
HSMCI->HSMCI_CMDR = SD_WRITE_SINGLE_BLOCK;
while (!(HSMCI->HSMCI_SR & HSMCI_SR_CMDRDY));
(void) HSMCI->HSMCI_RSPR[0];
HSMCI->HSMCI_PTCR = HSMCI_PTCR_TXTEN;
while (1) {
if ((HSMCI->HSMCI_SR & (HSMCI_SR_NOTBUSY|HSMCI_SR_XFRDONE)) == (HSMCI_SR_NOTBUSY|HSMCI_SR_XFRDONE)) {
break;
}
}
/* Disable PDC */
HSMCI->HSMCI_PTCR = HSMCI_PTCR_RXTDIS | HSMCI_PTCR_TXTDIS;
HSMCI->HSMCI_MR &= ~(uint32_t)HSMCI_MR_PDCMODE;
return 1;
}
return 0;
}
/*
Notes on SD card:
1) CMD8 fails and CMD58 fails: must be MMC, thus initialize using CMD1
2) CMD8 fails and CMD58 passes: must be Ver1.x Standard Capacity SD Memory Card
3) CMD8 passes and CMD58 passes (CCS = 0): must be Ver2.00 or later Standard Capacity SD Memory Card
4) CMD8 passes and CMD58 passes (CCS = 1): must be Ver2.00 or later High Capacity SD Memory Card
5) CMD8 passes and CMD58 passes but indicates non compatible voltage range: unusable card
On card present
1. Send CMD 55 (resp 48bit)
followed by ACMD41 (resp48bit)
until bit 31 of response is '1'
2. Send CMD 2 (resp 136bit) - card ID
3. Send CMD 3 (resp 48 bit) - new RCA returned
4. Send CMD 9 (resp 136) - CSD
5. Send CMD 7 (resp 48) -
6. Send CMD 55 (resp 48bit)
followed by ACMD51 (resp48bit) - SCR stored as 2 32 bit values
Now decide what the card can do!
7. Set block length
8. Set bus width
9. Read block 0
*/
/*-----------------------------------------------------------------------*/
/* Initialize Disk Drive */
/*-----------------------------------------------------------------------*/
DSTATUS disk_initialize (
BYTE drv /* Physical drive nmuber (0) */
)
{
if (drv) return STA_NOINIT; /* Supports only single drive */
if ( sd_card_ready() == 0 ) return RES_NOTRDY;
return RES_OK;
}
/*-----------------------------------------------------------------------*/
/* Get Disk Status */
/*-----------------------------------------------------------------------*/
DSTATUS disk_status (
BYTE drv /* Physical drive number (0) */
)
{
if (drv) return STA_NOINIT; /* Supports only single drive */
if ( sd_card_ready() == 0 ) return RES_NOTRDY;
return RES_OK;
}
/*-----------------------------------------------------------------------*/
/* Read Sector(s) */
/*-----------------------------------------------------------------------*/
uint32_t dma_sd_buffer[512/4];
DRESULT disk_read (
BYTE drv, /* Physical drive nmuber (0) */
BYTE *buff, /* Pointer to the data buffer to store read data */
DWORD sector, /* Start sector number (LBA) */
BYTE count /* Sector count (1..255) */
)
{
uint32_t result ;
if (drv || !count) return RES_PARERR;
if ( sd_card_ready() == 0 ) return RES_NOTRDY;
do {
result = sd_read_block(sector, dma_sd_buffer) ;
if (result) {
memcpy(buff, dma_sd_buffer, 512);
sector += 1 ;
buff += 512 ;
count -= 1 ;
}
else {
count = 1 ; // Flag error
break ;
}
} while ( count ) ;
if (!count)
return RES_OK;
if (++sdErrorCount > 3)
Card_state = SD_ST_ERR;
return RES_ERROR;
}
/*-----------------------------------------------------------------------*/
/* Write Sector(s) */
/*-----------------------------------------------------------------------*/
extern const char * s_warning;
DRESULT disk_write (
BYTE drv, /* Physical drive nmuber (0) */
const BYTE *buff, /* Pointer to the data to be written */
DWORD sector, /* Start sector number (LBA) */
BYTE count /* Sector count (1..255) */
)
{
uint32_t result ;
if (drv || !count) return RES_PARERR;
if ( sd_card_ready() == 0 ) return RES_NOTRDY;
do {
while (1) {
memcpy(dma_sd_buffer, buff, 512);
result = sd_write_block(sector, dma_sd_buffer) ;
sd_read_block(sector, dma_sd_buffer) ;
if (!memcmp(dma_sd_buffer, buff, 512))
break;
else {
TRACE_ERROR("Block %d ko SR=%.2X\r\n", sector, HSMCI->HSMCI_SR);
// DUMP(buff, 512);
// DUMP(copy, 512);
}
}
if (result) {
sector += 1 ;
buff += 512 ;
count -= 1 ;
}
else {
count = 1 ; // Flag error
break ;
}
} while ( count ) ;
if (!count)
return RES_OK;
if (++sdErrorCount > 3)
Card_state = SD_ST_ERR;
return RES_ERROR;
}
/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions */
/*-----------------------------------------------------------------------*/
DRESULT disk_ioctl (
BYTE drv, /* Physical drive nmuber (0) */
BYTE ctrl, /* Control code */
void *buff /* Buffer to send/receive control data */
)
{
DRESULT res;
if (drv) return RES_PARERR;
res = RES_ERROR;
if (ctrl == CTRL_POWER) {
#if 0
switch (ptr[0]) {
case 0: /* Sub control code (POWER_OFF) */
power_off(); /* Power off */
res = RES_OK;
break;
case 1: /* Sub control code (POWER_GET) */
ptr[1] = (BYTE)power_status();
res = RES_OK;
break;
default :
res = RES_PARERR;
}
#endif
}
else {
switch (ctrl) {
case CTRL_SYNC : /* Make sure that no pending write process. Do not remove this or written sector might not left updated. */
res = RES_OK;
break;
case GET_SECTOR_COUNT : /* Get number of sectors on the disk (DWORD) */
*(DWORD*)buff = SD_GET_BLOCKNR();
res = RES_OK;
break;
case GET_SECTOR_SIZE : /* Get R/W sector size (WORD) */
*(WORD*)buff = 512;
res = RES_OK;
break;
case GET_BLOCK_SIZE : /* Get erase block size in unit of sector (DWORD) */
*(WORD*)buff = 1;
res = RES_OK;
break;
#if 0
case MMC_GET_TYPE : /* Get card type flags (1 byte) */
*ptr = CardType;
res = RES_OK;
break;
case MMC_GET_CSD : /* Receive CSD as a data block (16 bytes) */
if (send_cmd(CMD9, 0) == 0 /* READ_CSD */
&& rcvr_datablock(ptr, 16))
res = RES_OK;
break;
case MMC_GET_CID : /* Receive CID as a data block (16 bytes) */
if (send_cmd(CMD10, 0) == 0 /* READ_CID */
&& rcvr_datablock(ptr, 16))
res = RES_OK;
break;
case MMC_GET_OCR : /* Receive OCR as an R3 resp (4 bytes) */
if (send_cmd(CMD58, 0) == 0) { /* READ_OCR */
for (n = 4; n; n--) *ptr++ = rcvr_spi();
res = RES_OK;
}
break;
case MMC_GET_SDSTAT : /* Receive SD statsu as a data block (64 bytes) */
if (send_cmd(ACMD13, 0) == 0) { /* SD_STATUS */
rcvr_spi();
if (rcvr_datablock(ptr, 64))
res = RES_OK;
}
break;
#endif
default:
res = RES_PARERR;
break;
}
// BSS deselect();
}
return res;
}