⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ffs_port_mmc.c

📁 The Fat Fs module is a middleware that written in ANSI C. There is no platform dependence, so long a
💻 C
📖 第 1 页 / 共 2 页
字号:
/***********************************************************
*         FFS/FAT Port to MMC/SD-slot using SPI-mode       *
*                                                          *
*          by  Frank Goetze  -  www.embedded-os.de         *
************************************************************
*                     FFS_Port_MMC.c                       *
*                 FFS/FAT to MMC(SPI) PORT                 *
************************************************************
*      - code generation            Frank Goetze   06/2007 *
*      - redesign & SDHC-support    Frank Goetze   09/2007 *
*      - split SD1.xx and (HD-)MMC  Frank Goetze   01/2008 *
*        detection                                         *
*      - add support for older      Frank Goetze   01/2008 *
*        MMCs and none-standard SDs                        *
*      - add support for MMCplus    Frank Goetze   02/2008 *
*        (HS-MMC) and HD-MMC cards                         *
*        -> HD-MMC not tested !!!                          *
*      - add lost lines for HD-MMC  Frank Goetze   03/2008 *
*      - add support for SAM7SExx   Frank Goetze   04/2008 *
*        and DMA mode for sectors                          *
*      - small bugfix for HD-MMC    Frank Goetze   01/2009 *
*                                                          *
***********************************************************/

#include "../../inc/MMC/FFS_Port_MMC.h"

#define MMC_EXT_CSD_CHECK                                  // optional support for HS-MMC(MMCplus) and HD-MMC (--> tested on AT91SAM7SExx)

/****************** constant variables ********************/
OS_CONST U08 OS_ROMDATA MMC_m[] = {10,12,13,15,20,25,30,35,40,45,50,55,60,70,80};

/******************* global variables *********************/
FFS_SIZE  FFS_values;                                      // device-informations
U08       FFSp_data[16];                                   // array for reading Rx, CID, CSD (and later ext-CSD)
U08       FFSp_ver;                                        // holder for version (to support SDHC and HD-MMC)
U08       FFSp_sshift;                                     // holder for sec-to-addr shifter (on SDHC and HD-MMC its 0 since we use sector-numbers)
U32       MMC_Nac;                                         // time between CMD-R1 & data on reading (also Ncx)
U32       MMC_Nbs;                                         // time between data-responce & finish on writing (max busy-time)

#ifdef MMC_EXT_CSD_CHECK
 U08      FFSp_exCSD[512];
#endif

/*
************************************************************
*            write a command to the MMC/SD
************************************************************
*/
U08 MMCWriteCMD(U08 cmd, U32 arg, U08 end)
{
    U08 cnt, res;

    cnt = 0;
    switch(cmd) {                                          // get CRC7s for cmds in front of CRC-OFF
        case MMC_GO_IDLE_STATE: res = 0x95; break;         // valid CRC7 for RESET
        case SD_SEND_IF_COND: res = 0x86; break;           // valid CRC7 for IF_COND(0x1AA) on SD/SDHC-cards
        default: res = 0xFF; break;
    }
    FFSPort_MMC_Send(0xFF);                                // wait "Nrc" in front of CMD
    FFSPort_MMC_CS_ON;                                     // enable MMC-interface
    FFSPort_MMC_Send(cmd | 0x40);                          // write CMD plus start-flag
    FFSPort_MMC_Send((U08)(arg >> 24));                    // write parameter (automatic endian corrected)
    FFSPort_MMC_Send((U08)(arg >> 16));
    FFSPort_MMC_Send((U08)(arg >>  8));
    FFSPort_MMC_Send((U08)(arg));
    FFSPort_MMC_Send(res);                                 // write (dummy)-CRC7
    if(cmd == MMC_STOP_TRANSMISSION)
        FFSPort_MMC_Send(0xFF);                            // skip stuff-byte after STOP_TRANSMISSION cmd
    do {
        res = FFSPort_MMC_Send(0xFF); cnt++;               // wait "Ncr" for R1 or R1b (normally 1..8 pings)
    } while((res == 0xFF) && (cnt < 8));
    if(res == 0xFE) res = FFSPort_MMC_Send(0xFF) >> 1;     // older MMC-cards comes 1-bit to early on R1
    if(end) FFSPort_MMC_CS_OFF;                            // disable MMC-interface
    return(res);                                           // last value
}

