diff options
Diffstat (limited to 'os/hal/ports/SAMA/LLD/SDMMCv1')
18 files changed, 1201 insertions, 155 deletions
diff --git a/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc.c b/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc.c index 04f2a619e..c47c520af 100644 --- a/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc.c +++ b/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc.c @@ -95,7 +95,8 @@ void SdMmcUpdateInformation(SdmmcDriver *drv, bool csd, bool extData) uint8_t SDMMC_Lib_SdStart(SdmmcDriver *drv, bool * retry)
{
uint64_t mem_size;
- uint32_t freq, drv_err, status;
+ //uint32_t freq;
+ uint32_t drv_err, status;
uint8_t error;
bool flag;
sSdCard *pSd = &drv->card;
@@ -153,7 +154,7 @@ uint8_t SDMMC_Lib_SdStart(SdmmcDriver *drv, bool * retry) if (error)
return error;
else {
- TRACE_1("RCA=%u\n\r",drv->card.wAddress );
+ TRACE_DEBUG_1("RCA=%u\n\r",drv->card.wAddress );
}
/* SEND_CSD (CMD9) to obtain the Card Specific Data (CSD register),
@@ -250,12 +251,14 @@ uint8_t SDMMC_Lib_SdStart(SdmmcDriver *drv, bool * retry) }
else {
drv->card.wBlockSize = 512;
- mem_size = SD_CSD_TOTAL_SIZE(pSd);
+ mem_size = SD_CSD_TOTAL_SIZE(pSd->CSD);
drv->card.dwNbBlocks = (uint32_t)(mem_size >> 9);
drv->card.dwTotalSize = mem_size >> 32 ? 0xFFFFFFFF
: (uint32_t)mem_size;
}
+//TO BE DONE
+#if 0
/* Automatically select the max device clock frequency */
/* Calculate transfer speed */
freq = SdmmcGetMaxFreq(drv);
@@ -266,10 +269,10 @@ uint8_t SDMMC_Lib_SdStart(SdmmcDriver *drv, bool * retry) error = HwSetClock(drv, &freq);
drv->card.dwCurrSpeed = freq;
if (error != SDMMC_OK && error != SDMMC_CHANGED) {
- TRACE_1("clk %s\n\r", SD_StringifyRetCode(error));
+ TRACE_ERROR_1("clk %s\n\r", SD_StringifyRetCode(error));
return error;
}
-
+#endif
/* Check device status and eat past exceptions, which would otherwise
* prevent upcoming data transaction routines from reliably checking
* fresh exceptions. */
@@ -277,8 +280,11 @@ uint8_t SDMMC_Lib_SdStart(SdmmcDriver *drv, bool * retry) if (error)
return error;
status = status & ~STATUS_STATE & ~STATUS_READY_FOR_DATA & ~STATUS_APP_CMD;
- //if (status)
- // trace_warning("st %lx\n\r", status);
+
+ //warning
+ if (status) {
+ TRACE_WARNING_1("st %lx\n\r", status);
+ }
return SDMMC_OK;
}
@@ -457,7 +463,7 @@ uint8_t SdMmcSelect(SdmmcDriver *drv, uint16_t address, uint8_t statCheck) if (currState == targetState)
return 0;
if (currState != srcState) {
- TRACE_1("st %lx\n\r", currState);
+ TRACE_ERROR_1("st %lx\n\r", currState);
return SDMMC_ERR;
}
break;
diff --git a/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc.h b/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc.h index 8b03a8bb8..f675996e4 100644 --- a/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc.h +++ b/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc.h @@ -171,8 +171,7 @@ extern const uint16_t sdmmcTransUnits[8]; extern const uint8_t sdTransMultipliers[16]; extern const uint8_t mmcTransMultipliers[16]; extern void SdParamReset(sSdCard * pSd); -extern uint32_t SdmmcDecodeTransSpeed(uint32_t code, - const uint16_t * unitCodes, const uint8_t * multiCodes); +extern uint32_t SdmmcDecodeTransSpeed(uint32_t code,const uint16_t * unitCodes, const uint8_t * multiCodes); diff --git a/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_cmds.c b/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_cmds.c index 246a9f1ab..2a9b8a529 100644 --- a/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_cmds.c +++ b/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_cmds.c @@ -186,7 +186,7 @@ uint8_t Cmd1(SdmmcDriver *drv, bool * hc) ocr & SD_OCR_VDD_34_35 ? 'X' : '.',
ocr & SD_OCR_VDD_35_36 ? 'X' : '.');
#endif
- TRACE_1("Device access 0x%lx\n\r", ocr >> 29 & 0x3ul);
+ TRACE_INFO_1("Device access 0x%lx\n\r", ocr >> 29 & 0x3ul);
*hc = (ocr & MMC_OCR_ACCESS_MODE) == MMC_OCR_ACCESS_SECTOR? true : false;
@@ -415,6 +415,30 @@ uint8_t Cmd11(SdmmcDriver *drv, uint32_t * pStatus) }
/**
+ * Forces the card to stop transmission
+ * \param pSd Pointer to a SD card driver instance.
+ * \param pStatus Pointer to a status variable.
+ */
+uint8_t Cmd12(SdmmcDriver *drv, uint32_t * pStatus)
+{
+ sSdmmcCommand *pCmd = &drv->cmd;
+ uint8_t bRc;
+
+ _ResetCmd(pCmd);
+
+ /* Fill command */
+ pCmd->bCmd = 12;
+ pCmd->cmdOp.wVal = SDMMC_CMD_CSTOP | SDMMC_CMD_bmBUSY;
+ pCmd->pResp = pStatus;
+
+ drv->timeout_elapsed = -1;
+ /* Send command */
+ bRc = sdmmcSendCmd(drv);
+ return bRc;
+}
+
+
+/**
* Addressed card sends its status register.
* Returns the command transfer result (see SendMciCommand).
* \param drv Pointer to \ref SdmmcDriver instance.
@@ -466,6 +490,47 @@ uint8_t Cmd14(SdmmcDriver *drv, uint8_t * pData, uint8_t len, uint32_t * pStatus bRc = sdmmcSendCmd(drv);
return bRc;
}
+
+/**
+ * Continously transfers datablocks from card to host until interrupted by a
+ * STOP_TRANSMISSION command.
+ * \param pSd Pointer to a SD card driver instance.
+ * \param nbBlocks Number of blocks to send.
+ * \param pData Pointer to the buffer to be filled.
+ * The buffer shall follow the peripheral and DMA alignment requirements.
+ * \param address Data Address on SD/MMC card.
+ * \param pStatus Pointer to the response status.
+ * \param fCallback Pointer to optional callback invoked on command end.
+ * NULL: Function return until command finished.
+ * Pointer: Return immediately and invoke callback at end.
+ * Callback argument is fixed to a pointer to sSdCard instance.
+ */
+uint8_t Cmd18(SdmmcDriver *drv,
+ uint16_t * nbBlock,
+ uint8_t * pData,
+ uint32_t address, uint32_t * pStatus)
+{
+ sSdmmcCommand *pCmd = &drv->cmd;
+ uint8_t bRc;
+
+ _ResetCmd(pCmd);
+
+ /* Fill command */
+ pCmd->cmdOp.wVal = SDMMC_CMD_CDATARX(1);
+ pCmd->bCmd = 18;
+ pCmd->dwArg = address;
+ pCmd->pResp = pStatus;
+ pCmd->wBlockSize = drv->card.wCurrBlockLen;
+ pCmd->wNbBlocks = *nbBlock;
+ pCmd->pData = pData;
+ drv->timeout_elapsed = -1;
+ /* Send command */
+ bRc = sdmmcSendCmd(drv);
+ if (bRc == SDMMC_CHANGED)
+ *nbBlock = pCmd->wNbBlocks;
+ return bRc;
+}
+
/**
* A host sends the bus test data pattern to a card.
* \param drv Pointer to \ref SdmmcDriver instance.
@@ -513,6 +578,152 @@ uint8_t Cmd16(SdmmcDriver *drv, uint16_t blkLen) return bRc;
}
+
+/**
+ * Read single block command
+ * \param pSd Pointer to a SD card driver instance.
+ * \param pData Pointer to the buffer to be filled.
+ * The buffer shall follow the peripheral and DMA alignment requirements.
+ * \param address Data Address on SD/MMC card.
+ * \param pStatus Pointer response buffer as status return.
+ * \param fCallback Pointer to optional callback invoked on command end.
+ * NULL: Function return until command finished.
+ * Pointer: Return immediately and invoke callback at end.
+ * Callback argument is fixed to a pointer to sSdCard instance.
+ */
+uint8_t Cmd17(SdmmcDriver *drv,
+ uint8_t * pData,
+ uint32_t address, uint32_t * pStatus)
+{
+ sSdmmcCommand *pCmd = &drv->cmd;
+ uint8_t bRc;
+
+ _ResetCmd(pCmd);
+
+ /* Fill command */
+ pCmd->cmdOp.wVal = SDMMC_CMD_CDATARX(1);
+ pCmd->bCmd = 17;
+ pCmd->dwArg = address;
+ pCmd->pResp = pStatus;
+ pCmd->wBlockSize =drv->card.wCurrBlockLen;
+ pCmd->wNbBlocks = 1;
+ pCmd->pData = pData;
+
+
+ drv->timeout_elapsed = -1;
+ /* Send command */
+ bRc = sdmmcSendCmd(drv);
+ return bRc;
+}
+
+
+/**
+ * Defines the number of blocks (read/write) and the reliable writer parameter
+ * (write) for a block read or write command
+ * data (CSD) on the CMD line.
+ * Returns the command transfer result (see SendMciCommand).
+ * \param pSd Pointer to a SD card driver instance.
+ * \param write Write Request parameter.
+ * \param blocks number of blocks.
+ */
+uint8_t Cmd23(SdmmcDriver *drv, uint8_t write, uint32_t blocks, uint32_t * pStatus)
+{
+ sSdmmcCommand *pCmd = &drv->cmd;
+ uint8_t bRc;
+
+ _ResetCmd(pCmd);
+
+ /* Fill command */
+ pCmd->cmdOp.wVal = SDMMC_CMD_CNODATA(1);
+ pCmd->bCmd = 23;
+ pCmd->wNbBlocks = 0;
+ pCmd->dwArg = write << 31 | blocks;
+ pCmd->pResp = pStatus;
+
+ drv->timeout_elapsed = -1;
+ /* Send command */
+ bRc = sdmmcSendCmd(drv);
+ return bRc;
+}
+
+/**
+ * Write single block command
+ * \param pSd Pointer to a SD card driver instance.
+ * \param blockSize Block size (shall be set to 512 in case of high capacity).
+ * \param pData Pointer to the buffer to be filled.
+ * The buffer shall follow the peripheral and DMA alignment requirements.
+ * \param address Data Address on SD/MMC card.
+ * \param pStatus Pointer to response buffer as status.
+ * \param fCallback Pointer to optional callback invoked on command end.
+ * NULL: Function return until command finished.
+ * Pointer: Return immediately and invoke callback at end.
+ * Callback argument is fixed to a pointer to sSdCard instance.
+ */
+uint8_t Cmd24(SdmmcDriver *drv,
+ uint8_t * pData,
+ uint32_t address, uint32_t * pStatus)
+{
+ sSdmmcCommand *pCmd = &drv->cmd;
+ uint8_t bRc;
+
+ _ResetCmd(pCmd);
+
+ /* Fill command */
+ pCmd->cmdOp.wVal = SDMMC_CMD_CDATATX(1);
+ pCmd->bCmd = 24;
+ pCmd->dwArg = address;
+ pCmd->pResp = pStatus;
+ pCmd->wBlockSize =drv->card.wCurrBlockLen;
+ pCmd->wNbBlocks = 1;
+ pCmd->pData = pData;
+ drv->timeout_elapsed = -1;
+ /* Send command */
+ bRc = sdmmcSendCmd(drv);
+ return bRc;
+}
+
+/**
+ * Write multiple block command
+ * \param pSd Pointer to a SD card driver instance.
+ * \param blockSize Block size (shall be set to 512 in case of high capacity).
+ * \param nbBlock Number of blocks to send.
+ * \param pData Pointer to the buffer to be filled.
+ * The buffer shall follow the peripheral and DMA alignment requirements.
+ * \param address Data Address on SD/MMC card.
+ * \param pStatus Pointer to the response buffer as status.
+ * \param fCallback Pointer to optional callback invoked on command end.
+ * NULL: Function return until command finished.
+ * Pointer: Return immediately and invoke callback at end.
+ * Callback argument is fixed to a pointer to sSdCard instance.
+ */
+uint8_t Cmd25(SdmmcDriver *drv,
+ uint16_t * nbBlock,
+ uint8_t * pData,
+ uint32_t address, uint32_t * pStatus)
+{
+ sSdmmcCommand *pCmd = &drv->cmd;
+ uint8_t bRc;
+
+ _ResetCmd(pCmd);
+
+ /* Fill command */
+ pCmd->cmdOp.wVal = SDMMC_CMD_CDATATX(1);
+ pCmd->bCmd = 25;
+ pCmd->dwArg = address;
+ pCmd->pResp = pStatus;
+ pCmd->wBlockSize =drv->card.wCurrBlockLen;
+ pCmd->wNbBlocks = *nbBlock;
+ pCmd->pData = pData;
+
+ drv->timeout_elapsed = -1;
+ /* Send command */
+ bRc = sdmmcSendCmd(drv);
+ if (bRc == SDMMC_CHANGED)
+ *nbBlock = pCmd->wNbBlocks;
+ return bRc;
+}
+
+
/**
* SDIO IO_RW_DIRECT command, response R5.
* \return the command transfer result (see SendMciCommand).
@@ -588,7 +799,7 @@ uint8_t Acmd6(SdmmcDriver *drv, uint8_t busWidth) sSdmmcCommand *pCmd = &drv->cmd;
uint8_t error;
- TRACE_1("Acmd%u\n\r", 6);
+ TRACE_INFO_1("Acmd%u\n\r", 6);
error = Cmd55(drv, drv->card.wAddress);
@@ -603,7 +814,7 @@ uint8_t Acmd6(SdmmcDriver *drv, uint8_t busWidth) }
else {
if (error) {
- TRACE_2("Acmd%u %s\n\r", 6, SD_StringifyRetCode(error));
+ TRACE_ERROR_2("Acmd%u %s\n\r", 6, SD_StringifyRetCode(error));
}
}
return error;
@@ -626,7 +837,7 @@ uint8_t Acmd13(SdmmcDriver *drv, uint8_t * pSSR, uint32_t * pResp) //assert(pSd);
- TRACE_1("Acmd%u\n\r", 13);
+ TRACE_INFO_1("Acmd%u\n\r", 13);
error = Cmd55(drv, drv->card.wAddress);
@@ -647,7 +858,7 @@ uint8_t Acmd13(SdmmcDriver *drv, uint8_t * pSSR, uint32_t * pResp) } else {
if (error) {
- TRACE_2("Acmd%u %s\n\r", 13, SD_StringifyRetCode(error));
+ TRACE_ERROR_2("Acmd%u %s\n\r", 13, SD_StringifyRetCode(error));
}
}
return error;
@@ -713,7 +924,7 @@ uint8_t Acmd41(SdmmcDriver *drv, bool * low_sig_lvl, bool * hc) /* Supply voltage range is incompatible */
rc = SDMMC_BUSY;
if (rc != SDMMC_OK) {
- TRACE_2("Acmd%u %s\n\r", 41, SD_StringifyRetCode(rc));
+ TRACE_ERROR_2("Acmd%u %s\n\r", 41, SD_StringifyRetCode(rc));
}
else {
#if 0
@@ -761,7 +972,7 @@ uint8_t Acmd51(SdmmcDriver *drv, uint8_t * pSCR, uint32_t * pResp) uint8_t error;
- TRACE_1("Acmd%u\n\r", 51);
+ TRACE_INFO_1("Acmd%u\n\r", 51);
error = Cmd55(drv, drv->card.wAddress);
@@ -783,7 +994,7 @@ uint8_t Acmd51(SdmmcDriver *drv, uint8_t * pSCR, uint32_t * pResp) } else {
if (error) {
- TRACE_2("Acmd%u %s\n\r", 51, SD_StringifyRetCode(error));
+ TRACE_ERROR_2("Acmd%u %s\n\r", 51, SD_StringifyRetCode(error));
}
}
return error;
@@ -833,7 +1044,7 @@ uint8_t MmcCmd6(SdmmcDriver *drv, const void *pSwitchArg, uint32_t * pResp) bRc = sdmmcSendCmd(drv);
if (!bRc && pResp && *pResp & STATUS_MMC_SWITCH) {
- TRACE_1("st %lx\n\r", *pResp);
+ TRACE_INFO_1("st %lx\n\r", *pResp);
}
return bRc;
}
diff --git a/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_cmds.h b/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_cmds.h index 014986e22..6de912fe8 100644 --- a/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_cmds.h +++ b/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_cmds.h @@ -103,6 +103,60 @@ typedef struct _SdioCmd52Arg { #define STATUS_ADDRESS_MISALIGN (1UL << 30)
#define STATUS_ADDR_OUT_OR_RANGE (1UL << 31)
+#define STATUS_STOP ((uint32_t)( STATUS_CARD_IS_LOCKED \
+ | STATUS_COM_CRC_ERROR \
+ | STATUS_ILLEGAL_COMMAND \
+ | STATUS_CC_ERROR \
+ | STATUS_ERROR \
+ | STATUS_STATE \
+ | STATUS_READY_FOR_DATA ))
+
+#define STATUS_WRITE ((uint32_t)( STATUS_ADDR_OUT_OR_RANGE \
+ | STATUS_ADDRESS_MISALIGN \
+ | STATUS_BLOCK_LEN_ERROR \
+ | STATUS_WP_VIOLATION \
+ | STATUS_CARD_IS_LOCKED \
+ | STATUS_COM_CRC_ERROR \
+ | STATUS_ILLEGAL_COMMAND \
+ | STATUS_CC_ERROR \
+ | STATUS_ERROR \
+ | STATUS_ERASE_RESET \
+ | STATUS_STATE \
+ | STATUS_READY_FOR_DATA ))
+
+#define STATUS_READ ((uint32_t)( STATUS_ADDR_OUT_OR_RANGE \
+ | STATUS_ADDRESS_MISALIGN \
+ | STATUS_BLOCK_LEN_ERROR \
+ | STATUS_CARD_IS_LOCKED \
+ | STATUS_COM_CRC_ERROR \
+ | STATUS_ILLEGAL_COMMAND \
+ | STATUS_CARD_ECC_FAILED \
+ | STATUS_CC_ERROR \
+ | STATUS_ERROR \
+ | STATUS_ERASE_RESET \
+ | STATUS_STATE \
+ | STATUS_READY_FOR_DATA ))
+
+#define STATUS_SD_SWITCH ((uint32_t)( STATUS_ADDR_OUT_OR_RANGE \
+ | STATUS_CARD_IS_LOCKED \
+ | STATUS_COM_CRC_ERROR \
+ | STATUS_ILLEGAL_COMMAND \
+ | STATUS_CARD_ECC_FAILED \
+ | STATUS_CC_ERROR \
+ | STATUS_ERROR \
+ | STATUS_UNERRUN \
+ | STATUS_OVERRUN \
+ /*| STATUS_STATE*/))
+
+#define STATUS_MMC_SWITCH ((uint32_t)( STATUS_CARD_IS_LOCKED \
+ | STATUS_COM_CRC_ERROR \
+ | STATUS_ILLEGAL_COMMAND \
+ | STATUS_CC_ERROR \
+ | STATUS_ERROR \
+ | STATUS_ERASE_RESET \
+ /*| STATUS_STATE*/ \
+ /*| STATUS_READY_FOR_DATA*/ \
+ | STATUS_SWITCH_ERROR ))
#define SD_OCR_S18A (1ul << 24) /**< Switching to 1.8V signaling level Accepted */
#define SDIO_OCR_MP (0x1ul << 27) /**< SDIO: Memory present */
@@ -190,12 +244,24 @@ extern uint8_t Cmd5(SdmmcDriver *drv, uint32_t * pIo); extern uint8_t Cmd7(SdmmcDriver *drv, uint16_t address);
extern uint8_t Cmd9(SdmmcDriver *drv);
extern uint8_t Cmd11(SdmmcDriver *drv, uint32_t * pStatus);
+extern uint8_t Cmd12(SdmmcDriver *drv, uint32_t * pStatus);
extern uint8_t Cmd13(SdmmcDriver *drv, uint32_t * pStatus);
extern uint8_t Cmd14(SdmmcDriver *drv, uint8_t * pData, uint8_t len, uint32_t * pStatus);
extern uint8_t Cmd16(SdmmcDriver *drv, uint16_t blkLen);
+extern uint8_t Cmd17(SdmmcDriver *drv,
+ uint8_t * pData,
+ uint32_t address, uint32_t * pStatus);
+extern uint8_t Cmd18(SdmmcDriver *drv,uint16_t * nbBlock,uint8_t * pData,uint32_t address, uint32_t * pStatus);
extern uint8_t Cmd19(SdmmcDriver *drv, uint8_t * pData, uint8_t len, uint32_t * pStatus);
-
+extern uint8_t Cmd23(SdmmcDriver *drv, uint8_t write, uint32_t blocks, uint32_t * pStatus);
+extern uint8_t Cmd24(SdmmcDriver *drv,
+ uint8_t * pData,
+ uint32_t address, uint32_t * pStatus);
+extern uint8_t Cmd25(SdmmcDriver *drv,
+ uint16_t * nbBlock,
+ uint8_t * pData,
+ uint32_t address, uint32_t * pStatus);
extern uint8_t Cmd52(SdmmcDriver *drv,uint8_t wrFlag,uint8_t funcNb, uint8_t rdAfterWr, uint32_t addr, uint32_t * pIoData);
extern uint8_t Cmd55(SdmmcDriver *drv, uint16_t cardAddr);
diff --git a/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_device.c b/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_device.c index ca28cc051..8c05bf133 100644 --- a/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_device.c +++ b/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_device.c @@ -66,13 +66,13 @@ uint8_t sdmmc_device_lowlevelcfg(SdmmcDriver *driver) pmc_set_main_oscillator_freq(BOARD_MAIN_CLOCK_EXT_OSC);
- TRACE_1("Processor clock: %u MHz\r\n", ((unsigned)(pmc_get_processor_clock() / 1000000) ));
- TRACE_1("Master clock: %u MHz\r\n", ((unsigned)(pmc_get_master_clock() / 1000000)) );
-
+ TRACE_INFO_1("Processor clock: %u MHz\r\n", ((unsigned)(pmc_get_processor_clock() / 1000000) ));
+ TRACE_INFO_1("Master clock: %u MHz\r\n", ((unsigned)(pmc_get_master_clock() / 1000000)) );
+#if SDMMC_USE_TC == 1
driver->tctimer_id = get_tc_id_from_addr(driver->config->tctimer,driver->config->tc_chan);
pmc_configure_peripheral(driver->tctimer_id, NULL, true);
-
+#endif
if (driver->config->slot_id == SDMMC_SLOT0) {
@@ -180,18 +180,17 @@ uint8_t sdmmc_device_lowlevelcfg(SdmmcDriver *driver) if (res) {
//check res
res = IS_CACHE_ALIGNED(driver->config->data_buf);
- TRACE_2("check data buf %d %08x\r\n", res, driver->config->data_buf);
+ TRACE_DEBUG_2("check data buf %d %08x\r\n", res, driver->config->data_buf);
res &= IS_CACHE_ALIGNED(driver->config->data_buf_size);
- TRACE_2("check data_buf_size %d %08x\r\n", res,
+ TRACE_DEBUG_2("check data_buf_size %d %08x\r\n", res,
driver->config->data_buf_size);
res &= IS_CACHE_ALIGNED(driver->card.EXT);
- TRACE_2("check libExt %d %08x\r\n", res, driver->card.EXT);
+ TRACE_DEBUG_2("check libExt %d %08x\r\n", res, driver->card.EXT);
//res &= IS_CACHE_ALIGNED(sizeof(driver->card.EXT));
//TRACE_2("check size libExt %d %08x\r\n",rc,sizeof(driver->card.EXT));
if (!res) {
- TRACE(
- "WARNING: buffers are not aligned on data cache lines. Please fix this before enabling DMA.\n\r");
+ TRACE_WARNING("WARNING: buffers are not aligned on data cache lines. Please fix this before enabling DMA.\n\r");
driver->use_polling = true;
} else {
driver->use_polling = false;
@@ -217,13 +216,11 @@ bool sdmmc_device_initialize(SdmmcDriver *driver) driver->blk_size = (val <= 0x2 ? (512 << val) : 512);
//Configure the TC Timer
-
+#if SDMMC_USE_TC == 1
pmc_configure_peripheral(driver->tctimer_id, NULL, true);
-
tc_configure(driver->config->tctimer, driver->config->tc_chan, TC_CMR_WAVE | TC_CMR_WAVSEL_UP | TC_CMR_CPCDIS | TC_CMR_BURST_NONE | TC_CMR_TCCLKS_TIMER_CLOCK2);
-
driver->config->tctimer->TC_CHANNEL[driver->config->tc_chan].TC_EMR |= TC_EMR_NODIVCLK;
-
+#endif
/* Perform the initial I/O calibration sequence, manually.
* Allow tSTARTUP = 2 usec for the analog circuitry to start up.
* CNTVAL = fHCLOCK / (4 * (1 / tSTARTUP)) */
@@ -257,7 +254,7 @@ bool sdmmc_device_initialize(SdmmcDriver *driver) driver->regs->SDMMC_TCR = (driver->regs->SDMMC_TCR & ~SDMMC_TCR_DTCVAL_Msk) | SDMMC_TCR_DTCVAL(exp);
- TRACE_1("Set DAT line timeout to %lu ms\n\r", (10UL << (exp + 13UL))/ (base_freq / 100UL));
+ TRACE_DEBUG_1("Set DAT line timeout to %lu ms\n\r", (10UL << (exp + 13UL))/ (base_freq / 100UL));
/* Reset the peripheral. This will reset almost all registers.
* It doesn't affect I/O calibration however. */
@@ -334,7 +331,7 @@ uint8_t sdmmc_device_identify(SdmmcDriver *drv) if (drv->state != MCID_IDLE )
return SDMMC_STATE;
- do {
+ Retry:
/* After power-on or CMD0, all cards?
* CMD lines are in input mode, waiting for start bit of the next command.
* The cards are initialized with a default relative card address
@@ -343,7 +340,7 @@ uint8_t sdmmc_device_identify(SdmmcDriver *drv) error = SdMmcIdentify(drv);
if (error) {
- TRACE_1("Identify %s\n\r", SD_StringifyRetCode(error));
+ TRACE_ERROR_1("Identify %s\n\r", SD_StringifyRetCode(error));
return error;
}
@@ -366,12 +363,10 @@ uint8_t sdmmc_device_identify(SdmmcDriver *drv) if (!error) {
drv->card.bSpeedMode = SDMMC_TIM_SD_SDR12;
- //goto Retry;
+ goto Retry;
}
}
}
-
-
#ifndef SDMMC_TRIM_SDIO
else if (drv->card.bCardType & CARD_TYPE_bmSDIO)
error = SdioInit(drv);
@@ -381,15 +376,14 @@ uint8_t sdmmc_device_identify(SdmmcDriver *drv) error = MmcInit(drv);
#endif
else {
- TRACE_1("Identify %s\n\r", "failed");
+ TRACE_ERROR_1("Identify %s\n\r", "failed");
return SDMMC_NOT_INITIALIZED;
}
if (error) {
- TRACE_1("Init %s\n\r", SD_StringifyRetCode(error));
+ TRACE_ERROR_1("Init %s\n\r", SD_StringifyRetCode(error));
return error;
}
- } while (retry==1);
drv->card.bStatus = SDMMC_OK;
@@ -428,21 +422,32 @@ void sdmmc_device_deInit(SdmmcDriver *drv) Fetch:
/* Fetch normal events */
events = regs->SDMMC_NISTR;
+#if SDMMC_USE_TC == 1
if (driver->use_polling) {
- if (driver->expect_auto_end
-
+ if (
+ driver->expect_auto_end
&& !(driver->config->tctimer->TC_CHANNEL[driver->config->tc_chan].TC_SR & TC_SR_CLKSTA)
-
)
events |= SDMMC_NISTR_CUSTOM_EVT;
+
+
} else {
if (driver->expect_auto_end) {
while (driver->config->tctimer->TC_CHANNEL[driver->config->tc_chan].TC_SR & TC_SR_CLKSTA);
-
events |= SDMMC_NISTR_CUSTOM_EVT;
}
}
+#else
+
+ if (driver->expect_auto_end)
+ {
+ while ( chSysIsCounterWithinX(chSysGetRealtimeCounterX(),driver->start_cycles ,driver->start_cycles+driver->timeout_cycles) );
+ events |= SDMMC_NISTR_CUSTOM_EVT;
+ }
+
+
+#endif
if (!events)
return;
//TRACE_1("events %08x\n\r",events);
@@ -661,9 +666,9 @@ void sdmmc_device_deInit(SdmmcDriver *drv) * Counter for this purpose. */
if (has_data && (cmd->bCmd == 18 || cmd->bCmd == 25)
&& !driver->use_set_blk_cnt) {
-
+#if SDMMC_USE_TC == 1
driver->config->tctimer->TC_CHANNEL[driver->config->tc_chan].TC_CCR = TC_CCR_CLKEN | TC_CCR_SWTRG;
-
+#endif
driver->expect_auto_end = true;
//#ifndef NDEBUG
// if (!set->cmd_line_released)
@@ -734,10 +739,12 @@ void sdmmc_device_deInit(SdmmcDriver *drv) && cmd->dwArg & 1ul << 31 && !cmd->cmdOp.bmBits.checkBsy)) {
/* Currently in the function switching period, wait for the
* delay preconfigured in sdmmc_send_command(). */
-
+#if SDMMC_USE_TC == 1
driver->config->tctimer->TC_CHANNEL[driver->config->tc_chan].TC_CCR = TC_CCR_CLKEN | TC_CCR_SWTRG;
while (driver->config->tctimer->TC_CHANNEL[driver->config->tc_chan].TC_SR & TC_SR_CLKSTA) ;
-
+#else
+ while ( chSysIsCounterWithinX(chSysGetRealtimeCounterX(),driver->start_cycles ,driver->start_cycles+driver->timeout_cycles) );
+#endif
}
/* Release this command */
@@ -878,14 +885,16 @@ void sdmmc_device_deInit(SdmmcDriver *drv) uint32_t eister;
uint32_t mask;
uint32_t len;
+#if SDMMC_USE_TC == 1
uint32_t cycles;
+#endif
uint16_t cr;
uint16_t tmr;
uint8_t mc1r;
uint8_t rc = SDMMC_OK;
- //TRACE_1("[command] start %d\r\n",driver->cmd.bCmd);
+ TRACE_DEBUG_1("[command] start %d\r\n",driver->cmd.bCmd);
if (driver->state == MCID_OFF)
return SDMMC_STATE;
@@ -962,7 +971,7 @@ void sdmmc_device_deInit(SdmmcDriver *drv) driver->dat_lines_released = false;
driver->expect_auto_end = false;
driver->cmd.bStatus = rc;
- //TRACE_1("command set status %d\r\n",driver->cmd.bStatus);
+ TRACE_DEBUG_1("command set status %d\r\n",driver->cmd.bStatus);
tmr = (regs->SDMMC_TMR & ~SDMMC_TMR_MSBSEL & ~SDMMC_TMR_DTDSEL
& ~SDMMC_TMR_ACMDEN_Msk & ~SDMMC_TMR_BCEN & ~SDMMC_TMR_DMAEN)
@@ -1101,12 +1110,16 @@ void sdmmc_device_deInit(SdmmcDriver *drv) * bits, hence 48 device clock cycles.
* The sum of the above timings is the maximum time CMD12 will
* take to complete. */
-
+#if SDMMC_USE_TC == 1
cycles = pmc_get_peripheral_clock(driver->tctimer_id) / (driver->dev_freq / (2ul + 64ul + 48ul));
- //TRACE_1("[command] has_data wait %d cycles\r\n",cycles);
+ TRACE_DEBUG_1("[command] has_data wait %d cycles\r\n",cycles);
/* The Timer operates with RC >= 1 */
driver->config->tctimer->TC_CHANNEL[driver->config->tc_chan].TC_RC = max_u32(cycles, 1);
+#else
+ driver->timeout_cycles = 2+64+48;
+ driver->start_cycles = chSysGetRealtimeCounterX();
+#endif
}
/* With SD devices, the 8-cycle function switching period will apply,
@@ -1114,18 +1127,21 @@ void sdmmc_device_deInit(SdmmcDriver *drv) * Note that MMC devices don't require this fixed delay, but regarding
* GO_IDLE_STATE we have no mean to filter the MMC requests out. */
else if (wait_switch) {
-
+#if SDMMC_USE_TC == 1
cycles = pmc_get_peripheral_clock(driver->tctimer_id) / (driver->dev_freq / 8ul);
- //TRACE_1("[command] wait_switch %d cycles\r\n",cycles);
+ TRACE_DEBUG_1("[command] wait_switch %d cycles\r\n",cycles);
driver->config->tctimer->TC_CHANNEL[driver->config->tc_chan].TC_RC = max_u32(cycles, 1);
-
+#else
+ driver->timeout_ticks = 8;
+ driver->start_cycles = chSysGetRealtimeCounterX();
+#endif
}
if (!driver->use_polling) {
regs->SDMMC_NISIER |= SDMMC_NISIER_BRDRDY | SDMMC_NISIER_BWRRDY | SDMMC_NISIER_TRFC | SDMMC_NISIER_CMDC | SDMMC_NISIER_CINT;
regs->SDMMC_EISIER = eister;
}
- //TRACE_1("[command] finish %d OK\r\n",driver->cmd.bCmd);
+ TRACE_DEBUG_1("[command] finish %d OK\r\n",driver->cmd.bCmd);
return SDMMC_OK;
}
@@ -1150,7 +1166,7 @@ void sdmmc_device_deInit(SdmmcDriver *drv) //#if TRACE_LEVEL >= TRACE_LEVEL_DEBUG
if (bCtl != SDMMC_IOCTL_BUSY_CHECK && bCtl != SDMMC_IOCTL_GET_DEVICE) {
- TRACE_2("SDMMC_IOCTL_%s(%lu)\n\r", SD_StringifyIOCtrl(bCtl),driver->control_param );
+ TRACE_DEBUG_2("SDMMC_IOCTL_%s(%lu)\n\r", SD_StringifyIOCtrl(bCtl),driver->control_param );
}
//#endif
@@ -1217,7 +1233,7 @@ void sdmmc_device_deInit(SdmmcDriver *drv) if (driver->control_param > 0xff)
return SDMMC_PARAM;
rc = sdmmc_set_bus_width(driver, driver->control_param);
- TRACE_1("Using a %u-bit data bus\n\r", sdmmc_get_bus_width(driver));
+ TRACE_DEBUG_1("Using a %u-bit data bus\n\r", sdmmc_get_bus_width(driver));
break;
case SDMMC_IOCTL_GET_HSMODE:
@@ -1283,7 +1299,7 @@ void sdmmc_device_deInit(SdmmcDriver *drv) sdmmc_set_device_clock(driver, driver->control_param);
- TRACE_1("Clocking the device at %lu Hz\n\r", driver->dev_freq);
+ TRACE_DEBUG_1("Clocking the device at %lu Hz\n\r", driver->dev_freq);
if (driver->dev_freq > 95000000ul
&& (driver->tim_mode == SDMMC_TIM_MMC_HS200
|| driver->tim_mode == SDMMC_TIM_SD_SDR104
@@ -1345,7 +1361,7 @@ void sdmmc_device_deInit(SdmmcDriver *drv) //#if TRACE_LEVEL >= TRACE_LEVEL_ERROR
if (rc != SDMMC_OK && rc != SDMMC_CHANGED
&& bCtl != SDMMC_IOCTL_BUSY_CHECK) {
- TRACE_2("SDMMC_IOCTL_%s ended with %s\n\r",SD_StringifyIOCtrl(bCtl), SD_StringifyRetCode(rc));
+ TRACE_ERROR_2("SDMMC_IOCTL_%s ended with %s\n\r",SD_StringifyIOCtrl(bCtl), SD_StringifyRetCode(rc));
}
//#endif
return rc;
@@ -1988,7 +2004,7 @@ static uint8_t sdmmc_set_bus_width(SdmmcDriver *driver, uint8_t bits) *pIoValClk = drv->control_param;
- TRACE_1("Device clk %lu kHz\n\r", drv->control_param / 1000UL);
+ TRACE_DEBUG_1("Device clk %lu kHz\n\r", drv->control_param / 1000UL);
}
return rc;
}
diff --git a/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_device.h b/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_device.h index ebe0da07d..340feb172 100644 --- a/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_device.h +++ b/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_device.h @@ -350,15 +350,6 @@ or not by mechanical write protect switch */ -#define STATUS_MMC_SWITCH ((uint32_t)( STATUS_CARD_IS_LOCKED \
- | STATUS_COM_CRC_ERROR \
- | STATUS_ILLEGAL_COMMAND \
- | STATUS_CC_ERROR \
- | STATUS_ERROR \
- | STATUS_ERASE_RESET \
- /*| STATUS_STATE*/ \
- /*| STATUS_READY_FOR_DATA*/ \
- | STATUS_SWITCH_ERROR ))
#define t_usleep(d,t) sdmmc_device_sleep(d,t,2)
#define t_msleep(d,t) sdmmc_device_sleep(d,t,1)
diff --git a/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_ff.c b/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_ff.c new file mode 100644 index 000000000..49b667bd7 --- /dev/null +++ b/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_ff.c @@ -0,0 +1,307 @@ +/* ---------------------------------------------------------------------------- + * SAM Software Package License + * ---------------------------------------------------------------------------- + * Copyright (c) 2015, Atmel Corporation + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the disclaimer below. + * + * Atmel's name may not be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ---------------------------------------------------------------------------- + */ + +/* ---------------------------------------------------------------------------- + * This file is based on the template source file named diskio.c, + * part of the FatFs Module R0.10b: + * Low level disk I/O module skeleton for FatFs (C)ChaN, 2014 + * If a working storage control module is available, it should be + * attached to the FatFs via a glue function rather than modifying it. + * This is an example of glue functions to attach various existing + * storage control modules to the FatFs module with a defined API. + * ---------------------------------------------------------------------------- + */ + +#include "hal.h" +#include "ccportab.h" +#include "ffconf.h" +#include "diskio.h" + +#include <string.h> +#include "sama_sdmmc_lld.h" +#include "ch_sdmmc_device.h" +#include "ch_sdmmc_sd.h" +#include "ch_sdmmc_sdio.h" +#include "ch_sdmmc_trace.h" +/*---------------------------------------------------------------------------- + * Definitions + *----------------------------------------------------------------------------*/ + +/** + * \brief Access the SD/MMC Library instances owned by the application. + * Used upon calls from the FatFs Module. + * + * Shall be implemented by the application. + */ +extern bool CC_WEAK sdmmcGetInstance(uint8_t index, SdmmcDriver **sdmmcp) ; + +/*---------------------------------------------------------------------------- + * Exported functions + *----------------------------------------------------------------------------*/ + +/** + * \brief Initialize a Drive. + * \param slot Physical drive number (0..). + * \return Drive status flags; STA_NOINIT if the specified drive does not exist. + */ +DSTATUS disk_initialize(BYTE slot) +{ + SdmmcDriver *sdmmcp = NULL; + uint8_t rc; + + if (!sdmmcGetInstance(slot, &sdmmcp)) + return STA_NOINIT; + + + rc = SD_GetStatus(sdmmcp); + + if (rc == SDMMC_NOT_SUPPORTED) + return STA_NODISK | STA_NOINIT; +#if 0 + if (sdmmcp->state != MCID_IDLE ) + sdmmc_device_deInit(sdmmcp); + + /* FIXME a delay with the bus held off may be required by the device */ + rc = sdmmc_device_start(sdmmcp); + + if (rc == SDMMC_OK) { + rc = sdmmc_device_identify(sdmmcp); + } +#endif + + return rc == SDMMC_OK ? 0 : STA_NOINIT; +} + +/** + * \brief Get Drive Status. + * \param slot Physical drive number (0..). + * \return Drive status flags; STA_NODISK if there is currently no device in + * the specified slot. + */ +DSTATUS disk_status(BYTE slot) +{ + SdmmcDriver *sdmmcp = NULL; + uint8_t rc; + + if (!sdmmcGetInstance(slot, &sdmmcp)) + return STA_NODISK | STA_NOINIT; + + rc = SD_GetStatus(sdmmcp); + + if (rc == SDMMC_NOT_SUPPORTED) + return STA_NODISK | STA_NOINIT; + else if (rc != SDMMC_OK) + return STA_NOINIT; + /* Well, no restriction on this drive */ + return 0; +} + +/** + * \brief Read Sector(s). + * \param slot Physical drive number (0..). + * \param buff Data buffer to store read data. + * \param sector Sector address in LBA. + * \param count Number of sectors to read. + * \return Result code; RES_OK if successful. + */ +DRESULT disk_read(BYTE slot, BYTE* buff, DWORD sector, UINT count) +{ + SdmmcDriver *sdmmcp = NULL; + DRESULT res; + uint32_t blk_size, addr = sector, len = count; + uint8_t rc; + + if (!sdmmcGetInstance(slot, &sdmmcp)) + return RES_PARERR; + + blk_size = sdmmcp->card.wBlockSize; + + if (blk_size == 0) + return RES_NOTRDY; + + if (blk_size < FF_MIN_SS) { + if (FF_MIN_SS % blk_size) + return RES_PARERR; + addr = sector * (FF_MIN_SS / blk_size); + len = count * (FF_MIN_SS / blk_size); + } + + if (count <= 1) + rc = SD_ReadBlocks(sdmmcp, addr, buff, len); + else + rc = SD_Read(sdmmcp, addr, buff, len); + + if (rc == SDMMC_OK || rc == SDMMC_CHANGED) + res = RES_OK; + else if (rc == SDMMC_ERR_IO || rc == SDMMC_ERR_RESP || rc == SDMMC_ERR) + res = RES_ERROR; + else if (rc == SDMMC_NO_RESPONSE || rc == SDMMC_BUSY + || rc == SDMMC_NOT_INITIALIZED || rc == SDMMC_LOCKED + || rc == SDMMC_STATE || rc == SDMMC_USER_CANCEL) + res = RES_NOTRDY; + else if (rc == SDMMC_PARAM || rc == SDMMC_NOT_SUPPORTED) + res = RES_PARERR; + else + res = RES_ERROR; + + return res; +} + +#if !FF_FS_READONLY +/** + * \brief Write Sector(s). + * + * \param slot Physical drive number (0..). + * \param buff Data to be written. + * \param sector Sector address in LBA. + * \param count Number of sectors to write. + * \return Result code; RES_OK if successful. + * + * \note The FatFs module will issue multiple sector transfer request + * (count > 1) to the disk I/O layer. The disk function should process + * the multiple sector transfer properly. Do not translate it into + * multiple single sector transfers to the media, or the data read/write + * performance may be drastically decreased. + */ +DRESULT disk_write(BYTE slot, const BYTE* buff, DWORD sector, UINT count) +{ + SdmmcDriver *sdmmcp = NULL; + DRESULT res; + uint32_t blk_size, addr = sector, len = count; + uint8_t rc; + + if (!sdmmcGetInstance(slot, &sdmmcp)) + return RES_PARERR; + + blk_size = sdmmcp->card.wBlockSize; + + if (blk_size < FF_MIN_SS) { + if (FF_MIN_SS % blk_size) + return RES_PARERR; + addr = sector * (FF_MIN_SS / blk_size); + len = count * (FF_MIN_SS / blk_size); + } + if (count <= 1) + rc = SD_WriteBlocks(sdmmcp, addr, buff, len); + else + rc = SD_Write(sdmmcp, addr, buff, len); + + if (rc == SDMMC_OK || rc == SDMMC_CHANGED) + res = RES_OK; + else if (rc == SDMMC_ERR_IO || rc == SDMMC_ERR_RESP || rc == SDMMC_ERR) + res = RES_ERROR; + else if (rc == SDMMC_NO_RESPONSE || rc == SDMMC_BUSY + || rc == SDMMC_NOT_INITIALIZED || rc == SDMMC_LOCKED + || rc == SDMMC_STATE || rc == SDMMC_USER_CANCEL) + res = RES_NOTRDY; + else if (rc == SDMMC_PARAM || rc == SDMMC_NOT_SUPPORTED) + res = RES_PARERR; + else + res = RES_ERROR; + return res; +} +#endif /* _FS_READONLY */ + +/** + * \brief Miscellaneous Functions. + * \param slot Physical drive number (0..). + * \param cmd Control code. + * \param buff Buffer to send/receive control data. + * \return Result code; RES_OK if successful. + */ +DRESULT disk_ioctl(BYTE slot, BYTE cmd, void* buff) +{ + SdmmcDriver *sdmmcp = NULL; + DRESULT res; + DWORD *param_u32 = (DWORD *)buff; + WORD *param_u16 = (WORD *)buff; + uint32_t blk_size, blk_count; + + if (!sdmmcGetInstance(slot, &sdmmcp)) + return RES_PARERR; + + switch (cmd) + { + case CTRL_SYNC: + /* SD/MMC devices do not seem to cache data beyond completion + * of the write commands. Note that if _FS_READONLY is enabled, + * this command is not needed. */ + res = RES_OK; + break; + + case GET_SECTOR_COUNT: + if (!buff) + return RES_PARERR; + blk_size = sdmmcp->card.wBlockSize; + blk_count = sdmmcp->card.dwNbBlocks; + + if (blk_size < FF_MIN_SS) + { + if (FF_MIN_SS % blk_size) + return RES_PARERR; + *param_u32 = blk_count / (FF_MIN_SS / blk_size); + } + else + *param_u32 = blk_count; + res = RES_OK; + break; + + case GET_SECTOR_SIZE: + /* Note that if _MAX_SS equals _MIN_SS i.e. the drive does not + * have to support several sector sizes, this command is not + * needed. */ + if (!buff) + return RES_PARERR; + blk_size = sdmmcp->card.wBlockSize; + *param_u16 = blk_size >= FF_MIN_SS ? blk_size : FF_MIN_SS; + res = RES_OK; + break; + + case GET_BLOCK_SIZE: + if (!buff) + return RES_PARERR; + /* On SD/MMC devices, erase block size is the same as write + * block size. + * Hence, erasing as little as one sector is allowed. */ + *param_u32 = 1; + res = RES_OK; + break; + + case CTRL_TRIM: + /* This TRIM-like command is not implemented. + * It would be required if _USE_TRIM was enabled. */ + res = RES_PARERR; + break; + + default: + res = RES_PARERR; + break; + } + return res; +} diff --git a/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_mmc.c b/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_mmc.c index a6206854e..601c95f2a 100644 --- a/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_mmc.c +++ b/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_mmc.c @@ -238,7 +238,7 @@ uint8_t MmcInit(SdmmcDriver *driver) error = error == SDMMC_CHANGED ? SDMMC_OK : error;
}
if (error != SDMMC_OK) {
- TRACE_1("HS %s\n\r", SD_StringifyRetCode(error));
+ TRACE_ERROR_1("HS %s\n\r", SD_StringifyRetCode(error));
return error;
}
}
@@ -271,7 +271,7 @@ uint8_t MmcInit(SdmmcDriver *driver) && tim_mode == SDMMC_TIM_MMC_HS_DDR)
driver->card.bSpeedMode = tim_mode;
else if (error) {
- TRACE_1("Width/DDR %s\n\r",
+ TRACE_ERROR_1("Width/DDR %s\n\r",
SD_StringifyRetCode(error));
return error;
}
@@ -306,7 +306,7 @@ uint8_t MmcInit(SdmmcDriver *driver) error = error == SDMMC_CHANGED ? SDMMC_OK : error;
}
if (error != SDMMC_OK) {
- TRACE_1("HS200 %s\n\r", SD_StringifyRetCode(error));
+ TRACE_ERROR_1("HS200 %s\n\r", SD_StringifyRetCode(error));
return error;
}
}
@@ -367,7 +367,7 @@ uint8_t MmcInit(SdmmcDriver *driver) return error;
status = status & ~STATUS_STATE & ~STATUS_READY_FOR_DATA & ~STATUS_APP_CMD;
if (status) {
- TRACE_1("st %lx\n\r", status);
+ TRACE_WARNING_1("st %lx\n\r", status);
}
return SDMMC_OK;
diff --git a/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_pmc.c b/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_pmc.c index 2f866296a..8a75a8656 100644 --- a/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_pmc.c +++ b/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_pmc.c @@ -3,7 +3,6 @@ #include "ch_sdmmc_pmc.h"
-
struct _pmc_main_osc {
uint32_t rc_freq;
uint32_t crystal_freq;
@@ -828,3 +827,5 @@ void pmc_disable_internal_osc(void) #endif
}
+
+
diff --git a/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_sama5d2.h b/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_sama5d2.h index 34a137b91..ae05cee2f 100644 --- a/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_sama5d2.h +++ b/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_sama5d2.h @@ -8,6 +8,8 @@ #define SB1_SIZE 64
#define SB2_SIZE 8
+#define SDMMC_BUFFER_SIZE (EXT_SIZE + SSR_SIZE + SCR_SIZE + SB1_SIZE + SB2_SIZE)
+
/** Frequency of the board main clock oscillator */
#define BOARD_MAIN_CLOCK_EXT_OSC 12000000
#define MAIN_CLOCK_INT_OSC 12000000
diff --git a/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_sd.c b/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_sd.c index 2f5e80a09..6363a0fac 100644 --- a/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_sd.c +++ b/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_sd.c @@ -6,7 +6,10 @@ #include "ch_sdmmc_sd.h"
#include "ch_sdmmc_sdio.h"
-
+static uint8_t PerformSingleTransfer(SdmmcDriver *driver,uint32_t address, uint8_t * pData, uint8_t isRead);
+static uint8_t MoveToTransferState(SdmmcDriver *driver,uint32_t address,uint16_t * nbBlocks, uint8_t * pData, uint8_t isRead);
+static uint8_t _StopCmd(SdmmcDriver *driver);
+static uint8_t _WaitUntilReady(SdmmcDriver *driver, uint32_t last_dev_status);
static uint8_t SdGetTimingFunction(uint8_t mode);
static void SdSelectSlowerTiming(bool high_sig, uint8_t * mode);
@@ -78,6 +81,154 @@ const char * SD_StringifyIOCtrl(uint32_t dwCtrl) }
#endif
+
+/**
+ * Read Blocks of data in a buffer pointed by pData. The buffer size must be at
+ * least 512 byte long. This function checks the SD card status register and
+ * address the card if required before sending the read command.
+ * \return 0 if successful; otherwise returns an \ref sdmmc_rc "error code".
+ * \param pSd Pointer to a SD card driver instance.
+ * \param address Address of the block to read.
+ * \param pData Data buffer whose size is at least the block size. It shall
+ * follow the peripheral and DMA alignment requirements.
+ * \param length Number of blocks to be read.
+ * \param pCallback Pointer to callback function that invoked when read done.
+ * 0 to start a blocked read.
+ * \param pArgs Pointer to callback function arguments.
+ */
+uint8_t SD_Read(SdmmcDriver *driver,uint32_t address,void *pData, uint32_t length)
+{
+ uint8_t *out = NULL;
+ uint32_t remaining, blk_no;
+ uint16_t limited;
+ uint8_t error = SDMMC_OK;
+
+
+ for (blk_no = address, remaining = length, out = (uint8_t *)pData;
+ remaining != 0 && error == SDMMC_OK;
+ blk_no += limited, remaining -= limited,
+ out += (uint32_t)limited * (uint32_t)driver->card.wCurrBlockLen)
+ {
+ limited = (uint16_t)min_u32(remaining, 65535);
+ error = MoveToTransferState(driver, blk_no, &limited, out, 1);
+ }
+ //debug
+ TRACE_DEBUG_3("SDrd(%lu,%lu) %s\n\r", address, length, SD_StringifyRetCode(error));
+ return error;
+}
+
+/**
+ * Write Blocks of data in a buffer pointed by pData. The buffer size must be at
+ * least 512 byte long. This function checks the SD card status register and
+ * address the card if required before sending the read command.
+ * \return 0 if successful; otherwise returns an \ref sdmmc_rc "error code".
+ * \param pSd Pointer to a SD card driver instance.
+ * \param address Address of the block to write.
+ * \param pData Data buffer whose size is at least the block size. It shall
+ * follow the peripheral and DMA alignment requirements.
+ * \param length Number of blocks to be write.
+ * \param pCallback Pointer to callback function that invoked when write done.
+ * 0 to start a blocked write.
+ * \param pArgs Pointer to callback function arguments.
+ */
+uint8_t SD_Write(SdmmcDriver *driver,uint32_t address,const void *pData,uint32_t length)
+{
+ uint8_t *in = NULL;
+ uint32_t remaining, blk_no;
+ uint16_t limited;
+ uint8_t error = SDMMC_OK;
+
+// assert(pSd != NULL);
+// assert(pData != NULL);
+
+ for (blk_no = address, remaining = length, in = (uint8_t *)pData;
+ remaining != 0 && error == SDMMC_OK;
+ blk_no += limited, remaining -= limited,
+ in += (uint32_t)limited * (uint32_t)driver->card.wCurrBlockLen) {
+ limited = (uint16_t)min_u32(remaining, 65535);
+ error = MoveToTransferState(driver, blk_no, &limited, in, 0);
+ }
+ //debug
+ TRACE_DEBUG_3("SDwr(%lu,%lu) %s\n\r", address, length, SD_StringifyRetCode(error));
+ return error;
+}
+
+/**
+ * Read Blocks of data in a buffer pointed by pData. The buffer size must be at
+ * least 512 byte long. This function checks the SD card status register and
+ * address the card if required before sending the read command.
+ * \return 0 if successful; otherwise returns an \ref sdmmc_rc "error code".
+ * \param pSd Pointer to a SD card driver instance.
+ * \param address Address of the block to read.
+ * \param nbBlocks Number of blocks to be read.
+ * \param pData Data buffer whose size is at least the block size. It shall
+ * follow the peripheral and DMA alignment requirements.
+ */
+uint8_t SD_ReadBlocks(SdmmcDriver *driver, uint32_t address, void *pData, uint32_t nbBlocks)
+{
+ uint8_t error = 0;
+ uint8_t *pBytes = (uint8_t *) pData;
+
+
+ //debug
+ TRACE_DEBUG_2("RdBlks(%lu,%lu)\n\r", address, nbBlocks);
+
+ while (nbBlocks--) {
+ error = PerformSingleTransfer(driver, address, pBytes, 1);
+ if (error)
+ break;
+ address += 1;
+ pBytes = &pBytes[512];
+ }
+ return error;
+}
+
+/**
+ * Write Block of data pointed by pData. The buffer size must be at
+ * least 512 byte long. This function checks the SD card status register and
+ * address the card if required before sending the read command.
+ * \return 0 if successful; otherwise returns an \ref sdmmc_rc "error code".
+ * \param pSd Pointer to a SD card driver instance.
+ * \param address Address of block to write.
+ * \param nbBlocks Number of blocks to be read
+ * \param pData Data buffer whose size is at least the block size. It shall
+ * follow the peripheral and DMA alignment requirements.
+ */
+uint8_t SD_WriteBlocks(SdmmcDriver *driver, uint32_t address, const void *pData, uint32_t nbBlocks)
+{
+ uint8_t error = 0;
+ uint8_t *pB = (uint8_t *) pData;
+
+
+ //debug
+ TRACE_DEBUG_2("WrBlks(%lu,%lu)\n\r", address, nbBlocks);
+
+ while (nbBlocks--) {
+ error = PerformSingleTransfer(driver, address, pB, 0);
+ if (error)
+ break;
+ address += 1;
+ pB = &pB[512];
+ }
+ return error;
+}
+
+uint8_t SD_GetStatus(SdmmcDriver *driver)
+{
+ uint32_t rc;
+
+ const sSdCard * pSd = &driver->card;
+
+ driver->control_param = 0;
+
+ rc = sdmmc_device_control(driver,SDMMC_IOCTL_GET_DEVICE);
+
+ if (rc != SDMMC_OK || !driver->control_param)
+ return SDMMC_NOT_SUPPORTED;
+
+ return pSd->bStatus == SDMMC_NOT_SUPPORTED ? SDMMC_ERR : pSd->bStatus;
+}
+
uint8_t SdDecideBuswidth(SdmmcDriver *drv)
{
uint8_t error, busWidth = 1;
@@ -155,7 +306,7 @@ uint8_t SdEnableHighSpeed(SdmmcDriver *drv) return SDMMC_ERR;
sfs_v1 = SD_SWITCH_ST_DATA_STRUCT_VER(drv->card.sandbox1) >= 0x01;
mode_mask = SD_SWITCH_ST_FUN_GRP1_INFO(drv->card.sandbox1);
- TRACE_1("Device timing functions: 0x%04x\n\r", mode_mask);
+ TRACE_DEBUG_1("Device timing functions: 0x%04x\n\r", mode_mask);
if (has_io && mode == SDMMC_TIM_SD_HS
&& !(mode_mask & 1 << SD_SWITCH_ST_ACC_HS))
return SDMMC_NOT_SUPPORTED;
@@ -181,7 +332,7 @@ uint8_t SdEnableHighSpeed(SdmmcDriver *drv) return SDMMC_STATE;
/* Check the electrical power requirements of this device */
val = SD_SWITCH_ST_FUN_GRP4_INFO(drv->card.sandbox1);
- TRACE_2("Device pwr & strength functions: 0x%04x & 0x%04x\n\r", val,
+ TRACE_DEBUG_2("Device pwr & strength functions: 0x%04x & 0x%04x\n\r", val,
SD_SWITCH_ST_FUN_GRP3_INFO(drv->card.sandbox1));
if (!(val & 1 << SD_SWITCH_ST_MAX_PWR_1_44W))
pwr_func = SD_SWITCH_ST_MAX_PWR_0_72W;
@@ -192,7 +343,7 @@ uint8_t SdEnableHighSpeed(SdmmcDriver *drv) if (error || status & STATUS_SWITCH_ERROR)
return SDMMC_ERR;
val = SD_SWITCH_ST_MAX_CURR_CONSUMPTION(drv->card.sandbox1);
- TRACE_1("Device max current: %u mA\n\r", val);
+ TRACE_DEBUG_1("Device max current: %u mA\n\r", val);
if (val == 0 || val > (1440 * 10) / 36)
SdSelectSlowerTiming(drv->card.bCardSigLevel != 0, &mode);
else if (sfs_v1) {
@@ -257,7 +408,7 @@ Switch: val = SD_SWITCH_ST_FUN_GRP4_RC(drv->card.sandbox1);
if (val != pwr_func) {
- TRACE_1("Device power limit 0x%x\n\r", val);
+ TRACE_DEBUG_1("Device power limit 0x%x\n\r", val);
}
Apply:
@@ -280,7 +431,7 @@ void SdGetExtInformation(SdmmcDriver *drv) if (error == SDMMC_OK) {
card_status &= ~STATUS_READY_FOR_DATA;
if (card_status != (STATUS_APP_CMD | STATUS_TRAN)) {
- TRACE_1("SCR st %lx\n\r", card_status);
+ TRACE_DEBUG_1("SCR st %lx\n\r", card_status);
}
}
@@ -289,7 +440,7 @@ void SdGetExtInformation(SdmmcDriver *drv) if (error == SDMMC_OK) {
card_status &= ~STATUS_READY_FOR_DATA;
if (card_status != (STATUS_APP_CMD | STATUS_TRAN)) {
- TRACE_1("SSR st %lx\n\r", card_status);
+ TRACE_DEBUG_1("SSR st %lx\n\r", card_status);
}
}
}
@@ -529,10 +680,10 @@ void SD_DumpStatus(const sSdCard *pSd) strcat(mode, "104");
}
- TRACE_4("%s, %u-bit data, in %s mode at %lu kHz\n\r", text, pSd->bBusMode, mode, (pSd->dwCurrSpeed / 1000UL) );
+ TRACE_DEBUG_4("%s, %u-bit data, in %s mode at %lu kHz\n\r", text, pSd->bBusMode, mode, (pSd->dwCurrSpeed / 1000UL) );
if (pSd->bCardType & CARD_TYPE_bmSDMMC) {
- TRACE_3("Device memory size: %lu MiB, %lu * %uB\n\r", SD_GetTotalSizeKB(pSd) / 1024ul, pSd->dwNbBlocks,pSd->wBlockSize);
+ TRACE_DEBUG_3("Device memory size: %lu MiB, %lu * %uB\n\r", SD_GetTotalSizeKB(pSd) / 1024ul, pSd->dwNbBlocks,pSd->wBlockSize);
}
@@ -779,3 +930,242 @@ void SD_DumpExtCSD(const uint8_t *pExtCSD) _PrintField("ER_GRP_DEF 0x%X\r\n", MMC_EXT_ERASE_GROUP_DEF(pExtCSD));
}
+
+
+/**
+ * Transfer a single data block.
+ * The device shall be in its Transfer State already.
+ * \param pSd Pointer to a SD card driver instance.
+ * \param address Address of the block to transfer.
+ * \param pData Data buffer, whose size is at least one block size.
+ * \param isRead Either 1 to read data from the device or 0 to write data.
+ * \return a \ref sdmmc_rc result code.
+ */
+static uint8_t PerformSingleTransfer(SdmmcDriver *driver,uint32_t address, uint8_t * pData, uint8_t isRead)
+{
+ uint8_t result = SDMMC_OK, error;
+ uint32_t sdmmc_address, status;
+
+ /* Convert block address into device-expected unit */
+ if (driver->card.bCardType & CARD_TYPE_bmHC)
+ sdmmc_address = address;
+ else if (address <= 0xfffffffful / driver->card.wCurrBlockLen)
+ sdmmc_address = address * driver->card.wCurrBlockLen;
+ else
+ return SDMMC_PARAM;
+
+ if (isRead)
+ /* Read a single data block */
+ error = Cmd17(driver, pData, sdmmc_address, &status);
+ else
+ /* Write a single data block */
+ error = Cmd24(driver, pData, sdmmc_address, &status);
+
+ if (!error) {
+ status = status & (isRead ? STATUS_READ : STATUS_WRITE)
+ & ~STATUS_READY_FOR_DATA & ~STATUS_STATE;
+ if (status) {
+ //error
+ TRACE_1("st %lx\n\r", status);
+ error = SDMMC_ERR;
+ }
+ }
+ if (error) {
+ //error
+ TRACE_ERROR_3("Cmd%u(0x%lx) %s\n\r", isRead ? 17 : 24,sdmmc_address, SD_StringifyRetCode(error));
+ result = error;
+ error = Cmd13(driver, &status);
+ if (error) {
+ driver->card.bStatus = error;
+ return result;
+ }
+ error = _WaitUntilReady(driver, status);
+ if (error) {
+ driver->card.bStatus = error;
+ return result;
+ }
+ }
+ return result;
+}
+
+/**
+ * Move SD card to transfer state. The buffer size must be at
+ * least 512 byte long. This function checks the SD card status register and
+ * address the card if required before sending the transfer command.
+ * Returns 0 if successful; otherwise returns an code describing the error.
+ * \param pSd Pointer to a SD card driver instance.
+ * \param address Address of the block to transfer.
+ * \param nbBlocks Pointer to count of blocks to transfer. Pointer to 0
+ * for infinite transfer. Upon return, points to the count of blocks actually
+ * transferred.
+ * \param pData Data buffer whose size is at least the block size.
+ * \param isRead 1 for read data and 0 for write data.
+ */
+static uint8_t MoveToTransferState(SdmmcDriver *driver,uint32_t address,uint16_t * nbBlocks, uint8_t * pData, uint8_t isRead)
+{
+ uint8_t result = SDMMC_OK, error;
+ uint32_t sdmmc_address, state, status;
+
+ /* Convert block address into device-expected unit */
+ if (driver->card.bCardType & CARD_TYPE_bmHC)
+ sdmmc_address = address;
+ else if (address <= 0xfffffffful / driver->card.wCurrBlockLen)
+ sdmmc_address = address * driver->card.wCurrBlockLen;
+ else
+ return SDMMC_PARAM;
+
+ if (driver->card.bSetBlkCnt) {
+ error = Cmd23(driver, 0, *nbBlocks, &status);
+ if (error)
+ return error;
+ }
+
+ if (isRead)
+ /* Move to Receiving data state */
+ error = Cmd18(driver, nbBlocks, pData, sdmmc_address, &status);
+ else
+ /* Move to Sending data state */
+ error = Cmd25(driver, nbBlocks, pData, sdmmc_address, &status);
+
+ if (error == SDMMC_CHANGED)
+ error = SDMMC_OK;
+
+ if (!error) {
+ status = status & (isRead ? STATUS_READ : STATUS_WRITE)
+ & ~STATUS_READY_FOR_DATA & ~STATUS_STATE;
+
+ if (driver->card.bStopMultXfer)
+ error = _StopCmd(driver);
+
+ if (status) {
+ //error
+ TRACE_DEBUG_1("st %lx\n\r", status);
+ /* TODO ignore STATUS_ADDR_OUT_OR_RANGE if the read
+ * operation is for the last block of memory area. */
+ error = SDMMC_ERR;
+ }
+ /* FIXME when not using the STOP_TRANSMISSION command (using the
+ * SET_BLOCK_COUNT command instead), we should issue the
+ * SEND_STATUS command, eat and handle any Execution Mode
+ * exception. */
+ }
+ if (error) {
+ //error
+ TRACE_ERROR_4("Cmd%u(0x%lx, %u) %s\n\r", isRead ? 18 : 25,sdmmc_address, *nbBlocks, SD_StringifyRetCode(error));
+ result = error;
+ error = Cmd13(driver, &status);
+
+ if (error) {
+ driver->card.bStatus = error;
+ return result;
+ }
+
+ state = status & STATUS_STATE;
+
+ if (state == STATUS_DATA || state == STATUS_RCV) {
+
+ error = Cmd12(driver, &status);
+
+ if (error == SDMMC_OK) {
+ //info
+ TRACE_INFO_1("st %lx\n\r", status);
+
+ if (status & (STATUS_ERASE_SEQ_ERROR
+ | STATUS_ERASE_PARAM | STATUS_UN_LOCK_FAILED
+ | STATUS_ILLEGAL_COMMAND
+ | STATUS_CIDCSD_OVERWRITE
+ | STATUS_ERASE_RESET | STATUS_SWITCH_ERROR))
+ result = SDMMC_STATE;
+ else if (status & (STATUS_COM_CRC_ERROR
+ | STATUS_CARD_ECC_FAILED | STATUS_ERROR))
+ result = SDMMC_ERR_IO;
+ else if (status & (STATUS_ADDR_OUT_OR_RANGE
+ | STATUS_ADDRESS_MISALIGN
+ | STATUS_BLOCK_LEN_ERROR
+ | STATUS_WP_VIOLATION
+ | STATUS_WP_ERASE_SKIP))
+ result = SDMMC_PARAM;
+ else if (status & STATUS_CC_ERROR)
+ result = SDMMC_ERR;
+ }
+ else if (error == SDMMC_NO_RESPONSE)
+ error = Cmd13(driver, &status);
+ if (error) {
+ driver->card.bStatus = error;
+ return result;
+ }
+ }
+ error = _WaitUntilReady(driver, status);
+
+ if (error) {
+ driver->card.bStatus = error;
+ return result;
+ }
+ }
+ return result;
+}
+
+/**
+ * Stop TX/RX
+ */
+static uint8_t _StopCmd(SdmmcDriver *driver)
+{
+ uint32_t status, state = STATUS_RCV;
+ uint32_t i;
+ uint8_t err, count;
+ /* When stopping a write operation, allow retrying several times */
+ for (i = 0; i < 9 && state == STATUS_RCV; i++) {
+ err = Cmd12(driver, &status);
+ if (err)
+ return err;
+ /* TODO handle any exception, raised in status; report that
+ * the data transfer has failed. */
+
+ /* Wait until ready. Allow 30 ms. */
+ for (count = 0; count < 6; count++) {
+ /* Wait for about 5 ms - which equals 5 system ticks */
+ t_msleep(driver,5);
+ err = Cmd13(driver, &status);
+ if (err)
+ return err;
+ state = status & STATUS_STATE;
+
+ /* Invalid state */
+ if (state == STATUS_IDLE || state == STATUS_READY
+ || state == STATUS_IDENT || state == STATUS_STBY
+ || state == STATUS_DIS)
+ return SDMMC_NOT_INITIALIZED;
+
+ /* Ready? */
+ if ((status & STATUS_READY_FOR_DATA) ==
+ STATUS_READY_FOR_DATA && state == STATUS_TRAN)
+ return SDMMC_OK;
+ }
+ }
+ return SDMMC_STATE;
+}
+
+static uint8_t _WaitUntilReady(SdmmcDriver *driver, uint32_t last_dev_status)
+{
+ uint32_t state, status = last_dev_status;
+ uint8_t err, count;
+
+ for (count = 0; count < 51; count++) {
+ state = status & STATUS_STATE;
+ if (state == STATUS_TRAN && status & STATUS_READY_FOR_DATA)
+ return SDMMC_OK;
+ /* Sending-data and Receive-data states may be encountered
+ * temporarily further to single-block data transfers. */
+ /* FIXME state 15 "reserved for I/O mode" may be allowed */
+ if (state != STATUS_TRAN && state != STATUS_PRG
+ && state != STATUS_DATA && state != STATUS_RCV)
+ return SDMMC_NOT_INITIALIZED;
+ /* Wait for about 10 ms - which equals 10 system ticks */
+ t_msleep(driver,10);
+ err = Cmd13(driver, &status);
+ if (err)
+ return err;
+ }
+ return SDMMC_BUSY;
+}
+
diff --git a/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_sd.h b/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_sd.h index d08778219..7708a88f1 100644 --- a/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_sd.h +++ b/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_sd.h @@ -75,10 +75,6 @@ #define SD_SWITCH_ST_FUN_GRP_FUN_BUSY(funNdx) (1 << (funNdx))
/** @}*/
-
-
-
-
/** We support 2.7 ~ 3.3V cards */
#define SD_HOST_VOLTAGE_RANGE (SD_OCR_VDD_27_28 +\
SD_OCR_VDD_28_29 +\
@@ -91,6 +87,10 @@ SD_OCR_VDD_35_36 )
+
+/** @}*/
+
+extern uint8_t SD_GetStatus(SdmmcDriver *driver);
extern uint8_t SdDecideBuswidth(SdmmcDriver *drv);
extern uint8_t SdEnableHighSpeed(SdmmcDriver *drv);
extern uint32_t SD_GetField(const uint8_t *reg, uint16_t reg_len, uint16_t field_start,
@@ -107,5 +107,10 @@ extern void SD_DumpSSR(const uint8_t *pSSR); extern const char * SD_StringifyRetCode(uint32_t dwRCode);
extern const char * SD_StringifyIOCtrl(uint32_t dwCtrl);
+extern uint8_t SD_Read(SdmmcDriver *driver,uint32_t address,void *pData, uint32_t length);
+extern uint8_t SD_Write(SdmmcDriver *driver,uint32_t address,const void *pData,uint32_t length);
+extern uint8_t SD_ReadBlocks(SdmmcDriver *driver, uint32_t address, void *pData, uint32_t nbBlocks);
+extern uint8_t SD_WriteBlocks(SdmmcDriver *driver, uint32_t address, const void *pData, uint32_t nbBlocks);
+extern uint8_t SD_ReadBlocks(SdmmcDriver *driver, uint32_t address, void *pData, uint32_t nbBlocks);
#endif /* CH_SDMMC_SD_H_ */
diff --git a/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_tc.c b/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_tc.c index b8898acb5..9b66742c7 100644 --- a/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_tc.c +++ b/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_tc.c @@ -3,6 +3,8 @@ #include "ch_sdmmc_pmc.h"
#include "ch_sdmmc_tc.h"
+#if SDMMC_USE_TC == 1
+
/*------------------------------------------------------------------------------
* Global functions
*------------------------------------------------------------------------------*/
@@ -249,3 +251,4 @@ uint32_t tc_get_cv(Tc* tc, uint32_t channel) return ch->TC_CV;
}
+#endif
diff --git a/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_trace.h b/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_trace.h index 1bb9ad15f..20ea20f50 100644 --- a/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_trace.h +++ b/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_trace.h @@ -23,7 +23,80 @@ extern BaseSequentialStream * ts; #define TRACE_4(s,v1,v2,v3,v4)
#define TRACE_5(s,v1,v2,v3,v4,v5)
#define TRACE_6(s,v1,v2,v3,v4,v5,v6)
-#define TRACE_LEV_1(s,v1)
+#endif
+
+#if SAMA_SDMMC_TRACE_LEVEL >= 1
+#define TRACE_INFO(s) TRACE(s)
+#define TRACE_INFO_1(s,v1) TRACE_1(s,v1)
+#define TRACE_INFO_2(s,v1,v2) TRACE_2(s,v1,v2)
+#define TRACE_INFO_3(s,v1,v2,v3) TRACE_3(s,v1,v2,v3)
+#define TRACE_INFO_4(s,v1,v2,v3,v4) TRACE_4(s,v1,v2,v3,v4)
+#define TRACE_INFO_5(s,v1,v2,v3,v4,v5) TRACE_5(s,v1,v2,v3,v4,v5)
+#define TRACE_INFO_6(s,v1,v2,v3,v4,v5,v6) TRACE_6(s,v1,v2,v3,v4,v5,v6)
+#else
+#define TRACE_INFO(s)
+#define TRACE_INFO_1(s,v1)
+#define TRACE_INFO_2(s,v1,v2)
+#define TRACE_INFO_3(s,v1,v2,v3)
+#define TRACE_INFO_4(s,v1,v2,v3,v4)
+#define TRACE_INFO_5(s,v1,v2,v3,v4,v5)
+#define TRACE_INFO_6(s,v1,v2,v3,v4,v5,v6)
+#endif
+
+
+#if SAMA_SDMMC_TRACE_LEVEL >= 2
+#define TRACE_WARNING(s) TRACE(s)
+#define TRACE_WARNING_1(s,v1) TRACE_1(s,v1)
+#define TRACE_WARNING_2(s,v1,v2) TRACE_2(s,v1,v2)
+#define TRACE_WARNING_3(s,v1,v2,v3) TRACE_3(s,v1,v2,v3)
+#define TRACE_WARNING_4(s,v1,v2,v3,v4) TRACE_4(s,v1,v2,v3,v4)
+#define TRACE_WARNING_5(s,v1,v2,v3,v4,v5) TRACE_5(s,v1,v2,v3,v4,v5)
+#define TRACE_WARNING_6(s,v1,v2,v3,v4,v5,v6) TRACE_6(s,v1,v2,v3,v4,v5,v6)
+#else
+#define TRACE_WARNING(s)
+#define TRACE_WARNING_1(s,v1)
+#define TRACE_WARNING_2(s,v1,v2)
+#define TRACE_WARNING_3(s,v1,v2,v3)
+#define TRACE_WARNING_4(s,v1,v2,v3,v4)
+#define TRACE_WARNING_5(s,v1,v2,v3,v4,v5)
+#define TRACE_WARNING_6(s,v1,v2,v3,v4,v5,v6)
+#endif
+
+
+#if SAMA_SDMMC_TRACE_LEVEL >= 3
+#define TRACE_ERROR(s) TRACE(s)
+#define TRACE_ERROR_1(s,v1) TRACE_1(s,v1)
+#define TRACE_ERROR_2(s,v1,v2) TRACE_2(s,v1,v2)
+#define TRACE_ERROR_3(s,v1,v2,v3) TRACE_3(s,v1,v2,v3)
+#define TRACE_ERROR_4(s,v1,v2,v3,v4) TRACE_4(s,v1,v2,v3,v4)
+#define TRACE_ERROR_5(s,v1,v2,v3,v4,v5) TRACE_5(s,v1,v2,v3,v4,v5)
+#define TRACE_ERROR_6(s,v1,v2,v3,v4,v5,v6) TRACE_6(s,v1,v2,v3,v4,v5,v6)
+#else
+#define TRACE_ERROR(s)
+#define TRACE_ERROR_1(s,v1)
+#define TRACE_ERROR_2(s,v1,v2)
+#define TRACE_ERROR_3(s,v1,v2,v3)
+#define TRACE_ERROR_4(s,v1,v2,v3,v4)
+#define TRACE_ERROR_5(s,v1,v2,v3,v4,v5)
+#define TRACE_ERROR_6(s,v1,v2,v3,v4,v5,v6)
+#endif
+
+#if SAMA_SDMMC_TRACE_LEVEL >= 4
+#define TRACE_DEBUG(s) TRACE(s)
+#define TRACE_DEBUG_1(s,v1) TRACE_1(s,v1)
+#define TRACE_DEBUG_2(s,v1,v2) TRACE_2(s,v1,v2)
+#define TRACE_DEBUG_3(s,v1,v2,v3) TRACE_3(s,v1,v2,v3)
+#define TRACE_DEBUG_4(s,v1,v2,v3,v4) TRACE_4(s,v1,v2,v3,v4)
+#define TRACE_DEBUG_5(s,v1,v2,v3,v4,v5) TRACE_5(s,v1,v2,v3,v4,v5)
+#define TRACE_DEBUG_6(s,v1,v2,v3,v4,v5,v6) TRACE_6(s,v1,v2,v3,v4,v5,v6)
+#else
+#define TRACE_DEBUG(s)
+#define TRACE_DEBUG_1(s,v1)
+#define TRACE_DEBUG_2(s,v1,v2)
+#define TRACE_DEBUG_3(s,v1,v2,v3)
+#define TRACE_DEBUG_4(s,v1,v2,v3,v4)
+#define TRACE_DEBUG_5(s,v1,v2,v3,v4,v5)
+#define TRACE_DEBUG_6(s,v1,v2,v3,v4,v5,v6)
#endif
diff --git a/os/hal/ports/SAMA/LLD/SDMMCv1/driver.mk b/os/hal/ports/SAMA/LLD/SDMMCv1/driver.mk index ae2e9f16a..13494bdc2 100644 --- a/os/hal/ports/SAMA/LLD/SDMMCv1/driver.mk +++ b/os/hal/ports/SAMA/LLD/SDMMCv1/driver.mk @@ -1,12 +1,13 @@ PLATFORMSRC += $(CHIBIOS)/os/hal/ports/SAMA/LLD/SDMMCv1/sama_sdmmc_lld.c \
$(CHIBIOS)/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_device.c \
$(CHIBIOS)/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_sdio.c \
- $(CHIBIOS)/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_pmc.c \
$(CHIBIOS)/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_cmds.c \
$(CHIBIOS)/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_tc.c \
$(CHIBIOS)/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_mmc.c \
$(CHIBIOS)/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_sd.c \
- $(CHIBIOS)/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc.c
+ $(CHIBIOS)/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc.c \
+ $(CHIBIOS)/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_ff.c \
+ $(CHIBIOS)/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_pmc.c
PLATFORMINC += $(CHIBIOS)/os/hal/ports/SAMA/LLD/SDMMCv1
diff --git a/os/hal/ports/SAMA/LLD/SDMMCv1/sama_sdmmc_conf.h b/os/hal/ports/SAMA/LLD/SDMMCv1/sama_sdmmc_conf.h index 560fcb1c7..0fb377549 100644 --- a/os/hal/ports/SAMA/LLD/SDMMCv1/sama_sdmmc_conf.h +++ b/os/hal/ports/SAMA/LLD/SDMMCv1/sama_sdmmc_conf.h @@ -14,12 +14,19 @@ typedef FATFS CH_SDMMC_FAT; #define SAMA_SDMMC_TRACE 0
#endif
+#ifndef SAMA_SDMMC_TRACE_LEVEL
+#define SAMA_SDMMC_TRACE_LEVEL 0
+#endif
/** Default block size for SD/MMC access */
#ifndef SDMMC_BLOCK_SIZE
#define SDMMC_BLOCK_SIZE 512
#endif
+#ifndef SDMMC_USE_TC
+#define SDMMC_USE_TC 0
+#endif
+
#endif //SAMA_SDMMC_CONF_H
diff --git a/os/hal/ports/SAMA/LLD/SDMMCv1/sama_sdmmc_lld.c b/os/hal/ports/SAMA/LLD/SDMMCv1/sama_sdmmc_lld.c index 105e18036..7aed656dc 100644 --- a/os/hal/ports/SAMA/LLD/SDMMCv1/sama_sdmmc_lld.c +++ b/os/hal/ports/SAMA/LLD/SDMMCv1/sama_sdmmc_lld.c @@ -23,7 +23,7 @@ */
#include "hal.h"
-
+#include "ccportab.h"
#if (HAL_USE_SDMMC == TRUE) || defined(__DOXYGEN__)
#include <string.h>
#include "sama_sdmmc_lld.h"
@@ -129,11 +129,9 @@ void sdmmcStart(SdmmcDriver *sdmmcp, const SamaSDMMCConfig *config) }
- TRACE_LEV_1("[%s] Cannot init board for MMC\r\n","ERROR");
+ TRACE_ERROR("Cannot init board for MMC\r\n");
sdmmcp->state = MCID_INIT_ERROR;
-
-
}
/**
@@ -177,7 +175,7 @@ uint8_t sdmmcSendCmd(SdmmcDriver *sdmmcp) uint8_t bRc;
if (sdmmcp->cmd.bCmd != 55) {
- TRACE_2("Cmd%u(%lx)\n\r", sdmmcp->cmd.bCmd, sdmmcp->cmd.dwArg);
+ TRACE_INFO_2("Cmd%u(%lx)\n\r", sdmmcp->cmd.bCmd, sdmmcp->cmd.dwArg);
}
bRc = sdmmc_device_command(sdmmcp);
@@ -198,6 +196,7 @@ uint8_t sdmmcSendCmd(SdmmcDriver *sdmmcp) sdmmcp->control_param = 1;
sdmmcp->timeout_elapsed = 0;
+ sdmmcp->timeout_ticks = 30*1000;
sdmmc_device_startTimeCount(sdmmcp);
do
@@ -221,18 +220,17 @@ uint8_t sdmmcSendCmd(SdmmcDriver *sdmmcp) }
bRc = sdmmcp->cmd.bStatus;
- //TRACE_1("post cmd bRc = %d\r\n",bRc);
+
if (bRc == SDMMC_CHANGED) {
- //TRACE_2("Changed Cmd%u %s\n\r", sdmmcp->cmd.bCmd,SD_StringifyRetCode(bRc));
+ TRACE_DEBUG_2("Changed Cmd%u %s\n\r", sdmmcp->cmd.bCmd,SD_StringifyRetCode(bRc));
}
else if (bRc != SDMMC_OK) {
- //TRACE_2("OK Cmd%u %s\n\r", sdmmcp->cmd.bCmd,SD_StringifyRetCode(bRc));
+ TRACE_DEBUG_2("OK Cmd%u %s\n\r", sdmmcp->cmd.bCmd,SD_StringifyRetCode(bRc));
}
else if (sdmmcp->cmd.cmdOp.bmBits.respType == 1 && sdmmcp->cmd.pResp) {
- //TRACE_2("Resp Cmd%u st %lx\n\r", sdmmcp->cmd.bCmd, *sdmmcp->cmd.pResp);
+ TRACE_DEBUG_2("Resp Cmd%u st %lx\n\r", sdmmcp->cmd.bCmd, *sdmmcp->cmd.pResp);
}
- //TRACE_1("[ret sending cmd] %d\r\n",bRc);
return bRc;
}
@@ -252,14 +250,14 @@ bool sdmmcOpenDevice(SdmmcDriver *sdmmcp) rc = sdmmc_device_start(sdmmcp);
if (rc != SDMMC_OK) {
- TRACE_1("SD/MMC device initialization failed: %d\n\r", rc);
+ TRACE_INFO_1("SD/MMC device initialization failed: %d\n\r", rc);
return false;
}
- if (sdmmc_device_identify(sdmmcp) == SDMMC_OK) {
+ if (sdmmc_device_identify(sdmmcp) != SDMMC_OK) {
return false;
}
- TRACE("SD/MMC device initialization successful\n\r");
+ TRACE_INFO("SD/MMC device initialization successful\n\r");
return true;
}
@@ -272,13 +270,13 @@ bool sdmmcCloseDevice(SdmmcDriver *sdmmcp) bool sdmmcShowDeviceInfo(SdmmcDriver *sdmmcp)
{
sSdCard *pSd =&sdmmcp->card;
- TRACE("Show Device Info:\n\r");
+ TRACE_INFO("Show Device Info:\n\r");
#ifndef SDMMC_TRIM_INFO
const uint8_t card_type = sdmmcp->card.bCardType;
- TRACE_1("Card Type: %d\n\r", card_type);
+ TRACE_INFO_1("Card Type: %d\n\r", card_type);
#endif
- TRACE("Dumping Status ... \n\r");
+ TRACE_INFO("Dumping Status ... \n\r");
SD_DumpStatus(pSd);
#ifndef SDMMC_TRIM_INFO
if (card_type & CARD_TYPE_bmSDMMC)
@@ -304,58 +302,24 @@ bool sdmmcShowDeviceInfo(SdmmcDriver *sdmmcp) bool sdmmcMountVolume(SdmmcDriver *sdmmcp, CH_SDMMC_FAT *fs)
{
-#if 0
- //TODO to be done
- const TCHAR drive_path[] = { '0' + sdmmcp->config->slot_id, ':', '\0' };
- DIR dir = { .sect = 0 };
- FILINFO fno = { 0 };
FRESULT res;
- bool is_dir, rc = true;
+ const TCHAR drive_path[] = { '0' + sdmmcp->config->slot_id, ':', '\0' };
(void)sdmmcp;
memset(fs, 0, sizeof(CH_SDMMC_FAT));
res = f_mount(fs, drive_path, 1);
if (res != FR_OK) {
- TRACE_1("Failed to mount FAT file system, error %d\n\r", res);
+ TRACE_INFO_1("Failed to mount FAT file system, error %d\n\r", res);
return false;
}
- res = f_opendir(&dir, drive_path);
- if (res != FR_OK) {
- TRACE_1("Failed to change to root directory, error %d\n\r", res);
- return false;
- } TRACE("Listing the files present in the root directory:\n\r");
- for (;;) {
- res = f_readdir(&dir, &fno);
- if (res != FR_OK) {
- TRACE_1("Error (%d) while listing files\n\r", res);
- rc = false;
- break;
- }
- if (fno.fname[0] == '\0')
- break;
- is_dir = fno.fattrib & AM_DIR ? true : false;
- TRACE_3(" %s%s%c\n\r", is_dir ? "[" : "", fno.fname,is_dir ? ']' : ' ');
- }
- res = f_closedir(&dir);
- if (res != FR_OK) {
- TRACE_1("Failed to close directory, error %d\n\r", res);
- rc = false;
- }
- return rc;
-#else
- (void)sdmmcp;
- (void)fs;
- return 0;
-#endif
+ return true;
}
bool sdmmcUnmountVolume(SdmmcDriver *sdmmcp)
{
- #if 0
- //TODO to be done
const TCHAR drive_path[] = { '0' + sdmmcp->config->slot_id, ':', '\0' };
FRESULT res;
bool rc = true;
@@ -365,13 +329,15 @@ bool sdmmcUnmountVolume(SdmmcDriver *sdmmcp) rc = false;
return rc;
-#else
- (void)sdmmcp;
- return 0;
-#endif
}
+bool CC_WEAK sdmmcGetInstance(uint8_t index, SdmmcDriver **sdmmcp)
+{
+ (void)index;
+ (void)sdmmcp;
+ return false;
+}
#endif /* HAL_USE_SDMMC == TRUE */
diff --git a/os/hal/ports/SAMA/LLD/SDMMCv1/sama_sdmmc_lld.h b/os/hal/ports/SAMA/LLD/SDMMCv1/sama_sdmmc_lld.h index 9b672c642..7093dd9b3 100644 --- a/os/hal/ports/SAMA/LLD/SDMMCv1/sama_sdmmc_lld.h +++ b/os/hal/ports/SAMA/LLD/SDMMCv1/sama_sdmmc_lld.h @@ -78,21 +78,18 @@ typedef struct { struct _pmc_periph_cfg pmccfg;
bool use_fastest_clock;
-
+#if SDMMC_USE_TC == 1
Tc * tctimer;
-
uint8_t tc_chan;
+#endif
uint8_t * bp;
uint8_t * data_buf;
uint32_t data_buf_size;
-
-
uint32_t * dma_table;
uint32_t dma_table_size;
-
} SamaSDMMCConfig;
@@ -132,6 +129,11 @@ struct SamaSDMMCDriver uint32_t timeout_ticks;
int8_t timeout_elapsed;
systime_t time,now;
+#if SDMMC_USE_TC == 0
+ rtcnt_t timeout_cycles;
+ rtcnt_t start_cycles;
+#endif
+
};
typedef sSdCard sdmmclib;
typedef struct SamaSDMMCDriver SdmmcDriver;
|