SDMMCv2 improvements.

git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@13276 27425a3e-05d8-49a3-a47f-9c15f0e5edd8
This commit is contained in:
Giovanni Di Sirio 2020-01-16 10:03:26 +00:00
parent f2fe3c2a49
commit 2af65517ae
3 changed files with 55 additions and 90 deletions

View File

@ -39,23 +39,6 @@
SDMMC_STA_CTIMEOUT | SDMMC_STA_DTIMEOUT | \ SDMMC_STA_CTIMEOUT | SDMMC_STA_DTIMEOUT | \
SDMMC_STA_TXUNDERR | SDMMC_STA_RXOVERR) 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. */ /* Driver exported variables. */
/*===========================================================================*/ /*===========================================================================*/
@ -96,6 +79,23 @@ static const SDCConfig sdc_default_cfg = {
/* Driver local functions. */ /* 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. * @brief Prepares to handle read transaction.
* @details Designed for read special registers from card. * @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) { uint8_t *buf, uint32_t bytes) {
osalDbgCheck(bytes < 0x1000000); 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.*/ /* Checks for errors and waits for the card to be ready for reading.*/
if (_sdc_wait_for_transfer_state(sdcp)) 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->IDMABASE0 = (uint32_t)buf;
sdcp->sdmmc->IDMACTRL = SDMMC_IDMA_IDMAEN; sdcp->sdmmc->IDMACTRL = SDMMC_IDMA_IDMAEN;
/* Transaction starts just after DTEN bit setting.*/
// sdcp->sdmmc->DCTRL |= SDMMC_DCTRL_DTEN;
return HAL_SUCCESS; return HAL_SUCCESS;
} }
@ -166,13 +163,13 @@ static bool sdc_lld_prepare_read(SDCDriver *sdcp, uint32_t startblk,
if (n > 1) { if (n > 1) {
/* Send read multiple blocks command to card.*/ /* 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])) startblk, resp) || MMCSD_R1_ERROR(resp[0]))
return HAL_FAILED; return HAL_FAILED;
} }
else { else {
/* Send read single block command.*/ /* 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])) startblk, resp) || MMCSD_R1_ERROR(resp[0]))
return HAL_FAILED; return HAL_FAILED;
} }
@ -204,13 +201,13 @@ static bool sdc_lld_prepare_write(SDCDriver *sdcp, uint32_t startblk,
if (n > 1) { if (n > 1) {
/* Write multiple blocks command.*/ /* 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])) startblk, resp) || MMCSD_R1_ERROR(resp[0]))
return HAL_FAILED; return HAL_FAILED;
} }
else { else {
/* Write single block command.*/ /* 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])) startblk, resp) || MMCSD_R1_ERROR(resp[0]))
return HAL_FAILED; return HAL_FAILED;
} }
@ -381,18 +378,16 @@ void sdc_lld_init(void) {
#if STM32_SDC_USE_SDMMC1 #if STM32_SDC_USE_SDMMC1
sdcObjectInit(&SDCD1); sdcObjectInit(&SDCD1);
SDCD1.thread = NULL; SDCD1.thread = NULL;
SDCD1.rtmo = SDMMC1_READ_TIMEOUT;
SDCD1.wtmo = SDMMC1_WRITE_TIMEOUT;
SDCD1.sdmmc = SDMMC1; SDCD1.sdmmc = SDMMC1;
SDCD1.clkfreq = STM32_SDMMC1CLK;
nvicEnableVector(STM32_SDMMC1_NUMBER, STM32_SDC_SDMMC1_IRQ_PRIORITY); nvicEnableVector(STM32_SDMMC1_NUMBER, STM32_SDC_SDMMC1_IRQ_PRIORITY);
#endif #endif
#if STM32_SDC_USE_SDMMC2 #if STM32_SDC_USE_SDMMC2
sdcObjectInit(&SDCD2); sdcObjectInit(&SDCD2);
SDCD2.thread = NULL; SDCD2.thread = NULL;
SDCD2.rtmo = SDMMC2_READ_TIMEOUT;
SDCD2.wtmo = SDMMC2_WRITE_TIMEOUT;
SDCD2.sdmmc = SDMMC2; SDCD2.sdmmc = SDMMC2;
SDCD2.clkfreq = STM32_SDMMC2CLK;
nvicEnableVector(STM32_SDMMC2_NUMBER, STM32_SDC_SDMMC2_IRQ_PRIORITY); nvicEnableVector(STM32_SDMMC2_NUMBER, STM32_SDC_SDMMC2_IRQ_PRIORITY);
#endif #endif
} }
@ -479,7 +474,7 @@ void sdc_lld_stop(SDCDriver *sdcp) {
void sdc_lld_start_clk(SDCDriver *sdcp) { void sdc_lld_start_clk(SDCDriver *sdcp) {
/* Initial clock setting: 400kHz, 1bit mode.*/ /* 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; sdcp->sdmmc->POWER |= SDMMC_POWER_PWRCTRL_0 | SDMMC_POWER_PWRCTRL_1;
/* TODO sdcp->sdmmc->CLKCR |= SDMMC_CLKCR_CLKEN;*/ /* 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) { void sdc_lld_set_data_clk(SDCDriver *sdcp, sdcbusclk_t clk) {
#if STM32_SDC_SDMMC_50MHZ
if (SDC_CLK_50MHz == clk) { if (SDC_CLK_50MHz == clk) {
sdcp->sdmmc->CLKCR = (sdcp->sdmmc->CLKCR & 0xFFFFFF00U) | sdcp->sdmmc->CLKCR = (sdcp->sdmmc->CLKCR & 0xFFFFFF00U) |
#if STM32_SDC_SDMMC_PWRSAV #if STM32_SDC_SDMMC_PWRSAV
SDMMC_CLKDIV_HS | SDMMC_CLKCR_BYPASS | sdc_lld_clkdiv(sdcp, 50000000) | SDMMC_CLKCR_PWRSAV;
SDMMC_CLKCR_PWRSAV;
#else #else
SDMMC_CLKDIV_HS | SDMMC_CLKCR_BYPASS; sdc_lld_clkdiv(sdcp, 50000000);
#endif #endif
} }
else { else {
#if STM32_SDC_SDMMC_PWRSAV #if STM32_SDC_SDMMC_PWRSAV
sdcp->sdmmc->CLKCR = (sdcp->sdmmc->CLKCR & 0xFFFFFF00U) | SDMMC_CLKDIV_HS | sdcp->sdmmc->CLKCR = (sdcp->sdmmc->CLKCR & 0xFFFFFF00U) |
SDMMC_CLKCR_PWRSAV; sdc_lld_clkdiv(sdcp, 25000000) | SDMMC_CLKCR_PWRSAV;
#else #else
sdcp->sdmmc->CLKCR = (sdcp->sdmmc->CLKCR & 0xFFFFFF00U) | SDMMC_CLKDIV_HS; sdcp->sdmmc->CLKCR = (sdcp->sdmmc->CLKCR & 0xFFFFFF00U) |
sdc_lld_clkdiv(sdcp, 25000000);
#endif #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); 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.*/ /* Checks for errors and waits for the card to be ready for reading.*/
if (_sdc_wait_for_transfer_state(sdcp)) 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->IDMABASE0 = (uint32_t)buf;
sdcp->sdmmc->IDMACTRL = SDMMC_IDMA_IDMAEN; 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) if (sdc_lld_prepare_read(sdcp, startblk, blocks, resp) == true)
goto error; goto error;
@ -805,7 +786,7 @@ bool sdc_lld_write_aligned(SDCDriver *sdcp, uint32_t startblk,
osalDbgCheck(blocks < 0x1000000 / MMCSD_BLOCK_SIZE); 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.*/ /* Checks for errors and waits for the card to be ready for writing.*/
if (_sdc_wait_for_transfer_state(sdcp)) 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->IDMABASE0 = (uint32_t)buf;
sdcp->sdmmc->IDMACTRL = SDMMC_IDMA_IDMAEN; 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) if (sdc_lld_wait_transaction_end(sdcp, blocks, resp) == true)
goto error; goto error;

View File

@ -66,25 +66,17 @@
#endif #endif
/** /**
* @brief Enable clock bypass. * @brief Write timeout in card clock cycles.
* @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.
*/ */
#if !defined(STM32_SDC_SDMMC_WRITE_TIMEOUT) || defined(__DOXYGEN__) #if !defined(STM32_SDC_SDMMC_WRITE_TIMEOUT) || defined(__DOXYGEN__)
#define STM32_SDC_SDMMC_WRITE_TIMEOUT 1000 #define STM32_SDC_SDMMC_WRITE_TIMEOUT 1000000
#endif #endif
/** /**
* @brief Read timeout in milliseconds. * @brief Read timeout in card clock cycles.
*/ */
#if !defined(STM32_SDC_SDMMC_READ_TIMEOUT) || defined(__DOXYGEN__) #if !defined(STM32_SDC_SDMMC_READ_TIMEOUT) || defined(__DOXYGEN__)
#define STM32_SDC_SDMMC_READ_TIMEOUT 1000 #define STM32_SDC_SDMMC_READ_TIMEOUT 1000000
#endif #endif
/** /**
@ -272,19 +264,15 @@ struct SDCDriver {
* @brief Thread waiting for I/O completion IRQ. * @brief Thread waiting for I/O completion IRQ.
*/ */
thread_reference_t thread; 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. * @brief Pointer to the SDMMC registers block.
* @note Needed for debugging aid. * @note Needed for debugging aid.
*/ */
SDMMC_TypeDef *sdmmc; SDMMC_TypeDef *sdmmc;
/**
* @brief Input clock frequency.
*/
uint32_t clkfreq;
}; };
/*===========================================================================*/ /*===========================================================================*/

View File

@ -251,9 +251,8 @@
*/ */
#define STM32_SDC_USE_SDMMC1 TRUE #define STM32_SDC_USE_SDMMC1 TRUE
#define STM32_SDC_SDMMC_UNALIGNED_SUPPORT TRUE #define STM32_SDC_SDMMC_UNALIGNED_SUPPORT TRUE
#define STM32_SDC_SDMMC_50MHZ FALSE #define STM32_SDC_SDMMC_WRITE_TIMEOUT 1000000
#define STM32_SDC_SDMMC_WRITE_TIMEOUT 1000 #define STM32_SDC_SDMMC_READ_TIMEOUT 1000000
#define STM32_SDC_SDMMC_READ_TIMEOUT 1000
#define STM32_SDC_SDMMC_CLOCK_DELAY 10 #define STM32_SDC_SDMMC_CLOCK_DELAY 10
#define STM32_SDC_SDMMC_PWRSAV TRUE #define STM32_SDC_SDMMC_PWRSAV TRUE
#define STM32_SDC_SDMMC1_IRQ_PRIORITY 9 #define STM32_SDC_SDMMC1_IRQ_PRIORITY 9