|
|
@@ -0,0 +1,729 @@
|
|
|
+#include "user.h"
|
|
|
+#define CMD0 (0) /* GO_IDLE_STATE */
|
|
|
+#define CMD1 (1) /* SEND_OP_COND */
|
|
|
+#define CMD2 (2)
|
|
|
+#define ACMD41 (0x80+41) /* SEND_OP_COND (SDC) */
|
|
|
+#define CMD8 (8) /* SEND_IF_COND */
|
|
|
+#define CMD9 (9) /* SEND_CSD */
|
|
|
+#define CMD10 (10) /* SEND_CID */
|
|
|
+#define CMD12 (12) /* STOP_TRANSMISSION */
|
|
|
+#define CMD13 (13) /* SEND_STATUS */
|
|
|
+#define ACMD13 (0x80+13) /* SD_STATUS (SDC) */
|
|
|
+#define CMD16 (16) /* SET_BLOCKLEN */
|
|
|
+#define CMD17 (17) /* READ_SINGLE_BLOCK */
|
|
|
+#define CMD18 (18) /* READ_MULTIPLE_BLOCK */
|
|
|
+#define CMD23 (23) /* SET_BLOCK_COUNT */
|
|
|
+#define ACMD23 (0x80+23) /* SET_WR_BLK_ERASE_COUNT (SDC) */
|
|
|
+#define CMD24 (24) /* WRITE_BLOCK */
|
|
|
+#define CMD25 (25) /* WRITE_MULTIPLE_BLOCK */
|
|
|
+#define CMD32 (32) /* ERASE_ER_BLK_START */
|
|
|
+#define CMD33 (33) /* ERASE_ER_BLK_END */
|
|
|
+#define CMD38 (38) /* ERASE */
|
|
|
+#define CMD55 (55) /* APP_CMD */
|
|
|
+#define CMD58 (58) /* READ_OCR */
|
|
|
+
|
|
|
+#define SD_CMD_GO_IDLE_STATE 0 /* CMD0 = 0x40 */
|
|
|
+#define SD_CMD_SEND_OP_COND 1 /* CMD1 = 0x41 */
|
|
|
+#define SD_CMD_SEND_IF_COND 8 /* CMD8 = 0x48 */
|
|
|
+#define SD_CMD_SEND_CSD 9 /* CMD9 = 0x49 */
|
|
|
+#define SD_CMD_SEND_CID 10 /* CMD10 = 0x4A */
|
|
|
+#define SD_CMD_STOP_TRANSMISSION 12 /* CMD12 = 0x4C */
|
|
|
+#define SD_CMD_SEND_STATUS 13 /* CMD13 = 0x4D */
|
|
|
+#define SD_CMD_SET_BLOCKLEN 16 /* CMD16 = 0x50 */
|
|
|
+#define SD_CMD_READ_SINGLE_BLOCK 17 /* CMD17 = 0x51 */
|
|
|
+#define SD_CMD_READ_MULT_BLOCK 18 /* CMD18 = 0x52 */
|
|
|
+#define SD_CMD_SET_BLOCK_COUNT 23 /* CMD23 = 0x57 */
|
|
|
+#define SD_CMD_WRITE_SINGLE_BLOCK 24 /* CMD24 = 0x58 */
|
|
|
+#define SD_CMD_WRITE_MULT_BLOCK 25 /* CMD25 = 0x59 */
|
|
|
+#define SD_CMD_PROG_CSD 27 /* CMD27 = 0x5B */
|
|
|
+#define SD_CMD_SET_WRITE_PROT 28 /* CMD28 = 0x5C */
|
|
|
+#define SD_CMD_CLR_WRITE_PROT 29 /* CMD29 = 0x5D */
|
|
|
+#define SD_CMD_SEND_WRITE_PROT 30 /* CMD30 = 0x5E */
|
|
|
+#define SD_CMD_SD_ERASE_GRP_START 32 /* CMD32 = 0x60 */
|
|
|
+#define SD_CMD_SD_ERASE_GRP_END 33 /* CMD33 = 0x61 */
|
|
|
+#define SD_CMD_UNTAG_SECTOR 34 /* CMD34 = 0x62 */
|
|
|
+#define SD_CMD_ERASE_GRP_START 35 /* CMD35 = 0x63 */
|
|
|
+#define SD_CMD_ERASE_GRP_END 36 /* CMD36 = 0x64 */
|
|
|
+#define SD_CMD_UNTAG_ERASE_GROUP 37 /* CMD37 = 0x65 */
|
|
|
+#define SD_CMD_ERASE 38 /* CMD38 = 0x66 */
|
|
|
+#define SD_CMD_SD_APP_OP_COND 41 /* CMD41 = 0x69 */
|
|
|
+#define SD_CMD_APP_CMD 55 /* CMD55 = 0x77 */
|
|
|
+#define SD_CMD_READ_OCR 58 /* CMD55 = 0x79 */
|
|
|
+#define SD_DEFAULT_BLOCK_SIZE (512)
|
|
|
+
|
|
|
+#define SD_DBG DBG_INFO
|
|
|
+enum
|
|
|
+{
|
|
|
+ DEV_SDCARD_SPI_DONE = SERVICE_EVENT_ID_START + 1,
|
|
|
+ SDCARD_STATE_IDLE = 0,
|
|
|
+ SDCARD_STATE_RUN,
|
|
|
+ SDCARD_STATE_READ,
|
|
|
+ SDCARD_STATE_WRITE,
|
|
|
+};
|
|
|
+
|
|
|
+static void SDHC_SpiCS(SDHC_SPICtrlStruct *Ctrl, uint8_t OnOff)
|
|
|
+{
|
|
|
+ uint8_t Temp[1] = {0xff};
|
|
|
+ GPIO_Output(Ctrl->CSPin, !OnOff);
|
|
|
+ if (!OnOff)
|
|
|
+ {
|
|
|
+ SPI_BlockTransfer(Ctrl->SpiID, Temp, Temp, 1);
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+static int32_t SPIFlash_SpiIrqCB(void *pData, void *pParam)
|
|
|
+{
|
|
|
+ SDHC_SPICtrlStruct *Ctrl = (SDHC_SPICtrlStruct *)pParam;
|
|
|
+#ifdef __BUILD_OS__
|
|
|
+ if (Ctrl->NotifyTask)
|
|
|
+ {
|
|
|
+ Task_SendEvent(Ctrl->NotifyTask, DEV_SDHC_SPI_DONE, 0, 0, 0);
|
|
|
+ }
|
|
|
+#endif
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static uint8_t CRC7(uint8_t * chr, int cnt)
|
|
|
+{
|
|
|
+ int i,a;
|
|
|
+ uint8_t crc,Data;
|
|
|
+ crc=0;
|
|
|
+ for (a=0;a<cnt;a++)
|
|
|
+ {
|
|
|
+ Data=chr[a];
|
|
|
+ for (i=0;i<8;i++)
|
|
|
+ {
|
|
|
+ crc <<= 1;
|
|
|
+
|
|
|
+ if ((Data & 0x80)^(crc & 0x80))
|
|
|
+ crc ^=0x09;
|
|
|
+ Data <<= 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ crc=(crc<<1)|1;
|
|
|
+ return(crc);
|
|
|
+}
|
|
|
+
|
|
|
+static void SDHC_SpiXfer(SDHC_SPICtrlStruct *Ctrl, uint8_t *Buf, uint16_t TxLen)
|
|
|
+{
|
|
|
+#ifdef __BUILD_OS__
|
|
|
+ Task_EventStruct Event;
|
|
|
+#endif
|
|
|
+#ifdef __BUILD_OS__
|
|
|
+ if (Ctrl->NotifyTask && Ctrl->TaskCB)
|
|
|
+ {
|
|
|
+ Ctrl->SPIError = 0;
|
|
|
+ SPI_SetCallbackFun(Ctrl->SpiID, SPIFlash_SpiIrqCB, Ctrl);
|
|
|
+ SPI_Transfer(Ctrl->SpiID, Buf, Buf, TxLen, Ctrl->IsSpiDMAMode);
|
|
|
+ if (Task_GetEvent(Ctrl->NotifyTask, DEV_SDHC_SPI_DONE, &Event, Ctrl->TaskCB, TxLen * CORE_TICK_1US + CORE_TICK_1MS))
|
|
|
+ {
|
|
|
+ Ctrl->SPIError = 1;
|
|
|
+ SPI_TransferStop(Ctrl->SpiID);
|
|
|
+ }
|
|
|
+ SPI_SetCallbackFun(Ctrl->SpiID, NULL, NULL);
|
|
|
+ }
|
|
|
+ else
|
|
|
+#endif
|
|
|
+ {
|
|
|
+ SPI_BlockTransfer(Ctrl->SpiID, Buf, Buf, TxLen);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static int32_t SDHC_SpiCmd(SDHC_SPICtrlStruct *Ctrl, uint8_t Cmd, uint32_t Arg, uint8_t NeedStop)
|
|
|
+{
|
|
|
+ uint64_t OpEndTick;
|
|
|
+ uint8_t i, TxLen, DummyLen;
|
|
|
+ int32_t Result = -ERROR_OPERATION_FAILED;
|
|
|
+ SDHC_SpiCS(Ctrl, 1);
|
|
|
+ Ctrl->TempData[0] = 0x40|Cmd;
|
|
|
+ BytesPutBe32(Ctrl->TempData + 1, Arg);
|
|
|
+ Ctrl->TempData[5] = CRC7(Ctrl->TempData, 5);
|
|
|
+
|
|
|
+ memset(Ctrl->TempData + 6, 0xff, 8);
|
|
|
+ TxLen = 14;
|
|
|
+
|
|
|
+ if (Ctrl->IsPrintData)
|
|
|
+ {
|
|
|
+ DBG_HexPrintf(Ctrl->TempData, TxLen);
|
|
|
+ }
|
|
|
+ Ctrl->SPIError = 0;
|
|
|
+ Ctrl->SDHCError = 0;
|
|
|
+ SDHC_SpiXfer(Ctrl, Ctrl->TempData, TxLen);
|
|
|
+ if (Ctrl->IsPrintData)
|
|
|
+ {
|
|
|
+ DBG_HexPrintf(Ctrl->TempData, TxLen);
|
|
|
+ }
|
|
|
+ for(i = 7; i < TxLen; i++)
|
|
|
+ {
|
|
|
+ if (Ctrl->TempData[i] != 0xff)
|
|
|
+ {
|
|
|
+ Ctrl->SDHCState = Ctrl->TempData[i];
|
|
|
+ if ((Ctrl->SDHCState == !Ctrl->IsInitDone) || !Ctrl->SDHCState)
|
|
|
+ {
|
|
|
+ Result = ERROR_NONE;
|
|
|
+ }
|
|
|
+ DummyLen = TxLen - i - 1;
|
|
|
+ memcpy(Ctrl->ExternResult, &Ctrl->TempData[i + 1], DummyLen);
|
|
|
+ Ctrl->ExternLen = DummyLen;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (NeedStop)
|
|
|
+ {
|
|
|
+ SDHC_SpiCS(Ctrl, 0);
|
|
|
+ }
|
|
|
+ return Result;
|
|
|
+}
|
|
|
+
|
|
|
+static int32_t SDHC_SpiReadRegData(SDHC_SPICtrlStruct *Ctrl, uint8_t *RegDataBuf, uint8_t DataLen)
|
|
|
+{
|
|
|
+ uint64_t OpEndTick;
|
|
|
+ int Result = ERROR_NONE;
|
|
|
+ uint16_t DummyLen;
|
|
|
+ uint16_t i,findResult;
|
|
|
+ Ctrl->SPIError = 0;
|
|
|
+ Ctrl->SDHCError = 0;
|
|
|
+ OpEndTick = GetSysTick() + Ctrl->SDHCReadBlockTo;
|
|
|
+ findResult = 0;
|
|
|
+ for(i = 0; i < Ctrl->ExternLen; i++)
|
|
|
+ {
|
|
|
+ if (0xfe == Ctrl->ExternResult[i])
|
|
|
+ {
|
|
|
+ DummyLen = Ctrl->ExternLen - i - 1;
|
|
|
+ if (Ctrl->IsPrintData)
|
|
|
+ {
|
|
|
+ DBG_HexPrintf(&Ctrl->ExternResult[i], DummyLen + 1);
|
|
|
+ }
|
|
|
+ memcpy(RegDataBuf, &Ctrl->ExternResult[i + 1], DummyLen);
|
|
|
+ memset(RegDataBuf + DummyLen, 0xff, DataLen - DummyLen);
|
|
|
+ SDHC_SpiXfer(Ctrl, RegDataBuf + DummyLen, DataLen - DummyLen);
|
|
|
+ if (Ctrl->IsPrintData)
|
|
|
+ {
|
|
|
+ DBG_HexPrintf(RegDataBuf + DummyLen, DataLen - DummyLen);
|
|
|
+ }
|
|
|
+ goto SDHC_SPIREADREGDATA_DONE;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ while((GetSysTick() < OpEndTick) && !Ctrl->SDHCError)
|
|
|
+ {
|
|
|
+ memset(Ctrl->TempData, 0xff, 40);
|
|
|
+ SDHC_SpiXfer(Ctrl, Ctrl->TempData, 40);
|
|
|
+ if (Ctrl->IsPrintData)
|
|
|
+ {
|
|
|
+ DBG_HexPrintf(Ctrl->TempData, 40);
|
|
|
+ }
|
|
|
+ for(i = 0; i < 40; i++)
|
|
|
+ {
|
|
|
+ if (0xfe == Ctrl->TempData[i])
|
|
|
+ {
|
|
|
+ DummyLen = 40 - i - 1;
|
|
|
+ if (DummyLen >= DataLen)
|
|
|
+ {
|
|
|
+ memcpy(RegDataBuf, &Ctrl->TempData[i + 1], DataLen);
|
|
|
+ goto SDHC_SPIREADREGDATA_DONE;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ memcpy(RegDataBuf, &Ctrl->TempData[i + 1], DummyLen);
|
|
|
+ memset(RegDataBuf + DummyLen, 0xff, DataLen - DummyLen);
|
|
|
+ SDHC_SpiXfer(Ctrl, RegDataBuf + DummyLen, DataLen - DummyLen);
|
|
|
+ goto SDHC_SPIREADREGDATA_DONE;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ Result = -ERROR_OPERATION_FAILED;
|
|
|
+SDHC_SPIREADREGDATA_DONE:
|
|
|
+ SDHC_SpiCS(Ctrl, 0);
|
|
|
+ return Result;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+static int32_t SDHC_SpiWriteBlockData(SDHC_SPICtrlStruct *Ctrl)
|
|
|
+{
|
|
|
+ uint64_t OpEndTick;
|
|
|
+ int Result = -ERROR_OPERATION_FAILED;
|
|
|
+ uint16_t TxLen, DoneFlag, waitCnt;
|
|
|
+ uint16_t i, crc16;
|
|
|
+ uint8_t *pBuf;
|
|
|
+ Ctrl->SPIError = 0;
|
|
|
+ Ctrl->SDHCError = 0;
|
|
|
+ OpEndTick = GetSysTick() + Ctrl->SDHCWriteBlockTo * CORE_TICK_1MS;
|
|
|
+ while( (Ctrl->DataBuf.Pos < Ctrl->DataBuf.MaxLen) && (GetSysTick() < OpEndTick) )
|
|
|
+ {
|
|
|
+ Ctrl->TempData[0] = 0xff;
|
|
|
+ Ctrl->TempData[1] = 0xff;
|
|
|
+ //SD_DBG("%u,%u", Ctrl->DataBuf.Pos, Ctrl->DataBuf.MaxLen);
|
|
|
+ Ctrl->TempData[2] = 0xfc;
|
|
|
+ memcpy(Ctrl->TempData + 3, Ctrl->DataBuf.Data + Ctrl->DataBuf.Pos * __SDHC_BLOCK_LEN__, __SDHC_BLOCK_LEN__);
|
|
|
+ crc16 = CRC16Cal(Ctrl->DataBuf.Data + Ctrl->DataBuf.Pos * __SDHC_BLOCK_LEN__, __SDHC_BLOCK_LEN__, 0, CRC16_CCITT_GEN, 0);
|
|
|
+ BytesPutBe16(Ctrl->TempData + 3 + __SDHC_BLOCK_LEN__, crc16);
|
|
|
+ Ctrl->TempData[5 + __SDHC_BLOCK_LEN__] = 0xff;
|
|
|
+ TxLen = 6 + __SDHC_BLOCK_LEN__;
|
|
|
+ SDHC_SpiXfer(Ctrl, Ctrl->TempData, TxLen);
|
|
|
+ if ((Ctrl->TempData[5 + __SDHC_BLOCK_LEN__] & 0x1f) != 0x05)
|
|
|
+ {
|
|
|
+ DBG("write data error ! x%02x", Ctrl->TempData[5 + __SDHC_BLOCK_LEN__]);
|
|
|
+ Ctrl->SDHCError = 1;
|
|
|
+ goto SDHC_SPIWRITEBLOCKDATA_DONE;
|
|
|
+ }
|
|
|
+ DoneFlag = 0;
|
|
|
+ waitCnt = 0;
|
|
|
+ while( (GetSysTick() < OpEndTick) && !DoneFlag )
|
|
|
+ {
|
|
|
+ TxLen = Ctrl->WriteWaitCnt?Ctrl->WriteWaitCnt:40;
|
|
|
+ memset(Ctrl->TempData, 0xff, TxLen);
|
|
|
+ SDHC_SpiXfer(Ctrl, Ctrl->TempData, TxLen);
|
|
|
+ for(i = 0; i < TxLen; i++)
|
|
|
+ {
|
|
|
+ if (Ctrl->TempData[i] == 0xff)
|
|
|
+ {
|
|
|
+ DoneFlag = 1;
|
|
|
+ if ((i + waitCnt) < sizeof(Ctrl->TempData))
|
|
|
+ {
|
|
|
+ if ((i + waitCnt) != Ctrl->WriteWaitCnt)
|
|
|
+ {
|
|
|
+// DBG("%u", Ctrl->WriteWaitCnt);
|
|
|
+ Ctrl->WriteWaitCnt = i + waitCnt;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ waitCnt += TxLen;
|
|
|
+ }
|
|
|
+ if (!DoneFlag)
|
|
|
+ {
|
|
|
+ DBG("write data timeout!");
|
|
|
+ Ctrl->SDHCError = 1;
|
|
|
+ goto SDHC_SPIWRITEBLOCKDATA_DONE;
|
|
|
+ }
|
|
|
+ Ctrl->DataBuf.Pos++;
|
|
|
+ OpEndTick = GetSysTick() + Ctrl->SDHCWriteBlockTo * CORE_TICK_1MS;
|
|
|
+ }
|
|
|
+ Result = ERROR_NONE;
|
|
|
+SDHC_SPIWRITEBLOCKDATA_DONE:
|
|
|
+ Ctrl->TempData[0] = 0xfd;
|
|
|
+ SPI_BlockTransfer(Ctrl->SpiID, Ctrl->TempData, Ctrl->TempData, 1);
|
|
|
+
|
|
|
+ OpEndTick = GetSysTick() + Ctrl->SDHCWriteBlockTo * CORE_TICK_1MS * Ctrl->DataBuf.MaxLen;
|
|
|
+ DoneFlag = 0;
|
|
|
+ while( (GetSysTick() < OpEndTick) && !DoneFlag )
|
|
|
+ {
|
|
|
+ TxLen = sizeof(Ctrl->TempData);
|
|
|
+ memset(Ctrl->TempData, 0xff, TxLen);
|
|
|
+ SDHC_SpiXfer(Ctrl, Ctrl->TempData, TxLen);
|
|
|
+ for(i = 0; i < TxLen; i++)
|
|
|
+ {
|
|
|
+ if (Ctrl->TempData[i] == 0xff)
|
|
|
+ {
|
|
|
+ DoneFlag = 1;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ SDHC_SpiCS(Ctrl, 0);
|
|
|
+
|
|
|
+ return Result;
|
|
|
+}
|
|
|
+
|
|
|
+static int32_t SDHC_SpiReadBlockData(SDHC_SPICtrlStruct *Ctrl)
|
|
|
+{
|
|
|
+ uint64_t OpEndTick;
|
|
|
+ int Result = -ERROR_OPERATION_FAILED;
|
|
|
+ uint16_t ReadLen, DummyLen, RemainingLen;
|
|
|
+ uint16_t i, crc16, crc16_check;
|
|
|
+ uint8_t *pBuf;
|
|
|
+ Ctrl->SPIError = 0;
|
|
|
+ Ctrl->SDHCError = 0;
|
|
|
+
|
|
|
+ OpEndTick = GetSysTick() + Ctrl->SDHCReadBlockTo * CORE_TICK_1MS;
|
|
|
+ while( (Ctrl->DataBuf.Pos < Ctrl->DataBuf.MaxLen) && (GetSysTick() < OpEndTick) )
|
|
|
+ {
|
|
|
+
|
|
|
+ DummyLen = (__SDHC_BLOCK_LEN__ >> 1);
|
|
|
+ memset(Ctrl->TempData, 0xff, DummyLen);
|
|
|
+// SD_DBG("%u,%u", Ctrl->DataBuf.Pos, Ctrl->DataBuf.MaxLen);
|
|
|
+ SDHC_SpiXfer(Ctrl, Ctrl->TempData, DummyLen);
|
|
|
+ RemainingLen = 0;
|
|
|
+ for(i = 0; i < DummyLen; i++)
|
|
|
+ {
|
|
|
+ if (Ctrl->TempData[i] == 0xfe)
|
|
|
+ {
|
|
|
+ ReadLen = (DummyLen - i - 1);
|
|
|
+ RemainingLen = __SDHC_BLOCK_LEN__ - ReadLen;
|
|
|
+ if (ReadLen)
|
|
|
+ {
|
|
|
+ memcpy(Ctrl->DataBuf.Data + Ctrl->DataBuf.Pos * __SDHC_BLOCK_LEN__, Ctrl->TempData + i + 1, ReadLen);
|
|
|
+ }
|
|
|
+// SD_DBG("%u,%u", ReadLen, RemainingLen);
|
|
|
+ goto READ_REST_DATA;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ continue;
|
|
|
+READ_REST_DATA:
|
|
|
+ pBuf = Ctrl->DataBuf.Data + Ctrl->DataBuf.Pos * __SDHC_BLOCK_LEN__ + ReadLen;
|
|
|
+ memset(pBuf, 0xff, RemainingLen);
|
|
|
+ SDHC_SpiXfer(Ctrl, pBuf, RemainingLen);
|
|
|
+ memset(Ctrl->TempData, 0xff, 2);
|
|
|
+ SPI_BlockTransfer(Ctrl->SpiID, Ctrl->TempData, Ctrl->TempData, 2);
|
|
|
+ crc16 = CRC16Cal(Ctrl->DataBuf.Data + Ctrl->DataBuf.Pos * __SDHC_BLOCK_LEN__, __SDHC_BLOCK_LEN__, 0, CRC16_CCITT_GEN, 0);
|
|
|
+ crc16_check = BytesGetBe16(Ctrl->TempData);
|
|
|
+ if (crc16 != crc16_check)
|
|
|
+ {
|
|
|
+ DBG("crc16 error %04x %04x", crc16, crc16_check);
|
|
|
+ Result = ERROR_NONE;
|
|
|
+ goto SDHC_SPIREADBLOCKDATA_DONE;
|
|
|
+ }
|
|
|
+ Ctrl->DataBuf.Pos++;
|
|
|
+ OpEndTick = GetSysTick() + Ctrl->SDHCReadBlockTo * CORE_TICK_1MS;
|
|
|
+ }
|
|
|
+ Result = ERROR_NONE;
|
|
|
+
|
|
|
+SDHC_SPIREADBLOCKDATA_DONE:
|
|
|
+ return Result;
|
|
|
+}
|
|
|
+
|
|
|
+void SDHC_SpiInitCard(void *pSDHC)
|
|
|
+{
|
|
|
+ uint8_t i;
|
|
|
+ uint64_t OpEndTick;
|
|
|
+ SDHC_SPICtrlStruct *Ctrl = (SDHC_SPICtrlStruct *)pSDHC;
|
|
|
+ memset(Ctrl->TempData, 0xff, 20);
|
|
|
+ Ctrl->IsInitDone = 0;
|
|
|
+ Ctrl->SDHCState = 0xff;
|
|
|
+ Ctrl->Info.CardCapacity = 0;
|
|
|
+ Ctrl->WriteWaitCnt = 40;
|
|
|
+ GPIO_Output(Ctrl->CSPin, 0);
|
|
|
+ SDHC_SpiXfer(Ctrl, Ctrl->TempData, 20);
|
|
|
+ GPIO_Output(Ctrl->CSPin, 1);
|
|
|
+ memset(Ctrl->TempData, 0xff, 20);
|
|
|
+ SDHC_SpiXfer(Ctrl, Ctrl->TempData, 20);
|
|
|
+ Ctrl->IsMMC = 0;
|
|
|
+ if (SDHC_SpiCmd(Ctrl, CMD0, 0, 1))
|
|
|
+ {
|
|
|
+ goto INIT_DONE;
|
|
|
+ }
|
|
|
+ OpEndTick = GetSysTick() + 100 * CORE_TICK_1MS;
|
|
|
+ if (SDHC_SpiCmd(Ctrl, CMD8, 0x1aa, 1)) //只支持2G以上的SDHC卡
|
|
|
+ {
|
|
|
+ goto INIT_DONE;
|
|
|
+ }
|
|
|
+WAIT_INIT_DONE:
|
|
|
+ if (GetSysTick() >= OpEndTick)
|
|
|
+ {
|
|
|
+ goto INIT_DONE;
|
|
|
+ }
|
|
|
+ if (SDHC_SpiCmd(Ctrl, SD_CMD_APP_CMD, 0, 1))
|
|
|
+ {
|
|
|
+ goto INIT_DONE;
|
|
|
+ }
|
|
|
+ if (SDHC_SpiCmd(Ctrl, SD_CMD_SD_APP_OP_COND, 0x40000000, 1))
|
|
|
+ {
|
|
|
+ goto INIT_DONE;
|
|
|
+ }
|
|
|
+ Ctrl->IsInitDone = !Ctrl->SDHCState;
|
|
|
+ if (!Ctrl->IsInitDone)
|
|
|
+ {
|
|
|
+ goto WAIT_INIT_DONE;
|
|
|
+ }
|
|
|
+ if (SDHC_SpiCmd(Ctrl, CMD58, 0, 1))
|
|
|
+ {
|
|
|
+ goto INIT_DONE;
|
|
|
+ }
|
|
|
+ Ctrl->OCR = BytesGetBe32(Ctrl->ExternResult);
|
|
|
+// SD_DBG("sdcard init OK OCR:0x%08x!", Ctrl->OCR);
|
|
|
+ return;
|
|
|
+INIT_DONE:
|
|
|
+ if (!Ctrl->IsInitDone)
|
|
|
+ {
|
|
|
+ SD_DBG("sdcard init fail!");
|
|
|
+ }
|
|
|
+ return;
|
|
|
+}
|
|
|
+
|
|
|
+void SDHC_SpiReadCardConfig(void *pSDHC)
|
|
|
+{
|
|
|
+ SDHC_SPICtrlStruct *Ctrl = (SDHC_SPICtrlStruct *)pSDHC;
|
|
|
+ uint8_t CSD_Tab[18];
|
|
|
+ uint8_t CID_Tab[18];
|
|
|
+ SD_CSD* Csd = &Ctrl->Info.Csd;
|
|
|
+ SD_CID* Cid = &Ctrl->Info.Cid;
|
|
|
+ SD_CardInfo *pCardInfo = &Ctrl->Info;
|
|
|
+ uint64_t Temp;
|
|
|
+ uint8_t flag_SDHC = (Ctrl->OCR & 0x40000000) >> 30;
|
|
|
+
|
|
|
+ if (Ctrl->Info.CardCapacity) return;
|
|
|
+
|
|
|
+ if (SDHC_SpiCmd(Ctrl, CMD9, 0, 0))
|
|
|
+ {
|
|
|
+ goto READ_CONFIG_ERROR;
|
|
|
+ }
|
|
|
+ if (Ctrl->SDHCState)
|
|
|
+ {
|
|
|
+ goto READ_CONFIG_ERROR;
|
|
|
+ }
|
|
|
+ if (SDHC_SpiReadRegData(Ctrl, CSD_Tab, 18))
|
|
|
+ {
|
|
|
+ goto READ_CONFIG_ERROR;
|
|
|
+ }
|
|
|
+ /*************************************************************************
|
|
|
+ CSD header decoding
|
|
|
+ *************************************************************************/
|
|
|
+
|
|
|
+ /* Byte 0 */
|
|
|
+ Csd->CSDStruct = (CSD_Tab[0] & 0xC0) >> 6;
|
|
|
+ Csd->Reserved1 = CSD_Tab[0] & 0x3F;
|
|
|
+
|
|
|
+ /* Byte 1 */
|
|
|
+ Csd->TAAC = CSD_Tab[1];
|
|
|
+
|
|
|
+ /* Byte 2 */
|
|
|
+ Csd->NSAC = CSD_Tab[2];
|
|
|
+
|
|
|
+ /* Byte 3 */
|
|
|
+ Csd->MaxBusClkFrec = CSD_Tab[3];
|
|
|
+
|
|
|
+ /* Byte 4/5 */
|
|
|
+ Csd->CardComdClasses = (CSD_Tab[4] << 4) | ((CSD_Tab[5] & 0xF0) >> 4);
|
|
|
+ Csd->RdBlockLen = CSD_Tab[5] & 0x0F;
|
|
|
+
|
|
|
+ /* Byte 6 */
|
|
|
+ Csd->PartBlockRead = (CSD_Tab[6] & 0x80) >> 7;
|
|
|
+ Csd->WrBlockMisalign = (CSD_Tab[6] & 0x40) >> 6;
|
|
|
+ Csd->RdBlockMisalign = (CSD_Tab[6] & 0x20) >> 5;
|
|
|
+ Csd->DSRImpl = (CSD_Tab[6] & 0x10) >> 4;
|
|
|
+
|
|
|
+ /*************************************************************************
|
|
|
+ CSD v1/v2 decoding
|
|
|
+ *************************************************************************/
|
|
|
+
|
|
|
+ if(!flag_SDHC)
|
|
|
+ {
|
|
|
+ Csd->version.v1.Reserved1 = ((CSD_Tab[6] & 0x0C) >> 2);
|
|
|
+
|
|
|
+ Csd->version.v1.DeviceSize = ((CSD_Tab[6] & 0x03) << 10)
|
|
|
+ | (CSD_Tab[7] << 2)
|
|
|
+ | ((CSD_Tab[8] & 0xC0) >> 6);
|
|
|
+ Csd->version.v1.MaxRdCurrentVDDMin = (CSD_Tab[8] & 0x38) >> 3;
|
|
|
+ Csd->version.v1.MaxRdCurrentVDDMax = (CSD_Tab[8] & 0x07);
|
|
|
+ Csd->version.v1.MaxWrCurrentVDDMin = (CSD_Tab[9] & 0xE0) >> 5;
|
|
|
+ Csd->version.v1.MaxWrCurrentVDDMax = (CSD_Tab[9] & 0x1C) >> 2;
|
|
|
+ Csd->version.v1.DeviceSizeMul = ((CSD_Tab[9] & 0x03) << 1)
|
|
|
+ |((CSD_Tab[10] & 0x80) >> 7);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ Csd->version.v2.Reserved1 = ((CSD_Tab[6] & 0x0F) << 2) | ((CSD_Tab[7] & 0xC0) >> 6);
|
|
|
+ Csd->version.v2.DeviceSize= ((CSD_Tab[7] & 0x3F) << 16) | (CSD_Tab[8] << 8) | CSD_Tab[9];
|
|
|
+ Csd->version.v2.Reserved2 = ((CSD_Tab[10] & 0x80) >> 8);
|
|
|
+ }
|
|
|
+
|
|
|
+ Csd->EraseSingleBlockEnable = (CSD_Tab[10] & 0x40) >> 6;
|
|
|
+ Csd->EraseSectorSize = ((CSD_Tab[10] & 0x3F) << 1)
|
|
|
+ |((CSD_Tab[11] & 0x80) >> 7);
|
|
|
+ Csd->WrProtectGrSize = (CSD_Tab[11] & 0x7F);
|
|
|
+ Csd->WrProtectGrEnable = (CSD_Tab[12] & 0x80) >> 7;
|
|
|
+ Csd->Reserved2 = (CSD_Tab[12] & 0x60) >> 5;
|
|
|
+ Csd->WrSpeedFact = (CSD_Tab[12] & 0x1C) >> 2;
|
|
|
+ Csd->MaxWrBlockLen = ((CSD_Tab[12] & 0x03) << 2)
|
|
|
+ |((CSD_Tab[13] & 0xC0) >> 6);
|
|
|
+ Csd->WriteBlockPartial = (CSD_Tab[13] & 0x20) >> 5;
|
|
|
+ Csd->Reserved3 = (CSD_Tab[13] & 0x1F);
|
|
|
+ Csd->FileFormatGrouop = (CSD_Tab[14] & 0x80) >> 7;
|
|
|
+ Csd->CopyFlag = (CSD_Tab[14] & 0x40) >> 6;
|
|
|
+ Csd->PermWrProtect = (CSD_Tab[14] & 0x20) >> 5;
|
|
|
+ Csd->TempWrProtect = (CSD_Tab[14] & 0x10) >> 4;
|
|
|
+ Csd->FileFormat = (CSD_Tab[14] & 0x0C) >> 2;
|
|
|
+ Csd->Reserved4 = (CSD_Tab[14] & 0x03);
|
|
|
+ Csd->crc = (CSD_Tab[15] & 0xFE) >> 1;
|
|
|
+ Csd->Reserved5 = (CSD_Tab[15] & 0x01);
|
|
|
+#if 0
|
|
|
+ if (SDHC_SpiCmd(Ctrl, CMD10, 0, 0))
|
|
|
+ {
|
|
|
+ goto READ_CONFIG_ERROR;
|
|
|
+ }
|
|
|
+ if (Ctrl->SDHCState)
|
|
|
+ {
|
|
|
+ goto READ_CONFIG_ERROR;
|
|
|
+ }
|
|
|
+ if (SDHC_SpiReadRegData(Ctrl, CID_Tab, 18))
|
|
|
+ {
|
|
|
+ goto READ_CONFIG_ERROR;
|
|
|
+ }
|
|
|
+ /* Byte 0 */
|
|
|
+ Cid->ManufacturerID = CID_Tab[0];
|
|
|
+
|
|
|
+ /* Byte 1 */
|
|
|
+ Cid->OEM_AppliID = CID_Tab[1] << 8;
|
|
|
+
|
|
|
+ /* Byte 2 */
|
|
|
+ Cid->OEM_AppliID |= CID_Tab[2];
|
|
|
+
|
|
|
+ /* Byte 3 */
|
|
|
+ Cid->ProdName1 = CID_Tab[3] << 24;
|
|
|
+
|
|
|
+ /* Byte 4 */
|
|
|
+ Cid->ProdName1 |= CID_Tab[4] << 16;
|
|
|
+
|
|
|
+ /* Byte 5 */
|
|
|
+ Cid->ProdName1 |= CID_Tab[5] << 8;
|
|
|
+
|
|
|
+ /* Byte 6 */
|
|
|
+ Cid->ProdName1 |= CID_Tab[6];
|
|
|
+
|
|
|
+ /* Byte 7 */
|
|
|
+ Cid->ProdName2 = CID_Tab[7];
|
|
|
+
|
|
|
+ /* Byte 8 */
|
|
|
+ Cid->ProdRev = CID_Tab[8];
|
|
|
+
|
|
|
+ /* Byte 9 */
|
|
|
+ Cid->ProdSN = CID_Tab[9] << 24;
|
|
|
+
|
|
|
+ /* Byte 10 */
|
|
|
+ Cid->ProdSN |= CID_Tab[10] << 16;
|
|
|
+
|
|
|
+ /* Byte 11 */
|
|
|
+ Cid->ProdSN |= CID_Tab[11] << 8;
|
|
|
+
|
|
|
+ /* Byte 12 */
|
|
|
+ Cid->ProdSN |= CID_Tab[12];
|
|
|
+
|
|
|
+ /* Byte 13 */
|
|
|
+ Cid->Reserved1 |= (CID_Tab[13] & 0xF0) >> 4;
|
|
|
+ Cid->ManufactDate = (CID_Tab[13] & 0x0F) << 8;
|
|
|
+
|
|
|
+ /* Byte 14 */
|
|
|
+ Cid->ManufactDate |= CID_Tab[14];
|
|
|
+
|
|
|
+ /* Byte 15 */
|
|
|
+ Cid->CID_CRC = (CID_Tab[15] & 0xFE) >> 1;
|
|
|
+ Cid->Reserved2 = 1;
|
|
|
+#endif
|
|
|
+ if(flag_SDHC)
|
|
|
+ {
|
|
|
+ pCardInfo->LogBlockSize = 512;
|
|
|
+ pCardInfo->CardBlockSize = 512;
|
|
|
+ Temp = 1024 * pCardInfo->LogBlockSize;
|
|
|
+ pCardInfo->CardCapacity = (pCardInfo->Csd.version.v2.DeviceSize + 1) * Temp;
|
|
|
+ pCardInfo->LogBlockNbr = (pCardInfo->Csd.version.v2.DeviceSize + 1) * 1024;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ pCardInfo->CardCapacity = (pCardInfo->Csd.version.v1.DeviceSize + 1) ;
|
|
|
+ pCardInfo->CardCapacity *= (1 << (pCardInfo->Csd.version.v1.DeviceSizeMul + 2));
|
|
|
+ pCardInfo->LogBlockSize = 512;
|
|
|
+ pCardInfo->CardBlockSize = 1 << (pCardInfo->Csd.RdBlockLen);
|
|
|
+ pCardInfo->CardCapacity *= pCardInfo->CardBlockSize;
|
|
|
+ pCardInfo->LogBlockNbr = (pCardInfo->CardCapacity) / (pCardInfo->LogBlockSize);
|
|
|
+ }
|
|
|
+// DBG("卡容量 %lluKB", pCardInfo->CardCapacity/1024);
|
|
|
+ return;
|
|
|
+READ_CONFIG_ERROR:
|
|
|
+ Ctrl->IsInitDone = 0;
|
|
|
+ Ctrl->SDHCError = 1;
|
|
|
+ return;
|
|
|
+}
|
|
|
+
|
|
|
+void SDHC_SpiReadBlocks(void *pSDHC, uint8_t *Buf, uint32_t StartLBA, uint32_t BlockNums)
|
|
|
+{
|
|
|
+ uint8_t Retry = 0;
|
|
|
+ SDHC_SPICtrlStruct *Ctrl = (SDHC_SPICtrlStruct *)pSDHC;
|
|
|
+ Buffer_StaticInit(&Ctrl->DataBuf, Buf, BlockNums);
|
|
|
+SDHC_SPIREADBLOCKS_START:
|
|
|
+ if (SDHC_SpiCmd(Ctrl, CMD18, StartLBA + Ctrl->DataBuf.Pos, 0))
|
|
|
+ {
|
|
|
+ goto SDHC_SPIREADBLOCKS_ERROR;
|
|
|
+ }
|
|
|
+ if (SDHC_SpiReadBlockData(Ctrl))
|
|
|
+ {
|
|
|
+ goto SDHC_SPIREADBLOCKS_ERROR;
|
|
|
+ }
|
|
|
+ if (SDHC_SpiCmd(Ctrl, CMD12, 0, 1))
|
|
|
+ {
|
|
|
+ goto SDHC_SPIREADBLOCKS_ERROR;
|
|
|
+ }
|
|
|
+ if (Ctrl->DataBuf.Pos != Ctrl->DataBuf.MaxLen)
|
|
|
+ {
|
|
|
+ Retry++;
|
|
|
+ DBG("%d", Retry);
|
|
|
+ if (Retry > 3)
|
|
|
+ {
|
|
|
+
|
|
|
+ Ctrl->SDHCError = 1;
|
|
|
+ goto SDHC_SPIREADBLOCKS_ERROR;
|
|
|
+ }
|
|
|
+ goto SDHC_SPIREADBLOCKS_START;
|
|
|
+ }
|
|
|
+ return;
|
|
|
+SDHC_SPIREADBLOCKS_ERROR:
|
|
|
+ DBG("!");
|
|
|
+ Ctrl->IsInitDone = 0;
|
|
|
+ Ctrl->SDHCError = 1;
|
|
|
+ return;
|
|
|
+}
|
|
|
+
|
|
|
+void SDHC_SpiWriteBlocks(void *pSDHC, const uint8_t *Buf, uint32_t StartLBA, uint32_t BlockNums)
|
|
|
+{
|
|
|
+ uint8_t Retry = 0;
|
|
|
+ SDHC_SPICtrlStruct *Ctrl = (SDHC_SPICtrlStruct *)pSDHC;
|
|
|
+ Buffer_StaticInit(&Ctrl->DataBuf, Buf, BlockNums);
|
|
|
+SDHC_SPIREADBLOCKS_START:
|
|
|
+ if (SDHC_SpiCmd(Ctrl, CMD25, StartLBA + Ctrl->DataBuf.Pos, 0))
|
|
|
+ {
|
|
|
+ goto SDHC_SPIREADBLOCKS_ERROR;
|
|
|
+ }
|
|
|
+ if (SDHC_SpiWriteBlockData(Ctrl))
|
|
|
+ {
|
|
|
+ goto SDHC_SPIREADBLOCKS_ERROR;
|
|
|
+ }
|
|
|
+ if (Ctrl->DataBuf.Pos != Ctrl->DataBuf.MaxLen)
|
|
|
+ {
|
|
|
+ Retry++;
|
|
|
+ if (Retry > 3)
|
|
|
+ {
|
|
|
+ Ctrl->SDHCError = 1;
|
|
|
+ goto SDHC_SPIREADBLOCKS_ERROR;
|
|
|
+ }
|
|
|
+ goto SDHC_SPIREADBLOCKS_START;
|
|
|
+ }
|
|
|
+ return;
|
|
|
+SDHC_SPIREADBLOCKS_ERROR:
|
|
|
+ Ctrl->IsInitDone = 0;
|
|
|
+ Ctrl->SDHCError = 1;
|
|
|
+ return;
|
|
|
+}
|
|
|
+
|
|
|
+void *SDHC_SpiCreate(uint8_t SpiID, uint8_t CSPin)
|
|
|
+{
|
|
|
+ SDHC_SPICtrlStruct *Ctrl = zalloc(sizeof(SDHC_SPICtrlStruct));
|
|
|
+ Ctrl->CSPin = CSPin;
|
|
|
+ Ctrl->SpiID = SpiID;
|
|
|
+ Ctrl->SDHCReadBlockTo = 5 * CORE_TICK_1MS;
|
|
|
+ Ctrl->SDHCWriteBlockTo = 25 * CORE_TICK_1MS;
|
|
|
+// Ctrl->IsPrintData = 1;
|
|
|
+ return Ctrl;
|
|
|
+}
|
|
|
+
|
|
|
+uint32_t SDHC_GetLogBlockNbr(void *pSDHC)
|
|
|
+{
|
|
|
+ SDHC_SPICtrlStruct *Ctrl = (SDHC_SPICtrlStruct *)pSDHC;
|
|
|
+ return Ctrl->Info.LogBlockNbr;
|
|
|
+}
|
|
|
+
|
|
|
+uint8_t SDHC_IsReady(void *pSDHC)
|
|
|
+{
|
|
|
+ SDHC_SPICtrlStruct *Ctrl = (SDHC_SPICtrlStruct *)pSDHC;
|
|
|
+ if (!Ctrl->SDHCState && Ctrl->IsInitDone)
|
|
|
+ {
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|