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

📄 sdcard.c

📁 SD卡FAT文件系统
💻 C
字号:
/**
 * @file $RCSfile: sdcard.c,v $
 *
 * Copyright (c) 2006 XXXXX INC., All Rights Reserved
 *
 * @author	YongJian Guo <XXX@XXX>
 *
 * @version $Revision: 1.2.0.00 $
 * @date	$Date: 2006/10/13 06:46:18 $
 * @update	$Date: 2007/01/24 14:06:17 $
 * $Header: $
**/

/* Only rcvr_spi(), xmit_spi(), disk_timerproc(), disk_initialize () and */
/* some macros are platform dependent.                                   */
/*-----------------------------------------------------------------------*/

#include "sfr6n4.h"
#include "sdshare.h"
#include "diskio.h"

/* MMC/SD command (in SPI) */
#define CMD0	(0x40+0)	/* GO_IDLE_STATE */
#define CMD1	(0x40+1)	/* SEND_OP_COND */
#define CMD9	(0x40+9)	/* SEND_CSD */
#define CMD10	(0x40+10)	/* SEND_CID */
#define CMD12	(0x40+12)	/* STOP_TRANSMISSION */
#define CMD16	(0x40+16)	/* SET_BLOCKLEN */
#define CMD17	(0x40+17)	/* READ_SINGLE_BLOCK */
#define CMD18	(0x40+18)	/* READ_MULTIPLE_BLOCK */
#define CMD24	(0x40+24)	/* WRITE_BLOCK */
#define CMD25	(0x40+25)	/* WRITE_MULTIPLE_BLOCK */
#define CMD41	(0x40+41)	/* SEND_OP_COND (ACMD) */
#define CMD55	(0x40+55)	/* APP_CMD */
#define CMD58	(0x40+58)	/* READ_OCR */


/* Control signals (Platform dependent) */
#define SDCLK		p4_5			/* SD SCLK */
#define SDDI		p4_6			/* SD DI */
#define SDDO		p7_0			/* SD DO */
#define	SDCS		p4_7			/* SD CS */
#define SELECT()	SDCS = 0		/* SD CS = L */
#define	DESELECT()	SDCS = 1		/* SD CS = H */

#define SOCKPORT	p4				/* Socket control port */
#define SOCKWP		0x10			/* Write protect switch (PB5) */
#define SOCKINS		0x20			/* Card detect switch (PB4) */
#define CARDPWR		0x80			/* Card power (PE7) */


static volatile
uint8 Stat = STA_NOINIT;	/* Disk status */

static volatile
uint8 Timer1, Timer2;			/* 100Hz decrement timer */

/*-----------------------------------------------------------------------*/
/* Module Private Functions                                              */


/*--------------------------------*/
/* Transmit a byte to MMC via SPI */
/* (Platform dependent)           */

void delay(void)
{
	//uint8 n = 8;
	//while(n--)	
	
}


/* Control signals (Platform dependent) */
void xmit_spi (uint8 dat)
{
	uint8 n = 8;
	
delay();

	do {
		SDDI = (dat & 0x80) ? 1 : 0;
		dat <<= 1;
		SDCLK = 1;
		delay();
		SDCLK = 0;
		delay();
	} while (--n);
}


/*---------------------------------*/
/* Receive a byte from MMC via SPI */
/* (Platform dependent)            */
uint8 rcvr_spi(void)
{
	uint8 r = 0, n = 8;

delay();
	SDDI = 1;
	do {
		r <<= 1;
		if (SDDO) r++;
		SDCLK = 1;
		delay();
		SDCLK = 0;
		delay();
	} while (--n);
	return r;
}



/*---------------------*/
/* Wait for card ready */
uint8 wait_ready (void)
{
	uint8 res;


	Timer2 = 50;			/* Wait for ready in timeout of 500ms */
	rcvr_spi();
	do
		res = rcvr_spi();
	while ((res != 0xFF) && Timer2);
	return res;
}



/*--------------------------------*/
/* Receive a data packet from MMC */
BOOL rcvr_datablock (
	uint8 *buff,			/* Data buffer to store received data */
	uint8 wc				/* Word count (0 means 256 words) */
)
{
	uint8 token;


	Timer1 = 10;
	do {							/* Wait for data packet in timeout of 100ms */
		token = rcvr_spi();
	} while ((token == 0xFF) && Timer1);
	if(token != 0xFE) return FALSE;	/* If not valid data token, retutn with error */
	
	delay();
	delay();

	do {							/* Receive the data block into buffer */
		*buff++ = rcvr_spi();
		*buff++ = rcvr_spi();
	} while (--wc);
	rcvr_spi();						/* Discard CRC */
	rcvr_spi();

	return TRUE;					/* Return with success */
}



/*---------------------------*/
/* Send a data packet to MMC */