/*
************************************************************
*          write a R2..R7-command to the MMC/SD
************************************************************
*/
U08 MMCWriteCMD_Rx(U08 cmd, U32 arg, U08 OS_HUGE *buff, U32 count)
{
    U32 i;
    U08 r1;

    r1 = MMCWriteCMD(cmd, arg, 0);                         // send CMD(arg) and collect first 8bits of Rx (as R1)
    for(i = 0; i < count; i++) {                           // (older MMCs do not support the used cmds - so need here no correction)
        buff[i] = FFSPort_MMC_Send(0xFF);                  // read additional Rx bytes
    }
    FFSPort_MMC_CS_OFF;                                    // disable MMC-interface
    return(r1);                                            // return r1 for caller
}

/*
************************************************************
*              read status from the MMC/SD
************************************************************
*/
U08 MMCReadStatus(U08 r1)
{
    U08 r[3];

    r[0] = r1;                                             // notice R1
    r[1] = MMCWriteCMD(MMC_SEND_STATUS, 0, 0);             // read   R2
    r[2] = FFSPort_MMC_Send(0xFF);                         // control-read (should be 0xFF as readed data)
    FFSPort_MMC_CS_OFF;                                    // disable MMC-interface
    if(r[0] == 0xFF) return(FFS_PORT_ERR);                 // if no direct error-code given from caller, return

    // you can decode R1 & R2 here

    return(r1);                                            // return r1 for caller
}

/*
************************************************************
*              read a block from the MMC/SD
************************************************************
*/
U08 MMCReadBlock(U08 cmd, U32 arg, U08 OS_HUGE *buff, U32 count)
{
    U32 i;
    U08 res;

    i = 0;
    res = MMCWriteCMD(cmd, arg, 0);
    if(res != FFS_NO_ERR) {                                // wrong response! ..
        FFSPort_MMC_CS_OFF;                                // .. disable MMC-interface ...
        return(MMCReadStatus(res));                        // ... read status & return the error
    }
    do {
        res = FFSPort_MMC_Send(0xFF); i++;                 // wait "Nac"/"Ncx" for startbyte (0xFE)
    } while((res == 0xFF) && (i < MMC_Nac));
    if(i >= MMC_Nac) {                                     // startbyte received ? ..
        FFSPort_MMC_CS_OFF;                                // .. disable MMC-interface ...
        return(MMCReadStatus(res));                        // ... read status & return the error
    }
    if(!(res & 0x02)) {                                    // older MMC-cards comes 1-bit to early
        U08 s;

        for(i = 0; i < count; i++) {
            s = res << 7;                                  // save old bits of new byte
            res = FFSPort_MMC_Send(0xFF);                  // get new byte
            buff[i] = (res >> 1) | s;                      // store valid bits of new and saved bits
        }
    } else {                                               // --> actual cards
#ifdef USE_MMC_DMA
        FFSPort_MMC_RxBlock(buff, count);                  //   - read data via DMA
#else
        for(i = 0; i < count; i++) {
            buff[i] = FFSPort_MMC_Send(0xFF);              //   - read data
        }
#endif
    }
    FFSPort_MMC_Send(0xFF); FFSPort_MMC_Send(0xFF);        // read 2 bytes CRC16 (not used)
    FFSPort_MMC_CS_OFF;                                    // disable MMC-interface
    return(FFS_NO_ERR);
}

