Skip to content

Commit 82d65b8

Browse files
committed
fix(stm32): Optimize SDMMC timeout handling and clock divider
1 parent cda0a63 commit 82d65b8

File tree

2 files changed

+146
-85
lines changed

2 files changed

+146
-85
lines changed

bsp/stm32/libraries/HAL_Drivers/drivers/drv_sdmmc.c

Lines changed: 140 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2006-2023, RT-Thread Development Team
2+
* Copyright (c) 2006-2024 RT-Thread Development Team
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*
@@ -8,6 +8,7 @@
88
* 2020-05-23 liuduanfei first version
99
* 2020-08-25 wanghaijing add sdmmmc2
1010
* 2023-03-26 wdfk-prog Distinguish between SDMMC and SDIO drivers
11+
* 2024-08-05 wdfk-prog Optimize SDMMC timeout handling and clock divider
1112
*/
1213
#include "board.h"
1314

@@ -27,7 +28,6 @@
2728
#endif /* DRV_DEBUG */
2829
#include <rtdbg.h>
2930

30-
static struct stm32_sdio_class sdio_obj;
3131
static struct rt_mmcsd_host *host1;
3232
static struct rt_mmcsd_host *host2;
3333

@@ -55,6 +55,11 @@ struct rthw_sdio
5555
rt_align(SDIO_ALIGN_LEN)
5656
static rt_uint8_t cache_buf[SDIO_BUFF_SIZE];
5757

58+
static rt_uint32_t stm32_sdio_clk_get(void)
59+
{
60+
return SDIO_CLOCK_FREQ;
61+
}
62+
5863
/**
5964
* @brief This function get order from sdio.
6065
* @param data
@@ -154,10 +159,6 @@ static void rthw_sdio_wait_completed(struct rthw_sdio *sdio)
154159
return;
155160
}
156161

157-
if (sdio->pkg == RT_NULL)
158-
{
159-
return;
160-
}
161162
/* Get Card Specific Data */
162163
cmd->resp[0] = hsd->RESP1;
163164
if (resp_type(cmd) == RESP_R2)
@@ -221,6 +222,38 @@ static void rthw_sdio_wait_completed(struct rthw_sdio *sdio)
221222
}
222223
}
223224

225+
/**
226+
* @brief Calculate timeout for SDMMC data transfer.
227+
*
228+
* @note The timeout is estimated based on transfer size:
229+
* timeout = 100 ms + 2 ms per 512 bytes.
230+
* The result is clamped to the range [100 ms, 5000 ms].
231+
*
232+
* @param data Pointer to transfer data descriptor.
233+
*
234+
* @return Timeout in RT-Thread tick units.
235+
*/
236+
static rt_tick_t stm32_sdmmc_calc_timeout(struct mmcsd_data *data)
237+
{
238+
rt_size_t len;
239+
rt_uint32_t timeout_ms;
240+
241+
if (data == RT_NULL)
242+
return rt_tick_from_millisecond(100);
243+
244+
len = data->blks * data->blksize;
245+
246+
/* base timeout + size-based timeout */
247+
timeout_ms = 100 + (len / 512) * 2;
248+
249+
if (timeout_ms < 100)
250+
timeout_ms = 100;
251+
if (timeout_ms > 5000)
252+
timeout_ms = 5000;
253+
254+
return rt_tick_from_millisecond(timeout_ms);
255+
}
256+
224257
/**
225258
* @brief This function send command.
226259
* @param sdio rthw_sdio
@@ -262,7 +295,7 @@ static void rthw_sdio_send_command(struct rthw_sdio *sdio, struct sdio_pkg *pkg)
262295
/* data pre configuration */
263296
if (data != RT_NULL)
264297
{
265-
SCB_CleanInvalidateDCache();
298+
rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, cache_buf, data->blks * data->blksize);
266299

