📄 ffs_port_mmc.c
字号:
* initialise the MMC/SD-card and get some card-data
************************************************************
*/
FFS_SIZE *FFSPort_MediaInit(void)
{
U32 c_size, s_speed, s_div;
U16 c_size_mult;
U08 i;
FFSp_ver = FFSp_MARK_MMC; // mark as normal MMC-card at start-up
for(i = 0; i < 0xFF; i++) { _NOP(); _NOP(); _NOP(); } // wait for a stable card, 1ms (says MMC)
if(FFSPort_MediaDetect()) return(NULL); // media present ?
FFSPort_MMC_ReInit(); // reinit interface (clock)
for(i = 0; i < 10; i++) FFSPort_MMC_Send(0xFF); // start MMC/SD in SPI-Mode, card-reset (74+ ckl)
i = 0; // set IDLE_MODE (repeat)
while((MMCWriteCMD(MMC_GO_IDLE_STATE, 0, 1) != MMC_R1_IDLE_STATE) && (i < 0xFF)) i++;
if(i == 0xFF) return(NULL); // TimeOut error
// After CMD0 the SPI interface is initialized in the CRC OFF mode in default.
// But the CMD8 CRC verification is always enabled.
i = MMCWriteCMD_Rx(SD_SEND_IF_COND, 0x1AA, (U08 OS_HUGE *)FFSp_data, 4); // send CMD8 to see it is SD & extended card and expand ACMD41 (R1-part of R7)
// for not-MMC4.x and not-SD2.x cards CMD8 is unknown -- for MMC4.x cards CMD8 is not allowed here (in front of CMD1 / CMD58)
if(i <= MMC_R1_IDLE_STATE) { // ================== SD 2.00 ==================
FFSp_ver = FFSp_MARK_SD; // mark as SD-card
if(!(FFSp_data[2] & 0x01) || (FFSp_data[3] != 0xAA)) return(NULL); // check CMD8 R7-response -> unsupported card
c_size = 0; // repeat ACMD41 - HCS (High Capacity Support) bit is in the argument of ACMD41 (SD 2.00)
while(((MMCWriteCMD(MMC_APP_CMD, 0, 1) > MMC_R1_IDLE_STATE ) ||
(MMCWriteCMD(SD_SEND_OP_COND_ACMD41, 1UL << 30, 1) != FFS_NO_ERR)) && (c_size < 0xFFFF)) c_size++;
if(c_size == 0xFFFF) return(NULL); // TimeOut error
i = MMCWriteCMD_Rx(MMC_READ_OCR, 0, (U08 OS_HUGE *)FFSp_data, 4);
if(i != FFS_NO_ERR) return(NULL); // send CMD58 (check R1-part of R3) ..
FFSp_ver |= (FFSp_data[0] & 0x40) >> 6; // and copy CCS-bit from R3 (SDHC-card)
} else { // ============= SD 1.xx / (HD-)MMC ============
// why some SD 1.xx cards response with "bullshit" on CMD8 (like 0x82) but the rest is functional ???
// if(i & ~(MMC_R1_ILLEGAL_COM | MMC_R1_IDLE_STATE)) return(NULL); // more R1-flags than IDLE & ILLEGAL_CMD -> unsupported card
c_size = 0; i = MMC_R1_ILLEGAL_COM; // repeat ACMD41 - HCS (High Capacity Support) bit is NOT in the argument of ACMD41 (SD 1.xx)
while(((MMCWriteCMD(MMC_APP_CMD, 0, 1) > MMC_R1_IDLE_STATE ) ||
(i = MMCWriteCMD(SD_SEND_OP_COND_ACMD41, 0, 1) != FFS_NO_ERR)) && (c_size < 0xFFFF)) {
if(i & MMC_R1_ILLEGAL_COM) break;
c_size++;
}
if(c_size == 0xFFFF) return(NULL); // TimeOut error
if(i & MMC_R1_ILLEGAL_COM) { // ================== (HD-)MMC =================
FFSp_ver = FFSp_MARK_MMC; // be shure is marked as MMC-card
c_size = 0; s_div = 1UL << 30; // send MMC_OP_MODE w/wo HD-support (repeat)
while(((i = MMCWriteCMD(MMC_SEND_OP_COND, s_div, 1)) != FFS_NO_ERR) && (c_size < 0xFFFF)) {
c_size++;
if(i & (MMC_R1_PARAMETER | MMC_R1_ADDRESS)) s_div = 0; // switch back to normal MMC
}
if(c_size == 0xFFFF) return(NULL); // TimeOut error
if(s_div) { // if possible HD-MMC ..
i = MMCWriteCMD_Rx(MMC_READ_OCR, 0, (U08 OS_HUGE *)FFSp_data, 4);
if(i != FFS_NO_ERR) return(NULL); // .. send CMD58 (check R1-part of R3) ..
FFSp_ver |= ((FFSp_data[0] & 0x60) == 0x40)? FFSp_MARK_HDMMC : FFSp_MARK_MMC;
} // .. and test bit30/29 from R3 (HD-MMC card)
} else { // ================== SD 1.xx ==================
FFSp_ver = FFSp_MARK_SD; // mark as SD-card
}
}
/*********** get needed card information ***********/
i = MMCReadBlock(MMC_SEND_CID, 0, (U08 OS_HUGE *)FFSp_data, 16); // read CID for vendor- & product- ID
if(i != FFS_NO_ERR) return(NULL);
FFS_values.vp_id = ((U32)FFSp_data[0] << 16) | (((U16)FFSp_data[2] << 8) | FFSp_data[1]);
FFS_values.flags = 0; // copy vendor- & product-ID plus WP-bit=0
i = MMCReadBlock(MMC_SEND_CSD, 0, (U08 OS_HUGE *)FFSp_data, 16); // read CSD for card-speed & card-size
if(i != FFS_NO_ERR) return(NULL);
if((FFSp_ver == FFSp_MARK_SDHC) && (!(FFSp_data[0] & 0x3C))) { // doublecheck if SDHC-card with new CSD response ..
FFSp_ver = (FFSp_data[0] & 0xC0)? FFSp_MARK_SDHC : FFSp_MARK_SD; // SD-card plus .. scan of CSD-version (for SDHC cards)
}
for(s_speed = 1, i = FFSp_data[3] & 0x07; i > 0; s_speed *= 10, i--); // (TRAN_SPEED_tu*10)
s_speed *= (U32)(MMC_m[((FFSp_data[3] >> 3) & 0x0F) -1]) * 10000; // (TRAN_SPEED_tu*10) * (TRAN_SPEED_tv*10) * 10000 = x (in Hz)
s_speed = FFSPort_MMC_SetBR(s_speed); // set max-speed in Hz and return used-speed
// We calculate timings for High Capacity SD Memory Cards too, since we don't use a timer (for 100ms and 250ms).
// We use the fixed values of TAAC , NSAC and R2W_FACTOR of a SDHC-card to get clock-based time-out's !!!
for(s_div = 1000, i = 7 - (FFSp_data[1] & 0x07); i > 0; s_div *= 10, i--); // for: 1 / (TAAC_tu*10)
c_size = s_speed * (U32)(MMC_m[((FFSp_data[1] >> 3) & 0x0F) - 1]); // as: (TAAC_tv*10) * Fop
MMC_Nac = (10UL * (c_size / s_div) + 100UL * (U32)(FFSp_data[2])) / 8 + 1; // 10 * ( ((TAAC_tv*10) * Fop) / (TAAC_tu*10) + 100 * NSAC) / 8
MMC_Nbs = MMC_Nac * (U32)((FFSp_data[12] >> 2) & 0x07); // Nac * R2W
// some SD-cards have (in comparison with other cards) extrem low timings declared
// but are not running stable with it -> so we can fix this by adding extra timing
MMC_Nac *= 5; // expand timeouts to a "normal" range
MMC_Nbs *= 5;
switch(FFSp_ver) {
case FFSp_MARK_MMC: // ******************** normal MMC-cards *********************
case FFSp_MARK_SD: // ********************* normal SD-cards *********************
// the maximum capacity can be 4GB, defined by CSD structure and 32bit byte-addressing
// this is possible on: C_SIZE_MULT C_SIZE READ_BL_LEN
// 2^(7+2) * 2^12 * 2^11
// 512 * 4096 * 2048 = 4GB
c_size = ((U16)(FFSp_data[6] & 0x03) << 10) | ((U16)FFSp_data[7] << 2) | (FFSp_data[8] >> 6);
c_size_mult = 0x0001 << (2+(((FFSp_data[9] & 0x03) << 1) | (FFSp_data[10] >> 7)));
FFSp_sshift = FFSp_data[5] & 0x0F; // get READ_BL_LEN as shift-value
FFS_values.sectorsize = 0x0001UL << FFSp_sshift; // copy BytsPerSec from READ_BL_LEN
FFS_values.maxsectors = ((U32)c_size + 1) * c_size_mult; // get calculated MaxSectors
#ifdef MMC_EXT_CSD_CHECK
if(FFSp_ver == FFSp_MARK_MMC) { // only for MMC-cards ...
s_speed = MMCHandle_ExtCsd(FFSp_ver, s_speed, c_size, c_size_mult);
if(s_speed != 0) { // if EXT_CSD supported and a new speed set -> we have to recalculate the timings
for(s_div = 1000, i = 7 - (FFSp_data[1] & 0x07); i > 0; s_div *= 10, i--); // for: 1 / (TAAC_tu*10)
s_speed *= (U32)(MMC_m[((FFSp_data[1] >> 3) & 0x0F) - 1]); // as: (TAAC_tv*10) * Fop
MMC_Nac = (10UL * (s_speed / s_div) + 100UL * (U32)(FFSp_data[2])) / 8 + 1; // 10 * ( ((TAAC_tv*10) * Fop) / (TAAC_tu*10) + 100 * NSAC) / 8
MMC_Nbs = MMC_Nac * (U32)((FFSp_data[12] >> 2) & 0x07); // Nac * R2W
i = MMCReadBlock(MMC_SEND_EXTCSD, 0, (U08 OS_HUGE *)FFSp_exCSD, 512); // read EXT_CSD again for resync card-internally
}
}
#endif
break;
case FFSp_MARK_SDHC: // ***************** highcapacity SDHC-cards *****************
// the maximum capacity can be 2TB, defined by CSD 2.0 structure and 32bit block-addressing
// actual as maximum defined are 32GB (upper 6bit of C_SIZE should be zero says SD 2.00)
if((FFSp_data[5] & 0x0F) != 9) return(NULL); // control READ_BL_LEN - must be "9" on SDHC-cards
FFSp_sshift = 0; // code-compatibility -> no shift needed
FFS_values.sectorsize = 0x0001UL << 9; // set BytsPerSec fix
c_size = ((U32)(FFSp_data[7] & 0x3F) << 16) | ((U32)FFSp_data[8] << 8) | (FFSp_data[9]);
FFS_values.maxsectors = (c_size+1) << 10; // get MaxSectors -> mcap=(csize+1)*512k -> msec=mcap/BytsPerSec(fix)
break;
case FFSp_MARK_HDMMC: // ****************** high density MMC-cards *****************
FFSp_sshift = 1; // mark as invalid for HD-MMC (for a following check later)
#ifdef MMC_EXT_CSD_CHECK
c_size = ((U16)(FFSp_data[6] & 0x03) << 10) | ((U16)FFSp_data[7] << 2) | (FFSp_data[8] >> 6);
c_size_mult = 0x0001 << (2+(((FFSp_data[9] & 0x03) << 1) | (FFSp_data[10] >> 7)));
s_speed = MMCHandle_ExtCsd(FFSp_ver, s_speed, c_size, c_size_mult);
if(s_speed != 0) { // if EXT_CSD supported and a new speed set -> we have to recalculate the timings
if(FFSp_sshift != 0) return(NULL); // no valid HD-MMC marks in EXT_CSD
for(s_div = 1000, i = 7 - (FFSp_data[1] & 0x07); i > 0; s_div *= 10, i--); // for: 1 / (TAAC_tu*10)
s_speed *= (U32)(MMC_m[((FFSp_data[1] >> 3) & 0x0F) - 1]); // as: (TAAC_tv*10) * Fop
MMC_Nac = (10UL * (s_speed / s_div) + 100UL * (U32)(FFSp_data[2])) / 8 + 1; // 10 * ( ((TAAC_tv*10) * Fop) / (TAAC_tu*10) + 100 * NSAC) / 8
MMC_Nbs = MMC_Nac * (U32)((FFSp_data[12] >> 2) & 0x07); // Nac * R2W
i = MMCReadBlock(MMC_SEND_EXTCSD, 0, (U08 OS_HUGE *)FFSp_exCSD, 512); // read EXT_CSD again for resync card-internally
} else return(NULL); // not MMC4.x or EXT_CSD not supported
break;
#else
// !!! here in Germany I can't get any HD-MMC cards, so actual this code does not support HD-MMC cards !!!
// what is todo: - read extended-CSD
// - check EXT_CSD_REV and CARD_TYPE
// - read maxsectors = SEC_COUNT
// - set clock (normal /highspeed) and recalculate the timings
return(NULL);
//lint -unreachable
// break;
#endif
default: // ***** unknown type of MMC/SD-card *****
return(NULL);
//lint -unreachable
// break;
}
if(FFS_values.sectorsize != 512) { // if (actual) blocks of card greater 512-bytes (never on HD-MMC- and SDHC-cards)
i = MMCWriteCMD(MMC_SET_BLOCKLEN, 512, 1); // set blocklength of transfers to 512 to be shure (all cards must support this value)
if(i == FFS_NO_ERR) {
FFS_values.maxsectors *= (FFS_values.sectorsize / 512);
FFS_values.sectorsize = 512; // recalculate maxsectors, set sectorsize
FFSp_sshift = 9; // and set shift manually (possible only on none HD-MMC- and SDHC-cards)
}
}
return(&FFS_values); // return the card-size infos
}
/*
************************************************************
* read a hole sector from the MMC/SD
************************************************************
*/
U08 FFSPort_ReadSector(U32 sector, U08 OS_HUGE *buff)
{
U08 res;
res = FFSPort_MediaDetect();
if(res != FFS_NO_ERR) return(res); // media present ?
res = MMCReadBlock(MMC_READ_SINGLE_BLOCK, sector << FFSp_sshift, buff, FFS_values.sectorsize);
if(res != FFS_NO_ERR) return(MMCReadStatus(res)); // read a hole sector and ...
return(FFS_NO_ERR); // ... read status if was an error
}
/*
************************************************************
* write a hole sector to the MMC/SD
************************************************************
*/
U08 FFSPort_WriteSector(U32 sector, U08 OS_HUGE *buff)
{
U32 i;
U08 res;
res = FFSPort_MediaDetect();
if(res != FFS_NO_ERR) return(res); // media present ?
if(FFSPort_MMC_WP()) return(FFS_WR_PROTECT); // device is write protect
res = MMCWriteCMD(MMC_WRITE_SINGLE_BLOCK, sector << FFSp_sshift, 0);
if(res != FFS_NO_ERR) {
FFSPort_MMC_CS_OFF; return(MMCReadStatus(res)); // cmd24 R1-error -> WriteProtect ?
}
FFSPort_MMC_Send(0xFF); // wait "Nwr" in front of wr-data
FFSPort_MMC_Send(0xFE); // send startbyte
#ifdef USE_MMC_DMA
FFSPort_MMC_TxBlock(buff, FFS_values.sectorsize); // write datablock via DMA to MMC
#else
for(i = 0; i < FFS_values.sectorsize; i++) {
FFSPort_MMC_Send(buff[i]); // send datablock to MMC
}
#endif
FFSPort_MMC_Send(0xFF); FFSPort_MMC_Send(0xFF); // write dummy CRC16 to MMC
res = FFSPort_MMC_Send(0xFF); // get data-response (no "Nxx")
switch(res & MMC_DR_MASK) { // mask data-response code
case MMC_DR_REJECT_WRITE_ERROR: // ** data rejected due to a write error
FFSPort_MMC_CS_OFF; // disable MMC-interface
return(MMCReadStatus(res)); // read status & return the error
//lint -unreachable
// break;
case MMC_DR_ACCEPT: // ** data accepted
i = 0; // wait "Nbusy" while busy
while((FFSPort_MMC_Send(0xFF) != 0xFF) && (i < MMC_Nbs)) i++;
if(i < MMC_Nbs) break; // if error - too long busy
//lint -fallthrough
case MMC_DR_REJECT_CRC: // ** data rejected due to a CRC error
default:
FFSPort_MMC_CS_OFF; // disable MMC-interface
return(FFS_PORT_ERR); // error
//lint -unreachable
// break;
}
FFSPort_MMC_CS_OFF; // disable MMC-interface
return(FFS_NO_ERR); // no error
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -