/* * Authors (alphabetical order) * - Bertrand Songis * - Bryan J. Rentoul (Gruvin) * - Cameron Weeks * - Erez Raviv * - Jean-Pierre Parisy * - Karl Szmutny * - Michael Blandford * - Michal Hlavinka * - Pat Mackenzie * - Philip Moss * - Rob Thomson * - Romolo Manfredini * - 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; }