From 2af65517ae3abecec1f083a5024430b3f90c15d7 Mon Sep 17 00:00:00 2001 From: Giovanni Di Sirio Date: Thu, 16 Jan 2020 10:03:26 +0000 Subject: [PATCH] SDMMCv2 improvements. git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@13276 27425a3e-05d8-49a3-a47f-9c15f0e5edd8 --- os/hal/ports/STM32/LLD/SDMMCv2/hal_sdc_lld.c | 96 +++++++------------ os/hal/ports/STM32/LLD/SDMMCv2/hal_sdc_lld.h | 44 ++++----- .../cfg/stm32l4r9ai_discovery/mcuconf.h | 5 +- 3 files changed, 55 insertions(+), 90 deletions(-) diff --git a/os/hal/ports/STM32/LLD/SDMMCv2/hal_sdc_lld.c b/os/hal/ports/STM32/LLD/SDMMCv2/hal_sdc_lld.c index 7147d64ca..c6feb714d 100644 --- a/os/hal/ports/STM32/LLD/SDMMCv2/hal_sdc_lld.c +++ b/os/hal/ports/STM32/LLD/SDMMCv2/hal_sdc_lld.c @@ -39,23 +39,6 @@ SDMMC_STA_CTIMEOUT | SDMMC_STA_DTIMEOUT | \ SDMMC_STA_TXUNDERR | SDMMC_STA_RXOVERR) -#define SDMMC_CLKDIV_HS (2 - 2) -#define SDMMC_CLKDIV_LS (120 - 2) - -#define SDMMC1_WRITE_TIMEOUT \ - (((STM32_SDMMC1CLK / (SDMMC_CLKDIV_HS + 2)) / 1000) * \ - STM32_SDC_SDMMC_WRITE_TIMEOUT) -#define SDMMC1_READ_TIMEOUT \ - (((STM32_SDMMC1CLK / (SDMMC_CLKDIV_HS + 2)) / 1000) * \ - STM32_SDC_SDMMC_READ_TIMEOUT) - -#define SDMMC2_WRITE_TIMEOUT \ - (((STM32_SDMMC2CLK / (SDMMC_CLKDIV_HS + 2)) / 1000) * \ - STM32_SDC_SDMMC_WRITE_TIMEOUT) -#define SDMMC2_READ_TIMEOUT \ - (((STM32_SDMMC2CLK / (SDMMC_CLKDIV_HS + 2)) / 1000) * \ - STM32_SDC_SDMMC_READ_TIMEOUT) - /*===========================================================================*/ /* Driver exported variables. */ /*===========================================================================*/ @@ -96,6 +79,23 @@ static const SDCConfig sdc_default_cfg = { /* Driver local functions. */ /*===========================================================================*/ +/** + * @brief Calculates a clock divider for the specified frequency. + * @note The divider is calculated to not exceed the required frequency + * in case of non-integer division. + * + * @param[in] sdcp pointer to the @p SDCDriver object + * @param[in] f required frequency + */ +static uint32_t sdc_lld_clkdiv(SDCDriver *sdcp, uint32_t f) { + + if (f >= sdcp->clkfreq) { + return 0; + } + + return (sdcp->clkfreq + (f * 2) - 1) / (f * 2); +} + /** * @brief Prepares to handle read transaction. * @details Designed for read special registers from card. @@ -114,7 +114,7 @@ static bool sdc_lld_prepare_read_bytes(SDCDriver *sdcp, uint8_t *buf, uint32_t bytes) { osalDbgCheck(bytes < 0x1000000); - sdcp->sdmmc->DTIMER = sdcp->rtmo; + sdcp->sdmmc->DTIMER = STM32_SDC_SDMMC_READ_TIMEOUT; /* Checks for errors and waits for the card to be ready for reading.*/ if (_sdc_wait_for_transfer_state(sdcp)) @@ -136,9 +136,6 @@ static bool sdc_lld_prepare_read_bytes(SDCDriver *sdcp, sdcp->sdmmc->IDMABASE0 = (uint32_t)buf; sdcp->sdmmc->IDMACTRL = SDMMC_IDMA_IDMAEN; - /* Transaction starts just after DTEN bit setting.*/ -// sdcp->sdmmc->DCTRL |= SDMMC_DCTRL_DTEN; - return HAL_SUCCESS; } @@ -166,13 +163,13 @@ static bool sdc_lld_prepare_read(SDCDriver *sdcp, uint32_t startblk, if (n > 1) { /* Send read multiple blocks command to card.*/ - if (sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_READ_MULTIPLE_BLOCK, + if (sdc_lld_send_cmd_short_crc(sdcp, SDMMC_CMD_CMDTRANS | MMCSD_CMD_READ_MULTIPLE_BLOCK, startblk, resp) || MMCSD_R1_ERROR(resp[0])) return HAL_FAILED; } else { /* Send read single block command.*/ - if (sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_READ_SINGLE_BLOCK, + if (sdc_lld_send_cmd_short_crc(sdcp, SDMMC_CMD_CMDTRANS | MMCSD_CMD_READ_SINGLE_BLOCK, startblk, resp) || MMCSD_R1_ERROR(resp[0])) return HAL_FAILED; } @@ -204,13 +201,13 @@ static bool sdc_lld_prepare_write(SDCDriver *sdcp, uint32_t startblk, if (n > 1) { /* Write multiple blocks command.*/ - if (sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_WRITE_MULTIPLE_BLOCK, + if (sdc_lld_send_cmd_short_crc(sdcp, SDMMC_CMD_CMDTRANS | MMCSD_CMD_WRITE_MULTIPLE_BLOCK, startblk, resp) || MMCSD_R1_ERROR(resp[0])) return HAL_FAILED; } else { /* Write single block command.*/ - if (sdc_lld_send_cmd_short_crc(sdcp, MMCSD_CMD_WRITE_BLOCK, + if (sdc_lld_send_cmd_short_crc(sdcp, SDMMC_CMD_CMDTRANS | MMCSD_CMD_WRITE_BLOCK, startblk, resp) || MMCSD_R1_ERROR(resp[0])) return HAL_FAILED; } @@ -380,19 +377,17 @@ void sdc_lld_init(void) { #if STM32_SDC_USE_SDMMC1 sdcObjectInit(&SDCD1); - SDCD1.thread = NULL; - SDCD1.rtmo = SDMMC1_READ_TIMEOUT; - SDCD1.wtmo = SDMMC1_WRITE_TIMEOUT; - SDCD1.sdmmc = SDMMC1; + SDCD1.thread = NULL; + SDCD1.sdmmc = SDMMC1; + SDCD1.clkfreq = STM32_SDMMC1CLK; nvicEnableVector(STM32_SDMMC1_NUMBER, STM32_SDC_SDMMC1_IRQ_PRIORITY); #endif #if STM32_SDC_USE_SDMMC2 sdcObjectInit(&SDCD2); - SDCD2.thread = NULL; - SDCD2.rtmo = SDMMC2_READ_TIMEOUT; - SDCD2.wtmo = SDMMC2_WRITE_TIMEOUT; - SDCD2.sdmmc = SDMMC2; + SDCD2.thread = NULL; + SDCD2.sdmmc = SDMMC2; + SDCD2.clkfreq = STM32_SDMMC2CLK; nvicEnableVector(STM32_SDMMC2_NUMBER, STM32_SDC_SDMMC2_IRQ_PRIORITY); #endif } @@ -479,7 +474,7 @@ void sdc_lld_stop(SDCDriver *sdcp) { void sdc_lld_start_clk(SDCDriver *sdcp) { /* Initial clock setting: 400kHz, 1bit mode.*/ - sdcp->sdmmc->CLKCR = SDMMC_CLKDIV_LS; + sdcp->sdmmc->CLKCR = sdc_lld_clkdiv(sdcp, 4000000); sdcp->sdmmc->POWER |= SDMMC_POWER_PWRCTRL_0 | SDMMC_POWER_PWRCTRL_1; /* TODO sdcp->sdmmc->CLKCR |= SDMMC_CLKCR_CLKEN;*/ @@ -497,34 +492,23 @@ void sdc_lld_start_clk(SDCDriver *sdcp) { */ void sdc_lld_set_data_clk(SDCDriver *sdcp, sdcbusclk_t clk) { -#if STM32_SDC_SDMMC_50MHZ if (SDC_CLK_50MHz == clk) { sdcp->sdmmc->CLKCR = (sdcp->sdmmc->CLKCR & 0xFFFFFF00U) | #if STM32_SDC_SDMMC_PWRSAV - SDMMC_CLKDIV_HS | SDMMC_CLKCR_BYPASS | - SDMMC_CLKCR_PWRSAV; + sdc_lld_clkdiv(sdcp, 50000000) | SDMMC_CLKCR_PWRSAV; #else - SDMMC_CLKDIV_HS | SDMMC_CLKCR_BYPASS; + sdc_lld_clkdiv(sdcp, 50000000); #endif } else { #if STM32_SDC_SDMMC_PWRSAV - sdcp->sdmmc->CLKCR = (sdcp->sdmmc->CLKCR & 0xFFFFFF00U) | SDMMC_CLKDIV_HS | - SDMMC_CLKCR_PWRSAV; + sdcp->sdmmc->CLKCR = (sdcp->sdmmc->CLKCR & 0xFFFFFF00U) | + sdc_lld_clkdiv(sdcp, 25000000) | SDMMC_CLKCR_PWRSAV; #else - sdcp->sdmmc->CLKCR = (sdcp->sdmmc->CLKCR & 0xFFFFFF00U) | SDMMC_CLKDIV_HS; + sdcp->sdmmc->CLKCR = (sdcp->sdmmc->CLKCR & 0xFFFFFF00U) | + sdc_lld_clkdiv(sdcp, 25000000); #endif } -#else - (void)clk; - -#if STM32_SDC_SDMMC_PWRSAV - sdcp->sdmmc->CLKCR = (sdcp->sdmmc->CLKCR & 0xFFFFFF00U) | SDMMC_CLKDIV_HS | - SDMMC_CLKCR_PWRSAV; -#else - sdcp->sdmmc->CLKCR = (sdcp->sdmmc->CLKCR & 0xFFFFFF00U) | SDMMC_CLKDIV_HS; -#endif -#endif } /** @@ -746,7 +730,7 @@ bool sdc_lld_read_aligned(SDCDriver *sdcp, uint32_t startblk, osalDbgCheck(blocks < 0x1000000 / MMCSD_BLOCK_SIZE); - sdcp->sdmmc->DTIMER = sdcp->rtmo; + sdcp->sdmmc->DTIMER = STM32_SDC_SDMMC_READ_TIMEOUT; /* Checks for errors and waits for the card to be ready for reading.*/ if (_sdc_wait_for_transfer_state(sdcp)) @@ -769,9 +753,6 @@ bool sdc_lld_read_aligned(SDCDriver *sdcp, uint32_t startblk, sdcp->sdmmc->IDMABASE0 = (uint32_t)buf; sdcp->sdmmc->IDMACTRL = SDMMC_IDMA_IDMAEN; - /* Transaction starts just after DTEN bit setting.*/ - sdcp->sdmmc->DCTRL |= SDMMC_DCTRL_DTEN; - if (sdc_lld_prepare_read(sdcp, startblk, blocks, resp) == true) goto error; @@ -805,7 +786,7 @@ bool sdc_lld_write_aligned(SDCDriver *sdcp, uint32_t startblk, osalDbgCheck(blocks < 0x1000000 / MMCSD_BLOCK_SIZE); - sdcp->sdmmc->DTIMER = sdcp->wtmo; + sdcp->sdmmc->DTIMER = STM32_SDC_SDMMC_WRITE_TIMEOUT; /* Checks for errors and waits for the card to be ready for writing.*/ if (_sdc_wait_for_transfer_state(sdcp)) @@ -831,9 +812,6 @@ bool sdc_lld_write_aligned(SDCDriver *sdcp, uint32_t startblk, sdcp->sdmmc->IDMABASE0 = (uint32_t)buf; sdcp->sdmmc->IDMACTRL = SDMMC_IDMA_IDMAEN; - /* Transaction starts just after DTEN bit setting.*/ - sdcp->sdmmc->DCTRL |= SDMMC_DCTRL_DTEN; - if (sdc_lld_wait_transaction_end(sdcp, blocks, resp) == true) goto error; diff --git a/os/hal/ports/STM32/LLD/SDMMCv2/hal_sdc_lld.h b/os/hal/ports/STM32/LLD/SDMMCv2/hal_sdc_lld.h index 5a434108c..97c0e56df 100644 --- a/os/hal/ports/STM32/LLD/SDMMCv2/hal_sdc_lld.h +++ b/os/hal/ports/STM32/LLD/SDMMCv2/hal_sdc_lld.h @@ -66,25 +66,17 @@ #endif /** - * @brief Enable clock bypass. - * @note Allow clock speed up to 50 Mhz. - */ -#if !defined(STM32_SDC_SDMMC_50MHZ) || defined(__DOXYGEN__) -#define STM32_SDC_SDMMC_50MHZ FALSE -#endif - -/** - * @brief Write timeout in milliseconds. + * @brief Write timeout in card clock cycles. */ #if !defined(STM32_SDC_SDMMC_WRITE_TIMEOUT) || defined(__DOXYGEN__) -#define STM32_SDC_SDMMC_WRITE_TIMEOUT 1000 +#define STM32_SDC_SDMMC_WRITE_TIMEOUT 1000000 #endif /** - * @brief Read timeout in milliseconds. + * @brief Read timeout in card clock cycles. */ #if !defined(STM32_SDC_SDMMC_READ_TIMEOUT) || defined(__DOXYGEN__) -#define STM32_SDC_SDMMC_READ_TIMEOUT 1000 +#define STM32_SDC_SDMMC_READ_TIMEOUT 1000000 #endif /** @@ -247,44 +239,40 @@ struct SDCDriverVMT { */ struct SDCDriver { /** - * @brief Virtual Methods Table. + * @brief Virtual Methods Table. */ const struct SDCDriverVMT *vmt; _mmcsd_block_device_data /** - * @brief Current configuration data. + * @brief Current configuration data. */ const SDCConfig *config; /** - * @brief Various flags regarding the mounted card. + * @brief Various flags regarding the mounted card. */ sdcmode_t cardmode; /** - * @brief Errors flags. + * @brief Errors flags. */ sdcflags_t errors; /** - * @brief Card RCA. + * @brief Card RCA. */ uint32_t rca; /* End of the mandatory fields.*/ /** - * @brief Thread waiting for I/O completion IRQ. + * @brief Thread waiting for I/O completion IRQ. */ thread_reference_t thread; /** - * @brief DTIMER register value for read operations. - */ - uint32_t rtmo; - /** - * @brief DTIMER register value for write operations. - */ - uint32_t wtmo; - /** - * @brief Pointer to the SDMMC registers block. - * @note Needed for debugging aid. + * @brief Pointer to the SDMMC registers block. + * @note Needed for debugging aid. */ SDMMC_TypeDef *sdmmc; + /** + * @brief Input clock frequency. + */ + uint32_t clkfreq; }; /*===========================================================================*/ diff --git a/testhal/STM32/multi/SDMMC-FATFS/cfg/stm32l4r9ai_discovery/mcuconf.h b/testhal/STM32/multi/SDMMC-FATFS/cfg/stm32l4r9ai_discovery/mcuconf.h index 87b45082f..224402aea 100644 --- a/testhal/STM32/multi/SDMMC-FATFS/cfg/stm32l4r9ai_discovery/mcuconf.h +++ b/testhal/STM32/multi/SDMMC-FATFS/cfg/stm32l4r9ai_discovery/mcuconf.h @@ -251,9 +251,8 @@ */ #define STM32_SDC_USE_SDMMC1 TRUE #define STM32_SDC_SDMMC_UNALIGNED_SUPPORT TRUE -#define STM32_SDC_SDMMC_50MHZ FALSE -#define STM32_SDC_SDMMC_WRITE_TIMEOUT 1000 -#define STM32_SDC_SDMMC_READ_TIMEOUT 1000 +#define STM32_SDC_SDMMC_WRITE_TIMEOUT 1000000 +#define STM32_SDC_SDMMC_READ_TIMEOUT 1000000 #define STM32_SDC_SDMMC_CLOCK_DELAY 10 #define STM32_SDC_SDMMC_PWRSAV TRUE #define STM32_SDC_SDMMC1_IRQ_PRIORITY 9