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

📄 mmc.c

📁 AT91SAM7X256
💻 C
字号:
/*-----------------------------------------------------------------------*/
/* MMC/SDC (in SPI mode) control module  2006                   */
/*-----------------------------------------------------------------------*/

#include <stdio.h>

#include "ioat91sam7X256.h"
#include "mmc.h"


#define DBGU_RXD		AT91C_PA9_DRXD	  /* JP11 must be close */
#define DBGU_TXD		AT91C_PA10_DTXD	  /* JP12 must be close */

#define US_RXD_PIN		AT91C_PA5_RXD0    /* JP9 must be close */
#define US_TXD_PIN		AT91C_PA6_TXD0    /* JP7 must be close */
#define US_RTS_PIN		AT91C_PA7_RTS0    /* JP8 must be close */
#define US_CTS_PIN		AT91C_PA8_CTS0    /* JP6 must be close */

#define CARD_WP_PIN      AT91C_PIO_PA16
#define CARD_INS_PIN     AT91C_PIO_PA15
static AT91PS_PIO  pPIOA = AT91C_BASE_PIOA;
static AT91PS_SPI  pSPI  = AT91C_BASE_SPI0;

#define CARD_SELECT_PIN  AT91C_PA13_SPI0_NPCS1
#define SPI_CSR_NUM      0

#define SPI_SCBR_MIN     2


/* 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 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 CMD58	(0x40+58)	/* READ_OCR */


/* Control signals (Platform dependent) */
#define SELECT()	(pPIOA->PIO_CODR = CARD_SELECT_PIN) /* MMC CS = L */
#define	DESELECT()	(pPIOA->PIO_SODR = CARD_SELECT_PIN) /* MMC CS = H */

#define SOCKWP		CARD_WP_PIN			/* Write protect switch (PB5) */
#define SOCKINS		CARD_INS_PIN		/* Card detect switch (PB4) */

// #define POWER_ON()	PORTE &= ~0x80	/* Socke power (PE7) */
// #define POWER_OFF()	PORTE |=  0x80

#define POWER_ON()
#define POWER_OFF()

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

// AT91: thru systime
static volatile
BYTE Timer;			/* 100Hz decrement timer */



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


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

#define xmit_spi(dat) 	SPDR=(dat); loop_until_bit_is_set(SPSR,SPIF)

/*---------------------------------*/
/* Receive a byte from MMC via SPI */
/* (Platform dependent)            */

static
BYTE rcvr_spi()
{
	SPDR = 0xFF;
	loop_until_bit_is_set(SPSR, SPIF);
	return SPDR;
}

/* Alternative macro to receive data fast */
#define rcvr_spi_m(dst)	SPDR=0xFF; loop_until_bit_is_set(SPSR,SPIF); *(dst)=SPDR

#endif

extern void AT91F_DBGU_Printk(	char *buffer)   ;
extern void AT91F_DBGU_Init(void) ;
//********************************************************
/*void AT91F_DBGU_Printk(	char *buffer)
{
    while(*buffer != '\0') {
	while (!AT91F_US_TxReady((AT91PS_USART)AT91C_BASE_DBGU));
	AT91F_US_PutChar((AT91PS_USART)AT91C_BASE_DBGU, *buffer++);
    }
}

void AT91F_DBGU_Init(void)
{

}
 */
//*****************************************************

static void AT91_spiSetSpeed(BYTE speed)
{
	DWORD reg;

	if ( speed < SPI_SCBR_MIN ) speed = SPI_SCBR_MIN;
	if ( speed > 1 ) speed &= 0xFE;

	reg = pSPI->SPI_CSR[SPI_CSR_NUM];
	reg = ( reg & ~(AT91C_SPI_SCBR) ) | ( (DWORD)speed << 8 );
	pSPI->SPI_CSR[SPI_CSR_NUM] = reg;
}

static BYTE AT91_spi(BYTE outgoing)
{
	BYTE incoming;

	while( !( pSPI->SPI_SR & AT91C_SPI_TDRE ) ); // transfer compl. wait
	pSPI->SPI_TDR = (WORD)( outgoing );
	while( !( pSPI->SPI_SR & AT91C_SPI_RDRF ) ); // wait for char
	incoming = (BYTE)( pSPI->SPI_RDR );

	return incoming;
}

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

static
void xmit_spi(BYTE dat)
{
	AT91_spi(dat);
}

/*---------------------------------*/
/* Receive a byte from MMC via SPI */
/* (Platform dependent)            */

static
BYTE rcvr_spi(void)
{
	return AT91_spi(0xff);
}

/* Alternative "macro" (not at AT91 so far) to receive data fast */
static
void rcvr_spi_m(BYTE *dst)
{
	*dst = rcvr_spi();
}


/*---------------------*/
/* Wait for card ready */

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

/*--------------------------------*/
/* Receive a data packet from MMC */

extern
BOOL rcvr_datablock (
	BYTE *buff,			/* Data buffer to store received data */
	BYTE wc				/* Word count (0 means 256 words) */
)
{
	BYTE token;

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

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

	return TRUE;					/* Return with success */
}



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

