📄 mmc.c
字号:
{
i = mmc_send_cmd(MMC_GO_IDLE_STATE, 0, 40);
SPI_8(0xff);
if (i >= 0)
{
if (i == MMC_R1_IDLE_STATE) return mmc_ok; // success!
#ifdef mmc_debug
mmc_show_r1("mmc error:", i);
if (i == 0) WriteStr_uart0("mmc error: non-idle state\r\n");
#endif
}
else
{
#ifdef mmc_debug
WriteStr_uart0("mmc_idle_state_error\r\n");
#endif
}
}
// timeout/error
if (i < 0)
return i;
else
return mmc_err_fail;
}
static int mmc_ready_state(void)
{ // put the MMC in ready state
//
// apparently this can take 100's of milliseconds! .. this is not our experience though
T_MMC_Info *mmc_info = (T_MMC_Info*)&MMC_Info;
int i = mmc_send_cmd2(MMC_SEND_OP_COND, 0, mmc_info->spi_sclk_speed >> 10, true);
#ifdef mmc_debug
if (i < 0) WriteStr_uart0("mmc_ready_state_error\r\n");
#endif
return i;
}
static int mmc_set_crc(bool Enable)
{ // turn off/on CRC checking
//
// note: it's OFF by default
int i;
if (!Enable)
i = mmc_send_cmd2(MMC_CRC_ON_OFF, 0, 5, true);
else
i = mmc_send_cmd2(MMC_CRC_ON_OFF, 1, 5, true);
#ifdef mmc_debug
if (i < 0) WriteStr_uart0("mmc_set_crc_error\r\n");
#endif
return i;
}
static int mmc_get_cid(void)
{ // read the MMC CID register
T_MMC_Info *mmc_info = (T_MMC_Info*)&MMC_Info;
int i;
_u8 b;
_u8 *buf;
_u8 buffer[16];
#ifdef mmc_debug1
char s[48];
#endif
i = mmc_read_data(MMC_SEND_CID, 0, buffer, sizeof(buffer));
if (i < 0)
{ // time-out/error
#ifdef mmc_debug
WriteStr_uart0("mmc_get_cid_error 1\r\n");
#endif
return i;
}
#ifdef mmc_use_crc
i = CheckCRC7(&buffer, sizeof(buffer)); // check the crc in the packet
if (i < 0)
{
#ifdef mmc_debug
WriteStr_uart0("mmc_get_cid_error 2\r\n");
#endif
return i; // crc error
}
#endif
// *******************************
// extract the info from the data
buf = (_u8*)&buffer;
mmc_info->mid = *buf++;
mmc_info->oid = *buf++;
mmc_info->oid = (mmc_info->oid << 8) | *buf++;
memcpy(mmc_info->pnm, buf, 7);
mmc_info->pnm[7] = 0;
buf += 7;
b = *buf++;
mmc_info->prv_ms = b >> 4;
mmc_info->prv_ls = b & 0x0f;
mmc_info->psn = *buf++;
mmc_info->psn = (mmc_info->psn << 8) | *buf++;
mmc_info->psn = (mmc_info->psn << 8) | *buf++;
b = *buf++;
mmc_info->mdt_month = b >> 4;
mmc_info->mdt_year = b & 0x0f;
b = *buf++; // crc7
// *******************************
#ifdef mmc_debug1
WriteStr_uart0("\r\n");
sprintf(s, "mmc manufacture id: %u\r\n", mmc_info->mid);
WriteStr_uart0(s);
sprintf(s, "mmc oem/application id: %u\r\n", mmc_info->oid);
WriteStr_uart0(s);
WriteStr_uart0("mmc product name: ");
WriteStr_uart0(mmc_info->pnm);
WriteStr_uart0("\r\n");
sprintf(s, "mmc product revision: %u.%u\r\n", mmc_info->prv_ms, mmc_info->prv_ls);
WriteStr_uart0(s);
sprintf(s, "mmc serial number: %u\r\n", mmc_info->psn);
WriteStr_uart0(s);
sprintf(s, "mmc manufacture month-year: %u-%u\r\n", mmc_info->mdt_month, 1997 + mmc_info->mdt_year);
WriteStr_uart0(s);
#endif
// *******************************
return mmc_ok;
}
static int mmc_get_csd(void)
{ // read the MMC CSD register
T_MMC_Info *mmc_info = (T_MMC_Info*)&MMC_Info;
int i;
_u8 b;
_u8 *buf;
_u8 buffer[16];
#ifdef mmc_debug1
char s[48];
#endif
i = mmc_read_data(MMC_SEND_CSD, 0, buffer, sizeof(buffer));
if (i < 0)
{
#ifdef mmc_debug
WriteStr_uart0("mmc_get_csd_error 1\r\n");
#endif
return i;
}
#ifdef mmc_use_crc
i = CheckCRC7(&buffer, sizeof(buffer)); // check the crc in the packet
if (i < 0)
{
#ifdef mmc_debug
WriteStr_uart0("mmc_get_csd_error 2\r\n");
#endif
return i; // crc error
}
#endif
// *******************************
// extract the info from the data
buf = (_u8*)&buffer;
b = *buf++;
mmc_info->csd_structure = b >> 6;
mmc_info->prot = (b >> 2) & 0x0f;
mmc_info->taac = *buf++;
mmc_info->nsac = *buf++;
mmc_info->tran_speed = *buf++;
mmc_info->ccc = *buf++;
b = *buf++;
mmc_info->ccc = (mmc_info->ccc << 4) | (b >> 4);
mmc_info->read_bl_len = b & 0x0f;
b = *buf++;
mmc_info->read_bl_partial = (b >> 7) & 0x01;
mmc_info->write_blk_misalign = (b >> 6) & 0x01;
mmc_info->read_blk_misalign = (b >> 5) & 0x01;
mmc_info->dsr_imp = (b >> 4) & 0x01;
mmc_info->c_size = b & 0x03;
mmc_info->c_size = (mmc_info->c_size << 8) | *buf++;
b = *buf++;
mmc_info->c_size = (mmc_info->c_size << 2) | (b >> 6);
mmc_info->vdd_r_curr_min = (b >> 3) & 0x07;
mmc_info->vdd_r_curr_max = b & 0x07;
b = *buf++;
mmc_info->vdd_w_curr_min = (b >> 5) & 0x07;
mmc_info->vdd_w_curr_max = (b >> 2) & 0x07;
mmc_info->c_size_mult = b & 0x03;
b = *buf++;
mmc_info->c_size_mult = (mmc_info->c_size_mult << 1) | (b >> 7);
mmc_info->erase_sector_size = (b >> 2) & 0x1f;
mmc_info->erase_grp_size = b & 0x03;
b = *buf++;
mmc_info->erase_grp_size = (mmc_info->erase_grp_size << 3) | (b >> 5);
mmc_info->wp_grp_size = b & 0x1f;
b = *buf++;
mmc_info->wp_grp_enable = (b >> 7);
mmc_info->default_ecc = (b >> 5) & 0x03;
mmc_info->r2w_factor = (b >> 2) & 0x07;
mmc_info->write_bl_len = b & 0x03;
b = *buf++;
mmc_info->write_bl_len = (mmc_info->write_bl_len << 2) | (b >> 6);
mmc_info->write_bl_partial = (b >> 5) & 0x01;
b = *buf++;
mmc_info->copy = (b >> 6) & 0x01;
mmc_info->perm_write_protect = (b >> 5) & 0x01;
mmc_info->tmp_write_protect = (b >> 4) & 0x01;
mmc_info->eec = b & 0x03;
b = *buf++; // crc7
// ************************************************************
// calculate the size of the MMC ..
// card sectors
// card sector size (in bytes)
// card size (in bytes)
mmc_info->size_sector = 1L << mmc_info->read_bl_len;
mmc_info->size_bytes = mmc_info->c_size + 1;
mmc_info->size_bytes <<= mmc_info->c_size_mult + 2;
mmc_info->size_sectors = mmc_info->size_bytes;
mmc_info->size_bytes <<= mmc_info->read_bl_len;
// ************************************************************
// calculate the maximum transfer speed (bits/s) (spi/ssp sclk speed) we can use for this MMC
mmc_info->max_transfer_speed = (_u32)mmc_calc_mantissa((mmc_info->tran_speed >> 3) & 0x0f); // mantissa
if (mmc_info->max_transfer_speed > 0)
{
b = mmc_info->tran_speed & 0x07; // exponent
switch (b)
{
case 0 : mmc_info->max_transfer_speed *= 10000;
break;
case 1 : mmc_info->max_transfer_speed *= 100000;
break;
case 2 : mmc_info->max_transfer_speed *= 1000000;
break;
case 3 : mmc_info->max_transfer_speed *= 10000000;
break;
default : mmc_info->max_transfer_speed = 0;
break;
}
}
// ************************************************************
// calculate the 'maximum' time-out values (in micro-seconds)
mmc_info->max_read_timeout_us = (_u32)mmc_calc_mantissa((mmc_info->taac >> 3) & 0x0f); // mantissa
if (mmc_info->max_read_timeout_us > 0)
{
b = mmc_info->taac & 0x07; // exponent
switch (b)
{
case 0 : mmc_info->max_read_timeout_us = 1;
break;
case 1 : mmc_info->max_read_timeout_us = 1;
break;
case 2 : mmc_info->max_read_timeout_us = 1;
break;
case 3 : // mmc_info->max_read_timeout_us *= 1;
break;
case 4 : mmc_info->max_read_timeout_us *= 10;
break;
case 5 : mmc_info->max_read_timeout_us *= 100;
break;
case 6 : mmc_info->max_read_timeout_us *= 1000;
break;
case 7 : mmc_info->max_read_timeout_us *= 10000;
break;
default : mmc_info->max_read_timeout_us = 0;
break;
}
}
if (mmc_info->max_read_timeout_us < 1) mmc_info->max_read_timeout_us = 100000; // default to 100ms
if (mmc_info->r2w_factor <= 5)
mmc_info->max_write_timeout_us = mmc_info->max_read_timeout_us << mmc_info->r2w_factor;
else
mmc_info->max_write_timeout_us = mmc_info->max_read_timeout_us << 5;
// ************************************************************
#ifdef mmc_debug1
WriteStr_uart0("\r\n");
sprintf(s, "mmc_csd_structure: %u\r\n", mmc_info->csd_structure);
WriteStr_uart0(s);
sprintf(s, "mmc_prot: %u\r\n", mmc_info->prot);
WriteStr_uart0(s);
sprintf(s, "mmc_taac: %0.2X (%u %u)\r\n", mmc_info->taac, (mmc_info->taac >> 3) & 0x0f, mmc_info->taac & 0x07);
WriteStr_uart0(s);
sprintf(s, "mmc_nsac: %u (%u)\r\n", mmc_info->nsac, mmc_info->nsac * 100);
WriteStr_uart0(s);
sprintf(s, "mmc_tran_speed: %0.2X (%u %u) (%u)\r\n", mmc_info->tran_speed, (mmc_info->tran_speed >> 3) & 0x0f, mmc_info->tran_speed & 0x07, b = mmc_info->tran_speed);
WriteStr_uart0(s);
sprintf(s, "mmc_ccc: %0.4X\r\n", mmc_info->ccc);
WriteStr_uart0(s);
sprintf(s, "mmc_read_bl_len: %u (%u)\r\n", mmc_info->read_bl_len, 1L << mmc_info->read_bl_len);
WriteStr_uart0(s);
sprintf(s, "mmc_read_bl_partial: %u\r\n", mmc_info->read_bl_partial);
WriteStr_uart0(s);
sprintf(s, "mmc_write_blk_misalign: %u\r\n", mmc_info->write_blk_misalign);
WriteStr_uart0(s);
sprintf(s, "mmc_read_blk_misalign: %u\r\n", mmc_info->read_blk_misalign);
WriteStr_uart0(s);
sprintf(s, "mmc_dsr_imp: %u\r\n", mmc_info->dsr_imp);
WriteStr_uart0(s);
sprintf(s, "mmc_c_size: %u\r\n", mmc_info->c_size);
WriteStr_uart0(s);
sprintf(s, "mmc_vdd_r_curr_min: %u\r\n", mmc_info->vdd_r_curr_min);
WriteStr_uart0(s);
sprintf(s, "mmc_vdd_r_curr_max: %u\r\n", mmc_info->vdd_r_curr_max);
WriteStr_uart0(s);
sprintf(s, "mmc_vdd_w_curr_min: %u\r\n", mmc_info->vdd_w_curr_min);
WriteStr_uart0(s);
sprintf(s, "mmc_vdd_w_curr_max: %u\r\n", mmc_info->vdd_w_curr_max);
WriteStr_uart0(s);
sprintf(s, "mmc_c_size_mult: %u (%u)\r\n", mmc_info->c_size_mult, 1L << mmc_info->c_size_mult);
WriteStr_uart0(s);
sprintf(s, "mmc_erase_sector_size: %u (%u)\r\n", mmc_info->erase_sector_size, mmc_info->erase_sector_size + 1);
WriteStr_uart0(s);
sprintf(s, "mmc_erase_grp_size: %u (%u)\r\n", mmc_info->erase_grp_size, mmc_info->erase_grp_size + 1);
WriteStr_uart0(s);
sprintf(s, "mmc_wp_grp_size: %u (%u)\r\n", mmc_info->wp_grp_size, mmc_info->wp_grp_size + 1);
WriteStr_uart0(s);
sprintf(s, "mmc_wp_grp_enable: %u\r\n", mmc_info->wp_grp_enable);
WriteStr_uart0(s);
sprintf(s, "mmc_default_ecc: %u\r\n", mmc_info->default_ecc);
WriteStr_uart0(s);
sprintf(s, "mmc_r2w_factor: %u (%u)\r\n", mmc_info->r2w_factor, 1L << mmc_info->r2w_factor);
WriteStr_uart0(s);
sprintf(s, "mmc_write_bl_len: %u (%u)\r\n", mmc_info->write_bl_len, 1L << mmc_info->write_bl_len);
WriteStr_uart0(s);
sprintf(s, "mmc_write_bl_partial: %u\r\n", mmc_info->write_bl_partial);
WriteStr_uart0(s);
sprintf(s, "mmc_copy: %u\r\n", mmc_info->copy);
WriteStr_uart0(s);
sprintf(s, "mmc_perm_write_protect: %u\r\n", mmc_info->perm_write_protect);
WriteStr_uart0(s);
sprintf(s, "mmc_tmp_write_protect: %u\r\n", mmc_info->tmp_write_protect);
WriteStr_uart0(s);
sprintf(s, "mmc_eec: %u\r\n", mmc_info->eec);
WriteStr_uart0(s);
WriteStr_uart0("\r\n");
sprintf(s, "mmc_size_bytes: %u\r\n", mmc_info->size_bytes);
WriteStr_uart0(s);
sprintf(s, "mmc_size_sector: %u\r\n", mmc_info->size_sector);
WriteStr_uart0(s);
sprintf(s, "mmc_size_sectors: %u\r\n", mmc_info->size_sectors);
WriteStr_uart0(s);
sprintf(s, "mmc_max_transfer_speed: %ubps\r\n", mmc_info->max_transfer_speed);
WriteStr_uart0(s);
sprintf(s, "mmc_max_read_timeout: %uus (%uus typical)\r\n", mmc_info->max_read_timeout_us, mmc_info->max_read_timeout_us / 10);
WriteStr_uart0(s);
sprintf(s, "mmc_max_write_timeout: %uus (%uus typical)\r\n", mmc_info->max_write_timeout_us, mmc_info->max_write_timeout_us / 10);
WriteStr_uart0(s);
#endif
// ************************************************************
return mmc_ok;
}
static int mmc_get_ocr(void)
{ // read the MMC OCR register
//
// note: not all MMC/SD's support this command when in SPI mode (but some do) .. worth a go though!
T_MMC_Info *mmc_info = (T_MMC_Info*)&MMC_Info;
int i;
_u8 b;
#ifdef mmc_debug1
char s[48];
#endif
i = mmc_send_cmd2(MMC_READ_OCR, 0, 5, false); // send command
if (i < 0)
{
#ifdef mmc_debug
WriteStr_uart0("mmc_get_ocr_error\r\n");
#endif
return i;
}
#ifdef mmc_debug1
WriteStr_uart0("mmc_ocr:");
#endif
mmc_info->ocr = 0;
for (i = 4; i > 0; i--)
{
if (!mmc_inserted()) return mmc_err_not_inserted; // mmc not inserted
b = SPI_8(0xff); // read data byte
mmc_info->ocr = (mmc_info->ocr << 8) | b; // save data byte
#ifdef mmc_debug1
sprintf(s, " %0.2X", b);
WriteStr_uart0(s);
#endif
}
SPI_8(0xff);
#ifdef mmc_debug1
WriteStr_uart0("\r\n");
if (mmc_info->ocr & Bit31) WriteStr_uart0("mmc ocr: BUSY\r\n");
if (mmc_info->ocr & Bit23) WriteStr_uart0("mmc ocr: 3.5V - 3.6V\r\n");
if (mmc_info->ocr & Bit22) WriteStr_uart0("mmc ocr: 3.4V - 3.5V\r\n");
if (mmc_info->ocr & Bit21) WriteStr_uart0("mmc ocr: 3.3V - 3.4V\r\n");
if (mmc_info->ocr & Bit20) WriteStr_uart0("mmc ocr: 3.2V - 3.3V\r\n");
if (mmc_info->ocr & Bit19) WriteStr_uart0("mmc ocr: 3.1V - 3.2V\r\n");
if (mmc_info->ocr & Bit18) WriteStr_uart0("mmc ocr: 3.0V - 3.1V\r\n");
if (mmc_info->ocr & Bit17) WriteStr_uart0("mmc ocr: 2.9V - 3.0V\r\n");
if (mmc_info->ocr & Bit16) WriteStr_uart0("mmc ocr: 2.8V - 2.9V\r\n");
if (mmc_info->ocr & Bit15) WriteStr_uart0("mmc ocr: 2.7V - 2.8V\r\n");
if (mmc_info->ocr & Bit14) WriteStr_uart0("mmc ocr: 2.6V - 2.7V\r\n");
if (mmc_info->ocr & Bit13) WriteStr_uart0("mmc ocr: 2.5V - 2.6V\r\n");
if (mmc_info->ocr & Bit12) WriteStr_uart0("mmc ocr: 2.4V - 2.5V\r\n");
if (mmc_info->ocr & Bit11) WriteStr_uart0("mmc ocr: 2.3V - 2.4V\r\n");
if (mmc_info->ocr & Bit10) WriteStr_uart0("mmc ocr: 2.2V - 2.3V\r\n");
if (mmc_info->ocr & Bit9) WriteStr_uart0("mmc ocr: 2.1V - 2.2V\r\n");
if (mmc_info->ocr & Bit8) WriteStr_uart0("mmc ocr: 2.0V - 2.1V\r\n");
#endif
return mmc_ok;
}
static int mmc_set_blocklen(_u32 size_bytes)
{ // set the data block length (used when reading/writing sector(s)
T_MMC_Info *mmc_info = (T_MMC_Info*)&MMC_Info;
int i;
i = mmc_send_cmd2(MMC_SET_BLOCKLEN, size_bytes, 5, true); // send command
if (i < 0) return i; // error
mmc_info->last_block_len = size_bytes; // remember what we have set the block length too - saves doing it again if no change
return mmc_ok;
}
// *********************************************
// public routines
bool mmc_inserted(void)
{ // test the card slot switch state ..
//
// a physical switch on the MMC card slot that makes/breaks depending on whether card is inserted or not
//
// return TRUE if the MMC appears to be inserted, elese return FALSE
#ifdef mmc_use_switch
if (MMC_SWITCH_PIN & MMC_SWITCH_BIT)
return false; // card not inserted (switch is not pulling the pin down to gnd)
else
return true; // card inserted
#else
return true; // not monitoring the card slot switch
#endif
}
void mmc_deselect(void)
{ // de-chip-select the MMC
register _u8 b = 0xff;
register int i;
#ifdef mmc_debug1
char s[24];
#endif
#ifdef mmc_debug1
WriteStr_uart0("\r\nmmc_send:");
#endif
for (i = 10; i > 0; i--)
{
if (!mmc_inserted()) break; // MMC not inserted
SPI_8(b);
#ifdef mmc_debug1
sprintf(s, " %0.2X", b);
WriteStr_uart0(s);
#endif
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -