ST意法半导体
直播中

张生

10年用户 929经验值
擅长:光电显示 接口/总线/驱动
私信 关注
[问答]

STM32H750 SDMMC和IDMA问题求解

我有在 STM32H750 上运行的代码,它使用 HAL 驱动程序将音频从 microSD (SDMMC + IDMA) 流式传输到 DAC (SAI + DMA)。我主要进行 16 扇区读取,读取速度约为每秒 300 次(每 93 毫秒读取 28 次 16 扇区)。该卡以 50MHz 的总线速度轻松处理此问题。我正在使用正弦波音频数据并使用频谱分析仪监控输出,以便轻松发现任何问题。

所有读取都使用 AXI 内存,我有一个为此内存正确启用的 MPU 区域,并且正在进行缓存管理,就像我在其他 STM32 处理器上成功完成的那样。除了一个例外,一切都很好。

我的问题是大约每隔一两个小时(或更多),HAL_SD_ReadBlocks_DMA() 函数超时一次。“超时”是指发送了读取多块命令并收到了正确的响应,但后续中断从未发生,等待读取完成的代码(通过检查 SD 中断中清除的标志) ,超时。

HAL 函数调用 SDMMC_CmdReadMultiBlock(),后者依次调用 SDMMC_SendCommand() 和 SDMMC_GetCmdResp1();我已经对代码进行了检测,以在命令超时时保留 SDMMC 状态寄存器的值,并且没有发现任何异常情况。

最有趣的是,我发现如果我在 SDMMC_SendCommand() 和 SDMMC_GetCmdResp1() 函数之间插入一个很小的延迟,我几乎可以立即以完全相同的方式让命令超时。对 SDMMC_GetCmdResp1() 的调用通常紧跟在对 SDMMC_SendCommand() 的调用之后,因此如果它们之间的延迟导致这种情况,那么我想如果此时发生另一个中断,这可能是一个问题。我尝试在这些调用周围禁用 SAI DMA 中断,但它似乎没有帮助。

我通读了勘误表,没有看到任何适用于此的内容。发送命令和检查响应之间的小延迟会导致问题,这似乎很奇怪。

回帖(1)

陈利妮

2023-2-3 10:05:00
我发现了问题,并想传递 CubeMX 生成的文件“sd_diskio.c”中似乎存在的错误。问题出在 SD_Read() 函数中:



  • /**
  •   * @brief  Reads Sector(s)
  •   * @param  lun : not used
  •   * @param  *buff: Data buffer to store read data
  •   * @param  sector: Sector address (LBA)
  •   * @param  count: Number of sectors to read (1..128)
  •   * @retval DRESULT: Operation result
  •   */
  •               
  • DRESULT SD_read(BYTE lun, BYTE *buff, DWORD sector, UINT count)
  • {
  •   DRESULT res = RES_ERROR;
  •   uint32_t timeout;
  • #if defined(ENABLE_SCRATCH_BUFFER)
  •   uint8_t ret;
  • #endif
  • #if (ENABLE_SD_DMA_CACHE_MAINTENANCE == 1)
  •   uint32_t alignedAddr;
  • #endif

  •   /*
  •   * ensure the SDCard is ready for a new operation
  •   */

  •   if (SD_CheckStatusWithTimeout(SD_TIMEOUT) < 0)
  •   {
  •     return res;
  •   }

  • #if defined(ENABLE_SCRATCH_BUFFER)
  •   if (!((uint32_t)buff & 0x3))
  •   {
  • #endif
  •     if(BSP_SD_ReadBlocks_DMA((uint32_t*)buff,
  •                              (uint32_t) (sector),
  •                              count) == MSD_OK)
  •     {
  •       ReadStatus = 0;
  •       /* Wait that the reading process is completed or a timeout occurs */
  •       timeout = HAL_GetTick();
  •       while((ReadStatus == 0) && ((HAL_GetTick() - timeout) < SD_TIMEOUT))
  •       {
  •       }
  •       /* incase of a timeout return error */
  •       if (ReadStatus == 0)
  •       {
  •         res = RES_ERROR;
  •       }
  •       else
  •       {
  •         ReadStatus = 0;
  •         timeout = HAL_GetTick();

在调用 BSP_SD_ReadBlocks_DMA() 之后,ReadStatus 设置为 0。BSP_SD_ReadBlocks() 的作用是发出读取命令并在读取完成时启动中断,进而将 ReadStatus 设置为 1,表示完成。您可以看到问题:有时,这一切都发生在将 ReadStatus 设置为 0 的下一行之前,因此它不会随后被设置,因为中断已经发生。解决方案是将此行移动到函数的顶部。

SD_write() 函数也有类似的潜力,但相应的 WriteStatus = 0 设置在该函数所属的顶部。
举报

更多回帖

发帖
×
20
完善资料,
赚取积分