123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541 |
- /*-----------------------------------------------------------------------*/
- /* MMC/SDC (in SPI mode) control module (C)ChaN, 2007 */
- /*-----------------------------------------------------------------------*/
- /* Only rcvr_spi(), xmit_spi(), disk_timerproc() and some macros */
- /* are platform dependent. */
- /*-----------------------------------------------------------------------*/
- #include "obj_spi_sd_stm32.h"
- /*--------------------------------------------------------------------------
- Module Private Functions
- ---------------------------------------------------------------------------*/
-
- extern SPI_HandleTypeDef hspi2;
- #define SD_SPIDriver hspi2
- static volatile DSTATUS Stat = STA_NOINIT; /* Disk status */
- static volatile BYTE Timer1, Timer2; /* 100Hz decrement timer */
- static BYTE CardType; /* b0:MMC, b1:SDC, b2:Block addressing */
- static BYTE PowerFlag = 0; /* indicates if "power" is on */
- static
- void SELECT(void)
- {
- HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_RESET);
- }
- static
- void DESELECT(void)
- {
- HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_SET);
- }
- static
- void xmit_spi(BYTE Data)
- {
- while (HAL_SPI_GetState(&SD_SPIDriver) != HAL_SPI_STATE_READY);
- HAL_SPI_Transmit(&SD_SPIDriver, &Data, 1, 5000);
- }
- static BYTE rcvr_spi(void)
- {
- unsigned char Dummy, Data;
- Dummy = 0xFF;
- Data = 0;
- while ((HAL_SPI_GetState(&SD_SPIDriver) != HAL_SPI_STATE_READY))
- ;
- HAL_SPI_TransmitReceive(&SD_SPIDriver, &Dummy, &Data, 1, 5000);
- return Data;
- }
- static
- void rcvr_spi_m(BYTE *dst) {
- *dst = rcvr_spi();
- }
- /*-----------------------------------------------------------------------*/
- /* Wait for card ready */
- /*-----------------------------z------------------------------------------*/
- static BYTE wait_ready(void) {
- BYTE res;
- Timer2 = 50;
- rcvr_spi();
- do
- res = rcvr_spi();
- while ((res != 0xFF) && Timer2);
- return res;
- }
- /*-----------------------------------------------------------------------*/
- /* Power Control (Platform dependent) */
- /*-----------------------------------------------------------------------*/
- /* When the target system does not support socket power control, there */
- /* is nothing to do in these functions and chk_power always returns 1. */
- static
- void power_on(void) {
- unsigned char i, cmd_arg[6];
- unsigned int Count = 0x1FFF;
- DESELECT();
- for (i = 0; i < 10; i++)
- xmit_spi(0xFF);
-
- SELECT();
- cmd_arg[0] = (CMD0 | 0x40);
- cmd_arg[1] = 0;
- cmd_arg[2] = 0;
- cmd_arg[3] = 0;
- cmd_arg[4] = 0;
- cmd_arg[5] = 0x95;
- for (i = 0; i < 6; i++)
- xmit_spi(cmd_arg[i]);
- while ((rcvr_spi() != 0x01) && Count)
- Count--;
- DESELECT();
- xmit_spi(0XFF);
- PowerFlag = 1;
- }
- static
- void power_off(void) {
- PowerFlag = 0;
- }
- static
- int chk_power(void) /* Socket power state: 0=off, 1=on */
- {
- return PowerFlag;
- }
- /*-----------------------------------------------------------------------*/
- /* Receive a data packet from MMC */
- /*-----------------------------------------------------------------------*/
- static bool rcvr_datablock(BYTE *buff, /* Data buffer to store received data */
- UINT btr /* Byte count (must be even number) */
- ) {
- BYTE 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 */
- do { /* Receive the data block into buffer */
- rcvr_spi_m(buff++);
- rcvr_spi_m(buff++);
- } while (btr -= 2);
- rcvr_spi(); /* Discard CRC */
- rcvr_spi();
- return TRUE; /* Return with success */
- }
- /*-----------------------------------------------------------------------*/
- /* Send a data packet to MMC */
- /*-----------------------------------------------------------------------*/
- #if _READONLY == 0
- static bool xmit_datablock(const BYTE *buff, /* 512 byte data block to be transmitted */
- BYTE token /* Data/Stop token */
- ) {
- BYTE resp, wc;
- uint32_t i = 0;
- if (wait_ready() != 0xFF)
- return FALSE;
- xmit_spi(token); /* Xmit data token */
- if (token != 0xFD) { /* Is data token */
- wc = 0;
- do { /* Xmit the 512 byte data block to MMC */
- xmit_spi(*buff++);
- xmit_spi(*buff++);
- } while (--wc);
- rcvr_spi();
- rcvr_spi();
- while (i <= 64) {
- resp = rcvr_spi(); /* Reveive data response */
- if ((resp & 0x1F) == 0x05) /* If not accepted, return with error */
- break;
- i++;
- }
- while (rcvr_spi() == 0)
- ;
- }
- if ((resp & 0x1F) == 0x05)
- return TRUE;
- else
- return FALSE;
- }
- #endif /* _READONLY */
- /*-----------------------------------------------------------------------*/
- /* 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] */
- n = 0;
- if (cmd == CMD0)
- n = 0x95; /* CRC for CMD0(0) */
- if (cmd == CMD8)
- n = 0x87; /* CRC for CMD8(0x1AA) */
- xmit_spi(n);
- /* 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 */
- /*-----------------------------------------------------------------------*/
- DSTATUS SD_disk_initialize(BYTE drv /* Physical drive nmuber (0) */
- ) {
- BYTE n, ty, ocr[4];
- if (drv)
- return STA_NOINIT; /* Supports only single drive */
- if (Stat & STA_NODISK)
- return Stat; /* No card in the socket */
- power_on(); /* Force socket power on */
- //send_initial_clock_train();
- SELECT(); /* CS = L */
- ty = 0;
- if (send_cmd(CMD0, 0) == 1) { /* Enter Idle state */
- Timer1 = 100; /* Initialization timeout of 1000 msec */
- if (send_cmd(CMD8, 0x1AA) == 1) { /* SDC Ver2+ */
- for (n = 0; n < 4; n++)
- ocr[n] = rcvr_spi();
- if (ocr[2] == 0x01 && ocr[3] == 0xAA) { /* The card can work at vdd range of 2.7-3.6V */
- do {
- if (send_cmd(CMD55, 0) <= 1
- && send_cmd(CMD41, 1UL << 30) == 0)
- break; /* ACMD41 with HCS bit */
- } while (Timer1);
- if (Timer1 && send_cmd(CMD58, 0) == 0) { /* Check CCS bit */
- for (n = 0; n < 4; n++)
- ocr[n] = rcvr_spi();
- ty = (ocr[0] & 0x40) ? 6 : 2;
- }
- }
- } else { /* SDC Ver1 or MMC */
- ty = (send_cmd(CMD55, 0) <= 1 && send_cmd(CMD41, 0) <= 1) ? 2 : 1; /* SDC : MMC */
- do {
- if (ty == 2) {
- if (send_cmd(CMD55, 0) <= 1 && send_cmd(CMD41, 0) == 0)
- break; /* ACMD41 */
- } else {
- if (send_cmd(CMD1, 0) == 0)
- break; /* CMD1 */
- }
- } while (Timer1);
- if (!Timer1 || send_cmd(CMD16, 512) != 0) /* Select R/W block length */
- ty = 0;
- }
- }
- CardType = ty;
- DESELECT(); /* CS = H */
- rcvr_spi(); /* Idle (Release DO) */
- if (ty) /* Initialization succeded */
- Stat &= ~STA_NOINIT; /* Clear STA_NOINIT */
- else
- /* Initialization failed */
- power_off();
- return Stat;
- }
- /*-----------------------------------------------------------------------*/
- /* Get Disk Status */
- /*-----------------------------------------------------------------------*/
- DSTATUS SD_disk_status(BYTE drv /* Physical drive nmuber (0) */
- ) {
- if (drv)
- return STA_NOINIT; /* Supports only single drive */
- return Stat;
- }
- /*-----------------------------------------------------------------------*/
- /* Read Sector(s) */
- /*-----------------------------------------------------------------------*/
- DRESULT SD_disk_read(BYTE pdrv, BYTE* buff, DWORD sector, UINT count) {
- if (pdrv || !count)
- return RES_PARERR;
- if (Stat & STA_NOINIT)
- return RES_NOTRDY;
- if (!(CardType & 4))
- sector *= 512; /* Convert to byte address if needed */
- SELECT(); /* CS = L */
- if (count == 1) { /* Single block read */
- if ((send_cmd(CMD17, sector) == 0) /* READ_SINGLE_BLOCK */
- && rcvr_datablock(buff, 512))
- count = 0;
- } else { /* Multiple block read */
- if (send_cmd(CMD18, sector) == 0) { /* READ_MULTIPLE_BLOCK */
- do {
- if (!rcvr_datablock(buff, 512))
- 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 SD_disk_write(BYTE pdrv, const BYTE* buff, DWORD sector, UINT count) {
- if (pdrv || !count)
- return RES_PARERR;
- if (Stat & STA_NOINIT)
- return RES_NOTRDY;
- if (Stat & STA_PROTECT)
- return RES_WRPRT;
- if (!(CardType & 4))
- sector *= 512; /* Convert to byte address if needed */
- 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 (CardType & 2) {
- send_cmd(CMD55, 0);
- send_cmd(CMD23, count); /* ACMD23 */
- }
- 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 /* _READONLY */
- /*-----------------------------------------------------------------------*/
- /* Miscellaneous Functions */
- /*-----------------------------------------------------------------------*/
- DRESULT SD_disk_ioctl(BYTE drv, /* Physical drive nmuber (0) */
- BYTE ctrl, /* Control code */
- void *buff /* Buffer to send/receive control data */
- ) {
- DRESULT res;
- BYTE n, csd[16], *ptr = buff;
- WORD csize;
- if (drv)
- return RES_PARERR;
- res = RES_ERROR;
- if (ctrl == CTRL_POWER) {
- switch (*ptr) {
- case 0: /* Sub control code == 0 (POWER_OFF) */
- if (chk_power())
- power_off(); /* Power off */
- res = RES_OK;
- break;
- case 1: /* Sub control code == 1 (POWER_ON) */
- power_on(); /* Power on */
- res = RES_OK;
- break;
- case 2: /* Sub control code == 2 (POWER_GET) */
- *(ptr + 1) = (BYTE) chk_power();
- res = RES_OK;
- break;
- default:
- res = RES_PARERR;
- }
- } else {
- if (Stat & STA_NOINIT)
- return RES_NOTRDY;
- SELECT(); /* CS = L */
- switch (ctrl) {
- case GET_SECTOR_COUNT: /* Get number of sectors on the disk (DWORD) */
- if ((send_cmd(CMD9, 0) == 0) && rcvr_datablock(csd, 16)) {
- if ((csd[0] >> 6) == 1) { /* SDC ver 2.00 */
- csize = csd[9] + ((WORD) csd[8] << 8) + 1;
- *(DWORD*) buff = (DWORD) csize << 10;
- } else { /* MMC or SDC ver 1.XX */
- n = (csd[5] & 15) + ((csd[10] & 128) >> 7)
- + ((csd[9] & 3) << 1) + 2;
- csize = (csd[8] >> 6) + ((WORD) csd[7] << 2)
- + ((WORD) (csd[6] & 3) << 10) + 1;
- *(DWORD*) buff = (DWORD) csize << (n - 9);
- }
- res = RES_OK;
- }
- break;
- case GET_SECTOR_SIZE: /* Get sectors on the disk (WORD) */
- *(WORD*) buff = 512;
- res = RES_OK;
- break;
- case CTRL_SYNC: /* Make sure that data has been written */
- if (wait_ready() == 0xFF)
- 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))
- 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))
- 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;
- }
- // case MMC_GET_TYPE : /* Get card type flags (1 byte) */
- // *ptr = CardType;
- // res = RES_OK;
- // break;
- default:
- res = RES_PARERR;
- }
- DESELECT(); /* CS = H */
- rcvr_spi(); /* Idle (Release DO) */
- }
- return res;
- }
- /*-----------------------------------------------------------------------*/
- /* Device Timer Interrupt Procedure (Platform dependent) */
- /*-----------------------------------------------------------------------*/
- /* This function must be called in period of 10ms */
- void disk_timerproc(void) {
- // BYTE n, s;
- BYTE n;
- n = Timer1; /* 100Hz decrement timer */
- if (n)
- Timer1 = --n;
- n = Timer2;
- if (n)
- Timer2 = --n;
- }
- volatile unsigned short int sdcard_timer;
- void inline sdcard_systick_timerproc(void) {
- ++sdcard_timer;
- if (sdcard_timer >= 100) {
- sdcard_timer = 0;
- disk_timerproc();
- }
- }
- /*---------------------------------------------------------*/
- /* 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 SD_get_fattime(void) {
- return ((2007UL - 1980) << 25) // Year = 2007
- | (6UL << 21) // Month = June
- | (5UL << 16) // Day = 5
- | (11U << 11) // Hour = 11
- | (38U << 5) // Min = 38
- | (0U >> 1) // Sec = 0
- ;
- }
|