#ifndef _READONLY
BOOL xmit_datablock (
	const uint8 *buff,	/* 512 byte data block to be transmitted */
	uint8 token			/* Data/Stop token */
)
{
	uint8 resp, wc = 0;


	if (wait_ready() != 0xFF) return FALSE;

	xmit_spi(token);					/* Xmit data token */
	if (token != 0xFD) {	/* Is data token */
		do {							/* Xmit the 512 byte data block to MMC */
			xmit_spi(*buff++);
			xmit_spi(*buff++);
		} while (--wc);
		xmit_spi(0xFF);					/* CRC (Dummy) */
		xmit_spi(0xFF);
		resp = rcvr_spi();				/* Reveive data response */
		if ((resp & 0x1F) != 0x05)		/* If not accepted, return with error */
			return FALSE;
	}

	return TRUE;
}
#endif


/*------------------------------*/
/* Send a command packet to MMC */
uint8 send_cmd (
	uint8 cmd,		/* Command byte */
	uint32 arg		/* Argument */
)
{
	uint8 n, res;

	if(cmd != CMD0){
		if (wait_ready() != 0xFF) return 0xFF;
		wait_ready();
	}

	/* Send command packet */
	xmit_spi(cmd);						/* Command */
	xmit_spi((uint8)(arg >> 24));		/* Argument[31..24] */
	xmit_spi((uint8)(arg >> 16));		/* Argument[23..16] */
	xmit_spi((uint8)(arg >> 8));			/* Argument[15..8] */
	xmit_spi((uint8)arg);				/* Argument[7..0] */
	xmit_spi(0x95);						/* CRC (valid for only CMD0) */

	/* Receive command response */
	if (cmd == CMD12) rcvr_spi();		/* Skip a stuff byte when stop reading */
	n = 10;								/* Wait for a valid response in timeout of 10 attempts */
	do
		res = rcvr_spi();
	while ((res & 0x80) && --n);

	return res;			/* Return with the response value */
}



/*-----------------------------------------------------------------------*/
/* Public Functions                                                      */


/*-----------------------*/
/* Initialize Disk Drive */
/* (Platform dependent)  */

uint8 disk_initialize ()
{
	uint8 n, f;

	f = 0;
	if (!(Stat & STA_NODISK)) {

		DESELECT();				/* CS = H */

		n = 10;					/* Dummy clock */
		do
			rcvr_spi();
		while (--n);

		SELECT();				/* CS = L */
//		if (send_cmd(CMD0, 0) == 1) {			/* Enter Idle state */
			send_cmd(CMD0, 0);
			Timer1 = 100;						/* Wait for card ready in timeout of 1 sec */
			while (Timer1 && send_cmd(CMD1, 0));
			if (Timer1) {
				f = 1;							/* When device goes ready, break */
			} else {
				Timer1 = 100;
				while (Timer1) {				/* Retry initialization with ACMD41 */
					if (send_cmd(CMD55, 0) & 0xFE) continue;
					if (send_cmd(CMD41, 0) == 0) {
						f = 1; break;			/* When device goes ready, break */
					}
				}
			}
//		}
		if (f && (send_cmd(CMD16, 512) == 0))	/* Select R/W block length */
			f = 2;

		DESELECT();				/* CS = H */
		rcvr_spi();				/* Idle (Release DO) */
	}

	if (f == 2)
		Stat &= ~STA_NOINIT;	/* When initialization succeeded, clear STA_NOINIT */
	else
		disk_shutdown();		/* Otherwise force uninitialized */

	return Stat;
}



/*-----------------------*/
/* Shutdown              */
/* (Platform dependent)  */


uint8 disk_shutdown ()
{
	/* IO.PDR5.uint8 = 0x00; */		/* Disable driver */
	/* IO.PCR5 = 0x80; */
	/* IO.PDR5.uint8 = 0x80;	*/	/* Power OFF */

	Stat |= STA_NOINIT;

	return Stat;
}



/*--------------------*/
/* Return Disk Status */

uint8 disk_status ()
{
	return Stat;
}



/*----------------*/
/* Read Sector(s) */

uint16 disk_read (
	uint8 *buff,			/* Data buffer to store read data */
	uint32 sector,		/* Sector number (LBA) */
	uint8 count			/* Sector count (1..255) */
)
{
	if (Stat & STA_NOINIT) return RES_NOTRDY;
	if (!count) return RES_PARERR;

	sector *= 512;		/* LBA --> byte address */

	SELECT();			/* CS = L */

	if (count == 1) {	/* Single block read */
		if ((send_cmd(CMD17, sector) == 0)	/* READ_SINGLE_BLOCK */
			&& rcvr_datablock(buff, (uint8)(512/2)))
			count = 0;
	}
	else {				/* Multiple block read */
		if (send_cmd(CMD18, sector) == 0) {	/* READ_MULTIPLE_BLOCK */
			do {
				if (!rcvr_datablock(buff, (uint8)(512/2))) break;
				buff += 512;
			} while (--count);
			send_cmd(CMD12, 0);				/* STOP_TRANSMISSION */
		}
	}

	DESELECT();			/* CS = H */
	rcvr_spi();			/* Idle (Release DO) */

	return count ? RES_ERROR : RES_OK;
}



