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

📄 mmc.c

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

// Basic MMC/SD erase/read/write - with or without full crc error checking (see top of mmc.h file).
// also reads all possible info on the MMC/SD - card size etc, though not all info is avaliable in SPI mode.
//
// free code, free usage, modify as you see fit, no ties.
//
// last updated 11:25 19th March 2007.
//
// appears to be bug free (famous last words) but wouldunt swear by it!
//
// we do do the crc calcs while we are waiting for each byte to finish being moved out the SPI
// tx register to the MMC/SD so the crc calcs shouldnt slow things down - unless you use a high spi sclk
// rate (not possible on SPI0).
//
// in our case the SD card is on SPI port-0 (could be moved to the SSP port (still SPI mode) for more speed.
//
// LOTS of ascii debug info sent down the UART-0 port to your terminal program if you
// compile with the mmc_debug1 option (see top of mmc.h file).
//
// note..
// the debug info is sent down the uart port at a high rate, as we don't use any kind of hand shaking then
// your terminal program may not be able to keep up (more than one we tested can't cope).
// the result maybe what looks like a mess/corrupted MMC/SD data in the terminals rx window - but this
// is not the case (unless of cause it is???).
//
// anuva note..
// enabling the mmc_debug1 info slows the code down 10 fold (or more)! .. mainly due to the limited uart
// port speed the debug info is being pushed down.
//
// n anuva note..
// one thing we did notice while writing this was that if the MMC card is improperly accessed at
// some point (due to early bugs), then the card requires a power-cycle before you can access it
// properly again - a note you should bare in mind if you intend using MMC/SD's in your projects!!!!
// (design into your project a way to power cycle the MMC/SD just incase I guess - would allow for
// hot swapping as well if you did - assuming you monitor the card slot switch(s)!).
//
// this module was fully tested on a 64MB SD card - no idea if it works with all cards though!
//
// A BIG NOTE ..
// the sector test routine (bottom of this file) uses 2 local large buffers (large for embedded) for
// sector data - make sure your stack size is big enough to hold em!!!!!!! .. you have been warned!!
// our project was set to a stack size of 2048 bytes (over kill i know).
// you could always move the buffers from local to global though if you want too so as not to need
// a large stack size.
// you could also just delete the sector test function altogether! - remove the reference to it in mmc.h if you do.
//
// heap usage is zero (no malloc's etc).

#include "mmc.h"

#include <string.h>

#ifdef mmc_debug
#include <stdio.h>
#endif

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

// MMC commands
#define MMC_GO_IDLE_STATE					0
#define MMC_SEND_OP_COND					1
#define MMC_ALL_SEND_CID					2
#define MMC_SET_RELATIVE_ADDR				3
#define MMC_SWITCH							6
#define MMC_SEND_CSD							9
#define MMC_SEND_CID							10
#define MMC_READ_DAT_UNTIL_STOP			11
#define MMC_STOP_TRANSMISSION				12
#define MMC_SEND_STATUS						13
#define MMC_GO_INACTIVE_STATE				15	// mmc/sd card power cycle needed after sending this command!!!!
#define MMC_SET_BLOCKLEN					16
#define MMC_READ_SINGLE_BLOCK				17
#define MMC_READ_MULTIPLE_BLOCK			18
#define MMC_WRITE_DAT_UNTIL_STOP			20
#define MMC_SET_BLOCK_COUNT				23
#define MMC_WRITE_BLOCK						24
#define MMC_WRITE_MULTIPLE_BLOCK			25
#define MMC_PROGRAM_CSD						27
#define MMC_SET_WRITE_PROT					28
#define MMC_CLR_WRITE_PROT					29
#define MMC_SEND_WRITE_PROT				30
#define MMC_TAG_SECTOR_START				32
#define MMC_TAG_SECTOR_END					33
#define MMC_UNTAG_SECTOR					34
#define MMC_TAG_ERASE_GROUP_START		35
#define MMC_TAG_ERARE_GROUP_END			36
#define MMC_UNTAG_ERASE_GROUP				37
#define MMC_ERASE								38
#define MMC_LOCK_UNLOCK						42
#define MMC_APP_CMD							55
#define MMC_GEN_CMD							56
#define MMC_READ_OCR							58
#define MMC_CRC_ON_OFF						59