267300
reg_cmd |= SDMMC_CMD_CMDTRANS;
268301
__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)
292325
/* Waiting for data to be sent to completion */
293326
if (data != RT_NULL)
294327
{
295-
volatile rt_uint32_t count = SDIO_TX_RX_COMPLETE_TIMEOUT_LOOPS;
328+
rt_tick_t start = rt_tick_get();
329+
rt_tick_t timeout = stm32_sdmmc_calc_timeout(data);
296330

297-
while (count && (hsd->STA & SDMMC_STA_DPSMACT))
331+
while (hsd->STA & SDMMC_STA_DPSMACT)
298332
{
299-
count--;
333+
if ((rt_tick_get() - start) >= timeout)
334+
{
335+
cmd->err = -RT_ETIMEOUT;
336+
break;
337+
}
300338
}
301339

302-
if ((count == 0) || (hsd->STA & SDIO_ERRORS))
340+
if ((hsd->STA & SDIO_ERRORS) != 0)
303341
{
304342
cmd->err = -RT_ERROR;
305343
}
@@ -311,7 +349,7 @@ static void rthw_sdio_send_command(struct rthw_sdio *sdio, struct sdio_pkg *pkg)
311349
if (data->flags & DATA_DIR_READ)
312350
{
313351
rt_memcpy(data->buf, cache_buf, data->blks * data->blksize);
314-
SCB_CleanInvalidateDCache();
352+
rt_hw_cpu_dcache_ops(RT_HW_CACHE_INVALIDATE, cache_buf, data->blks * data->blksize);
315353
}
316354
}
317355
}
@@ -378,6 +416,33 @@ static void rthw_sdio_iocfg(struct rt_mmcsd_host *host, struct rt_mmcsd_io_cfg *
378416
SDMMC_InitTypeDef Init = {0};
379417
rt_uint32_t sdmmc_clk = sdio->sdio_des.clk_get();
380418

419+
rt_bool_t stop_flag = RT_TRUE;
420+
421+
switch (io_cfg->power_mode & 0X03)
422+
{
423+
case MMCSD_POWER_OFF:
424+
/* Set Power State to OFF */
425+
(void)SDMMC_PowerState_OFF(hsd->Instance);
426+
stop_flag = RT_TRUE;
427+
break;
428+
case MMCSD_POWER_UP:
429+
/* In F4 series chips, 0X01 is reserved bit and has no practical effect.
430+
For F7 series chips, 0X01 is power-on after power-off,The SDMMC disables the function and the card clock stops.
431+
For H7 series chips, 0X03 is the power-on function.
432+
*/
433+
stop_flag = RT_TRUE;
434+
break;
435+
case MMCSD_POWER_ON:
436+
stop_flag = RT_FALSE;
437+
break;
438+
default:
439+
LOG_W("unknown power mode %d", io_cfg->power_mode);
440+
stop_flag = RT_FALSE;
441+
break;
442+
}
443+
444+
if(stop_flag == RT_TRUE) return;
445+
381446
if (sdmmc_clk < 400 * 1000)
382447
{
383448
LOG_E("The clock rate is too low! rata:%d", sdmmc_clk);
@@ -422,91 +487,88 @@ static void rthw_sdio_iocfg(struct rt_mmcsd_host *host, struct rt_mmcsd_io_cfg *
422487
Init.BusWide = SDMMC_BUS_WIDE_1B;
423488
}
424489
Init.HardwareFlowControl = hsd->Init.HardwareFlowControl;
425-
/* Check if user Clock div < Normal speed 25Mhz, no change in Clockdiv */
426-
if (hsd->Init.ClockDiv >= (sdmmc_clk / (2U * SD_NORMAL_SPEED_FREQ)))
427-
{
428-
Init.ClockDiv = hsd->Init.ClockDiv;
429-
}
430-
//CARD_ULTRA_HIGH_SPEED :UHS-I SD Card <50Mo/s for SDR50, DDR5 Cards and <104Mo/s for SDR104, Spec version 3.01
431-
else if (MMCSD_TIMING_UHS_SDR50 <= io_cfg->timing && io_cfg->timing <= MMCSD_TIMING_UHS_DDR50)
432-
{
433-
/* UltraHigh speed SD card,user Clock div */
434-
Init.ClockDiv = hsd->Init.ClockDiv;
435-
}
436-
//CARD_HIGH_SPEED: High Speed Card <25Mo/s , Spec version 2.00
437-
else if (io_cfg->timing == MMCSD_TIMING_SD_HS)
490+
/* Keep user clock divider if current setting is already <= normal speed */
491+
if (clk != SD_INIT_FREQ)
438492
{
439-
/* High speed SD card, Max Frequency = 50Mhz */
440-
if (hsd->Init.ClockDiv == 0U)
493+
if (hsd->Init.ClockDiv >= (sdmmc_clk / (2U * SD_NORMAL_SPEED_FREQ)))
441494
{
442-
if (sdmmc_clk > SD_HIGH_SPEED_FREQ)
443-
{
444-
Init.ClockDiv = sdmmc_clk / (2U * SD_HIGH_SPEED_FREQ);
445-
}
446-
else
447-
{
448-
Init.ClockDiv = hsd->Init.ClockDiv;
449-
}
495+
Init.ClockDiv = hsd->Init.ClockDiv;
450496
}
451-
else
497+
//CARD_ULTRA_HIGH_SPEED :UHS-I SD Card <50Mo/s for SDR50, DDR5 Cards and <104Mo/s for SDR104, Spec version 3.01
498+
else if (MMCSD_TIMING_UHS_SDR50 <= io_cfg->timing && io_cfg->timing <= MMCSD_TIMING_UHS_DDR50)
499+
{
500+
/* UltraHigh speed SD card,user Clock div */
501+
Init.ClockDiv = hsd->Init.ClockDiv;
502+
}
503+
//CARD_HIGH_SPEED: High Speed Card <25Mo/s , Spec version 2.00
504+
else if (io_cfg->timing == MMCSD_TIMING_SD_HS)
452505
{
453-
if ((sdmmc_clk/(2U * hsd->Init.ClockDiv)) > SD_HIGH_SPEED_FREQ)
506+
/* High speed SD card, Max Frequency = 50Mhz */
507+
if (hsd->Init.ClockDiv == 0U)
454508
{
455-
Init.ClockDiv = sdmmc_clk / (2U * SD_HIGH_SPEED_FREQ);
509+
if (sdmmc_clk > SD_HIGH_SPEED_FREQ)
510+
{
511+
Init.ClockDiv = sdmmc_clk / (2U * SD_HIGH_SPEED_FREQ);
512+
}
513+
else
514+
{
515+
Init.ClockDiv = hsd->Init.ClockDiv;
516+
}
456517
}
457518
else
458519
{
459-
Init.ClockDiv = hsd->Init.ClockDiv;
520+
if ((sdmmc_clk/(2U * hsd->Init.ClockDiv)) > SD_HIGH_SPEED_FREQ)
521+
{
522+
Init.ClockDiv = sdmmc_clk / (2U * SD_HIGH_SPEED_FREQ);
523+
}
524+
else
525+
{
526+
Init.ClockDiv = hsd->Init.ClockDiv;
527+
}
460528
}
461529
}
462-
}
463-
//CARD_NORMAL_SPEED: Normal Speed Card <12.5Mo/s , Spec Version 1.01
464-
else if (io_cfg->timing == MMCSD_TIMING_LEGACY)
465-
{
466-
/* No High speed SD card, Max Frequency = 25Mhz */
467-
if (hsd->Init.ClockDiv == 0U)
530+
//CARD_NORMAL_SPEED: Normal Speed Card <12.5Mo/s , Spec Version 1.01
531+
else if (io_cfg->timing == MMCSD_TIMING_LEGACY)
468532
{
469-
if (sdmmc_clk > SD_NORMAL_SPEED_FREQ)
533+
/* No High speed SD card, Max Frequency = 25Mhz */
534+
if (hsd->Init.ClockDiv == 0U)
470535
{
471-
Init.ClockDiv = sdmmc_clk / (2U * SD_NORMAL_SPEED_FREQ);
536+
if (sdmmc_clk > SD_NORMAL_SPEED_FREQ)
537+
{
538+
Init.ClockDiv = sdmmc_clk / (2U * SD_NORMAL_SPEED_FREQ);
539+
}
540+
else
541+
{
542+
Init.ClockDiv = hsd->Init.ClockDiv;
543+
}
472544
}
473545
else
474546
{
475-
Init.ClockDiv = hsd->Init.ClockDiv;
547+
if ((sdmmc_clk/(2U * hsd->Init.ClockDiv)) > SD_NORMAL_SPEED_FREQ)
548+
{
549+
Init.ClockDiv = sdmmc_clk / (2U * SD_NORMAL_SPEED_FREQ);
550+
}
551+
else
552+
{
553+
Init.ClockDiv = hsd->Init.ClockDiv;
554+
}
476555
}
477556
}
478557
else
479558
{
480-
if ((sdmmc_clk/(2U * hsd->Init.ClockDiv)) > SD_NORMAL_SPEED_FREQ)
481-
{
482-
Init.ClockDiv = sdmmc_clk / (2U * SD_NORMAL_SPEED_FREQ);
483-
}
484-
else
485-
{
486-
Init.ClockDiv = hsd->Init.ClockDiv;
487-
}
559+
Init.ClockDiv = hsd->Init.ClockDiv;
488560
}
489561
}
562+
else
563+
{
564+
Init.ClockDiv = hsd->Init.ClockDiv;
565+
}
490566
(void)SDMMC_Init(hsd->Instance, Init);
491567
}
492-
switch ((io_cfg->power_mode)&0X03)
568+
if((io_cfg->power_mode & 0X03) == MMCSD_POWER_ON)
493569
{
494-
case MMCSD_POWER_OFF:
495-
/* Set Power State to OFF */
496-
(void)SDMMC_PowerState_OFF(hsd->Instance);
497-
break;
498-
case MMCSD_POWER_UP:
499-
/* In F4 series chips, 0X01 is reserved bit and has no practical effect.
500-
For F7 series chips, 0X01 is power-on after power-off,The SDMMC disables the function and the card clock stops.
501-
For H7 series chips, 0X03 is the power-on function.
502-
*/
503-
case MMCSD_POWER_ON:
504570
/* Set Power State to ON */
505571
(void)SDMMC_PowerState_ON(hsd->Instance);
506-
break;
507-
default:
508-
LOG_W("unknown power mode %d", io_cfg->power_mode);
509-
break;
510572
}
511573
}
512574

