📄 mmc.c
字号:
#ifdef mmc_debug1
WriteStr_uart0("\r\n");
#endif
MMC_CS_SET = MMC_CS_BIT; // MMC CS line high
#ifdef mmc_debug
WriteStr_uart0("\r\nmmc_DESELECT\r\n");
#endif
#ifdef mmc_debug1
sprintf(s, "mmc_send: %0.2X", b);
WriteStr_uart0(s);
#endif
SPI_8(b); // a few more clocks are needed after CS line goes high ..
// else the MMC card won't release the SPI DOUT bus line
#ifdef mmc_debug1
WriteStr_uart0("\r\n");
#endif
}
int mmc_init(void)
{ // initialize the mmc
//
// chip-select the MMC
// set it in SPI mode
// get what MMC details we can
//
// if all ok, then leave it chip-selected, else de-chip-select it and return error code
T_MMC_Info *mmc_info = (T_MMC_Info*)&MMC_Info;
volatile _s32 clk;
int i, j;
_u16 crc;
_u16 w;
_u8 b;
_u8 r1, r2;
_u8 *buf;
#ifdef mmc_debug
char s[48];
#endif
#ifdef mmc_debug
WriteStr_uart0("\r\nmmc init ..\r\n");
#endif
// *************************
#ifdef mmc_use_switch
MMC_SWITCH_DIR &= ~MMC_SWITCH_BIT; // MMC card slot switch pin as input
#endif
MMC_CS_SET = MMC_CS_BIT; // MMC CS line high
MMC_CS_DIR |= MMC_CS_BIT; // ensure pin is an output
MMC_CS_SET = MMC_CS_BIT; // ensure MMC CS line is high
// YOU MUST MAKE A NOTE OF THE SPI SCK SPEED HERE ...
mmc_info->spi_sclk_speed = SPI_Initialize(100000, true, false, false, false, false, true, NULL); // configure SPI port for an MMC/SD card (slow 100KHz clock - until we know the max speed the MMC can do)
#ifdef mmc_debug
sprintf(s, "\r\nmmc spi sclk speed set to: %ubps\r\n", mmc_info->spi_sclk_speed);
WriteStr_uart0(s);
#endif
// *******************
// wait for approx 1us ..
//
// there are slower devices on the SPI bus that may
// have just been de-selected, give em time to settle
// before chip-selecting the MMC.
clk = cclk >> 23;
while (clk-- > 0);
// *************************
if (!mmc_inserted())
{ // mmc not inserted
#ifdef mmc_debug
WriteStr_uart0("mmc not inserted\r\n");
#endif
return mmc_err_not_inserted;
}
// *******************
// send 80 clock pulses to the MMC
#ifdef mmc_debug1
WriteStr_uart0("\r\nmmc_send:");
#endif
b = 0xff;
for (i = 10; i > 0; i--)
{
SPI_SendByte(b); // send a byte down the SPI port
#ifdef mmc_debug1
sprintf(s, " %0.2X", b);
WriteStr_uart0(s);
#endif
SPI_WaitForTxGetRx(); // wait for the byte to be sent
}
#ifdef mmc_debug1
WriteStr_uart0("\r\n");
#endif
// *******************
// chip-select the MMC
MMC_CS_CLR = MMC_CS_BIT; // set MMC CS line low
#ifdef mmc_debug
WriteStr_uart0("\r\nmmc_SELECT\r\n");
#endif
// *******************
i = mmc_info->spi_sclk_speed;
memset(mmc_info, 0, sizeof(T_MMC_Info)); // we are going to (re) fill this area with the card info
mmc_info->spi_sclk_speed = i;
// *******************
i = mmc_idle_state(); // set MMC to idle state
if (i < 0)
{ // error
mmc_deselect();
return i;
}
w = mmc_get_status(); // read the MMC status register
if (w != MMC_R1_IDLE_STATE)
{ // wrong state
mmc_deselect();
#ifdef mmc_debug
WriteStr_uart0("mmc_init_get_status_error\r\n");
#endif
return mmc_err_invalid_state;
}
i = mmc_ready_state(); // set MMC to ready state
if (i < 0)
{ // error
mmc_deselect();
#ifdef mmc_debug
WriteStr_uart0("mmc_init_ready_state_error\r\n");
#endif
return i;
}
#ifdef mmc_use_crc
i = mmc_set_crc(true); // enable MMC CRC checking
#else
i = mmc_set_crc(false); // disable MMC CRC checking
#endif
if (i < 0)
{ // error
mmc_deselect();
return i;
}
i = mmc_get_ocr(); // read the MMC OCR register (not all MMC's support this command is SPI mode).
// ignore error result
i = mmc_get_cid(); // read the MMC CID register
if (i < 0)
{ // error
mmc_deselect();
return i;
}
i = mmc_get_csd(); // read the MMC CSD register
if (i < 0)
{ // error
mmc_deselect();
return i;
}
// *************************
// now switch to a faster sclk speed - now that we know the max speed of the MMC
i = pclk; // start with max speed
if (i > mmc_info->max_transfer_speed) i = mmc_info->max_transfer_speed; // limit to cards speed
// YOU MUST MAKE A NOTE OF THE SPI SCK SPEED HERE ...
mmc_info->spi_sclk_speed = SPI_Initialize(i, true, false, false, false, false, true, NULL); // configure SPI port for an MMC/SD card (fast clock)
#ifdef mmc_debug
sprintf(s, "\r\nmmc spi sclk speed set to: %ubps\r\n", mmc_info->spi_sclk_speed); // show the actual sclk speed of the SPI port
WriteStr_uart0(s);
#endif
// *************************
// calculate the time-out counts for sector read/write/erase
i = mmc_info->spi_sclk_speed >> 8;
mmc_info->max_read_timeout_count = ((_u64)mmc_info->max_read_timeout_us * (_u32)i) >> 15;
mmc_info->max_write_timeout_count = ((_u64)mmc_info->max_write_timeout_us * (_u32)i) >> 15;
#ifdef mmc_debug
sprintf(s, "\r\nmmc read time-out count: %u\r\n", mmc_info->max_read_timeout_count);
WriteStr_uart0(s);
sprintf(s, "\r\nmmc write time-out count: %u\r\n", mmc_info->max_write_timeout_count);
WriteStr_uart0(s);
#endif
//112500 = 250ms
// *************************
// check to see if all still works at the faster sclk speed ..
// by asking for the status register
w = mmc_get_status(); // get current status
if (w != 0)
{ // invalid state
mmc_deselect();
#ifdef mmc_debug
WriteStr_uart0("mmc_init_get_status_error 2\r\n");
#endif
return mmc_err_invalid_state;
}
// *************************
#ifdef mmc_debug
WriteStr_uart0("\r\nmmc init OK!\r\n");
#endif
return mmc_ok; // ok
}
int mmc_write_sector(void *buffer, _u32 sector, int num_of_bytes)
{ // write data to an MMC sector
//
// a successful mmc_init() must have been called before using this function
T_MMC_Info *mmc_info = (T_MMC_Info*)&MMC_Info;
int i;
int write_bl_size = 1L << mmc_info->write_bl_len; // sector size (in bytes)
#ifdef mmc_debug
WriteStr_uart0("\r\nmmc write block ..\r\n");
#endif
if (!mmc_inserted()) return mmc_err_not_inserted; // mmc not inserted
if (sector >= mmc_info->size_sectors) return mmc_err_invalid_address; // sector doesn't exist - address out of range
if (num_of_bytes < 1) return mmc_err_invalid_data_size; // why come here if you don't want any bytes written?
else
if (num_of_bytes > write_bl_size) return mmc_err_invalid_data_size; // no more than '1 sector size' bytes!
if (!mmc_info->write_bl_partial)
{ // partial blocks not allowed - 'num_of_bytes' MUST be a full sector size
if (num_of_bytes != write_bl_size) return mmc_err_invalid_data_size;
}
if (num_of_bytes != mmc_info->last_block_len)
{
i = mmc_set_blocklen(num_of_bytes); // set the MMC data block length
if (i < 0) return i; // error
}
i = mmc_write_data(MMC_WRITE_BLOCK, sector << 9, buffer, num_of_bytes);
if (i < 0) return i; // error
#ifdef mmc_debug
WriteStr_uart0("\r\nmmc write block OK!\r\n");
#endif
return mmc_ok;
}
int mmc_read_sector(void *buffer, _u32 sector, int num_of_bytes)
{ // read data from an MMC sector
//
// a successful mmc_init() must have been called before using this function
T_MMC_Info *mmc_info = (T_MMC_Info*)&MMC_Info;
int i;
int read_bl_size = 1L << mmc_info->read_bl_len; // sector size (in bytes)
#ifdef mmc_debug
WriteStr_uart0("\r\nmmc read block ..\r\n");
#endif
if (!mmc_inserted()) return mmc_err_not_inserted; // mmc not inserted
if (sector >= mmc_info->size_sectors) return mmc_err_invalid_address; // sector doesn't exist
if (num_of_bytes < 1) return mmc_err_invalid_data_size; // why come here if you don't want any bytes?
else
if (num_of_bytes > read_bl_size) return mmc_err_invalid_data_size; // no more than '1 sector size' bytes!
if (!mmc_info->read_bl_partial)
{ // partial blocks not allowed - 'num_of_bytes' MUST be a full sector size
if (num_of_bytes != read_bl_size) return mmc_err_invalid_data_size;
}
if (num_of_bytes != mmc_info->last_block_len)
{
i = mmc_set_blocklen(num_of_bytes); // set the MMC data block length
if (i < 0) return i; // error
}
i = mmc_read_data(MMC_READ_SINGLE_BLOCK, sector << 9, buffer, num_of_bytes);
if (i < 0) return i; // error
#ifdef mmc_debug
WriteStr_uart0("mmc read block OK!\r\n");
#endif
return mmc_ok;
}
int mmc_erase_sectors(_u32 start_sector, int num_of_sectors)
{ // erase one or more sectors
//
// a successful mmc_init() must have been called before using this function
T_MMC_Info *mmc_info = (T_MMC_Info*)&MMC_Info;
int i;
#ifdef mmc_debug
WriteStr_uart0("\r\nmmc erase sector(s) ..\r\n");
#endif
if (start_sector >= mmc_info->size_sectors) return mmc_err_invalid_address; // sector doesn't exist - address out of range
num_of_sectors--;
if (num_of_sectors < 0) return mmc_err_invalid_sector_count; // wut?
else
if (num_of_sectors > mmc_info->erase_sector_size) return mmc_err_invalid_sector_count; // too many sectors in one go
if ((start_sector + num_of_sectors) >= mmc_info->size_sectors) return mmc_err_invalid_address; // sector(s) doesn't exist - address out of range
// set address of first sector to be erased
i = mmc_send_cmd2(MMC_TAG_SECTOR_START, start_sector << 9, 5, true); // send command
if (i < 0) return i;
// set address of last sector to be erased
i = mmc_send_cmd2(MMC_TAG_SECTOR_END, (start_sector + num_of_sectors) << 9, 5, true); // send command
if (i < 0) return i;
// erase the sector(s)
i = mmc_send_cmd(MMC_ERASE, 0, 40);
if (i < 0)
{
#ifdef mmc_debug
WriteStr_uart0("mmc_erase_sectors_error 1\r\n");
#endif
return i;
}
// wait for erase to complete
// i = mmc_get_response(0x00, false, mmc_info->spi_sclk_speed >> 4); // wait for a non 0x00 byte
// // wait for upto 500ms
i = mmc_get_response(0x00, false, mmc_info->max_write_timeout_count); // wait for a non 0x00 byte
SPI_8(0xff);
if (i < 0 || i == 0x00)
{ // time out/card not inserted
#ifdef mmc_debug
if (i == 0x00)
WriteStr_uart0("mmc_erase_sectors time-out\r\n");
else
WriteStr_uart0("mmc_erase_sectors_error 2\r\n");
#endif
return mmc_err_timeout;
}
#ifdef mmc_debug
WriteStr_uart0("mmc erase sector(s) OK!\r\n");
#endif
return mmc_ok;
}
int mmc_write_sectors(void *buffer, _u32 start_sector, int num_of_sectors)
{ // select the MMC
// write sector(s)
// de-select the MMC
T_MMC_Info *mmc_info = (T_MMC_Info*)&MMC_Info;
int i, j;
_u8 *buf = (_u8*)buffer;
_u32 write_sector_size = 1L << mmc_info->write_bl_len;
i = mmc_init();
if (i < 0) return i;
for (j = 0; j < num_of_sectors; j++)
{
i = mmc_write_sector(buf, start_sector, write_sector_size);
if (i < 0) break;
start_sector++;
buf += write_sector_size;
}
if (mmc_inserted()) j = mmc_idle_state();
mmc_deselect();
return i;
}
int mmc_read_sectors(void *buffer, _u32 start_sector, int num_of_sectors)
{ // select the MMC
// read sector(s)
// de-select the MMC
T_MMC_Info *mmc_info = (T_MMC_Info*)&MMC_Info;
int i, j;
_u8 *buf = (_u8*)buffer;
_u32 read_sector_size = 1L << mmc_info->read_bl_len;
i = mmc_init();
if (i < 0) return i;
for (j = 0; j < num_of_sectors; j++)
{
i = mmc_read_sector(buf, start_sector, read_sector_size);
if (i < 0) break;
start_sector++;
buf += read_sector_size;
}
if (mmc_inserted()) j = mmc_idle_state();
mmc_deselect();
return i;
}
int mmc_test_sector(_u32 sector)
{ // do a sector save/erase/write/read/erase/restore test on a desired sector in the MMC/SD.
//
// make sure your stack size of big enough for all this data!!!!!!!!!!!!!
// otherwise make the local buffers global.
// or even delete this function (the program does not need it at all).
//
// step 1: save current sector data into a buffer (for later restore)
// step 2: erase the sector
// step 3: read sector data - see if it really is erased
// step 4: write own data pattern to the sector
// step 5: read the data pattern back
// step 6: erase the sector again
// step 7: write the original data back to the sector
// step 8: check the data pattern we read back is exactly as we wrote to it
// step 9: return how many byte differences there were in our data pattern write/read stage
T_MMC_Info *mmc_info = (T_MMC_Info*)&MMC_Info;
int i, j, k, errors;
char buffer1[512], buffer2[512]; // size of a sector
char *buf;
#ifdef mmc_debug
char s[48];
#endif
#ifdef mmc_debug
sprintf(s, "\r\nmmc sector test 2 (sector %u) ..\r\n", sector);
WriteStr_uart0(s);
#endif
i = mmc_init(); // select and init the MMC
if (i < 0) return i; // error
i = mmc_read_sector(&buffer1, sector, mmc_info->size_sector); // save current sector data (it will restored after our sector test)
if (i < 0)
{ // error
mmc_deselect();
return i;
}
i = mmc_erase_sectors(sector, 1); // erase the sector (not needed but hey)
i = mmc_read_sector(&buffer2, sector, mmc_info->size_sector); // read the erased sector
if (i < 0)
{ // error
mmc_write_sector(&buffer1, sector, mmc_info->size_sector); // 'try' to restore the sector data
mmc_deselect();
return i;
}
buf = buffer2;
for (i = 0, j = mmc_info->size_sector; j > 0; j--)
{ // create a data pattern to write to the sector
*buf++ = i;
i = (i + 3) & 0xff;
}
i = mmc_write_sector(&buffer2, sector, mmc_info->size_sector); // write our own data pattern to the sector
if (i < 0)
{ // error
mmc_write_sector(&buffer1, sector, mmc_info->size_sector); // 'try' to restore the sector data
mmc_deselect();
return i;
}
memset(&buffer2, 0, mmc_info->size_sector); // wipe our data pattern from the buffer
i = mmc_read_sector(&buffer2, sector, mmc_info->size_sector); // read our own data back from the sector
i = mmc_erase_sectors(sector, 1); // erase the sector (not needed)
mmc_write_sector(&buffer1, sector, mmc_info->size_sector); // try to restore sector data to original data
mmc_deselect(); // deselect the MMC
// count how many byte differences there are between our write/read data pattern (hopefully no differences)
errors = 0;
buf = buffer2;
for (i = 0, j = mmc_info->size_sector; j > 0; j--)
{
if (*buf++ != i) errors++;
i = (i + 3) & 0xff;
}
#ifdef mmc_debug
#ifdef mmc_debug1
WriteStr_uart0("\r\n");
#endif
sprintf(s, "mmc sector test complete .. %d byte errors\r\n", errors);
WriteStr_uart0(s);
#endif
return errors; // return the number of bytes errors we detected
// this should be ZERO!
}
// *********************************************
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -