mirror of
https://github.com/RT-Thread/rt-thread.git
synced 2026-06-01 04:14:28 +08:00
fix[stm32[SDMMC]: Optimize SDMMC timeout handling and clock divider
RT-Thread BSP Static Build Check / 🔍 Summary of Git Diff Changes (push) Has been cancelled
pkgs_test / change (push) Has been cancelled
utest_auto_run / A9 :components/dfs.cfg (push) Has been cancelled
utest_auto_run / A9 :components/lwip.cfg (push) Has been cancelled
utest_auto_run / A9 :components/netdev.cfg (push) Has been cancelled
utest_auto_run / A9 :components/sal.cfg (push) Has been cancelled
utest_auto_run / A9 :cpp11/cpp11.cfg (push) Has been cancelled
utest_auto_run / AARCH64-rtsmart :default.cfg (push) Has been cancelled
utest_auto_run / A9-rtsmart :default.cfg (push) Has been cancelled
utest_auto_run / RISCV-rtsmart :default.cfg (push) Has been cancelled
utest_auto_run / XUANTIE-rtsmart :default.cfg (push) Has been cancelled
utest_auto_run / AARCH64 :default.cfg (push) Has been cancelled
utest_auto_run / AARCH64-smp :default.cfg (push) Has been cancelled
utest_auto_run / A9 :default.cfg (push) Has been cancelled
utest_auto_run / A9-smp :default.cfg (push) Has been cancelled
utest_auto_run / RISCV :default.cfg (push) Has been cancelled
utest_auto_run / RISCV-smp :default.cfg (push) Has been cancelled
utest_auto_run / A9 :kernel/atomic_c11.cfg (push) Has been cancelled
utest_auto_run / RISCV :kernel/atomic_c11.cfg (push) Has been cancelled
utest_auto_run / A9 :kernel/ipc.cfg (push) Has been cancelled
utest_auto_run / A9 :kernel/kernel_basic.cfg (push) Has been cancelled
utest_auto_run / A9 :kernel/mem.cfg (push) Has been cancelled
RT-Thread BSP Static Build Check / ${{ matrix.legs.RTT_BSP }} (push) Has been cancelled
RT-Thread BSP Static Build Check / collect-artifacts (push) Has been cancelled
Weekly CI Scheduler / Trigger and Monitor CIs (push) Has been cancelled
Weekly CI Scheduler / Create Discussion Report (push) Has been cancelled
RT-Thread BSP Static Build Check / 🔍 Summary of Git Diff Changes (push) Has been cancelled
pkgs_test / change (push) Has been cancelled
utest_auto_run / A9 :components/dfs.cfg (push) Has been cancelled
utest_auto_run / A9 :components/lwip.cfg (push) Has been cancelled
utest_auto_run / A9 :components/netdev.cfg (push) Has been cancelled
utest_auto_run / A9 :components/sal.cfg (push) Has been cancelled
utest_auto_run / A9 :cpp11/cpp11.cfg (push) Has been cancelled
utest_auto_run / AARCH64-rtsmart :default.cfg (push) Has been cancelled
utest_auto_run / A9-rtsmart :default.cfg (push) Has been cancelled
utest_auto_run / RISCV-rtsmart :default.cfg (push) Has been cancelled
utest_auto_run / XUANTIE-rtsmart :default.cfg (push) Has been cancelled
utest_auto_run / AARCH64 :default.cfg (push) Has been cancelled
utest_auto_run / AARCH64-smp :default.cfg (push) Has been cancelled
utest_auto_run / A9 :default.cfg (push) Has been cancelled
utest_auto_run / A9-smp :default.cfg (push) Has been cancelled
utest_auto_run / RISCV :default.cfg (push) Has been cancelled
utest_auto_run / RISCV-smp :default.cfg (push) Has been cancelled
utest_auto_run / A9 :kernel/atomic_c11.cfg (push) Has been cancelled
utest_auto_run / RISCV :kernel/atomic_c11.cfg (push) Has been cancelled
utest_auto_run / A9 :kernel/ipc.cfg (push) Has been cancelled
utest_auto_run / A9 :kernel/kernel_basic.cfg (push) Has been cancelled
utest_auto_run / A9 :kernel/mem.cfg (push) Has been cancelled
RT-Thread BSP Static Build Check / ${{ matrix.legs.RTT_BSP }} (push) Has been cancelled
RT-Thread BSP Static Build Check / collect-artifacts (push) Has been cancelled
Weekly CI Scheduler / Trigger and Monitor CIs (push) Has been cancelled
Weekly CI Scheduler / Create Discussion Report (push) Has been cancelled
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
* Copyright (c) 2006-2026 RT-Thread Development Team
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*
|
*
|
||||||
@@ -8,6 +8,7 @@
|
|||||||
* 2020-05-23 liuduanfei first version
|
* 2020-05-23 liuduanfei first version
|
||||||
* 2020-08-25 wanghaijing add sdmmmc2
|
* 2020-08-25 wanghaijing add sdmmmc2
|
||||||
* 2023-03-26 wdfk-prog Distinguish between SDMMC and SDIO drivers
|
* 2023-03-26 wdfk-prog Distinguish between SDMMC and SDIO drivers
|
||||||
|
* 2024-08-05 wdfk-prog Optimize SDMMC timeout handling and clock divider
|
||||||
*/
|
*/
|
||||||
#include "board.h"
|
#include "board.h"
|
||||||
|
|
||||||
@@ -27,7 +28,6 @@
|
|||||||
#endif /* DRV_DEBUG */
|
#endif /* DRV_DEBUG */
|
||||||
#include <rtdbg.h>
|
#include <rtdbg.h>
|
||||||
|
|
||||||
static struct stm32_sdio_class sdio_obj;
|
|
||||||
static struct rt_mmcsd_host *host1;
|
static struct rt_mmcsd_host *host1;
|
||||||
static struct rt_mmcsd_host *host2;
|
static struct rt_mmcsd_host *host2;
|
||||||
|
|
||||||
@@ -55,6 +55,11 @@ struct rthw_sdio
|
|||||||
rt_align(SDIO_ALIGN_LEN)
|
rt_align(SDIO_ALIGN_LEN)
|
||||||
static rt_uint8_t cache_buf[SDIO_BUFF_SIZE];
|
static rt_uint8_t cache_buf[SDIO_BUFF_SIZE];
|
||||||
|
|
||||||
|
static rt_uint32_t stm32_sdio_clk_get(void)
|
||||||
|
{
|
||||||
|
return SDIO_CLOCK_FREQ;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief This function get order from sdio.
|
* @brief This function get order from sdio.
|
||||||
* @param data
|
* @param data
|
||||||
@@ -154,10 +159,6 @@ static void rthw_sdio_wait_completed(struct rthw_sdio *sdio)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sdio->pkg == RT_NULL)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
/* Get Card Specific Data */
|
/* Get Card Specific Data */
|
||||||
cmd->resp[0] = hsd->RESP1;
|
cmd->resp[0] = hsd->RESP1;
|
||||||
if (resp_type(cmd) == RESP_R2)
|
if (resp_type(cmd) == RESP_R2)
|
||||||
@@ -221,6 +222,38 @@ static void rthw_sdio_wait_completed(struct rthw_sdio *sdio)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Calculate timeout for SDMMC data transfer.
|
||||||
|
*
|
||||||
|
* @note The timeout is estimated based on transfer size:
|
||||||
|
* timeout = 100 ms + 2 ms per 512 bytes.
|
||||||
|
* The result is clamped to the range [100 ms, 5000 ms].
|
||||||
|
*
|
||||||
|
* @param data Pointer to transfer data descriptor.
|
||||||
|
*
|
||||||
|
* @return Timeout in RT-Thread tick units.
|
||||||
|
*/
|
||||||
|
static rt_tick_t stm32_sdmmc_calc_timeout(struct rt_mmcsd_data *data)
|
||||||
|
{
|
||||||
|
rt_size_t len;
|
||||||
|
rt_uint32_t timeout_ms;
|
||||||
|
|
||||||
|
if (data == RT_NULL)
|
||||||
|
return rt_tick_from_millisecond(100);
|
||||||
|
|
||||||
|
len = data->blks * data->blksize;
|
||||||
|
|
||||||
|
/* base timeout + size-based timeout */
|
||||||
|
timeout_ms = 100 + (len / 512) * 2;
|
||||||
|
|
||||||
|
if (timeout_ms < 100)
|
||||||
|
timeout_ms = 100;
|
||||||
|
if (timeout_ms > 5000)
|
||||||
|
timeout_ms = 5000;
|
||||||
|
|
||||||
|
return rt_tick_from_millisecond(timeout_ms);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief This function send command.
|
* @brief This function send command.
|
||||||
* @param sdio rthw_sdio
|
* @param sdio rthw_sdio
|
||||||
@@ -262,7 +295,7 @@ static void rthw_sdio_send_command(struct rthw_sdio *sdio, struct sdio_pkg *pkg)
|
|||||||
/* data pre configuration */
|
/* data pre configuration */
|
||||||
if (data != RT_NULL)
|
if (data != RT_NULL)
|
||||||
{
|
{
|
||||||
SCB_CleanInvalidateDCache();
|
rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, cache_buf, data->blks * data->blksize);
|
||||||
|
|
||||||
reg_cmd |= SDMMC_CMD_CMDTRANS;
|
reg_cmd |= SDMMC_CMD_CMDTRANS;
|
||||||
__HAL_SD_DISABLE_IT(&sdio->sdio_des.hw_sdio, SDMMC_MASK_CMDRENDIE | SDMMC_MASK_CMDSENTIE);
|
__HAL_SD_DISABLE_IT(&sdio->sdio_des.hw_sdio, SDMMC_MASK_CMDRENDIE | SDMMC_MASK_CMDSENTIE);
|
||||||
@@ -292,14 +325,19 @@ static void rthw_sdio_send_command(struct rthw_sdio *sdio, struct sdio_pkg *pkg)
|
|||||||
/* Waiting for data to be sent to completion */
|
/* Waiting for data to be sent to completion */
|
||||||
if (data != RT_NULL)
|
if (data != RT_NULL)
|
||||||
{
|
{
|
||||||
volatile rt_uint32_t count = SDIO_TX_RX_COMPLETE_TIMEOUT_LOOPS;
|
rt_tick_t start = rt_tick_get();
|
||||||
|
rt_tick_t timeout = stm32_sdmmc_calc_timeout(data);
|
||||||
|
|
||||||
while (count && (hsd->STA & SDMMC_STA_DPSMACT))
|
while (hsd->STA & SDMMC_STA_DPSMACT)
|
||||||
{
|
{
|
||||||
count--;
|
if ((rt_tick_get() - start) >= timeout)
|
||||||
|
{
|
||||||
|
cmd->err = -RT_ETIMEOUT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((count == 0) || (hsd->STA & SDIO_ERRORS))
|
if ((hsd->STA & SDIO_ERRORS) != 0)
|
||||||
{
|
{
|
||||||
cmd->err = -RT_ERROR;
|
cmd->err = -RT_ERROR;
|
||||||
}
|
}
|
||||||
@@ -311,7 +349,7 @@ static void rthw_sdio_send_command(struct rthw_sdio *sdio, struct sdio_pkg *pkg)
|
|||||||
if (data->flags & DATA_DIR_READ)
|
if (data->flags & DATA_DIR_READ)
|
||||||
{
|
{
|
||||||
rt_memcpy(data->buf, cache_buf, data->blks * data->blksize);
|
rt_memcpy(data->buf, cache_buf, data->blks * data->blksize);
|
||||||
SCB_CleanInvalidateDCache();
|
rt_hw_cpu_dcache_ops(RT_HW_CACHE_INVALIDATE, cache_buf, data->blks * data->blksize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -371,143 +409,129 @@ static void rthw_sdio_request(struct rt_mmcsd_host *host, struct rt_mmcsd_req *r
|
|||||||
*/
|
*/
|
||||||
static void rthw_sdio_iocfg(struct rt_mmcsd_host *host, struct rt_mmcsd_io_cfg *io_cfg)
|
static void rthw_sdio_iocfg(struct rt_mmcsd_host *host, struct rt_mmcsd_io_cfg *io_cfg)
|
||||||
{
|
{
|
||||||
rt_uint32_t temp, clk_src;
|
rt_uint32_t req_clk = io_cfg->clock;
|
||||||
rt_uint32_t clk = io_cfg->clock;
|
rt_uint32_t clk = req_clk;
|
||||||
struct rthw_sdio *sdio = host->private_data;
|
struct rthw_sdio *sdio = host->private_data;
|
||||||
SD_HandleTypeDef *hsd = &sdio->sdio_des.hw_sdio;
|
SD_HandleTypeDef *hsd = &sdio->sdio_des.hw_sdio;
|
||||||
SDMMC_InitTypeDef Init = {0};
|
SDMMC_InitTypeDef Init = {0};
|
||||||
rt_uint32_t sdmmc_clk = sdio->sdio_des.clk_get();
|
rt_uint32_t sdmmc_clk = sdio->sdio_des.clk_get();
|
||||||
|
|
||||||
if (sdmmc_clk < 400 * 1000)
|
rt_bool_t stop_flag = RT_TRUE;
|
||||||
{
|
switch (io_cfg->power_mode & 0X03)
|
||||||
LOG_E("The clock rate is too low! rata:%d", sdmmc_clk);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (clk > host->freq_max)
|
|
||||||
clk = host->freq_max;
|
|
||||||
|
|
||||||
if (clk > sdmmc_clk)
|
|
||||||
{
|
|
||||||
LOG_W("Setting rate is greater than clock source rate.");
|
|
||||||
clk = sdmmc_clk;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_D("clk:%dK width:%s%s%s power:%s%s%s",
|
|
||||||
clk / 1000,
|
|
||||||
io_cfg->bus_width == MMCSD_BUS_WIDTH_8 ? "8" : "",
|
|
||||||
io_cfg->bus_width == MMCSD_BUS_WIDTH_4 ? "4" : "",
|
|
||||||
io_cfg->bus_width == MMCSD_BUS_WIDTH_1 ? "1" : "",
|
|
||||||
io_cfg->power_mode == MMCSD_POWER_OFF ? "OFF" : "",
|
|
||||||
io_cfg->power_mode == MMCSD_POWER_UP ? "UP" : "",
|
|
||||||
io_cfg->power_mode == MMCSD_POWER_ON ? "ON" : ""
|
|
||||||
);
|
|
||||||
|
|
||||||
if (sdmmc_clk != 0U)
|
|
||||||
{
|
|
||||||
hsd->Init.ClockDiv = sdmmc_clk / (2U * SD_INIT_FREQ);
|
|
||||||
/* Configure the SDMMC peripheral */
|
|
||||||
Init.ClockEdge = hsd->Init.ClockEdge;
|
|
||||||
Init.ClockPowerSave = hsd->Init.ClockPowerSave;
|
|
||||||
if (io_cfg->bus_width == MMCSD_BUS_WIDTH_4)
|
|
||||||
{
|
|
||||||
Init.BusWide = SDMMC_BUS_WIDE_4B;
|
|
||||||
}
|
|
||||||
else if (io_cfg->bus_width == MMCSD_BUS_WIDTH_8)
|
|
||||||
{
|
|
||||||
Init.BusWide = SDMMC_BUS_WIDE_8B;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Init.BusWide = SDMMC_BUS_WIDE_1B;
|
|
||||||
}
|
|
||||||
Init.HardwareFlowControl = hsd->Init.HardwareFlowControl;
|
|
||||||
/* Check if user Clock div < Normal speed 25Mhz, no change in Clockdiv */
|
|
||||||
if (hsd->Init.ClockDiv >= (sdmmc_clk / (2U * SD_NORMAL_SPEED_FREQ)))
|
|
||||||
{
|
|
||||||
Init.ClockDiv = hsd->Init.ClockDiv;
|
|
||||||
}
|
|
||||||
//CARD_ULTRA_HIGH_SPEED :UHS-I SD Card <50Mo/s for SDR50, DDR5 Cards and <104Mo/s for SDR104, Spec version 3.01
|
|
||||||
else if (MMCSD_TIMING_UHS_SDR50 <= io_cfg->timing && io_cfg->timing <= MMCSD_TIMING_UHS_DDR50)
|
|
||||||
{
|
|
||||||
/* UltraHigh speed SD card,user Clock div */
|
|
||||||
Init.ClockDiv = hsd->Init.ClockDiv;
|
|
||||||
}
|
|
||||||
//CARD_HIGH_SPEED: High Speed Card <25Mo/s , Spec version 2.00
|
|
||||||
else if (io_cfg->timing == MMCSD_TIMING_SD_HS)
|
|
||||||
{
|
|
||||||
/* High speed SD card, Max Frequency = 50Mhz */
|
|
||||||
if (hsd->Init.ClockDiv == 0U)
|
|
||||||
{
|
|
||||||
if (sdmmc_clk > SD_HIGH_SPEED_FREQ)
|
|
||||||
{
|
|
||||||
Init.ClockDiv = sdmmc_clk / (2U * SD_HIGH_SPEED_FREQ);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Init.ClockDiv = hsd->Init.ClockDiv;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if ((sdmmc_clk/(2U * hsd->Init.ClockDiv)) > SD_HIGH_SPEED_FREQ)
|
|
||||||
{
|
|
||||||
Init.ClockDiv = sdmmc_clk / (2U * SD_HIGH_SPEED_FREQ);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Init.ClockDiv = hsd->Init.ClockDiv;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//CARD_NORMAL_SPEED: Normal Speed Card <12.5Mo/s , Spec Version 1.01
|
|
||||||
else if (io_cfg->timing == MMCSD_TIMING_LEGACY)
|
|
||||||
{
|
|
||||||
/* No High speed SD card, Max Frequency = 25Mhz */
|
|
||||||
if (hsd->Init.ClockDiv == 0U)
|
|
||||||
{
|
|
||||||
if (sdmmc_clk > SD_NORMAL_SPEED_FREQ)
|
|
||||||
{
|
|
||||||
Init.ClockDiv = sdmmc_clk / (2U * SD_NORMAL_SPEED_FREQ);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Init.ClockDiv = hsd->Init.ClockDiv;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if ((sdmmc_clk/(2U * hsd->Init.ClockDiv)) > SD_NORMAL_SPEED_FREQ)
|
|
||||||
{
|
|
||||||
Init.ClockDiv = sdmmc_clk / (2U * SD_NORMAL_SPEED_FREQ);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Init.ClockDiv = hsd->Init.ClockDiv;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(void)SDMMC_Init(hsd->Instance, Init);
|
|
||||||
}
|
|
||||||
switch ((io_cfg->power_mode)&0X03)
|
|
||||||
{
|
{
|
||||||
case MMCSD_POWER_OFF:
|
case MMCSD_POWER_OFF:
|
||||||
/* Set Power State to OFF */
|
/* Set Power State to OFF */
|
||||||
(void)SDMMC_PowerState_OFF(hsd->Instance);
|
(void)SDMMC_PowerState_OFF(hsd->Instance);
|
||||||
|
stop_flag = RT_TRUE;
|
||||||
break;
|
break;
|
||||||
case MMCSD_POWER_UP:
|
case MMCSD_POWER_UP:
|
||||||
/* In F4 series chips, 0X01 is reserved bit and has no practical effect.
|
/* In F4 series chips, 0X01 is reserved bit and has no practical effect.
|
||||||
For F7 series chips, 0X01 is power-on after power-off,The SDMMC disables the function and the card clock stops.
|
For F7 series chips, 0X01 is power-on after power-off,The SDMMC disables the function and the card clock stops.
|
||||||
For H7 series chips, 0X03 is the power-on function.
|
For H7 series chips, 0X03 is the power-on function.
|
||||||
*/
|
*/
|
||||||
|
stop_flag = RT_TRUE;
|
||||||
|
break;
|
||||||
case MMCSD_POWER_ON:
|
case MMCSD_POWER_ON:
|
||||||
/* Set Power State to ON */
|
stop_flag = RT_FALSE;
|
||||||
(void)SDMMC_PowerState_ON(hsd->Instance);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
LOG_W("unknown power mode %d", io_cfg->power_mode);
|
LOG_W("unknown power mode %d", io_cfg->power_mode);
|
||||||
|
stop_flag = RT_FALSE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if(stop_flag == RT_TRUE)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clk == 0U)
|
||||||
|
{
|
||||||
|
LOG_E("invalid target clock: 0");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sdmmc_clk < 400 * 1000)
|
||||||
|
{
|
||||||
|
LOG_E("The clock rate is too low! rate:%u", sdmmc_clk);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clk > host->freq_max)
|
||||||
|
clk = host->freq_max;
|
||||||
|
|
||||||
|
if (clk > (sdmmc_clk / 2U))
|
||||||
|
{
|
||||||
|
LOG_W("Setting rate is greater than controller max output rate.");
|
||||||
|
clk = sdmmc_clk / 2U;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Configure the SDMMC peripheral */
|
||||||
|
Init.ClockEdge = hsd->Init.ClockEdge;
|
||||||
|
Init.ClockPowerSave = hsd->Init.ClockPowerSave;
|
||||||
|
if (io_cfg->bus_width == MMCSD_BUS_WIDTH_4)
|
||||||
|
{
|
||||||
|
Init.BusWide = SDMMC_BUS_WIDE_4B;
|
||||||
|
}
|
||||||
|
else if (io_cfg->bus_width == MMCSD_BUS_WIDTH_8)
|
||||||
|
{
|
||||||
|
Init.BusWide = SDMMC_BUS_WIDE_8B;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Init.BusWide = SDMMC_BUS_WIDE_1B;
|
||||||
|
}
|
||||||
|
Init.HardwareFlowControl = hsd->Init.HardwareFlowControl;
|
||||||
|
|
||||||
|
/* Identification mode: use initialization frequency */
|
||||||
|
if (clk <= SD_INIT_FREQ)
|
||||||
|
{
|
||||||
|
clk = SD_INIT_FREQ;
|
||||||
|
}
|
||||||
|
/* CARD_HIGH_SPEED: High Speed Card <50Mo/s , Spec version 2.00 */
|
||||||
|
else if (io_cfg->timing == MMCSD_TIMING_SD_HS)
|
||||||
|
{
|
||||||
|
/* High speed SD card, Max Frequency = 50Mhz */
|
||||||
|
if (clk > SD_HIGH_SPEED_FREQ)
|
||||||
|
clk = SD_HIGH_SPEED_FREQ;
|
||||||
|
}
|
||||||
|
/* CARD_NORMAL_SPEED: Normal Speed Card <12.5Mo/s , Spec Version 1.01 */
|
||||||
|
else if (io_cfg->timing == MMCSD_TIMING_LEGACY)
|
||||||
|
{
|
||||||
|
/* No High speed SD card, Max Frequency = 25Mhz */
|
||||||
|
if (clk > SD_NORMAL_SPEED_FREQ)
|
||||||
|
clk = SD_NORMAL_SPEED_FREQ;
|
||||||
|
}
|
||||||
|
/* CARD_ULTRA_HIGH_SPEED :UHS-I SD Card <50Mo/s for SDR50, DDR5 Cards and <104Mo/s for SDR104, Spec version 3.01 UltraHigh speed SD card */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* UltraHigh speed SD card,user Clock div: keep clk */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Round-up division to ensure SDMMC_CK does not exceed target clk
|
||||||
|
* SDMMC_CK = SDMMCCLK / (2 * ClockDiv)
|
||||||
|
*/
|
||||||
|
Init.ClockDiv = (sdmmc_clk + (2U * clk) - 1U) / (2U * clk);
|
||||||
|
|
||||||
|
LOG_D("clk_req:%uK clk_set:%uK clk_real:%uK div:%u width:%s%s%s power:%s%s%s",
|
||||||
|
req_clk / 1000U,
|
||||||
|
clk / 1000U,
|
||||||
|
(Init.ClockDiv != 0U) ? (sdmmc_clk / (2U * Init.ClockDiv)) / 1000U : 0U,
|
||||||
|
Init.ClockDiv,
|
||||||
|
io_cfg->bus_width == MMCSD_BUS_WIDTH_8 ? "8" : "",
|
||||||
|
io_cfg->bus_width == MMCSD_BUS_WIDTH_4 ? "4" : "",
|
||||||
|
io_cfg->bus_width == MMCSD_BUS_WIDTH_1 ? "1" : "",
|
||||||
|
(io_cfg->power_mode & 0x03) == MMCSD_POWER_OFF ? "OFF" : "",
|
||||||
|
(io_cfg->power_mode & 0x03) == MMCSD_POWER_UP ? "UP" : "",
|
||||||
|
(io_cfg->power_mode & 0x03) == MMCSD_POWER_ON ? "ON" : ""
|
||||||
|
);
|
||||||
|
|
||||||
|
(void)SDMMC_Init(hsd->Instance, Init);
|
||||||
|
|
||||||
|
if((io_cfg->power_mode & 0X03) == MMCSD_POWER_ON)
|
||||||
|
{
|
||||||
|
/* Set Power State to ON */
|
||||||
|
(void)SDMMC_PowerState_ON(hsd->Instance);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -528,7 +552,7 @@ void rthw_sdio_irq_update(struct rt_mmcsd_host *host, rt_int32_t enable)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
LOG_D("disable sdio irq");
|
LOG_D("disable sdio irq");
|
||||||
__HAL_SD_ENABLE_IT(&sdio->sdio_des.hw_sdio, SDMMC_IT_SDIOIT);
|
__HAL_SD_DISABLE_IT(&sdio->sdio_des.hw_sdio, SDMMC_IT_SDIOIT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -578,7 +602,7 @@ struct rt_mmcsd_host *sdio_host_create(struct stm32_sdio_des *sdio_des)
|
|||||||
|
|
||||||
if (sdio_des == RT_NULL)
|
if (sdio_des == RT_NULL)
|
||||||
{
|
{
|
||||||
LOG_E("L:%d F:%s",(sdio_des == RT_NULL ? "sdio_des is NULL" : ""));
|
LOG_E("sdio_des is NULL");
|
||||||
return RT_NULL;
|
return RT_NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -586,7 +610,7 @@ struct rt_mmcsd_host *sdio_host_create(struct stm32_sdio_des *sdio_des)
|
|||||||
|
|
||||||
if (sdio == RT_NULL)
|
if (sdio == RT_NULL)
|
||||||
{
|
{
|
||||||
LOG_E("L:%d F:%s malloc rthw_sdio fail");
|
LOG_E("malloc rthw_sdio fail");
|
||||||
return RT_NULL;
|
return RT_NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -596,12 +620,13 @@ struct rt_mmcsd_host *sdio_host_create(struct stm32_sdio_des *sdio_des)
|
|||||||
|
|
||||||
if (host == RT_NULL)
|
if (host == RT_NULL)
|
||||||
{
|
{
|
||||||
LOG_E("L:%d F:%s mmcsd alloc host fail");
|
LOG_E("mmcsd alloc host fail");
|
||||||
rt_free(sdio);
|
rt_free(sdio);
|
||||||
return RT_NULL;
|
return RT_NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
rt_memcpy(&sdio->sdio_des, sdio_des, sizeof(struct stm32_sdio_des));
|
rt_memcpy(&sdio->sdio_des, sdio_des, sizeof(struct stm32_sdio_des));
|
||||||
|
sdio->sdio_des.clk_get = (sdio_des->clk_get == RT_NULL ? stm32_sdio_clk_get : sdio_des->clk_get);
|
||||||
#ifdef BSP_USING_SDIO1
|
#ifdef BSP_USING_SDIO1
|
||||||
if(sdio_des->hw_sdio.Instance == SDMMC1)
|
if(sdio_des->hw_sdio.Instance == SDMMC1)
|
||||||
{
|
{
|
||||||
@@ -630,14 +655,14 @@ struct rt_mmcsd_host *sdio_host_create(struct stm32_sdio_des *sdio_des)
|
|||||||
#endif
|
#endif
|
||||||
host->max_seg_size = SDIO_BUFF_SIZE;
|
host->max_seg_size = SDIO_BUFF_SIZE;
|
||||||
host->max_dma_segs = 1;
|
host->max_dma_segs = 1;
|
||||||
host->max_blk_size = 512;
|
host->max_blk_size = BLOCKSIZE;
|
||||||
host->max_blk_count = 512;
|
host->max_blk_count = SDIO_BUFF_SIZE / host->max_blk_size;
|
||||||
|
|
||||||
/* link up host and sdio */
|
/* link up host and sdio */
|
||||||
sdio->host = host;
|
sdio->host = host;
|
||||||
host->private_data = sdio;
|
host->private_data = sdio;
|
||||||
|
|
||||||
rthw_sdio_irq_update(host, 1);
|
rthw_sdio_irq_update(host, RT_TRUE);
|
||||||
|
|
||||||
/* ready to change */
|
/* ready to change */
|
||||||
mmcsd_change(host);
|
mmcsd_change(host);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2006-2023, RT-Thread Development Team
|
* Copyright (c) 2006-2026 RT-Thread Development Team
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*
|
*
|
||||||
@@ -8,6 +8,7 @@
|
|||||||
* 2020-05-23 liuduanfei first version
|
* 2020-05-23 liuduanfei first version
|
||||||
* 2020-08-25 wanghaijing add sdmmmc2
|
* 2020-08-25 wanghaijing add sdmmmc2
|
||||||
* 2023-03-26 wdfk-prog Distinguish between SDMMC and SDIO drivers
|
* 2023-03-26 wdfk-prog Distinguish between SDMMC and SDIO drivers
|
||||||
|
* 2024-08-05 wdfk-prog Optimize SDMMC timeout handling and clock divider
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __DRV_SDMMC_H__
|
#ifndef __DRV_SDMMC_H__
|
||||||
@@ -21,9 +22,6 @@
|
|||||||
#include <drivers/dev_mmcsd_core.h>
|
#include <drivers/dev_mmcsd_core.h>
|
||||||
#include <drivers/dev_sdio.h>
|
#include <drivers/dev_sdio.h>
|
||||||
|
|
||||||
#define SDIO_BUFF_SIZE 4096
|
|
||||||
#define SDIO_ALIGN_LEN 32
|
|
||||||
|
|
||||||
#define SDIO1_BASE_ADDRESS (SDMMC1_BASE)
|
#define SDIO1_BASE_ADDRESS (SDMMC1_BASE)
|
||||||
#define SDIO2_BASE_ADDRESS (SDMMC2_BASE)
|
#define SDIO2_BASE_ADDRESS (SDMMC2_BASE)
|
||||||
|
|
||||||
@@ -39,15 +37,15 @@
|
|||||||
#define SDIO_ALIGN_LEN (32)
|
#define SDIO_ALIGN_LEN (32)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef SDIO_MAX_FREQ
|
|
||||||
#define SDIO_MAX_FREQ (25 * 1000 * 1000)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Frequencies used in the driver for clock divider calculation */
|
/* Frequencies used in the driver for clock divider calculation */
|
||||||
#define SD_INIT_FREQ 400000U /* Initalization phase : 400 kHz max */
|
#define SD_INIT_FREQ 400000U /* Initalization phase : 400 kHz max */
|
||||||
#define SD_NORMAL_SPEED_FREQ 25000000U /* Normal speed phase : 25 MHz max */
|
#define SD_NORMAL_SPEED_FREQ 25000000U /* Normal speed phase : 25 MHz max */
|
||||||
#define SD_HIGH_SPEED_FREQ 50000000U /* High speed phase : 50 MHz max */
|
#define SD_HIGH_SPEED_FREQ 50000000U /* High speed phase : 50 MHz max */
|
||||||
|
|
||||||
|
#ifndef SDIO_MAX_FREQ
|
||||||
|
#define SDIO_MAX_FREQ (SD_HIGH_SPEED_FREQ)
|
||||||
|
#endif
|
||||||
|
|
||||||
#define SDIO_ERRORS \
|
#define SDIO_ERRORS \
|
||||||
(SDMMC_STA_IDMATE | SDMMC_STA_ACKTIMEOUT | \
|
(SDMMC_STA_IDMATE | SDMMC_STA_ACKTIMEOUT | \
|
||||||
SDMMC_STA_RXOVERR | SDMMC_STA_TXUNDERR | \
|
SDMMC_STA_RXOVERR | SDMMC_STA_TXUNDERR | \
|
||||||
|
|||||||
Reference in New Issue
Block a user