/*-----------------*/
/* Write Sector(s) */

#ifndef _READONLY
uint16 disk_write (
	const uint8 *buff,	/* Data to be written */
	uint32 sector,		/* Sector number (LBA) */
	uint8 count			/* Sector count (1..255) */
)
{
	if (Stat & STA_NOINIT) return RES_NOTRDY;
	if (Stat & STA_PROTECT) return RES_WRPRT;
	if (!count) return RES_PARERR;
	sector *= 512;		/* LBA --> byte address */

	SELECT();			/* CS = L */

	if (count == 1) {	/* Single block write */
		if ((send_cmd(CMD24, sector) == 0)	/* WRITE_BLOCK */
			&& xmit_datablock(buff, 0xFE))
			count = 0;
	}
	else {				/* Multiple block write */
		if (send_cmd(CMD25, sector) == 0) {	/* WRITE_MULTIPLE_BLOCK */
			do {
				if (!xmit_datablock(buff, 0xFC)) break;
				buff += 512;
			} while (--count);
			if (!xmit_datablock(0, 0xFD))	/* STOP_TRAN token */
				count = 1;
		}
	}

	DESELECT();			/* CS = H */
	rcvr_spi();			/* Idle (Release DO) */

	return count ? RES_ERROR : RES_OK;
}
#endif



/*--------------------------*/
/* Miscellaneous Functions  */

uint16 disk_ioctl (
	uint8 ctrl,		/* Control code */
	void *buff		/* Buffer to send/receive data block */
)
{
	uint16 res;
	uint8 n, csd[16], *p;
	uint16 csm, csize;
	
	
	if (Stat & STA_NOINIT) return RES_NOTRDY;

	SELECT();		/* CS = L */

	res = RES_ERROR;
	switch (ctrl) {
		case GET_SECTORS :	/* Get number of sectors on the disk (unsigned long) */
			if ((send_cmd(CMD9, 0) == 0) && rcvr_datablock(csd, 16/2)) {
				/* Calculate disk size */
/*				csm = 1 << (((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2);
				csize = ((uint16)(csd[8] & 3) >> 6) + (uint16)(csd[7] << 2) + ((uint16)(csd[6] & 3) << 10) + 1;
				*(uint32*)buff = (uint32)csize * csm;
				res = RES_OK;
*/
				n = csd[0] >> 6;
				switch (n) {
				case 0 :	/* CSD ver 1.XX */
					n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2;
					csize = (csd[8] >> 6) + ((uint16)csd[7] << 2) + ((uint16)(csd[6] & 3) << 10) + 1;
					*(uint32*)buff = (uint32)csize << (n - 9);
					res = RES_OK;
					break;
				case 1 :	/* CSD ver 2.00 */
					csize = csd[9] + ((uint16)csd[8] << 8) + 1;
					*(uint32*)buff = (uint32)csize << 10;
					res = RES_OK;
					break;
				}
			}
			break;

		case MMC_GET_CSD :	/* Receive CSD as a data block (16 bytes) */
			if ((send_cmd(CMD9, 0) == 0)	/* READ_CSD */
				&& rcvr_datablock(buff, 16/2))
				res = RES_OK;
			break;

		case MMC_GET_CID :	/* Receive CID as a data block (16 bytes) */
			if ((send_cmd(CMD10, 0) == 0)	/* READ_CID */
				&& rcvr_datablock(buff, 16/2))
				res = RES_OK;
			break;

		case MMC_GET_OCR :	/* Receive OCR as an R3 resp (4 bytes) */
			if (send_cmd(CMD58, 0) == 0) {	/* READ_OCR */
				for (n = 0, p = buff; n < 4; n++)
					*p++ = rcvr_spi();
				res = RES_OK;
			}
			break;

		default:
			res = RES_PARERR;
	}

	DESELECT();			/* CS = H */
	rcvr_spi();			/* Idle (Release DO) */

	return res;
}



/*---------------------------------------*/
/* Device timer interrupt procedure      */
/* This must be called in period of 10ms */
/* (Platform dependent)                  */

void disk_timerproc ()
{
	static uint8 pv;
	uint8 n, s;


	n = Timer1;						/* 100Hz decrement timer */
	if (n) Timer1 = --n;
	n = Timer2;
	if (n) Timer2 = --n;

	s = Stat;
	s &= ~STA_NODISK;

	Stat = s;

//	n = pv;
//	pv = SOCKPORT & (SOCKWP | SOCKINS);	/* Sapmle socket switch */

//	if (n == pv) {					/* Have contacts stabled? */
//		s = Stat;

//		if (pv & SOCKWP)			/* WP is H (write protected) */
//			s |= STA_PROTECT;
//		else						/* WP is L (write enabled) */
//			s &= ~STA_PROTECT;

//		if (pv & SOCKINS)			/* INS = H (Socket empty) */
//			s |= (STA_NODISK | STA_NOINIT);
//		else						/* INS = L (Card inserted) */
//			s &= ~STA_NODISK;

//		Stat = s;
//	}
}

⌨️ 快捷键说明

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