@@ -578,15 +640,15 @@ struct rt_mmcsd_host *sdio_host_create(struct stm32_sdio_des *sdio_des)
578640

579641
if (sdio_des == RT_NULL)
580642
{
581-
LOG_E("L:%d F:%s",(sdio_des == RT_NULL ? "sdio_des is NULL" : ""));
643+
LOG_E("sdio_des is NULL");
582644
return RT_NULL;
583645
}
584646

585647
sdio = rt_malloc(sizeof(struct rthw_sdio));
586648

587649
if (sdio == RT_NULL)
588650
{
589-
LOG_E("L:%d F:%s malloc rthw_sdio fail");
651+
LOG_E("malloc rthw_sdio fail");
590652
return RT_NULL;
591653
}
592654

@@ -596,12 +658,13 @@ struct rt_mmcsd_host *sdio_host_create(struct stm32_sdio_des *sdio_des)
596658

597659
if (host == RT_NULL)
598660
{
599-
LOG_E("L:%d F:%s mmcsd alloc host fail");
661+
LOG_E("mmcsd alloc host fail");
600662
rt_free(sdio);
601663
return RT_NULL;
602664
}
603665

604666
rt_memcpy(&sdio->sdio_des, sdio_des, sizeof(struct stm32_sdio_des));
667+
sdio->sdio_des.clk_get = (sdio_des->clk_get == RT_NULL ? stm32_sdio_clk_get : sdio_des->clk_get);
605668
#ifdef BSP_USING_SDIO1
606669
if(sdio_des->hw_sdio.Instance == SDMMC1)
607670
{
@@ -630,14 +693,14 @@ struct rt_mmcsd_host *sdio_host_create(struct stm32_sdio_des *sdio_des)
630693
#endif
631694
host->max_seg_size = SDIO_BUFF_SIZE;
632695
host->max_dma_segs = 1;
633-
host->max_blk_size = 512;
634-
host->max_blk_count = 512;
696+
host->max_blk_size = BLOCKSIZE;
697+
host->max_blk_count = BLOCKSIZE;
635698

636699
/* link up host and sdio */
637700
sdio->host = host;
638701
host->private_data = sdio;
639702

640-
rthw_sdio_irq_update(host, 1);
703+
rthw_sdio_irq_update(host, RT_TRUE);
641704

642705
/* ready to change */
643706
mmcsd_change(host);

0 commit comments

Comments
 (0)