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

📄 mmc.c.svn-base

📁 MP3 for ARM codec. [asm+C]
💻 SVN-BASE
📖 第 1 页 / 共 2 页
字号:

static void if_spiSetSpeed(unsigned char speed)
{
	unsigned long reg;
	AT91PS_SPI pSPI      = AT91C_BASE_SPI;

	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) ) | ( (unsigned long)speed << 8 );
	pSPI->SPI_CSR[SPI_CSR_NUM] = reg;
}

static void init_spi()
{
	BYTE i;
	AT91PS_SPI pSPI      = AT91C_BASE_SPI;
	AT91PS_PIO pPIOA     = AT91C_BASE_PIOA;
	AT91PS_PMC pPMC      = AT91C_BASE_PMC;
	// AT91PS_PDC pPDC_SPI  = AT91C_BASE_PDC_SPI;

	// disable PIO from controlling MOSI, MISO, SCK (=hand over to SPI)
	// keep CS untouched - used as GPIO pin during init
	pPIOA->PIO_PDR = AT91C_PA12_MISO | AT91C_PA13_MOSI | AT91C_PA14_SPCK; //  | NCPS_PDR_BIT;
	// set pin-functions in PIO Controller
	pPIOA->PIO_ASR = AT91C_PA12_MISO | AT91C_PA13_MOSI | AT91C_PA14_SPCK; /// not here: | NCPS_ASR_BIT;
	/// not here: pPIOA->PIO_BSR = NPCS_BSR_BIT;

	// set chip-select as output high (unselect card)
	pPIOA->PIO_PER  = NPCS_BSR_BIT; // enable PIO of CS-pin
	pPIOA->PIO_SODR = NPCS_BSR_BIT; // set
	pPIOA->PIO_OER  = NPCS_BSR_BIT; // output

	// enable peripheral clock for SPI ( PID Bit 5 )
	pPMC->PMC_PCER = ( (WORD) 1 << AT91C_ID_SPI ); // n.b. IDs are just bit-numbers

	// SPI enable and reset
	pSPI->SPI_CR = AT91C_SPI_SPIEN | AT91C_SPI_SWRST;

	// SPI mode: master, fixed periph. sel., FDIV=0, fault detection disabled
	pSPI->SPI_MR  = AT91C_SPI_MSTR | AT91C_SPI_PS_FIXED | AT91C_SPI_MODFDIS;

	// set PCS for fixed select
	pSPI->SPI_MR &= 0xFFF0FFFF; // clear old PCS - redundant (AT91lib)
	pSPI->SPI_MR |= ( (SPI_MR_PCS<<16) & AT91C_SPI_PCS ); // set PCS

	// set chip-select-register
	// 8 bits per transfer, CPOL=1, ClockPhase=0, DLYBCT = 0
	// TODO: Why has CPOL to be active here and non-active on LPC2000?
	//       Take closer look on timing diagrams in datasheets.
	/*
	MMC reads data on the rising edge => CPOL=CPHA can't work
	=> possible settings: CPOL=0, CPHA=1; CPOL=1, CPHA=0

	*/
	//pSPI->SPI_CSR[SPI_CSR_NUM] = AT91C_SPI_CPOL | AT91C_SPI_BITS_8 | AT91C_SPI_NCPHA;
	//pSPI->SPI_CSR[SPI_CSR_NUM] = AT91C_SPI_BITS_8 | AT91C_SPI_NCPHA; 
	pSPI->SPI_CSR[SPI_CSR_NUM] = AT91C_SPI_CPOL | AT91C_SPI_BITS_8; // ok
	//pSPI->SPI_CSR[SPI_CSR_NUM] = AT91C_SPI_BITS_8;

	// slow during init
	if_spiSetSpeed(0xFE); 

	// enable
	pSPI->SPI_CR = AT91C_SPI_SPIEN;

	/* Send 20 spi commands with card not selected */
	for(i=0;i<21;i++)
		xmit_spi(0xFF);

	/* enable automatic chip-select */
	pPIOA->PIO_ODR  = NPCS_BSR_BIT; // input
	pPIOA->PIO_CODR = NPCS_BSR_BIT; // clear
	// disable PIO from controlling the CS pin (=hand over to SPI)
	pPIOA->PIO_PDR = NCPS_PDR_BIT;
	// set pin-functions in PIO Controller
	pPIOA->PIO_ASR = NCPS_ASR_BIT;
	pPIOA->PIO_BSR = NPCS_BSR_BIT;

}

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


/*-----------------------*/
/* Initialize Disk Drive */

DSTATUS disk_initialize ()
{
	BYTE n;
	
	init_spi();

	Stat |= STA_NOINIT;
	if (!(Stat & STA_NODISK)) {
		#if 0
		n = 10;						/* Dummy clock */
		do
			rcvr_spi();
		while (--n);
		#endif
		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 */
		}
		DESELECT();			/* CS = H */
		rcvr_spi();			/* Idle (Release DO) */
	}

	// max speed
	if_spiSetSpeed(0x00);

	return Stat;
}



/*----------------*/
/* Shutdown       */


DSTATUS disk_shutdown ()
{
	return 0;
}



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

DSTATUS disk_status ()
{
	return Stat;
}



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

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 */
		//puts("doing single block read");
		if ((send_cmd(CMD17, sector) == 0)	/* READ_SINGLE_BLOCK */
			&& rcvr_datablock(buff, (BYTE)(512/2)))
			count = 0;
	}
	else {				/* Multiple block read */
		//puts("doing multi-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
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;
				*(DWORD*)ptr = (DWORD)csize * csm;
				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 */

void disk_timerproc ()
{
	BYTE n, s;


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

}


/*---------------------------------------------------------*/
/* User Provided Timer Function for FatFs module           */
/*---------------------------------------------------------*/
/* This is a real time clock service to be called from     */
/* FatFs module. Any valid time must be returned even if   */
/* the system does not support a real time clock.          */


DWORD get_fattime ()
{

	return	((2006UL-1980) << 25)	// Year = 2006
			| (2UL << 21)			// Month = Feb
			| (9UL << 16)			// Day = 9
			| (22U << 11)			// Hour = 22
			| (30U << 5)			// Min = 30
			| (0U >> 1)				// Sec = 0
			;

}

⌨️ 快捷键说明

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