硬汉嵌入式论坛

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

[SD/SDIO] ST这骚操作,解决H7的SDIO DMA的4字节对齐问题,搞了个复制粘贴

[复制链接]

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107077
QQ
发表于 2020-9-22 13:34:20 | 显示全部楼层 |阅读模式
其实H7自带了个SDIO DMA后,远没有使用通用DMA方便了,通用DMA可以轻松解决4字节对齐问题。

问题由来:

STM32H7的SDIO自带的DMA控制器数据传输的地址是强制4字节对齐,这就非常不方便了
http://www.armbbs.cn/forum.php?m ... id=94066&fromuid=58
(出处: 硬汉嵌入式论坛)


解决方法,如下代码,搞了个memcpy的骚操作,而且是512字节为单位的复制粘贴,SDIO批量块传输特性将发挥不出来:
  1.   /**
  2.   ******************************************************************************
  3.   * @file    sd_diskio_dma_template.c
  4.   * @author  MCD Application Team
  5.   * @brief   SD DMA Disk I/O template driver. This file needs to be renamed and
  6.              copied into the application project alongside the respective header
  7.              file.
  8.   ******************************************************************************
  9.   * @attention
  10.   *
  11.   * Copyright (c) 2019 STMicroelectronics. All rights reserved.
  12.   *
  13.   * This software component is licensed by ST under BSD 3-Clause license,
  14.   * the "License"; You may not use this file except in compliance with the
  15.   * License. You may obtain a copy of the License at:
  16.   *                       opensource.org/licenses/BSD-3-Clause
  17.   *
  18.   ******************************************************************************
  19. **/

  20. /* Includes ------------------------------------------------------------------*/
  21. #include <string.h>
  22. #include "ff_gen_drv.h"
  23. #include "sd_diskio_dma.h"

  24. /* Private typedef -----------------------------------------------------------*/
  25. /* Private define ------------------------------------------------------------*/
  26. /*
  27. * the following Timeout is useful to give the control back to the applications
  28. * in case of errors in either BSP_SD_ReadCpltCallback() or BSP_SD_WriteCpltCallback()
  29. * the value by default is as defined in the BSP platform driver otherwise 30 secs
  30. */

  31. #define SD_TIMEOUT 30 * 1000

  32. #define SD_DEFAULT_BLOCK_SIZE 512

  33. /*
  34. * Depending on the usecase, the SD card initialization could be done at the
  35. * application level, if it is the case define the flag below to disable
  36. * the BSP_SD_Init() call in the SD_Initialize().
  37. */

  38. /* #define DISABLE_SD_INIT */

  39. /*
  40. * when using cachable memory region, it may be needed to maintain the cache
  41. * validity. Enable the define below to activate a cache maintenance at each
  42. * read and write operation.
  43. * Notice: This is applicable only for cortex M7 based platform.
  44. */

  45. /* #define ENABLE_SD_DMA_CACHE_MAINTENANCE  1 */

  46. /*
  47. * Some DMA requires 4-Byte aligned address buffer to correctly read/wite data,
  48. * in FatFs some accesses aren't thus we need a 4-byte aligned scratch buffer to correctly
  49. * transfer data
  50. */
  51. /* #define ENABLE_SCRATCH_BUFFER */


  52. /* Private variables ---------------------------------------------------------*/

  53. #if defined(ENABLE_SCRATCH_BUFFER)
  54. #if defined (ENABLE_SD_DMA_CACHE_MAINTENANCE)
  55. ALIGN_32BYTES(static uint8_t scratch[BLOCKSIZE]); // 32-Byte aligned for cache maintenance
  56. #else
  57. __ALIGN_BEGIN static uint8_t scratch[BLOCKSIZE] __ALIGN_END;
  58. #endif
  59. #endif

  60. /* Disk status */
  61. static volatile DSTATUS Stat = STA_NOINIT;
  62. static volatile  UINT  WriteStatus = 0, ReadStatus = 0;
  63. /* Private function prototypes -----------------------------------------------*/
  64. static DSTATUS SD_CheckStatus(BYTE lun);
  65. DSTATUS SD_initialize (BYTE);
  66. DSTATUS SD_status (BYTE);
  67. DRESULT SD_read (BYTE, BYTE*, DWORD, UINT);
  68. #if _USE_WRITE == 1
  69. DRESULT SD_write (BYTE, const BYTE*, DWORD, UINT);
  70. #endif /* _USE_WRITE == 1 */
  71. #if _USE_IOCTL == 1
  72. DRESULT SD_ioctl (BYTE, BYTE, void*);
  73. #endif  /* _USE_IOCTL == 1 */

  74. const Diskio_drvTypeDef  SD_Driver =
  75. {
  76.   SD_initialize,
  77.   SD_status,
  78.   SD_read,
  79. #if  _USE_WRITE == 1
  80.   SD_write,
  81. #endif /* _USE_WRITE == 1 */

  82. #if  _USE_IOCTL == 1
  83.   SD_ioctl,
  84. #endif /* _USE_IOCTL == 1 */
  85. };

  86. /* Private functions ---------------------------------------------------------*/
  87. static int SD_CheckStatusWithTimeout(uint32_t timeout)
  88. {
  89.   uint32_t timer = HAL_GetTick();
  90.   /* block until SDIO IP is ready again or a timeout occur */
  91.   while(HAL_GetTick() - timer < timeout)
  92.   {
  93.     if (BSP_SD_GetCardState() == SD_TRANSFER_OK)
  94.     {
  95.       return 0;
  96.     }
  97.   }

  98.   return -1;
  99. }

  100. static DSTATUS SD_CheckStatus(BYTE lun)
  101. {
  102.   Stat = STA_NOINIT;

  103.   if(BSP_SD_GetCardState() == MSD_OK)
  104.   {
  105.     Stat &= ~STA_NOINIT;
  106.   }

  107.   return Stat;
  108. }

  109. /**
  110. * @brief  Initializes a Drive
  111. * @param  lun : not used
  112. * @retval DSTATUS: Operation status
  113. */
  114. DSTATUS SD_initialize(BYTE lun)
  115. {
  116. #if !defined(DISABLE_SD_INIT)

  117.   if(BSP_SD_Init() == MSD_OK)
  118.   {
  119.     Stat = SD_CheckStatus(lun);
  120.   }

  121. #else
  122.   Stat = SD_CheckStatus(lun);
  123. #endif
  124.   return Stat;
  125. }

  126. /**
  127. * @brief  Gets Disk Status
  128. * @param  lun : not used
  129. * @retval DSTATUS: Operation status
  130. */
  131. DSTATUS SD_status(BYTE lun)
  132. {
  133.   return SD_CheckStatus(lun);
  134. }

  135. /**
  136. * @brief  Reads Sector(s)
  137. * @param  lun : not used
  138. * @param  *buff: Data buffer to store read data
  139. * @param  sector: Sector address (LBA)
  140. * @param  count: Number of sectors to read (1..128)
  141. * @retval DRESULT: Operation result
  142. */
  143. DRESULT SD_read(BYTE lun, BYTE *buff, DWORD sector, UINT count)
  144. {
  145.   DRESULT res = RES_ERROR;
  146.   uint32_t timeout;
  147. #if defined(ENABLE_SCRATCH_BUFFER)
  148.   uint8_t ret;
  149. #endif
  150. #if (ENABLE_SD_DMA_CACHE_MAINTENANCE == 1)
  151.   uint32_t alignedAddr;
  152. #endif

  153.   /*
  154.   * ensure the SDCard is ready for a new operation
  155.   */

  156.   if (SD_CheckStatusWithTimeout(SD_TIMEOUT) < 0)
  157.   {
  158.     return res;
  159.   }

  160. #if defined(ENABLE_SCRATCH_BUFFER)
  161.   if (!((uint32_t)buff & 0x3))
  162.   {
  163. #endif
  164.     if(BSP_SD_ReadBlocks_DMA((uint32_t*)buff,
  165.                              (uint32_t) (sector),
  166.                              count) == MSD_OK)
  167.     {
  168.       ReadStatus = 0;
  169.       /* Wait that the reading process is completed or a timeout occurs */
  170.       timeout = HAL_GetTick();
  171.       while((ReadStatus == 0) && ((HAL_GetTick() - timeout) < SD_TIMEOUT))
  172.       {
  173.       }
  174.       /* incase of a timeout return error */
  175.       if (ReadStatus == 0)
  176.       {
  177.         res = RES_ERROR;
  178.       }
  179.       else
  180.       {
  181.         ReadStatus = 0;
  182.         timeout = HAL_GetTick();

  183.         while((HAL_GetTick() - timeout) < SD_TIMEOUT)
  184.         {
  185.           if (BSP_SD_GetCardState() == SD_TRANSFER_OK)
  186.           {
  187.             res = RES_OK;
  188. #if (ENABLE_SD_DMA_CACHE_MAINTENANCE == 1)
  189.             /*
  190.             the SCB_InvalidateDCache_by_Addr() requires a 32-Byte aligned address,
  191.             adjust the address and the D-Cache size to invalidate accordingly.
  192.             */
  193.             alignedAddr = (uint32_t)buff & ~0x1F;
  194.             SCB_InvalidateDCache_by_Addr((uint32_t*)alignedAddr, count*BLOCKSIZE + ((uint32_t)buff - alignedAddr));
  195. #endif
  196.             break;
  197.           }
  198.         }
  199.       }
  200.     }
  201. #if defined(ENABLE_SCRATCH_BUFFER)
  202.   }
  203.     else
  204.     {
  205.       /* Slow path, fetch each sector a part and memcpy to destination buffer */
  206.       int i;

  207.       for (i = 0; i < count; i++) {
  208.         ret = BSP_SD_ReadBlocks_DMA((uint32_t*)scratch, (uint32_t)sector++, 1);
  209.         if (ret == MSD_OK) {
  210.           /* wait until the read is successful or a timeout occurs */

  211.           timeout = HAL_GetTick();
  212.           while((ReadStatus == 0) && ((HAL_GetTick() - timeout) < SD_TIMEOUT))
  213.           {
  214.           }
  215.           if (ReadStatus == 0)
  216.           {
  217.             res = RES_ERROR;
  218.             break;
  219.           }
  220.           ReadStatus = 0;

  221. #if (ENABLE_SD_DMA_CACHE_MAINTENANCE == 1)
  222.           /*
  223.           *
  224.           * invalidate the scratch buffer before the next read to get the actual data instead of the cached one
  225.           */
  226.           SCB_InvalidateDCache_by_Addr((uint32_t*)scratch, BLOCKSIZE);
  227. #endif
  228.           memcpy(buff, scratch, BLOCKSIZE);
  229.           buff += BLOCKSIZE;
  230.         }
  231.         else
  232.         {
  233.           break;
  234.         }
  235.       }

  236.       if ((i == count) && (ret == MSD_OK))
  237.         res = RES_OK;
  238.     }
  239. #endif

  240.   return res;
  241. }
  242. /**
  243. * @brief  Writes Sector(s)
  244. * @param  lun : not used
  245. * @param  *buff: Data to be written
  246. * @param  sector: Sector address (LBA)
  247. * @param  count: Number of sectors to write (1..128)
  248. * @retval DRESULT: Operation result
  249. */
  250. #if _USE_WRITE == 1
  251. DRESULT SD_write(BYTE lun, const BYTE *buff, DWORD sector, UINT count)
  252. {
  253.   DRESULT res = RES_ERROR;
  254.   uint32_t timeout;
  255. #if defined(ENABLE_SCRATCH_BUFFER)
  256.   uint8_t ret;
  257.   int i;
  258. #endif

  259.    WriteStatus = 0;
  260. #if (ENABLE_SD_DMA_CACHE_MAINTENANCE == 1)
  261.   uint32_t alignedAddr;
  262. #endif

  263.   if (SD_CheckStatusWithTimeout(SD_TIMEOUT) < 0)
  264.   {
  265.     return res;
  266.   }

  267. #if defined(ENABLE_SCRATCH_BUFFER)
  268.   if (!((uint32_t)buff & 0x3))
  269.   {
  270. #endif
  271. #if (ENABLE_SD_DMA_CACHE_MAINTENANCE == 1)

  272.     /*
  273.     the SCB_CleanDCache_by_Addr() requires a 32-Byte aligned address
  274.     adjust the address and the D-Cache size to clean accordingly.
  275.     */
  276.     alignedAddr = (uint32_t)buff &  ~0x1F;
  277.     SCB_CleanDCache_by_Addr((uint32_t*)alignedAddr, count*BLOCKSIZE + ((uint32_t)buff - alignedAddr));
  278. #endif


  279.     if(BSP_SD_WriteBlocks_DMA((uint32_t*)buff,
  280.                               (uint32_t)(sector),
  281.                               count) == MSD_OK)
  282.     {
  283.       /* Wait that writing process is completed or a timeout occurs */

  284.       timeout = HAL_GetTick();
  285.       while((WriteStatus == 0) && ((HAL_GetTick() - timeout) < SD_TIMEOUT))
  286.       {
  287.       }
  288.       /* incase of a timeout return error */
  289.       if (WriteStatus == 0)
  290.       {
  291.         res = RES_ERROR;
  292.       }
  293.       else
  294.       {
  295.         WriteStatus = 0;
  296.         timeout = HAL_GetTick();

  297.         while((HAL_GetTick() - timeout) < SD_TIMEOUT)
  298.         {
  299.           if (BSP_SD_GetCardState() == SD_TRANSFER_OK)
  300.           {
  301.             res = RES_OK;
  302.             break;
  303.           }
  304.         }
  305.       }
  306.     }
  307. #if defined(ENABLE_SCRATCH_BUFFER)
  308.   }
  309.     else
  310.     {
  311.       /* Slow path, fetch each sector a part and memcpy to destination buffer */
  312. #if (ENABLE_SD_DMA_CACHE_MAINTENANCE == 1)
  313.       /*
  314.       * invalidate the scratch buffer before the next write to get the actual data instead of the cached one
  315.       */
  316.       SCB_InvalidateDCache_by_Addr((uint32_t*)scratch, BLOCKSIZE);
  317. #endif

  318.       for (i = 0; i < count; i++)
  319.       {
  320.         WriteStatus = 0;

  321.         memcpy((void *)scratch, (void *)buff, BLOCKSIZE);
  322.         buff += BLOCKSIZE;

  323.         ret = BSP_SD_WriteBlocks_DMA((uint32_t*)scratch, (uint32_t)sector++, 1);
  324.         if (ret == MSD_OK) {
  325.           /* wait for a message from the queue or a timeout */
  326.           timeout = HAL_GetTick();
  327.           while((WriteStatus == 0) && ((HAL_GetTick() - timeout) < SD_TIMEOUT))
  328.           {
  329.           }
  330.           if (WriteStatus == 0)
  331.           {
  332.             break;
  333.           }

  334.         }
  335.         else
  336.         {
  337.           break;
  338.         }
  339.       }
  340.       if ((i == count) && (ret == MSD_OK))
  341.         res = RES_OK;
  342.     }
  343. #endif
  344.   return res;
  345. }
  346. #endif /* _USE_WRITE == 1 */

  347. /**
  348. * @brief  I/O control operation
  349. * @param  lun : not used
  350. * @param  cmd: Control code
  351. * @param  *buff: Buffer to send/receive control data
  352. * @retval DRESULT: Operation result
  353. */
  354. #if _USE_IOCTL == 1
  355. DRESULT SD_ioctl(BYTE lun, BYTE cmd, void *buff)
  356. {
  357.   DRESULT res = RES_ERROR;
  358.   BSP_SD_CardInfo CardInfo;

  359.   if (Stat & STA_NOINIT) return RES_NOTRDY;

  360.   switch (cmd)
  361.   {
  362.     /* Make sure that no pending write process */
  363.   case CTRL_SYNC :
  364.     res = RES_OK;
  365.     break;

  366.     /* Get number of sectors on the disk (DWORD) */
  367.   case GET_SECTOR_COUNT :
  368.     BSP_SD_GetCardInfo(&CardInfo);
  369.     *(DWORD*)buff = CardInfo.LogBlockNbr;
  370.     res = RES_OK;
  371.     break;

  372.     /* Get R/W sector size (WORD) */
  373.   case GET_SECTOR_SIZE :
  374.     BSP_SD_GetCardInfo(&CardInfo);
  375.     *(WORD*)buff = CardInfo.LogBlockSize;
  376.     res = RES_OK;
  377.     break;

  378.     /* Get erase block size in unit of sector (DWORD) */
  379.   case GET_BLOCK_SIZE :
  380.     BSP_SD_GetCardInfo(&CardInfo);
  381.     *(DWORD*)buff = CardInfo.LogBlockSize / SD_DEFAULT_BLOCK_SIZE;
  382.         res = RES_OK;
  383.     break;

  384.   default:
  385.     res = RES_PARERR;
  386.   }

  387.   return res;
  388. }
  389. #endif /* _USE_IOCTL == 1 */



  390. /**
  391. * @brief Tx Transfer completed callbacks
  392. * @param hsd: SD handle
  393. * @retval None
  394. */

  395. /*
  396. ===============================================================================
  397. Select the correct function signature depending on your platform.
  398. please refer to the file "stm32xxxx_eval_sd.h" to verify the correct function
  399. prototype
  400. ===============================================================================
  401. */
  402. //void BSP_SD_WriteCpltCallback(uint32_t SdCard)
  403. void BSP_SD_WriteCpltCallback(void)
  404. {
  405.   WriteStatus = 1;
  406. }

  407. /**
  408. * @brief Rx Transfer completed callbacks
  409. * @param hsd: SD handle
  410. * @retval None
  411. */

  412. /*
  413. ===============================================================================
  414. Select the correct function signature depending on your platform.
  415. please refer to the file "stm32xxxx_eval_sd.h" to verify the correct function
  416. prototype
  417. ===============================================================================
  418. */
  419. //void BSP_SD_ReadCpltCallback(uint32_t SdCard)
  420. void BSP_SD_ReadCpltCallback(void)
  421. {
  422.   ReadStatus = 1;
  423. }

  424. /*
  425. ==============================================================================================
  426.   depending on the SD_HAL_Driver version, either the HAL_SD_ErrorCallback() or HAL_SD_AbortCallback()
  427.   or both could be defined, activate the callbacks below when suitable and needed
  428. ==============================================================================================
  429. void BSP_SD_AbortCallback(void)
  430. {
  431. }

  432. void    BSP_SD_ErrorCallback(void)
  433. {
  434. }
  435. */
  436. /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

复制代码






回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107077
QQ
 楼主| 发表于 2020-9-22 13:43:40 | 显示全部楼层
现在想想知道为什么使用SDIO自带DMA,因为通用的DMA性能不行,无法满足H7的SDMMC超高速模式

STM32H7的SDIO外接支持UHS-I 模式 (SDR12, SDR25, SDR50, SDR104和DDR50)需要1.8的电平转换器
http://www.armbbs.cn/forum.php?m ... id=89590&fromuid=58
(出处: 硬汉嵌入式论坛)

通用DMA性能:

STM32H7的SDIO外接支持UHS-I 模式 (SDR12, SDR25, SDR50, SDR104和DDR50)需要1.8的电平转换器
http://www.armbbs.cn/forum.php?m ... id=89590&fromuid=58
(出处: 硬汉嵌入式论坛)
回复

使用道具 举报

610

主题

3062

回帖

4912

积分

至尊会员

积分
4912
发表于 2020-9-22 17:12:16 | 显示全部楼层
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107077
QQ
 楼主| 发表于 2020-9-23 01:52:12 | 显示全部楼层
实际测试,官方提供的这种方式,性能略挫。
回复

使用道具 举报

2

主题

28

回帖

34

积分

新手上路

积分
34
发表于 2020-12-10 09:55:11 | 显示全部楼层
通用DMA 怎么做。有没有例子。
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107077
QQ
 楼主| 发表于 2020-12-10 10:34:27 | 显示全部楼层
终极菜鸟 发表于 2020-12-10 09:55
通用DMA 怎么做。有没有例子。

没有用通用DMA做,用的SDIO自带的专用DMA
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-5-16 15:47 , Processed in 0.218001 second(s), 25 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

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