#ifndef _READONLY
static
BOOL xmit_datablock (
	const BYTE *buff,	/* 512 byte data block to be transmitted */
	BYTE token			/* Data/Stop token */
)
{
	BYTE 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 */

extern
 BYTE send_cmd (
	BYTE cmd,		/* Command byte */
	DWORD arg		/* Argument */
)
{
	BYTE n, res;


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

	/* Send command packet */
	xmit_spi(cmd);						/* Command */
	xmit_spi((BYTE)(arg >> 24));		/* Argument[31..24] */
	xmit_spi((BYTE)(arg >> 16));		/* Argument[23..16] */
	xmit_spi((BYTE)(arg >> 8));			/* Argument[15..8] */
	xmit_spi((BYTE)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)  */

//extern
DSTATUS disk_initialize ()
{
	BYTE n;

	AT91PS_PMC pPMC      = AT91C_BASE_PMC;

	POWER_ON();					/* Socket power ON */
	//for (Timer = 3; Timer; );	/* Wait for 30ms */		
	for (unsigned int rep =30; rep>=1;rep-- );	
	/* MMC socket-switch init */
	// disable internal Pull-Ups if needed
		
	// disable PIO from controlling MOSI, MISO, SCK (=hand over to SPI)
	// keep CS untouched - used as GPIO pin during init
	pPIOA->PIO_PDR = AT91C_PA16_SPI0_MISO | AT91C_PA17_SPI0_MOSI | AT91C_PA18_SPI0_SPCK; //  | NCPS_PDR_BIT;
	// set pin-functions in PIO Controller
	pPIOA->PIO_ASR = AT91C_PA16_SPI0_MISO | AT91C_PA17_SPI0_MOSI | AT91C_PA18_SPI0_SPCK; /// not here: | NCPS_ASR_BIT;
	
	// set chip-select as output high (unselect card)
	pPIOA->PIO_PER  = CARD_SELECT_PIN; // enable GPIO of CS-pin
	pPIOA->PIO_SODR = CARD_SELECT_PIN; // set high
	pPIOA->PIO_OER  = CARD_SELECT_PIN; // output enable
	
	// enable peripheral clock for SPI ( PID Bit 5 )
	pPMC->PMC_PCER = ( (DWORD) 1 << AT91C_ID_SPI0 ); // n.b. IDs are just bit-numbers
	
	// SPI enable and reset
	pSPI->SPI_CR = AT91C_SPI_SPIEN | AT91C_SPI_SWRST;
	
	// SPI mode: master, FDIV=0, fault detection disabled
	pSPI->SPI_MR  = AT91C_SPI_MSTR | AT91C_SPI_MODFDIS;
	
	// set chip-select-register
	// 8 bits per transfer, CPOL=1, ClockPhase=0, DLYBCT = 0
	pSPI->SPI_CSR[SPI_CSR_NUM] = AT91C_SPI_CPOL | AT91C_SPI_BITS_8;
	
	// slow during init
	AT91_spiSetSpeed(0xFE);
	
	// enable
	pSPI->SPI_CR = AT91C_SPI_SPIEN;

	Stat |= STA_NOINIT;
	if (!(Stat & STA_NODISK)) {
		n = 10;						/* Dummy clock */
		do
			rcvr_spi();
		while (--n);

		//AT91F_DBGU_Printk("SPI prepare done\n");    /////////////////////////////////////////

		SELECT();			/* CS = L */
		if (send_cmd(CMD0, 0) == 1) {			/* Enter Idle state */
			Timer = 100;						/* Wait for card ready in timeout of 1 sec */
			while (Timer && send_cmd(CMD1, 0));
			if (Timer) Stat &= ~STA_NOINIT;		/* When device goes ready, clear STA_NOINIT */
		}
		
		//AT91F_DBGU_Printk("CMD0 done timer = %i\n", Timer);
		
		DESELECT();			/* CS = H */
		rcvr_spi();			/* Idle (Release DO) */
		
		AT91_spiSetSpeed(SPI_SCBR_MIN);
	}

	if (Stat & STA_NOINIT)
		disk_shutdown();
	return Stat;
}

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

#if 0
DSTATUS disk_shutdown ()
{
	SPCR = 0;				/* Disable SPI function */
	DDRB  = 0b11000000;		/* Disable drivers */
	PORTB = 0b10110000;
	POWER_OFF();			/* Socket power OFF */

	Stat |= STA_NOINIT;

	return Stat;
}
#endif

DSTATUS disk_shutdown ()
{
	return 0;
}


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

DSTATUS disk_status ()
{
	return Stat;
}



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

extern DRESULT disk_read (
	BYTE *buff,		/* Data buffer to store read data */
	DWORD sector,		/* Sector number (LBA) */
	BYTE 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, (BYTE)(512/2)))
			count = 0;
	}
	else {				/* Multiple block read */
		if (send_cmd(CMD18, sector) == 0) {	/* READ_MULTIPLE_BLOCK */
			do {
				if (!rcvr_datablock(buff, (BYTE)(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
extern DRESULT disk_write (
	const BYTE *buff,	/* Data to be written */
	DWORD sector,		/* Sector number (LBA) */
	BYTE 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  */

DRESULT disk_ioctl (
	BYTE ctrl,		/* Control code */
	void *buff		/* Buffer to send/receive data block */
)
{
	DRESULT res;
	BYTE n, csd[16], *ptr = buff;
	WORD 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 = ((WORD)(csd[8] & 3) >> 6) + (WORD)(csd[7] << 2) + ((WORD)(csd[6] & 3) << 10) + 1;
#ifdef _BYTE_ACC
				ST_DWORD(ptr, (DWORD)csize * csm);
#else
				*(DWORD*)ptr = (DWORD)csize * csm;
#endif
				res = RES_OK;
			}
			break;

		case MMC_GET_CSD :	/* Receive CSD as a data block (16 bytes) */
			if ((send_cmd(CMD9, 0) == 0)	/* READ_CSD */
				&& rcvr_datablock(ptr, 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(ptr, 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; n < 4; n++)
					*ptr++ = 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 BYTE pv;
	BYTE n, s;
	n = Timer;						/* 100Hz decrement timer */
	if (n) Timer = --n;

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

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