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

📄 mmc.c

📁 MMC driver for LPC21
💻 C
📖 第 1 页 / 共 4 页
字号:

	#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 + -