// R1 bits
#define MMC_R1_BUSY							0x80
#define MMC_R1_PARAMETER_ERROR			0x40
#define MMC_R1_ADDRESS_ERROR				0x20
#define MMC_R1_ERASE_SEQ_ERROR			0x10
#define MMC_R1_COM_CRC_ERROR				0x08
#define MMC_R1_ILLEGAL_COM					0x04
#define MMC_R1_ERASE_RESET					0x02
#define MMC_R1_IDLE_STATE					0x01

// R2 bits
#define MMC_R2_OUT_OF_RANGE				0x80
#define MMC_R2_ERASE_PARAM_BAD			0x40
#define MMC_R2_WP_VIOLATION				0x20
#define MMC_R2_CARD_ECC_FAIL				0x10
#define MMC_R2_CC_ERROR						0x08	// CC error - card controller failure
#define MMC_R2_ERROR							0x04	// General or unknown error occured
#define MMC_R2_WP_ERASE_SKIP				0x02	// Write protect erase skip

// data tokens
#define MMC_SINGLE_BLK_RD					0xfe
#define MMC_MULTI_BLK_READ					0xfe
#define MMC_STRT_SINGLE_BLK_WR			0xfe
#define MMC_STRT_MULTI_BLK_WR				0xfc
#define MMC_STP_MULTI_BLK_WR				0xfd

// data error tokens
#define MMC_DE_MISALIGN						0x10
#define MMC_DE_ADDR_OUT_OF_RANGE			0x08
#define MMC_DE_CARD_EEC_FAIL				0x04
#define MMC_DE_CARD_ERROR					0x02
#define MMC_DE_EX_ERROR						0x01

// data response tokens
#define MMC_DR_ACCEPT						0x02
#define MMC_DR_REJECT_CRC					0x05
#define MMC_DR_REJECT_WRITE_ERROR		0x06

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

T_MMC_Info	MMC_Info = {0};		// info we get back from the MMC

// ****************************************
// SPI pass offs

#define SPI_Initialize(a, b, c, d, e, f, g, h)	SPI0_Initialize(a, b, c, d, e, f, g, h)
#define SPI_8(x)								SPI0_8(x)
#define SPI_16(x)								SPI0_16(x)
#define SPI_SendByte(x)							SPI0_SendByte(x)
#define SPI_WaitForTx()							SPI0_WaitForTx()
#define SPI_WaitForTxGetRx()					SPI0_WaitForTxGetRx()

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

#ifdef mmc_use_crc

#ifdef mmc_crc_tab

//const _u16 crc_table_16[] = {
const _u32 crc_table_16[] = {
	0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
	0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
	0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485, 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
	0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4, 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
	0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823, 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
	0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
	0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
	0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70, 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
	0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F, 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
	0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
	0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
	0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C, 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
	0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB, 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
	0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A, 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
	0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
	0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0};

#endif

static _u8 mmc_update_crc7(_u8 crc, _u8 b)
{	// update a crc7 value
	//
	// as the crc7 is only used on the command bytes and a couple of
	// short register reads (cid & csd) it's not worth tabling this.

	register _u8	d = b;
	register _u8	c = crc;
	register _u8	mask = 0x80;
	register _u8	poly = 0x09;		// x7 + x3 + 1
	register int	i;

	for (i = 8; i > 0; i--)
	{
		c <<= 1;
		if ((d ^ c) & mask) c ^= poly;
		d <<= 1;
	}

	return c;
}

#ifndef mmc_crc_tab
static _u16 mmc_update_crc16(_u16 crc, _u8 b)
{	// update a crc16 value
	//
	// bit-bang method - slow method (but conserves rom space)

	register _u16	d = (_u16)b << 8;
	register _u16	c = crc;
	register _u16	poly = 0x1021;		// x16 + x12 + x5 + 1 (CRC-CCITT)
	register _u16	mask = 0x8000;
	register int	i;

	for (i = 8; i > 0; i--)
	{
		if ((c ^ d) & mask)
			c = (c << 1) ^ poly;
		else
			c = (c << 1);
		d <<= 1;
	}

	return c;
}
#else

// look-up table method - several times faster (but needs more rom space for the look-up table)

#define mmc_update_crc16(crc, b)	(((crc << 8) & 0xff00) ^ crc_table_16[(crc >> 8) ^ b])

//static _u16 mmc_update_crc16(_u16 crc, _u8 b)
//{
//	return ((crc << 8) ^ crc_table_16[(crc >> 8) ^ b]);
//}

#endif

/*
static void mmc_create_crc_table_16(void)
{	// create the crc16 look-up table in ram

	int	i, j;
	_u16	d, crc;

	for (i = 0; i < 256; i++)
	{
		crc = 0;
		d = i << 8;
		for (j = 8; j > 0; j--)
		{
			if ((crc ^ d) & 0x8000)
				crc = (crc << 1) ^ 0x1021;	// x16 + x12 + x5 + 1 (CRC-CCITT)
			else
				crc = (crc << 1);
			d <<= 1;
		}
		crc_table_16[i] = crc;
	}
}
*/

static int CheckCRC7(void *buffer, int buf_size)
{	// check the crc located in a data packet
	int	i;
	_u8	*buf = (_u8*)buffer;
	_u8	crc;
	#ifdef mmc_debug
	char	s[56];
	#endif

	crc = 0;																						// init crc
	for (i = buf_size - 1; i > 0; i--) crc = mmc_update_crc7(crc, *buf++);	// calculate the crc
	crc = (crc << 1) | 0x01;

	if (crc == *buf) return mmc_ok;

	// crc mismatch

	#ifdef mmc_debug
	sprintf(s, "mmc crc7 error .. our crc: %0.2X   there crc: %0.2X\r\n", crc, *buf);
	WriteStr_uart0(s);
	#endif

	return mmc_err_data;
}

#endif

//*************************************************************************************
/*
void mmc_ISR(void)
{
    _u32	regValue;
	_u8		b;

	ctl_global_interrupts_re_enable_from_isr();

	S0SPINT = Bit0;					// clear interrupt flag

	regValue = S0SPSR;				// read status register - this also clears the flags

	if (regValue & S0SPSR_ABRT)
	{	// slave abort

	}

	if (regValue & S0SPSR_MODF)
	{	// mode fault

	}

	if (regValue & S0SPSR_ROVR)
	{	// read overrun

	}

	if (regValue & S0SPSR_WCOL)
	{	// write collison

	}

	if (regValue & S0SPSR_SPIF)
	{	// SPI transfer complete
		b = S0SPDR;		// read rx'ed byte

//		SPI0Status |= SPI0_TX_DONE;
//		TxCounter++;

		S0SPDR = 0xff;	// start another byte transfer
	}

	ctl_global_interrupts_un_re_enable_from_isr();
}
*/
//*************************************************************************************

#ifdef mmc_debug

void mmc_show_r1(char *s, _u8 r1)
{	// show the R1 response

	if (r1 & MMC_R1_BUSY)
	{
		WriteStr_uart0(s);
		WriteStr_uart0(" R1_BUSY\r\n");
	}

	if (r1 & MMC_R1_PARAMETER_ERROR)
	{
		WriteStr_uart0(s);
		WriteStr_uart0(" R1_PARAMETER_ERROR\r\n");
	}

	if (r1 & MMC_R1_ADDRESS_ERROR)
	{
		WriteStr_uart0(s);
		WriteStr_uart0(" R1_ADDRESS_ERROR\r\n");
	}

	if (r1 & MMC_R1_ERASE_SEQ_ERROR)
	{
		WriteStr_uart0(s);
		WriteStr_uart0(" R1_ERASE_SEQ_ERROR\r\n");
	}

	if (r1 & MMC_R1_COM_CRC_ERROR)
	{
		WriteStr_uart0(s);
		WriteStr_uart0(" R1_COM_CRC_ERROR\r\n");
	}

	if (r1 & MMC_R1_ILLEGAL_COM)
	{
		WriteStr_uart0(s);
		WriteStr_uart0(" R1_ILLEGAL_COM\r\n");
	}

	if (r1 & MMC_R1_ERASE_RESET)
	{
		WriteStr_uart0(s);
		WriteStr_uart0(" R1_ERASE_RESET\r\n");
	}

	if (r1 & MMC_R1_IDLE_STATE)
	{
		WriteStr_uart0(s);
		WriteStr_uart0(" R1_IDLE_STATE\r\n");
	}
}

void mmc_show_r2(char *s, _u8 r2)
{	// show the R2 response

	if (r2 & MMC_R2_OUT_OF_RANGE)
	{
		WriteStr_uart0(s);
		WriteStr_uart0(" R2_OUT_OF_RANGE\r\n");
	}

	if (r2 & MMC_R2_ERASE_PARAM_BAD)
	{
		WriteStr_uart0(s);
		WriteStr_uart0(" R2_ERASE_PARAM_BAD\r\n");
	}

	if (r2 & MMC_R2_WP_VIOLATION)
	{
		WriteStr_uart0(s);
		WriteStr_uart0(" R2_WP_VIOLATION\r\n");
	}

	if (r2 & MMC_R2_CARD_ECC_FAIL)
	{
		WriteStr_uart0(s);
		WriteStr_uart0(" R2_CARD_ECC_FAIL\r\n");
	}

	if (r2 & MMC_R2_CC_ERROR)
	{
		WriteStr_uart0(s);
		WriteStr_uart0(" R2_CC_ERROR\r\n");
	}

	if (r2 & MMC_R2_ERROR)
	{
		WriteStr_uart0(s);
		WriteStr_uart0(" R2_ERROR\r\n");
	}

	if (r2 & MMC_R2_WP_ERASE_SKIP)
	{
		WriteStr_uart0(s);
		WriteStr_uart0(" R2_WP_ERASE_SKIP\r\n");
	}
}

#endif

_u8 mmc_calc_mantissa(_u8 b)
{
	switch (b)
	{
		case 1	:	b = 10;
						break;
		case 2	:	b = 12;
						break;
		case 3	:	b = 13;
						break;
		case 4	:	b = 15;
						break;
		case 5	:	b = 20;
						break;
		case 6	:	b = 25;
						break;
		case 7	:	b = 30;
						break;
		case 8	:	b = 35;
						break;
		case 9	:	b = 40;
						break;
		case 10	:	b = 45;
						break;
		case 11	:	b = 50;
						break;
		case 12	:	b = 55;
						break;
		case 13	:	b = 60;
						break;
		case 14	:	b = 70;
						break;
		case 15	:	b = 80;
						break;
		default	:	b = 0;
						break;
	}
	return b;
}

static int mmc_get_response(_u8 byte, bool match, int max_loops)
{	// read the MMC until we ..
	//
	//	get a different rx'ed byte from the supplied byte .. if 'match' is false
	//   .. or ..
	//	get the same rx'ed byte from the supplied byte .. if 'match' is true

	register _u8	b;
	register int	i;
	#ifdef mmc_debug
	int				j = 0;
	char				s[8];
	#endif

	if (max_loops < 1) max_loops = 1;

	for (i = max_loops - 1; ; i--)
	{
		if (!mmc_inserted()) return mmc_err_not_inserted;	// the MMC is not in it's card slot!

		b = SPI_8(0xff);												// send byte & wait for returned byte

		#ifdef mmc_debug1
		if (j <= 0)
		{
			WriteStr_uart0("mmc_res:");
			j = 0;
		}
		sprintf(s, " %0.2X", b);
		WriteStr_uart0(s);
		j++;
		if (j >= 32)
		{
			WriteStr_uart0("\r\n");
			j = 0;
		}
		#endif

		if (match)
		{
			if (b == byte) break;		// the rx'ed byte is the same
		}
		else
		{
			if (b != byte) break;		// the rx'ed byte is different
		}

		if (i > 0) continue;				// still waiting

		// timeout

		#ifdef mmc_debug
		#ifdef mmc_debug1
		if (j > 0) WriteStr_uart0("\r\n");
		#endif
		WriteStr_uart0("mmc time-out\r\n");
		#endif

		return mmc_err_timeout;			// return time-out error code
	}

	#ifdef mmc_debug1
	if (j > 0) WriteStr_uart0("\r\n");
	#endif

	#ifdef mmc_debug
	WriteStr_uart0("waited for ");
	sprintf(s, "%u", (max_loops - 1) - i);
	WriteStr_uart0(s);
	WriteStr_uart0(" bytes for response\r\n");
	#endif

	return b;
}

static int mmc_send_cmd(_u8 cmd, _u32 arg, _u32 res_time)
{	// send an command to the MMC - return the response we get back

	_u8				cmd_buf[6];
	register _u8	b;
	register _u8	crc;
	register int	i;
	#ifdef mmc_debug
	char				s[24];
	#endif

	#ifdef mmc_debug
	switch (cmd)
	{
		case MMC_GO_IDLE_STATE				:	WriteStr_uart0("MMC_GO_IDLE_STATE");
														break;

⌨️ 快捷键说明

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