硬汉嵌入式论坛

 找回密码
 立即注册
查看: 250|回复: 7
收起左侧

[USB] STM32H7 EMMC USBHS(USB3300) MSC速度慢的问题

[复制链接]

1

主题

3

回帖

6

积分

新手上路

积分
6
发表于 5 天前 | 显示全部楼层 |阅读模式
本帖最后由 Winston 于 2026-1-4 15:56 编辑

近期仿照H7 Tool 实现了一下存储功能部分的设计, 因为项目上有需求要用到传感器的数据存储, 之前都是拿SD卡直接保存的, 但是有可能写入失败或因为震动导致连接不稳定. 准备切换到EMMC方案. 在USB MSC上碰到了不对劲的地方. MSC测速非常慢, 远远达不到正常测速的速度.

使用了STM32H743VI作为主处理器, 三星EMMC KLMBG2JETD-B041, 配合USB3300 做高速USB设备的方式.

[C] 纯文本查看 复制代码
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Supply configuration update enable
  */
  HAL_PWREx_ConfigSupply(PWR_LDO_SUPPLY);

  /** Configure the main internal regulator output voltage
  */
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE0);

  while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = 13;
  RCC_OscInitStruct.PLL.PLLN = 480;
  RCC_OscInitStruct.PLL.PLLP = 2;
  RCC_OscInitStruct.PLL.PLLQ = 20;
  RCC_OscInitStruct.PLL.PLLR = 4;
  RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_1;
  RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;
  RCC_OscInitStruct.PLL.PLLFRACN = 0;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2
                              |RCC_CLOCKTYPE_D3PCLK1|RCC_CLOCKTYPE_D1PCLK1;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2;
  RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)
  {
    Error_Handler();
  }

  /** Enables the Clock Security System
  */
  HAL_RCC_EnableCSS();
}


外部晶振26M, 主频480M, SDMMC1,2是PLL2R 即200MHZ. 在SDMMC中分频为2, 实际得到的频率      SDMMC_CK frequency = sdmmc_ker_ck / 4 = 50M, 应该已经到外设能够支持最大的上限.
d907592a-c30c-4596-adad-711bffcab115.png
开启对应的硬件流控. 开启CaChe.

使用片内测速代码, 测试得到的速度为:

f1553397-7c2d-4960-a71f-677e08f49c78.png
这个速度跟硬汉哥的测试结果类似, 我的可能偏慢一些.

使能USB MSC, 设置MSC缓冲为32KB
数据读取和写入函数如下:

[C] 纯文本查看 复制代码
/**
  * @brief  Reads data from the medium.
  * @param  lun: Logical unit number.
  * @param  buf: data buffer.
  * @param  blk_addr: Logical block address.
  * @param  blk_len: Blocks number.
  * @retval USBD_OK if all operations are OK else USBD_FAIL
  */
int8_t STORAGE_Read_HS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
{
  /* USER CODE BEGIN 13 */
        int8_t ret = USBD_FAIL;
        uint8_t cnt = 0;
        uint32_t timeout = 1000;

        HAL_StatusTypeDef status = HAL_MMC_ReadBlocks(&hmmc1, buf, blk_addr, blk_len, timeout);

        if (status == HAL_OK)
        {
//                printf("[USB MSC] HAL_MMC_ReadBlocks: OK\r\n");

                ret = USBD_OK;

                // 等待卡完成传输
                while (HAL_MMC_GetCardState(&hmmc1) != HAL_MMC_CARD_TRANSFER)
                {
                        ;
                }
        }
        else
        {
                // 打印失败的状态码
                printf("[USB MSC] HAL_MMC_ReadBlocks: FAIL, status=%d\r\n", status);
                // 获取并打印下卡状态
                printf("[USB MSC] CardState after fail: %d\r\n", HAL_MMC_GetCardState(&hmmc1));
                // 如果有详细错误原因,可以读取错误寄存器
                printf("[USB MSC] ErrorCode: 0x%08lX\r\n", HAL_MMC_GetError(&hmmc1));
        }

        return ret;
  /* USER CODE END 13 */
}

/**
  * @brief  Writes data into the medium.
  * @param  lun: Logical unit number.
  * @param  buf: data buffer.
  * @param  blk_addr: Logical block address.
  * @param  blk_len: Blocks number.
  * @retval USBD_OK if all operations are OK else USBD_FAIL
  */
int8_t STORAGE_Write_HS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
{
  /* USER CODE BEGIN 14 */
        int8_t ret = USBD_FAIL;
        uint8_t cnt = 0;
        uint32_t timeout = 5000;

        HAL_StatusTypeDef status = HAL_MMC_WriteBlocks(&hmmc1, buf, blk_addr, blk_len, timeout);

        if (status == HAL_OK)
        {
//                printf("[USB MSC] HAL_MMC_ReadBlocks: OK\r\n");

                ret = USBD_OK;

                // 等待卡完成传输
                while (HAL_MMC_GetCardState(&hmmc1) != HAL_MMC_CARD_TRANSFER)
                {
                        ;
                }
        }
        else
        {
                // 打印失败的状态码
                printf("[USB MSC] HAL_MMC_ReadBlocks: FAIL, status=%d\r\n", status);
                // 获取并打印下卡状态
                printf("[USB MSC] CardState after fail: %d\r\n", HAL_MMC_GetCardState(&hmmc1));
                // 如果有详细错误原因,可以读取错误寄存器
                printf("[USB MSC] ErrorCode: 0x%08lX\r\n", HAL_MMC_GetError(&hmmc1));
        }

        return ret;

  /* USER CODE END 14 */
}

/**
  * @brief  Returns the Max Supported LUNs.
  * @param  None
  * @retval Lun(s) number.
  */
int8_t STORAGE_GetMaxLun_HS(void)
{
  /* USER CODE BEGIN 15 */
        return (STORAGE_LUN_NBR - 1);
  /* USER CODE END 15 */
}


实际测试得到的结果

589b342c-9ebd-40a5-987d-22b97dfb671a.png

这个速度我感觉太慢了, 请问大家可能在那里出现了问题呢? 是否需要将写入改为DMA模式呢?  
我看USB整体的写入和读取调度都是在中断中完成的, 这里启用DMA似乎也没有任何意义, CPU还是需要死等DMA结束. 请大家赐教


回复

使用道具 举报

1万

主题

7万

回帖

12万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
120427
QQ
发表于 5 天前 | 显示全部楼层
图片没上传成功,图片要编辑里面单独上传下才行
回复

使用道具 举报

1

主题

3

回帖

6

积分

新手上路

积分
6
 楼主| 发表于 5 天前 | 显示全部楼层
eric2013 发表于 2026-1-4 15:48
图片没上传成功,图片要编辑里面单独上传下才行

已修改, 麻烦硬汉哥重新审核一下
回复

使用道具 举报

1

主题

25

回帖

33

积分

新手上路

积分
33
QQ
发表于 5 天前 | 显示全部楼层
楼主打开USB IP 的 DMA没有?

使能USB_IP_DMA.png

我画的开发板是STM32H723ZG + USB3300 + 三星64GEVO Plus 4线SD卡,格式化为FAT32,SDMMC 50MHz时钟
用 ThreadX + USBX + FileX,USB IP 打开 DMA,
USB MSC 读写函数都用 DMA API,32KB或64KB请求长度
FileX 用硬汉的测速例子,每次读写BUF也是 32KB (#define BUF_SIZE (32 * 1024))
Os编译优化下,电脑 ATTO 测MSC的速度甚至还比 STM32 本地 FileX 读写更快
本地FileX:
FileX测试FAT32读写速度.png
电脑ATTO:(UX_SLAVE_REQUEST_DATA_MAX_LENGTH 分别为 32KB 和 64KB)
UX_SLAVE_REQUEST_DATA_MAX_LENGTH=32768.png UX_SLAVE_REQUEST_DATA_MAX_LENGTH=65536.png




评分

参与人数 1金币 +20 收起 理由
cxrundo_embed + 20 很给力!

查看全部评分

回复

使用道具 举报

1万

主题

7万

回帖

12万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
120427
QQ
发表于 4 天前 | 显示全部楼层
Winston 发表于 2026-1-4 15:57
已修改, 麻烦硬汉哥重新审核一下

传输大文件,我看下实际速度多少。
回复

使用道具 举报

1

主题

3

回帖

6

积分

新手上路

积分
6
 楼主| 发表于 昨天 12:09 | 显示全部楼层
OldGerman 发表于 2026-1-4 23:05
楼主打开USB IP 的 DMA没有?

STM32H7 USB Internal DMA 打开后, 会有D cache的问题, 这个问题你是怎么解决的呢?
回复

使用道具 举报

1万

主题

7万

回帖

12万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
120427
QQ
发表于 16 小时前 | 显示全部楼层
Winston 发表于 2026-1-8 12:09
STM32H7 USB Internal DMA 打开后, 会有D cache的问题, 这个问题你是怎么解决的呢?

1、可以关闭MPU Cache
2、可以手动设置Clean和无效化。
回复

使用道具 举报

1

主题

3

回帖

6

积分

新手上路

积分
6
 楼主| 发表于 半小时前 | 显示全部楼层
今天抽空测试了下H7Tool的MSC EMMC性能, 我看跟我的似乎差不多. 那么这个问题就已经是整个通讯链路的上限了, ST H7 对比WCH USB HS 的单片机性能还是相差比较多的
ScreenShot_2026-01-09_155952_883.png

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2026-1-9 16:40 , Processed in 0.049501 second(s), 29 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表