/*
************************************************************
*            initialise the FFS-Port (no media-init)
************************************************************
*/
U08 FFSPort_Init(void)
{
    MMC_Nac = 8;                                           // Ncx as first "wait for data on read" value - up to CSD was read
    MMC_Nbs = 1024;                                        // Nbusy set, to be shure its not zero        - up to CSD was read
    if(FFSPort_MMC_Init()) return(FFS_PORT_ERR);           // init low-level (hardware specific)
    return(FFS_NO_ERR);
}

/*
************************************************************
*                check media presence
************************************************************
*/
U08 FFSPort_MediaDetect(void)
{
    if(FFSPort_MMC_CD()) {                                 // check if a card present
        MMC_Nac = 8;                                       // Ncx as first "wait for data on read" value - up to CSD was read
        MMC_Nbs = 1024;                                    // Nbusy set, to be shure its not zero        - up to CSD was read
        return(FFS_NO_MEDIA);
    }
    return(FFS_NO_ERR);
}

#ifdef MMC_EXT_CSD_CHECK
/*
************************************************************
*  check and handle EXT-CSD from MMCplus- & HD-MMC- cards
************************************************************
*/
U32 MMCHandle_ExtCsd(U08 card_type, U32 s_speed, U32 c_size, U16 c_size_mult)
{
    U32 h_speed, tmp;
    
    h_speed = 0;                                           // default no higher-speed is set
    if((((FFSp_data[0] & 0xC0) >> 6) >= 2) && (((FFSp_data[0] & 0x3C) >> 2) >= 4)) {         // be shure it's a MMC4.x card
        // why some cards are MMC4.x cards but do not support EXT_CSD ???
        // ... and why some cards are not MMC4.x but supports EXT_CSD ???
        if(MMCReadBlock(MMC_SEND_EXTCSD, 0, (U08 OS_HUGE *)FFSp_exCSD, 512) == FFS_NO_ERR) { // read EXT_CSD
            tmp = ((U32)(FFSp_exCSD[215]) << 24) | ((U32)(FFSp_exCSD[214]) << 16) | ((U32)(FFSp_exCSD[213]) << 8) | FFSp_exCSD[212];
            if((FFSp_exCSD[192] >= 2)) {                   // EXT_CSD.sec_count can only be valid for HD-MMC if EXT_CSD Rev. 1.2 and higher
                if((c_size == 0x0FFF) && (c_size_mult == (0x0001 << 9)) && (tmp != 0)) {
                    FFS_values.maxsectors = tmp;           // MMC4.2 says, "c_size" & "c_size_mult" should be set to "max" and a valid sec_count in EXT_CSD
                    FFS_values.sectorsize = 512;           // this sec_count is based on fix 512bytes/sector (also as default blocklength)
                    if(card_type == FFSp_MARK_HDMMC) {     // if HD-MMC -> we work block-based
                        FFSp_sshift = 0;                   // code-compatibility -> no shift needed 
                    }
                }
            }
            if(FFSp_exCSD[196] == 0x03) {                  // if hs-timing possible
                if(MMCWriteCMD(MMC_SWITCH, 0x03B90100, 1) == FFS_NO_ERR) { // 03-switch mode(write-byte) , B9-185(hs_timing) , 01-value , 00-set
                    h_speed = FFSPort_MMC_SetBR(52000000); // was switched -> set "EXT_CSD - high-speed" and return used-speed
                }
            } else h_speed = FFSPort_MMC_SetBR(26000000);  // set "EXT_CSD - normal-speed" and return used-speed
            for(tmp = 0; tmp < 0xFFFF; tmp++) { _NOP(); _NOP(); _NOP(); }   // wait for resync card-internally (processor-speed depending)
            if(h_speed <= s_speed) h_speed = 0;            // nothing changed (no timing recalculation needed)
        }
    }
    return(h_speed);                                       // if not zero -> timing recalculation is needed
}
#endif

/*
************************************************************

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -