📄 mmc.c
字号:
xmit_spi(*buff++);
} while (--wc);
#endif
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 */
static 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 in SPI mode) */
/* Receive command response */
if (cmd == CMD12) rcvr_spi(); /* Skip a stuff byte when stop reading */
n = 100; /* Wait for a valid response in timeout of 10 attempts */
do
{
res = rcvr_spi();
} while ((res & 0x80) && --n); /* MSB 1: error */
//iprintf("res: %i\n", res);
return res; /* Return with the response value */
}
/*=======================================================================*/
/* Public Functions */
/*=======================================================================*/
/*-----------------------*/
/* Initialize Disk Drive */
DSTATUS MMC_disk_initialize (void)
{
//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) */
}
// set speed
if_spiSetSpeed(SPI_DIV); /* SPI CK = F_CPU / SPI_DIV */
return Stat;
}
/*----------------*/
/* Shutdown */
DSTATUS MMC_disk_shutdown (void)
{
return 0;
}
/*--------------------*/
/* Return Disk Status */
DSTATUS MMC_disk_status (void)
{
return Stat;
}
/*----------------*/
/* Read Sector(s) */
DRESULT MMC_disk_read (
BYTE *buff, /* Data buffer to store read data */
DWORD sector, /* Sector number (LBA) */
BYTE count /* Sector count (1..255) */
)
{
if (!count) return RES_PARERR;
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) */
#if _READONLY == 0
DRESULT MMC_disk_write (
const BYTE *buff, /* Data to be written */
DWORD sector, /* Sector number (LBA) */
BYTE count /* Sector count (1..255) */
)
{
if (!count) return RES_PARERR;
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 MMC_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_SECTOR_COUNT : /* 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 (void)
{
BYTE n = 0;
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 + -