123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544 |
- #define TRUE 1
- #define FALSE 0
- #define bool BYTE
-
- #include "stm32f4xx_hal.h"
-
- #include "diskio.h"
- #include "fatfs_sd.h"
-
- uint16_t Timer1, Timer2; /* 1ms Timer Counter */
-
- static volatile DSTATUS Stat = STA_NOINIT; /* Disk Status */
- static uint8_t CardType; /* Type 0:MMC, 1:SDC, 2:Block addressing */
- static uint8_t PowerFlag = 0; /* Power flag */
-
- /***************************************
- * SPI functions
- **************************************/
-
- /* slave select */
- static void SELECT(void)
- {
- HAL_GPIO_WritePin(SD_CS_PORT, SD_CS_PIN, GPIO_PIN_RESET);
- HAL_Delay(1);
- }
-
- /* slave deselect */
- static void DESELECT(void)
- {
- HAL_GPIO_WritePin(SD_CS_PORT, SD_CS_PIN, GPIO_PIN_SET);
- HAL_Delay(1);
- }
-
- /* SPI transmit a byte */
- static void SPI_TxByte(uint8_t data)
- {
- while(!__HAL_SPI_GET_FLAG(HSPI_SDCARD, SPI_FLAG_TXE));
- HAL_SPI_Transmit(HSPI_SDCARD, &data, 1, SPI_TIMEOUT);
- }
-
- /* SPI transmit buffer */
- static void SPI_TxBuffer(uint8_t *buffer, uint16_t len)
- {
- while(!__HAL_SPI_GET_FLAG(HSPI_SDCARD, SPI_FLAG_TXE));
- HAL_SPI_Transmit(HSPI_SDCARD, buffer, len, SPI_TIMEOUT);
- }
-
- /* SPI receive a byte */
- static uint8_t SPI_RxByte(void)
- {
- uint8_t dummy, data;
- dummy = 0xFF;
-
- while(!__HAL_SPI_GET_FLAG(HSPI_SDCARD, SPI_FLAG_TXE));
- HAL_SPI_TransmitReceive(HSPI_SDCARD, &dummy, &data, 1, SPI_TIMEOUT);
-
- return data;
- }
-
- /* SPI receive a byte via pointer */
- static void SPI_RxBytePtr(uint8_t *buff)
- {
- *buff = SPI_RxByte();
- }
-
- /***************************************
- * SD functions
- **************************************/
-
- /* wait SD ready */
- static uint8_t SD_ReadyWait(void)
- {
- uint8_t res;
-
- /* timeout 500ms */
- Timer2 = 500;
-
- /* if SD goes ready, receives 0xFF */
- do {
- res = SPI_RxByte();
- } while ((res != 0xFF) && Timer2);
-
- return res;
- }
-
- /* power on */
- static void SD_PowerOn(void)
- {
- uint8_t args[6];
- uint32_t cnt = 0x1FFF;
-
- /* transmit bytes to wake up */
- DESELECT();
- for(int i = 0; i < 10; i++)
- {
- SPI_TxByte(0xFF);
- }
-
- /* slave select */
- SELECT();
-
- /* make idle state */
- args[0] = CMD0; /* CMD0:GO_IDLE_STATE */
- args[1] = 0;
- args[2] = 0;
- args[3] = 0;
- args[4] = 0;
- args[5] = 0x95; /* CRC */
-
- SPI_TxBuffer(args, sizeof(args));
-
- /* wait response */
- while ((SPI_RxByte() != 0x01) && cnt)
- {
- cnt--;
- }
-
- DESELECT();
- SPI_TxByte(0XFF);
-
- PowerFlag = 1;
- }
-
- /* power off */
- static void SD_PowerOff(void)
- {
- PowerFlag = 0;
- }
-
- /* check power flag */
- static uint8_t SD_CheckPower(void)
- {
- return PowerFlag;
- }
-
- /* receive data block */
- static bool SD_RxDataBlock(BYTE *buff, UINT len)
- {
- uint8_t token;
-
- /* timeout 200ms */
- Timer1 = 200;
-
- /* loop until receive a response or timeout */
- do {
- token = SPI_RxByte();
- } while((token == 0xFF) && Timer1);
-
- /* invalid response */
- if(token != 0xFE) return FALSE;
-
- /* receive data */
- do {
- SPI_RxBytePtr(buff++);
- } while(len--);
-
- /* discard CRC */
- SPI_RxByte();
- SPI_RxByte();
-
- return TRUE;
- }
-
- /* transmit data block */
- #if _USE_WRITE == 1
- static bool SD_TxDataBlock(const uint8_t *buff, BYTE token)
- {
- uint8_t resp;
- uint8_t i = 0;
-
- /* wait SD ready */
- if (SD_ReadyWait() != 0xFF) return FALSE;
-
- /* transmit token */
- SPI_TxByte(token);
-
- /* if it's not STOP token, transmit data */
- if (token != 0xFD)
- {
- SPI_TxBuffer((uint8_t*)buff, 512);
-
- /* discard CRC */
- SPI_RxByte();
- SPI_RxByte();
-
- /* receive response */
- while (i <= 64)
- {
- resp = SPI_RxByte();
-
- /* transmit 0x05 accepted */
- if ((resp & 0x1F) == 0x05) break;
- i++;
- }
-
- /* recv buffer clear */
- while (SPI_RxByte() == 0);
- }
-
- /* transmit 0x05 accepted */
- if ((resp & 0x1F) == 0x05) return TRUE;
-
- return FALSE;
- }
- #endif /* _USE_WRITE */
-
- /* transmit command */
- static BYTE SD_SendCmd(BYTE cmd, uint32_t arg)
- {
- uint8_t crc, res;
-
- /* wait SD ready */
- if (SD_ReadyWait() != 0xFF) return 0xFF;
-
- /* transmit command */
- SPI_TxByte(cmd); /* Command */
- SPI_TxByte((uint8_t)(arg >> 24)); /* Argument[31..24] */
- SPI_TxByte((uint8_t)(arg >> 16)); /* Argument[23..16] */
- SPI_TxByte((uint8_t)(arg >> 8)); /* Argument[15..8] */
- SPI_TxByte((uint8_t)arg); /* Argument[7..0] */
-
- /* prepare CRC */
- if(cmd == CMD0) crc = 0x95; /* CRC for CMD0(0) */
- else if(cmd == CMD8) crc = 0x87; /* CRC for CMD8(0x1AA) */
- else crc = 1;
-
- /* transmit CRC */
- SPI_TxByte(crc);
-
- /* Skip a stuff byte when STOP_TRANSMISSION */
- if (cmd == CMD12) SPI_RxByte();
-
- /* receive response */
- uint8_t n = 10;
- do {
- res = SPI_RxByte();
- } while ((res & 0x80) && --n);
-
- return res;
- }
-
- /***************************************
- * user_diskio.c functions
- **************************************/
-
- /* initialize SD */
- DSTATUS SD_disk_initialize(BYTE drv)
- {
- uint8_t n, type, ocr[4];
-
- /* single drive, drv should be 0 */
- if(drv) return STA_NOINIT;
-
- /* no disk */
- if(Stat & STA_NODISK) return Stat;
-
- /* power on */
- SD_PowerOn();
-
- /* slave select */
- SELECT();
-
- /* check disk type */
- type = 0;
-
- /* send GO_IDLE_STATE command */
- if (SD_SendCmd(CMD0, 0) == 1)
- {
- /* timeout 1 sec */
- Timer1 = 1000;
-
- /* SDC V2+ accept CMD8 command, http://elm-chan.org/docs/mmc/mmc_e.html */
- if (SD_SendCmd(CMD8, 0x1AA) == 1)
- {
- /* operation condition register */
- for (n = 0; n < 4; n++)
- {
- ocr[n] = SPI_RxByte();
- }
-
- /* voltage range 2.7-3.6V */
- if (ocr[2] == 0x01 && ocr[3] == 0xAA)
- {
- /* ACMD41 with HCS bit */
- do {
- if (SD_SendCmd(CMD55, 0) <= 1 && SD_SendCmd(CMD41, 1UL << 30) == 0) break;
- } while (Timer1);
-
- /* READ_OCR */
- if (Timer1 && SD_SendCmd(CMD58, 0) == 0)
- {
- /* Check CCS bit */
- for (n = 0; n < 4; n++)
- {
- ocr[n] = SPI_RxByte();
- }
-
- /* SDv2 (HC or SC) */
- type = (ocr[0] & 0x40) ? CT_SD2 | CT_BLOCK : CT_SD2;
- }
- }
- }
- else
- {
- /* SDC V1 or MMC */
- type = (SD_SendCmd(CMD55, 0) <= 1 && SD_SendCmd(CMD41, 0) <= 1) ? CT_SD1 : CT_MMC;
-
- do
- {
- if (type == CT_SD1)
- {
- if (SD_SendCmd(CMD55, 0) <= 1 && SD_SendCmd(CMD41, 0) == 0) break; /* ACMD41 */
- }
- else
- {
- if (SD_SendCmd(CMD1, 0) == 0) break; /* CMD1 */
- }
-
- } while (Timer1);
-
- /* SET_BLOCKLEN */
- if (!Timer1 || SD_SendCmd(CMD16, 512) != 0) type = 0;
- }
- }
-
- CardType = type;
-
- /* Idle */
- DESELECT();
- SPI_RxByte();
-
- /* Clear STA_NOINIT */
- if (type)
- {
- Stat &= ~STA_NOINIT;
- }
- else
- {
- /* Initialization failed */
- SD_PowerOff();
- }
-
- return Stat;
- }
-
- /* return disk status */
- DSTATUS SD_disk_status(BYTE drv)
- {
- if (drv) return STA_NOINIT;
- return Stat;
- }
-
- /* read sector */
- DRESULT SD_disk_read(BYTE pdrv, BYTE* buff, DWORD sector, UINT count)
- {
- /* pdrv should be 0 */
- if (pdrv || !count) return RES_PARERR;
-
- /* no disk */
- if (Stat & STA_NOINIT) return RES_NOTRDY;
-
- /* convert to byte address */
- if (!(CardType & CT_SD2)) sector *= 512;
-
- SELECT();
-
- if (count == 1)
- {
- /* READ_SINGLE_BLOCK */
- if ((SD_SendCmd(CMD17, sector) == 0) && SD_RxDataBlock(buff, 512)) count = 0;
- }
- else
- {
- /* READ_MULTIPLE_BLOCK */
- if (SD_SendCmd(CMD18, sector) == 0)
- {
- do {
- if (!SD_RxDataBlock(buff, 512)) break;
- buff += 512;
- } while (--count);
-
- /* STOP_TRANSMISSION */
- SD_SendCmd(CMD12, 0);
- }
- }
-
- /* Idle */
- DESELECT();
- SPI_RxByte();
-
- return count ? RES_ERROR : RES_OK;
- }
-
- /* write sector */
- #if _USE_WRITE == 1
- DRESULT SD_disk_write(BYTE pdrv, const BYTE* buff, DWORD sector, UINT count)
- {
- /* pdrv should be 0 */
- if (pdrv || !count) return RES_PARERR;
-
- /* no disk */
- if (Stat & STA_NOINIT) return RES_NOTRDY;
-
- /* write protection */
- if (Stat & STA_PROTECT) return RES_WRPRT;
-
- /* convert to byte address */
- if (!(CardType & CT_SD2)) sector *= 512;
-
- SELECT();
-
- if (count == 1)
- {
- /* WRITE_BLOCK */
- if ((SD_SendCmd(CMD24, sector) == 0) && SD_TxDataBlock(buff, 0xFE))
- count = 0;
- }
- else
- {
- /* WRITE_MULTIPLE_BLOCK */
- if (CardType & CT_SD1)
- {
- SD_SendCmd(CMD55, 0);
- SD_SendCmd(CMD23, count); /* ACMD23 */
- }
-
- if (SD_SendCmd(CMD25, sector) == 0)
- {
- do {
- if(!SD_TxDataBlock(buff, 0xFC)) break;
- buff += 512;
- } while (--count);
-
- /* STOP_TRAN token */
- if(!SD_TxDataBlock(0, 0xFD))
- {
- count = 1;
- }
- }
- }
-
- /* Idle */
- DESELECT();
- SPI_RxByte();
-
- return count ? RES_ERROR : RES_OK;
- }
- #endif /* _USE_WRITE */
-
- /* ioctl */
- DRESULT SD_disk_ioctl(BYTE drv, BYTE ctrl, void *buff)
- {
- DRESULT res;
- uint8_t n, csd[16], *ptr = buff;
- WORD csize;
-
- /* pdrv should be 0 */
- if (drv) return RES_PARERR;
- res = RES_ERROR;
-
- if (ctrl == CTRL_POWER)
- {
- switch (*ptr)
- {
- case 0:
- SD_PowerOff(); /* Power Off */
- res = RES_OK;
- break;
- case 1:
- SD_PowerOn(); /* Power On */
- res = RES_OK;
- break;
- case 2:
- *(ptr + 1) = SD_CheckPower();
- res = RES_OK; /* Power Check */
- break;
- default:
- res = RES_PARERR;
- }
- }
- else
- {
- /* no disk */
- if (Stat & STA_NOINIT) return RES_NOTRDY;
-
- SELECT();
-
- switch (ctrl)
- {
- case GET_SECTOR_COUNT:
- /* SEND_CSD */
- if ((SD_SendCmd(CMD9, 0) == 0) && SD_RxDataBlock(csd, 16))
- {
- if ((csd[0] >> 6) == 1)
- {
- /* SDC V2 */
- csize = csd[9] + ((WORD) csd[8] << 8) + 1;
- *(DWORD*) buff = (DWORD) csize << 10;
- }
- else
- {
- /* MMC or SDC V1 */
- 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:
- *(WORD*) buff = 512;
- res = RES_OK;
- break;
- case CTRL_SYNC:
- if (SD_ReadyWait() == 0xFF) res = RES_OK;
- break;
- case MMC_GET_CSD:
- /* SEND_CSD */
- if (SD_SendCmd(CMD9, 0) == 0 && SD_RxDataBlock(ptr, 16)) res = RES_OK;
- break;
- case MMC_GET_CID:
- /* SEND_CID */
- if (SD_SendCmd(CMD10, 0) == 0 && SD_RxDataBlock(ptr, 16)) res = RES_OK;
- break;
- case MMC_GET_OCR:
- /* READ_OCR */
- if (SD_SendCmd(CMD58, 0) == 0)
- {
- for (n = 0; n < 4; n++)
- {
- *ptr++ = SPI_RxByte();
- }
- res = RES_OK;
- }
- default:
- res = RES_PARERR;
- }
-
- DESELECT();
- SPI_RxByte();
- }
-
- return res;
- }
|