From bae22ff5bf8185b7ed2b6d26fb0d8f2c42253cfb Mon Sep 17 00:00:00 2001 From: areviu Date: Thu, 11 Jan 2018 21:41:51 +0000 Subject: update SDMMC driver and added test hal project git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@11264 35acf78f-673a-0410-8e92-d51de3d6d3f4 --- os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc.c | 22 +- os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc.h | 3 +- os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_cmds.c | 229 ++++++++++++- os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_cmds.h | 68 +++- os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_device.c | 102 +++--- os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_device.h | 9 - os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_ff.c | 307 +++++++++++++++++ os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_mmc.c | 8 +- os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_pmc.c | 3 +- os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_sama5d2.h | 2 + os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_sd.c | 408 ++++++++++++++++++++++- os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_sd.h | 13 +- os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_tc.c | 3 + os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_trace.h | 75 ++++- os/hal/ports/SAMA/LLD/SDMMCv1/driver.mk | 5 +- os/hal/ports/SAMA/LLD/SDMMCv1/sama_sdmmc_conf.h | 7 + os/hal/ports/SAMA/LLD/SDMMCv1/sama_sdmmc_lld.c | 80 ++--- os/hal/ports/SAMA/LLD/SDMMCv1/sama_sdmmc_lld.h | 12 +- 18 files changed, 1201 insertions(+), 155 deletions(-) create mode 100644 os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_ff.c (limited to 'os/hal/ports/SAMA/LLD/SDMMCv1') 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; @@ -414,6 +414,30 @@ uint8_t Cmd11(SdmmcDriver *drv, uint32_t * pStatus) return bRc; } +/** + * 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). @@ -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 +#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 #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; -- cgit v1.2.3