1196 lines
36 KiB
C++
1196 lines
36 KiB
C++
/*
|
|
* Authors (alphabetical order)
|
|
* - 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(), disk_timerproc() and some macros */
|
|
/* are platform dependent. */
|
|
/*-----------------------------------------------------------------------*/
|
|
|
|
#include "radio.h"
|
|
//extern unsigned long Master_frequency ;
|
|
extern void delay2ms() ;
|
|
#ifdef BOOT
|
|
#define TRUE 1
|
|
#endif
|
|
|
|
|
|
#ifndef BOOT
|
|
//#if !defined(SIMU)
|
|
//#include "CoOS.h"
|
|
//#endif
|
|
#endif
|
|
|
|
#include "diskio.h"
|
|
#include "board.h"
|
|
#ifndef BOOT
|
|
#include "debug.h"
|
|
#endif
|
|
// States for initialising card
|
|
#define SD_ST_EMPTY 0
|
|
#define SD_ST_INIT1 1
|
|
#define SD_ST_INIT2 2
|
|
#define SD_ST_IDLE 3
|
|
#define SD_ST_READY 4
|
|
#define SD_ST_IDENT 5
|
|
#define SD_ST_STBY 6
|
|
#define SD_ST_TRAN 7
|
|
#define SD_ST_DATA 8
|
|
|
|
// Bits in status register of Sd card
|
|
#define STATUS_READY_FOR_DATA (1UL << 8)
|
|
#define STATUS_TRAN (4UL << 9)
|
|
#define STATUS_STATE (0xFUL << 9)
|
|
|
|
|
|
|
|
uint32_t Card_ID[4] ;
|
|
uint32_t Card_SCR[2] ;
|
|
uint32_t Card_CSD[4] ;
|
|
uint32_t Card_state = SD_ST_EMPTY ;
|
|
uint32_t Sd_128_resp[4] ;
|
|
uint32_t Sd_rca ;
|
|
uint32_t Sd_status13 ;
|
|
uint32_t Cmd_A41_resp ;
|
|
uint32_t SpeedAllowed ;
|
|
|
|
uint32_t Sd_retries ;
|
|
|
|
/**
|
|
* Configure the MCI SDCBUS in the MCI_SDCR register. Only two modes available
|
|
*
|
|
* \param busWidth MCI bus width mode. 00: 1-bit, 10: 4-bit.
|
|
*/
|
|
uint32_t SD_SetBusWidth( uint32_t busWidth)
|
|
{
|
|
uint32_t mciSdcr;
|
|
|
|
if( (busWidth != HSMCI_SDCR_SDCBUS_1) && (busWidth != HSMCI_SDCR_SDCBUS_4) )
|
|
{
|
|
return (uint32_t)-1;
|
|
}
|
|
|
|
busWidth &= HSMCI_SDCR_SDCBUS_Msk ;
|
|
|
|
mciSdcr = (HSMCI->HSMCI_SDCR & ~(uint32_t)(HSMCI_SDCR_SDCBUS_Msk));
|
|
HSMCI->HSMCI_SDCR = mciSdcr | busWidth;
|
|
|
|
return 0;
|
|
}
|
|
|
|
#if 0
|
|
/**
|
|
* Configure the MCI_CFG to enable the HS mode
|
|
* \param hsEnable 1 to enable, 0 to disable HS mode.
|
|
*/
|
|
void SD_EnableHsMode( uint8_t hsEnable)
|
|
{
|
|
uint32_t cfgr;
|
|
|
|
cfgr = HSMCI->HSMCI_CFG;
|
|
if (hsEnable)
|
|
{
|
|
cfgr |= HSMCI_CFG_HSMODE;
|
|
}
|
|
else
|
|
{
|
|
cfgr &= ~(uint32_t)HSMCI_CFG_HSMODE;
|
|
}
|
|
|
|
HSMCI->HSMCI_CFG = cfgr;
|
|
}
|
|
#endif
|
|
|
|
/**
|
|
* 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 SD_SetSpeed( 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)
|
|
{
|
|
|
|
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;
|
|
|
|
// clkdiv = (Master_frequency / 2 / mciSpeed);
|
|
// /* Speed should not bigger than expired one */
|
|
// if (mciSpeed < Master_frequency/2/clkdiv)
|
|
// {
|
|
// clkdiv++;
|
|
// }
|
|
|
|
// if ( clkdiv > 0 )
|
|
// {
|
|
// clkdiv -= 1;
|
|
// }
|
|
}
|
|
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
|
|
|
|
|
|
uint32_t 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 1 ; // No response
|
|
}
|
|
else
|
|
{
|
|
return 1 ; // No Sdcard
|
|
}
|
|
}
|
|
|
|
|
|
#define SDMMC_APP_CMD (55| HSMCI_CMDR_SPCMD_STD \
|
|
| HSMCI_CMDR_RSPTYP_48_BIT \
|
|
| HSMCI_CMDR_TRCMD_NO_DATA \
|
|
| HSMCI_CMDR_MAXLAT)
|
|
|
|
uint32_t sd_cmd55()
|
|
{
|
|
return sdCommand( SDMMC_APP_CMD, Sd_rca ) ;
|
|
}
|
|
|
|
#define SDMMC_GO_IDLE_STATE (0 | HSMCI_CMDR_TRCMD_NO_DATA \
|
|
| HSMCI_CMDR_SPCMD_STD )
|
|
|
|
// returns 0 = OK, non-zero = fail
|
|
uint32_t sd_cmd0()
|
|
{
|
|
return sdCommand( SDMMC_GO_IDLE_STATE, 0 ) ;
|
|
}
|
|
#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 )
|
|
|
|
#define SDMMC_SEND_STATUS_CMD (13 | HSMCI_CMDR_TRCMD_NO_DATA \
|
|
| HSMCI_CMDR_SPCMD_STD \
|
|
| HSMCI_CMDR_RSPTYP_48_BIT \
|
|
| HSMCI_CMDR_MAXLAT )
|
|
|
|
// returns 0 = OK, non-zero = fail
|
|
uint32_t sd_cmd13(uint32_t *status)
|
|
{
|
|
uint32_t result = sdCommand( SDMMC_SEND_STATUS_CMD, Sd_rca ) ;
|
|
if (result)
|
|
return result;
|
|
Sd_status13 = *status = HSMCI->HSMCI_RSPR[0];
|
|
return 0 ;
|
|
}
|
|
|
|
// returns 0 = OK, non-zero = fail
|
|
uint32_t sd_cmd8()
|
|
{
|
|
return sdCommand( SD_SEND_IF_COND, 0X000001AA ) ;
|
|
}
|
|
|
|
uint32_t sd_acmd41()
|
|
{
|
|
uint32_t i;
|
|
Hsmci *phsmci = HSMCI;
|
|
|
|
if (CardIsConnected()) {
|
|
sd_cmd55();
|
|
phsmci->HSMCI_ARGR = 0x403F8000;
|
|
phsmci->HSMCI_CMDR = 0x00001069;
|
|
|
|
for (i = 0; i < 30000; i += 1) {
|
|
if (phsmci->HSMCI_SR & HSMCI_SR_CMDRDY) {
|
|
break;
|
|
}
|
|
}
|
|
return Cmd_A41_resp = phsmci->HSMCI_RSPR[0] ;
|
|
}
|
|
else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
// Get Card ID
|
|
// returns 0 = OK, non-zero = fail
|
|
uint32_t sd_cmd2()
|
|
{
|
|
uint32_t 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
|
|
// returns 0 = OK, non-zero = fail
|
|
uint32_t sd_cmd3()
|
|
{
|
|
uint32_t result = sdCommand( 0x00001043, 0 ) ;
|
|
if (result)
|
|
return result;
|
|
|
|
Sd_rca = HSMCI->HSMCI_RSPR[0];
|
|
return 0 ;
|
|
}
|
|
|
|
// Get CSD
|
|
uint32_t sd_cmd9()
|
|
{
|
|
uint32_t 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 /* TODO not the same */ )
|
|
|
|
// Select Card
|
|
uint32_t sd_cmd7()
|
|
{
|
|
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 SDMMC_SET_BLOCKLEN (16 | HSMCI_CMDR_TRCMD_NO_DATA \
|
|
| HSMCI_CMDR_SPCMD_STD \
|
|
| HSMCI_CMDR_RSPTYP_48_BIT \
|
|
| HSMCI_CMDR_MAXLAT_64 )
|
|
|
|
#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
|
|
uint32_t sd_acmd51( uint32_t *presult )
|
|
{
|
|
uint32_t i ;
|
|
uint32_t j = 0 ;
|
|
Hsmci *phsmci = HSMCI ;
|
|
|
|
if ( CardIsConnected() )
|
|
{
|
|
sd_cmd55() ;
|
|
// Block size = 64/ 8, nblocks = 1
|
|
phsmci->HSMCI_BLKR = ( ( 64 / 8 ) << 16 ) | 1 ;
|
|
phsmci->HSMCI_ARGR = 0 ;
|
|
phsmci->HSMCI_CMDR = SD_SEND_SCR ;
|
|
|
|
for ( i = 0 ; i < 50000 ; i += 1 )
|
|
{
|
|
if ( phsmci->HSMCI_SR & HSMCI_SR_RXRDY )
|
|
{
|
|
*presult++ = __REV(phsmci->HSMCI_RDR) ;
|
|
j += 0x10000000 ;
|
|
}
|
|
if ( ( phsmci->HSMCI_SR & ( HSMCI_SR_CMDRDY | HSMCI_SR_XFRDONE ) ) == ( HSMCI_SR_CMDRDY | HSMCI_SR_XFRDONE ) )
|
|
{
|
|
break ;
|
|
}
|
|
|
|
}
|
|
if ( i >= 50000 )
|
|
{
|
|
*presult = phsmci->HSMCI_SR ;
|
|
}
|
|
return i | j ; //phsmci->HSMCI_RSPR[0] ;
|
|
}
|
|
else
|
|
{
|
|
return 0 ;
|
|
}
|
|
}
|
|
|
|
#define SD_SET_BUS_WIDTH (6 | HSMCI_CMDR_SPCMD_STD | HSMCI_CMDR_RSPTYP_48_BIT \
|
|
| HSMCI_CMDR_MAXLAT)
|
|
|
|
// Set bus width to 4 bits, set speed to 9 MHz
|
|
uint32_t sd_acmd6()
|
|
{
|
|
uint32_t i ;
|
|
Hsmci *phsmci = HSMCI ;
|
|
|
|
if ( CardIsConnected() )
|
|
{
|
|
sd_cmd55() ;
|
|
phsmci->HSMCI_ARGR = 2 ; // Bus width 4 bits
|
|
phsmci->HSMCI_CMDR = SD_SET_BUS_WIDTH ;
|
|
|
|
for ( i = 0 ; i < 300000 ; i += 1 )
|
|
{
|
|
if ( phsmci->HSMCI_SR & HSMCI_SR_CMDRDY )
|
|
{
|
|
break ;
|
|
}
|
|
}
|
|
if ( i >= 300000 )
|
|
{
|
|
return 0 ;
|
|
}
|
|
SD_SetBusWidth( HSMCI_SDCR_SDCBUS_4 ) ;
|
|
uint32_t j ;
|
|
j = SpeedAllowed ;
|
|
if ( j > 9000000 )
|
|
{
|
|
j = 9000000 ;
|
|
}
|
|
|
|
SD_SetSpeed( j ) ;
|
|
if (Cmd_A41_resp & 0x40000000 ) // OCR_SD_CCS)
|
|
sd_cmd16();
|
|
return i ; //phsmci->HSMCI_RSPR[0] ;
|
|
}
|
|
else
|
|
{
|
|
return 0 ;
|
|
}
|
|
}
|
|
|
|
const uint8_t SpeedTable[] = { 1, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80 } ;
|
|
|
|
// This routine is called every 10 mS, and checks for card
|
|
// insertion and removal.
|
|
// When a card is inserted, it initialises it ready for read/write access.
|
|
void sd_poll_10mS()
|
|
{
|
|
uint32_t i ;
|
|
|
|
if ( !CardIsConnected() )
|
|
{
|
|
Card_state = SD_ST_EMPTY ;
|
|
Sd_rca = 0 ;
|
|
|
|
}
|
|
|
|
switch ( Card_state )
|
|
{
|
|
case SD_ST_EMPTY :
|
|
if ( CardIsConnected() ) {
|
|
Card_state = SD_ST_INIT1 ;
|
|
}
|
|
break ;
|
|
|
|
case SD_ST_INIT1 :
|
|
i = sd_cmd0() ; // Keep a 10mS delay after this before sd_cmd8()
|
|
if ( i == 0 )
|
|
{
|
|
Card_state = SD_ST_INIT2 ;
|
|
}
|
|
break ;
|
|
|
|
case SD_ST_INIT2 :
|
|
i = sd_cmd8() ;
|
|
if ( i == 0 )
|
|
{
|
|
Card_state = SD_ST_IDLE ;
|
|
}
|
|
break ;
|
|
|
|
case SD_ST_IDLE :
|
|
i = sd_acmd41() ;
|
|
if ( i & 0x80000000 ) {
|
|
Card_state = SD_ST_READY ;
|
|
}
|
|
break ;
|
|
|
|
case SD_ST_READY :
|
|
i = sd_cmd2() ;
|
|
if ( i == 0 )
|
|
{
|
|
Card_state = SD_ST_IDENT ;
|
|
}
|
|
break ;
|
|
|
|
case SD_ST_IDENT :
|
|
i = sd_cmd3() ; // Get new RCA
|
|
if ( i == 0 )
|
|
{
|
|
Card_state = SD_ST_STBY ;
|
|
}
|
|
break ;
|
|
|
|
case SD_ST_STBY :
|
|
i = sd_cmd9() ;
|
|
// Calc transmission speed
|
|
i = Card_CSD[0] & 0x0000007F ;
|
|
{
|
|
uint32_t j ;
|
|
j = i >> 3 ;
|
|
j = SpeedTable[j] ;
|
|
j *= 10000 ;
|
|
i &= 7 ;
|
|
if ( i-- )
|
|
{
|
|
j *= 10 ;
|
|
}
|
|
if ( i-- )
|
|
{
|
|
j *= 10 ;
|
|
}
|
|
if ( i )
|
|
{
|
|
j *= 10 ;
|
|
}
|
|
SpeedAllowed = j ;
|
|
}
|
|
i = sd_cmd7() ; // Select Card
|
|
Card_state = SD_ST_TRAN ;
|
|
Sd_retries = 5 ;
|
|
break ;
|
|
|
|
case SD_ST_TRAN :
|
|
i = sd_acmd51( Sd_128_resp ) ;
|
|
if ( i != 0 )
|
|
{
|
|
if ( --Sd_retries > 0 )
|
|
{
|
|
break ;
|
|
}
|
|
}
|
|
Card_SCR[0] = Sd_128_resp[0] ;
|
|
Card_SCR[1] = Sd_128_resp[1] ;
|
|
Card_state = SD_ST_DATA ;
|
|
i = sd_acmd6() ; // Set bus width to 4 bits, and speed to 9 MHz
|
|
// Should check the card can do this ****
|
|
break ;
|
|
}
|
|
}
|
|
|
|
// Checks for card ready for read/write
|
|
// returns 1 for YES, 0 for NO
|
|
uint32_t sd_card_ready( void )
|
|
{
|
|
if ( CardIsConnected() )
|
|
{
|
|
if ( Card_state == SD_ST_DATA )
|
|
{
|
|
return 1 ;
|
|
}
|
|
}
|
|
return 0 ;
|
|
}
|
|
|
|
uint32_t sd_cmd16()
|
|
{
|
|
// @Mike: there is something wrong here, where could I have find infos???
|
|
//#if 0
|
|
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;
|
|
}
|
|
//#else
|
|
// return 0;
|
|
//#endif
|
|
}
|
|
|
|
uint32_t sd_read_block(uint32_t block_no, uint32_t *data)
|
|
{
|
|
uint32_t result = 0;
|
|
Hsmci *phsmci = HSMCI;
|
|
uint32_t status = 0;
|
|
|
|
if (sd_card_ready())
|
|
{
|
|
// sd_cmd16();
|
|
|
|
// Wait for card to be ready for data transfers
|
|
do {
|
|
sd_cmd13(&status);
|
|
} while (((status & STATUS_READY_FOR_DATA) == 0)
|
|
|| ((status & STATUS_STATE) != STATUS_TRAN) );
|
|
|
|
// Block size = 512, nblocks = 1
|
|
phsmci->HSMCI_BLKR = ((512) << 16) | 1;
|
|
phsmci->HSMCI_MR = (phsmci->HSMCI_MR & (~(HSMCI_MR_BLKLEN_Msk|HSMCI_MR_FBYTE))) | (HSMCI_MR_PDCMODE|HSMCI_MR_WRPROOF|HSMCI_MR_RDPROOF) | (512 << 16);
|
|
phsmci->HSMCI_ARGR = Cmd_A41_resp & 0x40000000 ? block_no : block_no << 9;
|
|
phsmci->HSMCI_RPR = CONVERT_PTR(data);
|
|
phsmci->HSMCI_RCR = 512 / 4;
|
|
phsmci->HSMCI_PTCR = HSMCI_PTCR_RXTEN;
|
|
phsmci->HSMCI_CMDR = SD_READ_SINGLE_BLOCK;
|
|
|
|
uint8_t retry = 100;
|
|
while (retry-- > 0)
|
|
{
|
|
#ifndef BOOT
|
|
CoTickDelay(1); // 2ms
|
|
#else
|
|
delay2ms() ;
|
|
#endif
|
|
if (phsmci->HSMCI_SR & HSMCI_SR_ENDRX)
|
|
{
|
|
// phsmci->HSMCI_PTCR = HSMCI_PTCR_RXTDIS;
|
|
result = 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
phsmci->HSMCI_PTCR = HSMCI_PTCR_RXTDIS;
|
|
phsmci->HSMCI_MR &= ~HSMCI_MR_PDCMODE;
|
|
return result;
|
|
}
|
|
|
|
uint32_t sd_write_block( uint32_t block_no, uint32_t *data )
|
|
{
|
|
uint32_t result = 0;
|
|
Hsmci *phsmci = HSMCI;
|
|
uint32_t status = 0;
|
|
|
|
if (sd_card_ready())
|
|
{
|
|
// sd_cmd16();
|
|
// Wait for card to be ready for data transfers
|
|
do {
|
|
sd_cmd13(&status);
|
|
} while (((status & STATUS_READY_FOR_DATA) == 0)
|
|
|| ((status & STATUS_STATE) != STATUS_TRAN) );
|
|
|
|
// Block size = 512, nblocks = 1
|
|
phsmci->HSMCI_BLKR = ((512) << 16) | 1;
|
|
phsmci->HSMCI_MR = (phsmci->HSMCI_MR & (~(HSMCI_MR_BLKLEN_Msk|HSMCI_MR_FBYTE))) | (HSMCI_MR_PDCMODE|HSMCI_MR_WRPROOF|HSMCI_MR_RDPROOF) | (512 << 16);
|
|
phsmci->HSMCI_ARGR = Cmd_A41_resp & 0x40000000 ? block_no : block_no << 9;
|
|
phsmci->HSMCI_TPR = CONVERT_PTR(data);
|
|
phsmci->HSMCI_TCR = 512 / 4;
|
|
phsmci->HSMCI_CMDR = SD_WRITE_SINGLE_BLOCK;
|
|
phsmci->HSMCI_PTCR = HSMCI_PTCR_TXTEN;
|
|
|
|
uint8_t retry = 100;
|
|
while (retry-- > 0) {
|
|
#ifndef BOOT
|
|
CoTickDelay(1); // 2ms
|
|
#else
|
|
delay2ms() ;
|
|
#endif
|
|
if (phsmci->HSMCI_SR & HSMCI_SR_NOTBUSY)
|
|
{
|
|
// phsmci->HSMCI_PTCR = HSMCI_PTCR_TXTDIS;
|
|
result = 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
phsmci->HSMCI_PTCR = HSMCI_PTCR_TXTDIS;
|
|
phsmci->HSMCI_MR &= ~HSMCI_MR_PDCMODE;
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
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
|
|
|
|
*/
|
|
|
|
|
|
#include "ff.h"
|
|
#include "diskio.h"
|
|
|
|
/* FAT sub-type boundaries */
|
|
/* Note that the FAT spec by Microsoft says 4085 but Windows works with 4087! */
|
|
#define MIN_FAT16 4086 /* Minimum number of clusters for FAT16 */
|
|
#define MIN_FAT32 65526 /* Minimum number of clusters for FAT32 */
|
|
|
|
|
|
/* FatFs refers the members in the FAT structures as byte array instead of
|
|
/ structure member because there are incompatibility of the packing option
|
|
/ between compilers. */
|
|
|
|
#define BS_jmpBoot 0
|
|
#define BS_OEMName 3
|
|
#define BPB_BytsPerSec 11
|
|
#define BPB_SecPerClus 13
|
|
#define BPB_RsvdSecCnt 14
|
|
#define BPB_NumFATs 16
|
|
#define BPB_RootEntCnt 17
|
|
#define BPB_TotSec16 19
|
|
#define BPB_Media 21
|
|
#define BPB_FATSz16 22
|
|
#define BPB_SecPerTrk 24
|
|
#define BPB_NumHeads 26
|
|
#define BPB_HiddSec 28
|
|
#define BPB_TotSec32 32
|
|
#define BS_DrvNum 36
|
|
#define BS_BootSig 38
|
|
#define BS_VolID 39
|
|
#define BS_VolLab 43
|
|
#define BS_FilSysType 54
|
|
#define BPB_FATSz32 36
|
|
#define BPB_ExtFlags 40
|
|
#define BPB_FSVer 42
|
|
#define BPB_RootClus 44
|
|
#define BPB_FSInfo 48
|
|
#define BPB_BkBootSec 50
|
|
#define BS_DrvNum32 64
|
|
#define BS_BootSig32 66
|
|
#define BS_VolID32 67
|
|
#define BS_VolLab32 71
|
|
#define BS_FilSysType32 82
|
|
#define FSI_LeadSig 0
|
|
#define FSI_StrucSig 484
|
|
#define FSI_Free_Count 488
|
|
#define FSI_Nxt_Free 492
|
|
#define MBR_Table 446
|
|
#define BS_55AA 510
|
|
|
|
#define DIR_Name 0
|
|
#define DIR_Attr 11
|
|
#define DIR_NTres 12
|
|
#define DIR_CrtTime 14
|
|
#define DIR_CrtDate 16
|
|
#define DIR_FstClusHI 20
|
|
#define DIR_WrtTime 22
|
|
#define DIR_WrtDate 24
|
|
#define DIR_FstClusLO 26
|
|
#define DIR_FileSize 28
|
|
#define LDIR_Ord 0
|
|
#define LDIR_Attr 11
|
|
#define LDIR_Type 12
|
|
#define LDIR_Chksum 13
|
|
#define LDIR_FstClusLO 26
|
|
|
|
#ifdef BOOT
|
|
#if !defined(SIMU)
|
|
#include "Fat12.cpp"
|
|
#endif
|
|
#endif
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
/* Initialize Disk Drive */
|
|
/*-----------------------------------------------------------------------*/
|
|
|
|
DSTATUS disk_initialize (
|
|
BYTE drv /* Physical drive nmuber (0) */
|
|
)
|
|
{
|
|
#ifdef BOOT
|
|
if (drv==1) return RES_OK ; /* EEPROM */
|
|
#endif
|
|
if (drv) return STA_NOINIT; /* Supports only single drive */
|
|
if ( sd_card_ready() == 0 ) return RES_NOTRDY;
|
|
return RES_OK;
|
|
|
|
#if 0
|
|
BYTE n, cmd, ty, ocr[4];
|
|
|
|
|
|
if (drv) return STA_NOINIT; /* Supports only single drive */
|
|
|
|
if (Stat & STA_NODISK) return Stat; /* No card in the socket */
|
|
|
|
power_on(); /* Force socket power on */
|
|
FCLK_SLOW();
|
|
for (n = 10; n; n--) rcvr_spi(); /* 80 dummy clocks */
|
|
|
|
ty = 0;
|
|
if (send_cmd(CMD0, 0) == 1) { /* Enter Idle state */
|
|
Timer1 = 100; /* Initialization timeout of 1000 msec */
|
|
if (send_cmd(CMD8, 0x1AA) == 1) { /* SDv2? */
|
|
for (n = 0; n < 4; n++) ocr[n] = rcvr_spi(); /* Get trailing return value of R7 resp */
|
|
if (ocr[2] == 0x01 && ocr[3] == 0xAA) { /* The card can work at vdd range of 2.7-3.6V */
|
|
while (Timer1 && send_cmd(ACMD41, 1UL << 30)); /* Wait for leaving idle state (ACMD41 with HCS bit) */
|
|
if (Timer1 && send_cmd(CMD58, 0) == 0) { /* Check CCS bit in the OCR */
|
|
for (n = 0; n < 4; n++) ocr[n] = rcvr_spi();
|
|
ty = (ocr[0] & 0x40) ? CT_SD2 | CT_BLOCK : CT_SD2; /* SDv2 */
|
|
}
|
|
}
|
|
} else { /* SDv1 or MMCv3 */
|
|
if (send_cmd(ACMD41, 0) <= 1) {
|
|
ty = CT_SD1; cmd = ACMD41; /* SDv1 */
|
|
} else {
|
|
ty = CT_MMC; cmd = CMD1; /* MMCv3 */
|
|
}
|
|
while (Timer1 && send_cmd(cmd, 0)); /* Wait for leaving idle state */
|
|
if (!Timer1 || send_cmd(CMD16, 512) != 0) /* Set R/W block length to 512 */
|
|
ty = 0;
|
|
}
|
|
}
|
|
CardType = ty;
|
|
deselect();
|
|
|
|
if (ty) { /* Initialization succeded */
|
|
Stat &= ~STA_NOINIT; /* Clear STA_NOINIT */
|
|
FCLK_FAST();
|
|
} else { /* Initialization failed */
|
|
power_off();
|
|
}
|
|
|
|
return Stat;
|
|
#endif
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
/* Get Disk Status */
|
|
/*-----------------------------------------------------------------------*/
|
|
|
|
DSTATUS disk_status ( BYTE drv /* Physical drive number (0) */ )
|
|
{
|
|
|
|
if (drv==1) return RES_OK ; /* EEPROM */
|
|
if (drv) return STA_NOINIT; /* Supports only single drive */
|
|
if ( sd_card_ready() == 0 ) return RES_NOTRDY;
|
|
return RES_OK;
|
|
}
|
|
|
|
#if !defined(SIMU)
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
/* Read Sector(s) */
|
|
/*-----------------------------------------------------------------------*/
|
|
|
|
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 ( !count) return RES_PARERR ;
|
|
|
|
#ifdef BOOT
|
|
if (drv==1) /* EEPROM */
|
|
{
|
|
|
|
do
|
|
{
|
|
result = fat12Read( buff, sector ) ;
|
|
if (result)
|
|
{
|
|
sector += 1 ;
|
|
buff += 512 ;
|
|
count -= 1 ;
|
|
}
|
|
else
|
|
{
|
|
count = 1 ; // Flag error
|
|
break ;
|
|
}
|
|
} while ( count ) ;
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
if (drv ) return RES_PARERR;
|
|
|
|
if ( sd_card_ready() == 0 ) return RES_NOTRDY;
|
|
|
|
do {
|
|
result = sd_read_block( sector, ( uint32_t *)buff ) ;
|
|
if (result) {
|
|
sector += 1 ;
|
|
buff += 512 ;
|
|
count -= 1 ;
|
|
}
|
|
else {
|
|
count = 1 ; // Flag error
|
|
break ;
|
|
}
|
|
} while ( count ) ;
|
|
}
|
|
return count ? RES_ERROR : RES_OK;
|
|
}
|
|
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
/* Write Sector(s) */
|
|
/*-----------------------------------------------------------------------*/
|
|
|
|
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 ( !count) return RES_PARERR ;
|
|
|
|
#ifdef BOOT
|
|
if (drv==1) /* EEPROM */
|
|
{
|
|
count = fat12Write( buff, sector, count ) ;
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
if (drv ) return RES_PARERR;
|
|
|
|
if ( sd_card_ready() == 0 ) return RES_NOTRDY;
|
|
|
|
// TODO if (Stat & STA_PROTECT) return RES_WRPRT;
|
|
|
|
do {
|
|
result = sd_write_block( sector, ( uint32_t *)buff ) ;
|
|
if (result) {
|
|
sector += 1 ;
|
|
buff += 512 ;
|
|
count -= 1 ;
|
|
}
|
|
else {
|
|
count = 1 ; // Flag error
|
|
break ;
|
|
}
|
|
} while ( count ) ;
|
|
}
|
|
return count ? RES_ERROR : RES_OK;
|
|
}
|
|
|
|
#endif
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
/* Miscellaneous Functions */
|
|
/*-----------------------------------------------------------------------*/
|
|
|
|
DRESULT disk_ioctl (
|
|
BYTE drv, /* Physical drive nmuber (0) */
|
|
BYTE ctrl, /* Control code */
|
|
BYTE *buff /* Buffer to send/receive control data */
|
|
)
|
|
{
|
|
DRESULT res;
|
|
BYTE *csd = (BYTE*)&Card_CSD[0];
|
|
BYTE n; // csd[16], *ptr = buff;
|
|
WORD csize;
|
|
|
|
res = RES_ERROR;
|
|
#ifdef BOOT
|
|
if (drv==1)
|
|
{
|
|
switch (ctrl)
|
|
{
|
|
case CTRL_SYNC : /* Make sure that no pending write process. Do not remove this or written sector might not left updated. */
|
|
/* BSS if (select()) {
|
|
deselect(); */
|
|
res = RES_OK;
|
|
// }
|
|
break ;
|
|
|
|
case GET_SECTOR_COUNT : /* Get number of sectors on the disk (DWORD) */
|
|
#ifdef REVX
|
|
*(DWORD*)buff = (DWORD)2051 ;
|
|
#else
|
|
*(DWORD*)buff = (DWORD)1539 ;
|
|
#endif
|
|
res = RES_OK;
|
|
break;
|
|
|
|
case GET_SECTOR_SIZE : /* Get R/W sector size (WORD) */
|
|
*(WORD*)buff = 512;
|
|
res = RES_OK;
|
|
break;
|
|
|
|
}
|
|
return res ;
|
|
}
|
|
#endif
|
|
|
|
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. */
|
|
/* BSS if (select()) {
|
|
deselect(); */
|
|
res = RES_OK;
|
|
// }
|
|
break;
|
|
|
|
case GET_SECTOR_COUNT : /* Get number of sectors on the disk (DWORD) */
|
|
// if ((send_cmd(CMD9, 0) == 0) && rcvr_datablock(csd, 16)) {
|
|
if ((csd[0] >> 6) == 1) { /* SDC ver 2.00 */
|
|
csize = csd[9] + ((WORD)csd[8] << 8) + 1;
|
|
*(DWORD*)buff = (DWORD)csize << 10;
|
|
} else { /* SDC ver 1.XX or MMC*/
|
|
n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2;
|
|
csize = (csd[8] >> 6) + ((WORD)csd[7] << 2) + ((WORD)(csd[6] & 3) << 10) + 1;
|
|
*(DWORD*)buff = (DWORD)csize << (n - 9);
|
|
}
|
|
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) */
|
|
// only used in f_mkfs
|
|
#if 0
|
|
if (CardType & CT_SD2) { /* SDv2? */
|
|
if (send_cmd(ACMD13, 0) == 0) { /* Read SD status */
|
|
rcvr_spi();
|
|
if (rcvr_datablock(csd, 16)) { /* Read partial block */
|
|
for (n = 64 - 16; n; n--) rcvr_spi(); /* Purge trailing data */
|
|
*(DWORD*)buff = 16UL << (csd[10] >> 4);
|
|
res = RES_OK;
|
|
}
|
|
}
|
|
} else { /* SDv1 or MMCv3 */
|
|
if ((send_cmd(CMD9, 0) == 0) && rcvr_datablock(csd, 16)) { /* Read CSD */
|
|
if (CardType & CT_SD1) { /* SDv1 */
|
|
*(DWORD*)buff = (((csd[10] & 63) << 1) + ((WORD)(csd[11] & 128) >> 7) + 1) << ((csd[13] >> 6) - 1);
|
|
} else { /* MMCv3 */
|
|
*(DWORD*)buff = ((WORD)((csd[10] & 124) >> 2) + 1) * (((csd[11] & 3) << 3) + ((csd[11] & 224) >> 5) + 1);
|
|
}
|
|
res = RES_OK;
|
|
}
|
|
}
|
|
#endif
|
|
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;
|
|
}
|
|
|
|
// BSS deselect();
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|