硬汉嵌入式论坛

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

[SD/SDIO] 为什么STM32H7进不了SDMMC IDMA中断?

  [复制链接]

25

主题

68

回帖

143

积分

初级会员

积分
143
QQ
发表于 2020-2-19 13:27:43 | 显示全部楼层 |阅读模式
大家好!

因为我的程序使用了STM32H7的SDMMC2接TF卡,是采用轮询方式的。现在我感觉轮询方式读写TF卡的效率有点低,而且在读写过程中,还必须关闭所有中断。所以我想改为SDMMC2 IDMA方式来读写。

我的程序是直接寄存器开发的,没有使用HAL库。我在网上找了一些SDMMC1 IDMA例程,都是HAL库开发的。我直接修改SDMMC1 IDMA例程为SDMMC2 IDMA例程,在我的板子上也能正常SDMMC2 IDMA读写了。


但我费了很大力气,把HAL库移植到我的程序中,终于编译没错误了,但发现始终进不了SDMMC2 IDMA的中断,非常奇怪:
2020-02-19_130737.jpg 2020-02-19_130833.jpg

如上图,RX_Flag变量是要在IMDA中断程序的回调函数中,修改为1的。因为现在程序不能进IDMA中断,所以程序就在这里死循环了。
我看了数据缓存区buf,地址是ox24001FA4,是在AXI SRAM的,IDMA可以访问到的,而且ox24001FA4也是4字节对齐的。程序中也有配置并使能SDMMC2中断:
        HAL_NVIC_SetPriority(SDMMC2_IRQn,0,0);  //配置SDMMC2中断
        HAL_NVIC_EnableIRQ(SDMMC2_IRQn);        //使能SDMMC2中断


所以我现在是没办法了,移植的例程可以进IDMA中断,读写正常,但把例程移植进我的大程序后,就进不IDMA中断了。因为我对HAL库不熟悉,是不是还需要设置HAL哪些地方,才能进SDMMC IDMA中断?谢谢。
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107057
QQ
发表于 2020-2-19 15:14:28 | 显示全部楼层
不使用DMA测试下是否正常。
回复

使用道具 举报

25

主题

68

回帖

143

积分

初级会员

积分
143
QQ
 楼主| 发表于 2020-2-19 16:43:09 | 显示全部楼层
eric2013 发表于 2020-2-19 15:14
不使用DMA测试下是否正常。

不使用DMA,使用轮询方式读写完全正常。

我移植了别人的SDMMC1 IDMA例程,改为SDMMC2 IDMA例程,也完全正常。
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107057
QQ
发表于 2020-2-19 17:12:28 | 显示全部楼层
pnhywyb 发表于 2020-2-19 16:43
不使用DMA,使用轮询方式读写完全正常。

我移植了别人的SDMMC1 IDMA例程,改为SDMMC2 IDMA例程,也完 ...

重新读了一遍你的问题,明白你的意思了。

移植别人的程序能用,但是将别人的程序修改成自己的不能用。

这就很简单了,直接在这个修改后能用的例程基础逐步修改成自己的不就行了。。。
回复

使用道具 举报

36

主题

1445

回帖

1553

积分

至尊会员

积分
1553
发表于 2020-2-19 17:16:03 | 显示全部楼层
从你的描述也看不出来问题来,建议你将SD卡相关的全部更改为HAL库模式,这样可以参考官方的例程,解决起来比较快。
回复

使用道具 举报

14

主题

99

回帖

141

积分

初级会员

积分
141
发表于 2020-3-20 13:45:37 | 显示全部楼层
现在好了么?
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107057
QQ
发表于 2020-3-21 09:39:08 | 显示全部楼层

他的好了。
回复

使用道具 举报

25

主题

68

回帖

143

积分

初级会员

积分
143
QQ
 楼主| 发表于 2020-3-21 10:55:30 | 显示全部楼层

是的,最后我不知道是HAL库哪里的问题,索性直接把HAL库的HAL_SD_WriteBlocks_DMA函数和HAL_SD_IRQHandler函数,改写成寄存器的,读写就能进入中断了。HAL库就不用了,太绕了。好像能否进入IDMA中断,和这句有关:

SDMMC2->CMD |= 1<<6; //位6 CMDTRANS:CPSM 将命令视为数据传输命令、停止中断周期并向DPSM发出数据使能信号

后来我没去研究了,太复杂了。

现在IDMA读写测试正常了,但因为把SD写函数改为IDMA中断的,导致STM32连接电脑做USB读卡器不能正常工作,每次连接电脑都提示要格式化,并且格式化容量变为512KB,郁闷。
回复

使用道具 举报

14

主题

99

回帖

141

积分

初级会员

积分
141
发表于 2020-3-21 14:44:05 | 显示全部楼层
pnhywyb 发表于 2020-3-21 10:55
是的,最后我不知道是HAL库哪里的问题,索性直接把HAL库的HAL_SD_WriteBlocks_DMA函数和HAL_SD_IRQHandle ...

HAL库函数是不是直接调用HAL_SD_WriteBlocks_DMA函数就启用IMDA,不用另外设置了吧?现在写SD卡fatfs能达到多少的速度测试了么?谢谢~~
回复

使用道具 举报

25

主题

68

回帖

143

积分

初级会员

积分
143
QQ
 楼主| 发表于 2020-3-21 22:27:21 | 显示全部楼层
LR215 发表于 2020-3-21 14:44
HAL库函数是不是直接调用HAL_SD_WriteBlocks_DMA函数就启用IMDA,不用另外设置了吧?现在写SD卡fatfs能达 ...

  我根据HAL库函数,SD卡读写函数都改成寄存器操作了,IDMA中断模式。 我根据网上的例程,测试写文件成功:
res = f_open(&fnew, "0:FatFs写测试文件.txt",FA_CREATE_ALWAYS | FA_WRITE );
    if ( res == FR_OK )
    {
      /* 将指定存储区内容写入到文件内 */
      res = f_write(&fnew,WriteBuffer,sizeof(WriteBuffer),&fnum);
      if(res == FR_OK)
      {
        printf("》文件写入成功,写入字节数据:%d\n",fnum);
      }

说明我改写的SD IDMA写函数是对的,但却造成我的USB读卡器异常。切换回轮询方式的SD卡写函数,USB读卡器就正常了。

IDMA方式的SD写函数,应该比轮询方式的SD写函数快。不过我没有测试写速度,也不知道怎么测速度,不好意思。
回复

使用道具 举报

0

主题

1

回帖

1

积分

新手上路

积分
1
发表于 2020-9-4 20:08:14 | 显示全部楼层
我用的HAL库,也遇到了这个问题,请问有什么解决办法吗?[img]D:\QQ图片20200904200353.pngD:\QQ图片20200904200530.pngD:\QQ图片20200904200440.png[/img]
回复

使用道具 举报

9

主题

85

回帖

112

积分

初级会员

积分
112
发表于 2022-4-26 13:58:13 | 显示全部楼层
楼主在吗 ? @pnhywyb
我遇到跟你一模一样的问题,如果单独移植ARMFLY 的 V7.27 SDMMC IDMA例子,在 BSP_SD_ReadBlocks_DMA 运行时是可以正常工作并触发 SDMMC1_IRQHandler  , 但是当把此例子整合到自己的程序里,就无法触发 SDMMC1_IRQHandler中断了。
猜想是HAL 库的 IDMA中断在某种条件下被屏蔽了。或者行为异常干扰到中断向量了。 证据在于此时 SysTick_Handler 也停止运行 ,无法 超时退出。

不知楼主能否给出,HAL库的HAL_SD_WriteBlocks_DMA函数和HAL_SD_IRQHandler函数,改写成寄存器的 参考代码,测试下。

另外,不知硬汉哥能否也指点下!
非常感谢!
回复

使用道具 举报

9

主题

85

回帖

112

积分

初级会员

积分
112
发表于 2022-4-27 17:07:33 | 显示全部楼层
楼主和硬汉哥在吗?
能不能指点一下,搞了一周了,实在是没有办法。

多谢了!
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107057
QQ
发表于 2022-4-27 18:10:54 | 显示全部楼层
szjdb 发表于 2022-4-26 13:58
楼主在吗 ? @pnhywyb
我遇到跟你一模一样的问题,如果单独移植ARMFLY 的 V7.27 SDMMC IDMA例子,在 BSP_S ...

注意HAL库的版本,用同一个版本测试下。
回复

使用道具 举报

9

主题

85

回帖

112

积分

初级会员

积分
112
发表于 2022-4-28 10:23:41 | 显示全部楼层
多谢硬汉哥!

目前我用的 版本是  V1.8.0 ,算比较新的了,您的例子中是1.3 版本。 跟踪后发现 HAL_SD_ReadBlocks_DMA 能够正确读出第1个BLOCK, 而且没有任何出错信息返回,但就是不能触发中断,看函数内部已经打开中断屏蔽位
__HAL_SD_ENABLE_IT(hsd, (SDMMC_IT_DCRCFAIL | SDMMC_IT_DTIMEOUT | SDMMC_IT_RXOVERR | SDMMC_IT_DATAEND));
感觉这个中断被不知道被什么地方代码屏蔽了。

查手册也没看到这个IDMA中断申请通道的详细控制通道。 目前一直卡在这个地方了。

目前判断跟硬件无关,因为单独运行V7.27  IDMA是可以触发中断的。 初始化部分我已经改用v7.27的代码。

还请硬汉哥和众大神指点下。
回复

使用道具 举报

9

主题

85

回帖

112

积分

初级会员

积分
112
发表于 2022-4-29 13:49:18 | 显示全部楼层
硬汉哥能否帮忙问问楼主,能不能分享下寄存器版本的 SD_ReadBlocks_DMA、SD_WriteBlocks_DMA  和中断处理函数?

我现在用查询模式,写SD时明显干扰了播放音频,解决不了。

拜托了!
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107057
QQ
发表于 2022-4-29 15:32:35 | 显示全部楼层
szjdb 发表于 2022-4-29 13:49
硬汉哥能否帮忙问问楼主,能不能分享下寄存器版本的 SD_ReadBlocks_DMA、SD_WriteBlocks_DMA  和中断处理函 ...

RL-FlashFS是你所谓的寄存器方式,不知道你是否玩的转
[C] 纯文本查看 复制代码
/* -----------------------------------------------------------------------------
 * Copyright (c) 2013-2020 ARM Ltd.
 *
 * This software is provided 'as-is', without any express or implied warranty.
 * In no event will the authors be held liable for any damages arising from
 * the use of this software. Permission is granted to anyone to use this
 * software for any purpose, including commercial applications, and to alter
 * it and redistribute it freely, subject to the following restrictions:
 *
 * 1. The origin of this software must not be misrepresented; you must not
 *    claim that you wrote the original software. If you use this software in
 *    a product, an acknowledgment in the product documentation would be
 *    appreciated but is not required.
 *
 * 2. Altered source versions must be plainly marked as such, and must not be
 *    misrepresented as being the original software.
 *
 * 3. This notice may not be removed or altered from any source distribution.
 *
 *
 * $Date:        28. July 2020
 * $Revision:    V1.4
 *
 * Driver:       Driver_MCI0, Driver_MCI1
 * Configured:   via STM32CubeMx configuration tool
 * Project:      MCI Driver for ST STM32H7xx
 * --------------------------------------------------------------------------
 * Use the following configuration settings in the middleware component
 * to connect to this driver.
 *
 *   Configuration Setting                 Value   SDMMC Interface
 *   ---------------------                 -----   ---------------
 *   Connect to hardware via Driver_MCI# = 0       use SDMMC1
 *   Connect to hardware via Driver_MCI# = 1       use SDMMC2
 * -------------------------------------------------------------------------- */

/* History:
 *  Version 1.4
 *    Added handling for separate SD and MMC HAL layers
 *  Version 1.3
 *    Added busy signal handling after CMDREND interrupt
 *  Version 1.2
 *    Added data cache enable bit check
 *  Version 1.1
 *    Updated to be compliant with HAL drivers version 1.5.0
 *  Version 1.0
 *    Initial release
 */

/*! \page stm32h7_mci CMSIS-Driver MCI Setup 

The CMSIS-Driver MCI requires:
  - Setup of SDMMC1.
  - Optional Configuration for Card Detect Pin:
    - Configure arbitrary pin in GPIO_Input mode and add User Label: MemoryCard_CD0
    - Alternatively, define MemoryCard_CDx_Pin_Extern and implement function MCI_ReadCD in application
  - Optional Configuration for Write Protect Pin:
    - Configure arbitrary pin in GPIO_Input mode and add User Label: MemoryCard_WP0
    - Alternatively, define MemoryCard_WPx_Pin_Extern and implement function MCI_ReadWP in application
  - Configuring data buffers to reside in:
    - AXI SRAM when using SDMMC1 (Driver_MCI0)
    - AHB SRAM when using SDMMC2 (Driver_MCI1)
  - When using MMC devices:
    - Define MemoryCard_MMC0 if SDMMC1 uses MMC device (otherwise define is not required)
    - Define MemoryCard_MMC1 if SDMMC2 uses MMC device (otherwise define is not required)

\note The User Label name is used to connect the CMSIS-Driver to the GPIO pin.

The example below uses correct settings for STM32H743I-EVAL: 
  - SDMMC1 Mode:             SD 4bits Wide bus with dir voltage converter
  - Card Detect Input pin:   available by using MFX GPIO15 from application
  - Write Protect Input pin: not available

For different boards, refer to the hardware schematics to reflect correct setup values.

The STM32CubeMX configuration steps for Pinout, Clock, and System Configuration are 
listed below. Enter the values that are marked \b bold.
   
Pinout tab
----------
  1. Configure SDMMC1 mode
     - Peripherals \b SDMMC1: Mode=<b>SD 4 bits Wide bus with dir voltage converter</b>
          
Clock Configuration tab
-----------------------
  1. Configure SDMMC1,2 Clock Mux: Select PLL1Q or PLL2R clock source and set frequency below 200MHz.
  
Configuration tab
-----------------
  1. Under Connectivity open \b SDMMC1 Configuration:
     - <b>GPIO Settings</b>: review settings, no changes required
          Pin Name | Signal on Pin | GPIO mode | GPIO Pull-up/Pull..| Maximum out | User Label
          :--------|:--------------|:----------|:-------------------|:------------|:----------
          PB8      | SDMMC1_CKIN   | Alternate | No pull-up and no..| Very High   |.
          PB9      | SDMMC1_CDIR   | Alternate | No pull-up and no..| Very High   |.
          PC6      | SDMMC1_D0DIR  | Alternate | No pull-up and no..| Very High   |.
          PC7      | SDMMC1_D123DIR| Alternate | No pull-up and no..| Very High   |.
          PC8      | SDMMC1_D0     | Alternate | No pull-up and no..| Very High   |.
          PC9      | SDMMC1_D1     | Alternate | No pull-up and no..| Very High   |.
          PC10     | SDMMC1_D2     | Alternate | No pull-up and no..| Very High   |.
          PC11     | SDMMC1_D3     | Alternate | No pull-up and no..| Very High   |.
          PC12     | SDMMC1_CK     | Alternate | No pull-up and no..| Very High   |.
          PD2      | SDMMC1_CMD    | Alternate | No pull-up and no..| Very High   |.

     - <b>NVIC Settings</b>: enable interrupts
          Interrupt Table                      | Enable | Preemption Priority | Sub Priority
          :------------------------------------|:-------|:--------------------|:--------------
          SDMMC1 global interrupt              |\b ON   | 0                   | 0

     - Parameter Settings: not used
     - User Constants: not used

     Click \b OK to close the SDMMC1 Configuration dialog
  2. Under System open \b NVIC Configuration:
     - <b>Code generation</b>: Deselect "Generate IRQ Handler" for SDMMC1 global interrupt
     - <b>NVIC</b>: review settings, no changes required
     
     Click \b OK to close the NVIC Configuration dialog
*/

/*! \cond */

#include "MCI_STM32H7xx.h"

#define ARM_MCI_DRV_VERSION ARM_DRIVER_VERSION_MAJOR_MINOR(1,4)  /* driver version */

/* MCI0: Define Card Detect pin active state */
#if !defined(MemoryCard_CD0_Pin_Active)
  #define MemoryCard_CD0_Pin_Active GPIO_PIN_RESET
#endif

/* MCI0: Define Write Protect pin active state */
#if !defined(MemoryCard_WP0_Pin_Active)
  #define MemoryCard_WP0_Pin_Active GPIO_PIN_SET
#endif

/* MCI1: Define Card Detect pin active state */
#if !defined(MemoryCard_CD1_Pin_Active)
  #define MemoryCard_CD1_Pin_Active GPIO_PIN_RESET
#endif

/* MCI1: Define Write Protect pin active state */
#if !defined(MemoryCard_WP1_Pin_Active)
  #define MemoryCard_WP1_Pin_Active GPIO_PIN_SET
#endif

/* MCI0: Define Card Detect pin handling with external MCI_ReadCD() function */
#if defined(MemoryCard_CD0_Pin_Extern)
  #define MCI0_CD_PIN_EXT     1U
#else
  #define MCI0_CD_PIN_EXT     0U
#endif

/* MCI0: Define Write Protect pin handling with external MCI_ReadWP() function */
#if defined(MemoryCard_WP0_Pin_Extern)
  #define MCI0_WP_PIN_EXT     1U
#else
  #define MCI0_WP_PIN_EXT     0U
#endif

/* MCI1: Define Card Detect pin handling with external MCI_ReadCD() function */
#if defined(MemoryCard_CD1_Pin_Extern)
  #define MCI1_CD_PIN_EXT     1U
#else
  #define MCI1_CD_PIN_EXT     0U
#endif

/* MCI1: Define Write Protect pin handling with external MCI_ReadWP() function */
#if defined(MemoryCard_WP1_Pin_Extern)
  #define MCI1_WP_PIN_EXT     1U
#else
  #define MCI1_WP_PIN_EXT     0U
#endif

/* MCI0: Define MemoryCard_MMC0 if SDMMC1 is configured for MMC device */
#if !defined(MemoryCard_MMC0)
  #define MCI0_HANDLE_TYPE    0U
#else
  #define MCI0_HANDLE_TYPE    1U
#endif

/* MCI0: Define MemoryCard_MMC1 if SDMMC2 is configured for MMC device */
#if !defined(MemoryCard_MMC1)
  #define MCI1_HANDLE_TYPE    0U
#else
  #define MCI1_HANDLE_TYPE    1U
#endif

#if defined(MX_SDMMC1)
#if (MCI0_HANDLE_TYPE == 0)
#define MCI0_HANDLE      hsd1
extern SD_HandleTypeDef  hsd1;
#else
#define MCI0_HANDLE      hmmc1
extern MMC_HandleTypeDef hmmc1;
#endif

/* IRQ handler prototype */
void SDMMC1_IRQHandler (void);

#if (MCI0_CD_PIN != 0U)
static MCI_IO MCI0_IO_CD = { MX_MemoryCard_CD0_GPIOx,
                             MX_MemoryCard_CD0_GPIO_Pin, 0U,
                             MX_MemoryCard_CD0_GPIO_PuPd,
                             MemoryCard_CD0_Pin_Active };
#endif
#if (MCI0_WP_PIN != 0U)
static MCI_IO MCI0_IO_WP = { MX_MemoryCard_WP0_GPIOx,
                             MX_MemoryCard_WP0_GPIO_Pin, 0U,
                             MX_MemoryCard_WP0_GPIO_PuPd,
                             MemoryCard_WP0_Pin_Active };
#endif

/* MCI0 Information (Run-Time) */
static MCI_INFO MCI0_Info = {
  NULL,
  {0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U},
  NULL,
  0U,
  0U,
  0U,
  0U
};

/* MCI0 Resources */
static MCI_RESOURCES MCI0_Resources = {
  &MCI0_HANDLE,
  SDMMC1,
  #if (MCI0_CD_PIN != 0U)
  &MCI0_IO_CD,
  #else
  NULL,
  #endif
  #if (MCI0_WP_PIN != 0U)
  &MCI0_IO_WP,
  #else
  NULL,
  #endif
  &MCI0_Info
};

/* MCI0 Driver Capabilities */
static const ARM_MCI_CAPABILITIES MCI0_DriverCapabilities = {
  MCI0_CD_PIN | MCI0_CD_PIN_EXT,                  /* cd_state          */
  0U,                                             /* cd_event          */
  MCI0_WP_PIN | MCI0_WP_PIN_EXT,                  /* wp_state          */
  0U,                                             /* vdd               */
  0U,                                             /* vdd_1v8           */
  0U,                                             /* vccq              */
  0U,                                             /* vccq_1v8          */
  0U,                                             /* vccq_1v2          */
  MCI0_BUS_WIDTH_4,                               /* data_width_4      */
  MCI0_BUS_WIDTH_8,                               /* data_width_8      */
  0U,                                             /* data_width_4_ddr  */
  0U,                                             /* data_width_8_ddr  */
  1U,                                             /* high_speed        */
  0U,                                             /* uhs_signaling     */
  0U,                                             /* uhs_tuning        */
  0U,                                             /* uhs_sdr50         */
  0U,                                             /* uhs_sdr104        */
  0U,                                             /* uhs_ddr50         */
  0U,                                             /* uhs_driver_type_a */
  0U,                                             /* uhs_driver_type_c */
  0U,                                             /* uhs_driver_type_d */
  1U,                                             /* sdio_interrupt    */
  1U,                                             /* read_wait         */
  0U,                                             /* suspend_resume    */
  0U,                                             /* mmc_interrupt     */
  0U,                                             /* mmc_boot          */
  0U,                                             /* rst_n             */
  0U,                                             /* ccs               */
  0U                                              /* ccs_timeout       */
#if (defined(ARM_MCI_API_VERSION) && (ARM_MCI_API_VERSION >= 0x203U))
, 0U                                              /* reserved bits     */
#endif
};

#endif /* MX_SDMMC1 */

#if defined(MX_SDMMC2)
#if (MCI1_HANDLE_TYPE == 0)
#define MCI1_HANDLE      hsd2
extern SD_HandleTypeDef  hsd2;
#else
#define MCI1_HANDLE      hmmc2
extern MMC_HandleTypeDef hmmc2;
#endif

/* IRQ handler prototype */
void SDMMC2_IRQHandler (void);

#if (MCI1_CD_PIN != 0U)
static MCI_IO MCI1_IO_CD = { MX_MemoryCard_CD1_GPIOx,
                             MX_MemoryCard_CD1_GPIO_Pin, 0U,
                             MX_MemoryCard_CD1_GPIO_PuPd,
                             MemoryCard_CD1_Pin_Active };
#endif
#if (MCI1_WP_PIN != 0U)
static MCI_IO MCI1_IO_WP = { MX_MemoryCard_WP1_GPIOx,
                             MX_MemoryCard_WP1_GPIO_Pin, 0U,
                             MX_MemoryCard_WP1_GPIO_PuPd,
                             MemoryCard_WP1_Pin_Active };
#endif

/* MCI1 Information (Run-Time) */
static MCI_INFO MCI1_Info = {
  NULL,
  {0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U},
  NULL,
  0U,
  0U,
  0U,
  0U
};

/* MCI1 Resources */
static MCI_RESOURCES MCI1_Resources = {
  &MCI1_HANDLE,
  SDMMC2,
  #if (MCI1_CD_PIN != 0U)
  &MCI1_IO_CD,
  #else
  NULL,
  #endif
  #if (MCI1_WP_PIN != 0U)
  &MCI1_IO_WP,
  #else
  NULL,
  #endif
  &MCI1_Info
};

/* MCI1 Driver Capabilities */
static const ARM_MCI_CAPABILITIES MCI1_DriverCapabilities = {
  MCI1_CD_PIN | MCI1_CD_PIN_EXT,                  /* cd_state          */
  0U,                                             /* cd_event          */
  MCI1_WP_PIN | MCI1_WP_PIN_EXT,                  /* wp_state          */
  0U,                                             /* vdd               */
  0U,                                             /* vdd_1v8           */
  0U,                                             /* vccq              */
  0U,                                             /* vccq_1v8          */
  0U,                                             /* vccq_1v2          */
  MCI1_BUS_WIDTH_4,                               /* data_width_4      */
  MCI1_BUS_WIDTH_8,                               /* data_width_8      */
  0U,                                             /* data_width_4_ddr  */
  0U,                                             /* data_width_8_ddr  */
  1U,                                             /* high_speed        */
  0U,                                             /* uhs_signaling     */
  0U,                                             /* uhs_tuning        */
  0U,                                             /* uhs_sdr50         */
  0U,                                             /* uhs_sdr104        */
  0U,                                             /* uhs_ddr50         */
  0U,                                             /* uhs_driver_type_a */
  0U,                                             /* uhs_driver_type_c */
  0U,                                             /* uhs_driver_type_d */
  1U,                                             /* sdio_interrupt    */
  1U,                                             /* read_wait         */
  0U,                                             /* suspend_resume    */
  0U,                                             /* mmc_interrupt     */
  0U,                                             /* mmc_boot          */
  0U,                                             /* rst_n             */
  0U,                                             /* ccs               */
  0U                                              /* ccs_timeout       */
#if (defined(ARM_MCI_API_VERSION) && (ARM_MCI_API_VERSION >= 0x203U))
, 0U                                              /* reserved bits     */
#endif
};

#endif /* MX_SDMMC2 */


/* Driver Version */
static const ARM_DRIVER_VERSION DriverVersion = {
  ARM_MCI_API_VERSION,
  ARM_MCI_DRV_VERSION
};


/**
  \fn          void Control_SDMMC_Reset (SDMMC_TypeDef *instance)
  \brief       Reset SDMMC peripheral
*/
static void Control_SDMMC_Reset (SDMMC_TypeDef *instance) {

  if (instance == SDMMC1) {
    __HAL_RCC_SDMMC1_FORCE_RESET();
    __NOP(); __NOP(); __NOP(); __NOP();
    __HAL_RCC_SDMMC1_RELEASE_RESET();
  }
#if defined(SDMMC2)
  else {
    __HAL_RCC_SDMMC2_FORCE_RESET();
    __NOP(); __NOP(); __NOP(); __NOP();
    __HAL_RCC_SDMMC2_RELEASE_RESET();
  }
#endif
}

/**
  \fn          void Assign_SDMMC_Instance (uint32_t set, MCI_RESOURCES *mci)
  \brief       Set/Reset instance variable inside HAL handle structure
*/
static void Assign_SDMMC_Instance (uint32_t set, MCI_RESOURCES *mci) {
#if (defined(MX_SDMMC1) && (MCI0_HANDLE_TYPE == 0)) || \
    (defined(MX_SDMMC2) && (MCI1_HANDLE_TYPE == 0))
  SD_HandleTypeDef *h_sd;
#endif
#if (defined(MX_SDMMC1) && (MCI0_HANDLE_TYPE != 0)) || \
    (defined(MX_SDMMC2) && (MCI1_HANDLE_TYPE != 0))
  MMC_HandleTypeDef *h_mmc;
#endif

#if defined(MX_SDMMC1)
  if (mci == &MCI0_Resources) {
    #if (MCI0_HANDLE_TYPE == 0)
      h_sd = (SD_HandleTypeDef *)mci->h;
      /* Instance is the coresponding peripheral register inteface */
      if (set == 0) {
        h_sd->Instance = NULL;
      } else {
        h_sd->Instance = mci->reg;
      }
    #else
      h_mmc = (MMC_HandleTypeDef *)mci->h;
      /* Instance is the coresponding peripheral register inteface */
      if (set == 0) {
        h_mmc->Instance = NULL;
      } else {
        h_mmc->Instance = mci->reg;
      }
    #endif
  }
#endif

#if defined(MX_SDMMC2)
  if (mci == &MCI1_Resources) {
    #if (MCI1_HANDLE_TYPE == 0)
      h_sd = (SD_HandleTypeDef *)mci->h;
      /* Instance is the coresponding peripheral register inteface */
      if (set == 0) {
        h_sd->Instance = NULL;
      } else {
        h_sd->Instance = mci->reg;
      }
    #else
      h_mmc = (MMC_HandleTypeDef *)mci->h;
      /* Instance is the coresponding peripheral register inteface */
      if (set == 0) {
        h_mmc->Instance = NULL;
      } else {
        h_mmc->Instance = mci->reg;
      }
    #endif
  }
#endif
}

/**
  \fn          void Config_SDMMC_Msp (uint32_t init, MCI_RESOURCES *mci)
  \brief       Init/DeInit MSP layer
*/
static void Config_SDMMC_Msp (uint32_t init, MCI_RESOURCES *mci) {
#if defined(MX_SDMMC1)
  if (mci == &MCI0_Resources) {
    #if (MCI0_HANDLE_TYPE == 0)
      if (mci->h != NULL) {
        if (init == 0) {
          HAL_SD_MspDeInit (mci->h);
        } else {
          HAL_SD_MspInit (mci->h);
        }
      }
    #else
      if (mci->h != NULL) {
        if (init == 0) {
          HAL_MMC_MspDeInit (mci->h);
        } else {
          HAL_MMC_MspInit (mci->h);
        }
      }
    #endif
  }
#endif

#if defined(MX_SDMMC2)
  if (mci == &MCI1_Resources) {
    #if (MCI1_HANDLE_TYPE == 0)
      if (mci->h != NULL) {
        if (init == 0) {
          HAL_SD_MspDeInit (mci->h);
        } else {
          HAL_SD_MspInit (mci->h);
        }
      }
    #else
      if (mci->h != NULL) {
        if (init == 0) {
          HAL_MMC_MspDeInit (mci->h);
        } else {
          HAL_MMC_MspInit (mci->h);
        }
      }
    #endif
  }
#endif
}


/**
  \fn            int32_t MCI_ReadCD (uint32_t instance)
  \brief         Read Card Detect (CD) state.
  \param[in]     instance  MCI driver instance number (0:SDMMC1, 1:SDMMC2)
  \return        1:card detected, 0:card not detected, or error
  \note This function should be reimplemented in user application
*/
__WEAK int32_t MCI_ReadCD (uint32_t instance) {
  (void)instance;
  /* Default implementation */
  return (0);
}

/**
  \fn            int32_t MCI_ReadWP (uint32_t instance)
  \brief         Read Write Protect (WP) state.
  \param[in]     instance  MCI driver instance number (0:SDMMC1, 1:SDMMC2)
  \return        1:write protected, 0:not write protected, or error
  \note This function should be reimplemented in user application
*/
__WEAK int32_t MCI_ReadWP (uint32_t instance) {
  (void)instance;
  /* Default implementation */
  return (0);
}


/**
  \fn          ARM_DRV_VERSION GetVersion (void)
  \brief       Get driver version.
  \return      \ref ARM_DRV_VERSION
*/
static ARM_DRIVER_VERSION GetVersion (void) {
  return DriverVersion;
}


/**
  \fn          ARM_MCI_CAPABILITIES MCI_GetCapabilities (void)
  \brief       Get driver capabilities.
  \return      \ref ARM_MCI_CAPABILITIES
*/
static ARM_MCI_CAPABILITIES GetCapabilities (MCI_RESOURCES *mci) {
  ARM_MCI_CAPABILITIES cap;

  memset((void *)&cap, 0U, sizeof(ARM_MCI_CAPABILITIES));
#if defined(MX_SDMMC1)
  if (mci->reg == SDMMC1) { cap = MCI0_DriverCapabilities; }
#endif
#if defined(MX_SDMMC2)
  if (mci->reg == SDMMC2) { cap = MCI1_DriverCapabilities; }
#endif

  return (cap);
}


/**
  \fn            int32_t Initialize (ARM_MCI_SignalEvent_t cb_event)
  \brief         Initialize the Memory Card Interface
  \param[in]     cb_event  Pointer to \ref ARM_MCI_SignalEvent
  \return        \ref execution_status
*/
static int32_t Initialize (ARM_MCI_SignalEvent_t cb_event, MCI_RESOURCES *mci) {

  if (mci->info->flags & MCI_INIT) { return ARM_DRIVER_OK; }

  /* Set SDMMC instance pointer */
  Assign_SDMMC_Instance (1U, mci);

  /* Clear control structure */
  memset ((void *)mci->info, 0, sizeof (MCI_INFO));

  mci->info->cb_event = cb_event;
  mci->info->flags    = MCI_INIT;

  return ARM_DRIVER_OK;
}


/**
  \fn            int32_t Uninitialize (void)
  \brief         De-initialize Memory Card Interface.
  \return        \ref execution_status
*/
static int32_t Uninitialize (MCI_RESOURCES *mci) {

  mci->info->flags = 0U;

  /* Reset SDMMC instance pointer */
  Assign_SDMMC_Instance (0U, mci);

  return ARM_DRIVER_OK;
}


/**
  \fn            int32_t PowerControl (ARM_POWER_STATE state)
  \brief         Control Memory Card Interface Power.
  \param[in]     state   Power state \ref ARM_POWER_STATE
  \return        \ref execution_status
*/
static int32_t PowerControl (ARM_POWER_STATE state, MCI_RESOURCES *mci) {
  PLL1_ClocksTypeDef pll1_clk;
  PLL2_ClocksTypeDef pll2_clk;
  int32_t status;

  if ((state != ARM_POWER_OFF)  && 
      (state != ARM_POWER_FULL) && 
      (state != ARM_POWER_LOW)) {
    return ARM_DRIVER_ERROR_PARAMETER;
  }

  status = ARM_DRIVER_OK;

  switch (state) {
    case ARM_POWER_OFF:
      /* Reset/Dereset SDMMC peripheral */
      Control_SDMMC_Reset (mci->reg);

      Config_SDMMC_Msp (0U, mci);

      /* Clear status */
      mci->info->status.command_active   = 0U;
      mci->info->status.command_timeout  = 0U;
      mci->info->status.command_error    = 0U;
      mci->info->status.transfer_active  = 0U;
      mci->info->status.transfer_timeout = 0U;
      mci->info->status.transfer_error   = 0U;
      mci->info->status.sdio_interrupt   = 0U;
      mci->info->status.ccs              = 0U;

      mci->info->flags &= ~MCI_POWER;
      break;

    case ARM_POWER_FULL:
      if ((mci->info->flags & MCI_INIT)  == 0U) {
        return ARM_DRIVER_ERROR;
      }
      if ((mci->info->flags & MCI_POWER) != 0U) {
        return ARM_DRIVER_OK;
      }

      Config_SDMMC_Msp (1U, mci);

      /* Check SDMMC kernel clock source */
      if ((RCC->D1CCIPR & RCC_D1CCIPR_SDMMCSEL) == 0U) {
        /* pll1_q_ck */
        HAL_RCCEx_GetPLL1ClockFreq (&pll1_clk);
        mci->info->ker_clk = pll1_clk.PLL1_Q_Frequency;
      } else {
        /* pll2_r_ck */
        HAL_RCCEx_GetPLL2ClockFreq (&pll2_clk);
        mci->info->ker_clk = pll2_clk.PLL2_R_Frequency;
      }

      /* Clear response variable */
      mci->info->response = NULL;

      /* Enable SDMMC peripheral interrupts */
      mci->reg->MASK = SDMMC_MASK_DATAENDIE  |
                       SDMMC_MASK_CMDSENTIE  |
                       SDMMC_MASK_CMDRENDIE  |
                       SDMMC_MASK_DTIMEOUTIE |
                       SDMMC_MASK_CTIMEOUTIE |
                       SDMMC_MASK_DCRCFAILIE |
                       SDMMC_MASK_CCRCFAILIE |
                       SDMMC_MASK_BUSYD0ENDIE;

      /* Set max data timeout */
      mci->reg->DTIMER = 0xFFFFFFFF;

      /* Set transceiver polarity */
      mci->reg->POWER = SDMMC_POWER_DIRPOL;

      /* Set maximum clock divider */
      mci->reg->CLKCR = 0x3FF;
      
      /* Enable clock to the card (SDIO_CK) */
      mci->reg->POWER |= SDMMC_POWER_PWRCTRL_1 | SDMMC_POWER_PWRCTRL_0;

      mci->info->flags |= MCI_POWER;
      break;

    case ARM_POWER_LOW:
      return ARM_DRIVER_ERROR_UNSUPPORTED;
  }
  return status;
}


/**
  \fn            int32_t CardPower (uint32_t voltage)
  \brief         Set Memory Card supply voltage.
  \param[in]     voltage  Memory Card supply voltage
  \return        \ref execution_status
*/
static int32_t CardPower (uint32_t voltage, MCI_RESOURCES *mci) {
  (void)voltage;

  if ((mci->info->flags & MCI_POWER) == 0U) { return ARM_DRIVER_ERROR; }
  return ARM_DRIVER_OK;
}


/**
  \fn            int32_t ReadCD (void)
  \brief         Read Card Detect (CD) state.
  \return        1:card detected, 0:card not detected, or error
*/
static int32_t ReadCD (MCI_RESOURCES *mci) {
  int32_t val;

  if ((mci->info->flags & MCI_POWER) == 0U) { return ARM_DRIVER_ERROR; }

  val = 0;

  /* Read CD (Card Detect) Pin */
  #if (MCI0_CD_PIN != 0U) || (MCI1_CD_PIN != 0U) || (MCI0_CD_PIN_EXT != 0U) || (MCI1_CD_PIN_EXT != 0U)
    if (mci->io_cd != NULL) {
      /* Note: io->af holds MemoryCard_CD_Pin_Active definition */
      if (HAL_GPIO_ReadPin (mci->io_cd->port, mci->io_cd->pin) == mci->io_cd->af) {
        /* Card Detect switch is active */
        val = 1;
      }
    }
    else {
      /* Card detect pin not specified, call application */
      if (mci->reg == SDMMC1) {
        #if (MCI0_CD_PIN_EXT != 0U)
        val = MCI_ReadCD (0U);
        #endif
      }
      else {
        #if (MCI1_CD_PIN_EXT != 0U)
        val = MCI_ReadCD (1U);
        #endif
      }
    }
  #endif

  return (val);
}


/**
  \fn            int32_t ReadWP (void)
  \brief         Read Write Protect (WP) state.
  \return        1:write protected, 0:not write protected, or error
*/
static int32_t ReadWP (MCI_RESOURCES *mci) {
  int32_t val;

  if ((mci->info->flags & MCI_POWER) == 0U) { return ARM_DRIVER_ERROR; }

  val = 0;

  /* Read WP (Write Protect) Pin */
  #if (MCI0_WP_PIN != 0U) || (MCI1_WP_PIN != 0U) || (MCI0_WP_PIN_EXT != 0U) || (MCI1_WP_PIN_EXT != 0U)
    if (mci->io_wp != NULL) {
      /* Note: io->af holds MemoryCard_WP_Pin_Active definition */
      if (HAL_GPIO_ReadPin (mci->io_wp->port, mci->io_wp->pin) == mci->io_wp->af) {
        /* Write protect switch is active */
        val = 1;
      }
    }
    else {
      /* Write protect pin not specified, call application */
      if (mci->reg == SDMMC1) {
        #if (MCI0_WPPIN_EXT != 0U)
        val = MCI_ReadWP (0U);
        #endif
      }
      else {
        #if (MCI1_WP_PIN_EXT != 0U)
        val = MCI_ReadWP (1U);
        #endif
      }
    }
  #endif

  return (val);
}


/**
  \fn            int32_t SendCommand (uint32_t  cmd,
                                      uint32_t  arg,
                                      uint32_t  flags,
                                      uint32_t *response)
  \brief         Send Command to card and get the response.
  \param[in]     cmd       Memory Card command
  \param[in]     arg       Command argument
  \param[in]     flags     Command flags
  \param[out]    response  Pointer to buffer for response
  \return        \ref execution_status
*/
static int32_t SendCommand (uint32_t cmd, uint32_t arg, uint32_t flags, uint32_t *response, MCI_RESOURCES *mci) {
  uint32_t i, clkcr;

  if (((flags & MCI_RESPONSE_EXPECTED_Msk) != 0U) && (response == NULL)) {
    return ARM_DRIVER_ERROR_PARAMETER;
  }
  if ((mci->info->flags & MCI_SETUP) == 0U) {
    return ARM_DRIVER_ERROR;
  }
  if (mci->info->status.command_active) {
    return ARM_DRIVER_ERROR_BUSY;
  }
  mci->info->status.command_active   = 1U;
  mci->info->status.command_timeout  = 0U;
  mci->info->status.command_error    = 0U;
  mci->info->status.transfer_timeout = 0U;
  mci->info->status.transfer_error   = 0U;
  mci->info->status.ccs              = 0U;

  if (flags & ARM_MCI_CARD_INITIALIZE) {
    clkcr = mci->reg->CLKCR;

    if ((clkcr & SDMMC_CLKCR_PWRSAV) != 0) {
      mci->reg->CLKCR = (clkcr & ~SDMMC_CLKCR_PWRSAV);

      /* Determine SDMMC_CK frequency */
      i = mci->info->ker_clk / ((clkcr & 0x3FF) << 1U);
      
      /* Determine ratio between CPU and SDMMC_CK frequency */
      i = SystemCoreClock / i;

      for (i *= 74; i; i--) {
        ; /* Wait for at least 74 cycles */
      }
      mci->reg->CLKCR = clkcr;
    }
  }

  if (cmd == 11U) {
    /* Voltage switch procedure enable */
    mci->reg->POWER |= SDMMC_POWER_VSWITCHEN;
  }

  /* Set command register value */
  cmd = SDMMC_CMD_CPSMEN | (cmd & 0xFFU);

  mci->info->response = response;
  mci->info->flags   &= ~(MCI_RESP_CRC | MCI_RESP_LONG);

  switch (flags & ARM_MCI_RESPONSE_Msk) {
    case ARM_MCI_RESPONSE_NONE:
      /* No response expected (wait CMDSENT) */
      break;

    case ARM_MCI_RESPONSE_SHORT:
    case ARM_MCI_RESPONSE_SHORT_BUSY:
      /* Short response expected (wait CMDREND or CCRCFAIL) */
      cmd |= SDMMC_CMD_WAITRESP_0;
      break;

    case ARM_MCI_RESPONSE_LONG:
      mci->info->flags |= MCI_RESP_LONG;
      /* Long response expected (wait CMDREND or CCRCFAIL) */
      cmd |= SDMMC_CMD_WAITRESP_1 | SDMMC_CMD_WAITRESP_0;
      break;

    default:
      return ARM_DRIVER_ERROR;
  }
  if (flags & ARM_MCI_RESPONSE_CRC) {
    mci->info->flags |= MCI_RESP_CRC;
  }
  if (flags & ARM_MCI_TRANSFER_DATA) {
    mci->info->flags |= MCI_DATA_XFER;
  }

  /* Clear all interrupt flags */
  mci->reg->ICR = SDMMC_ICR_BIT_Msk;

  /* Send the command */
  mci->reg->ARG = arg;
  mci->reg->CMD = cmd;

  return ARM_DRIVER_OK;
}


/**
  \fn            int32_t SetupTransfer (uint8_t *data,
                                        uint32_t block_count,
                                        uint32_t block_size,
                                        uint32_t mode)
  \brief         Setup read or write transfer operation.
  \param[in,out] data         Pointer to data block(s) to be written or read
  \param[in]     block_count  Number of blocks
  \param[in]     block_size   Size of a block in bytes
  \param[in]     mode         Transfer mode
  \return        \ref execution_status
*/
static int32_t SetupTransfer (uint8_t *data, uint32_t block_count, uint32_t block_size, uint32_t mode, MCI_RESOURCES *mci) {
  uint32_t sz, dctrl, daddr;

  if ((data == NULL) || (block_count == 0U) || (block_size == 0U)) { return ARM_DRIVER_ERROR_PARAMETER; }

  if ((mci->info->flags & MCI_SETUP) == 0U) {
    return ARM_DRIVER_ERROR;
  }
  if (mci->info->status.transfer_active) {
    return ARM_DRIVER_ERROR_BUSY;
  }
  
  daddr = (uint32_t)data;

  mci->reg->IDMABASE0 = daddr;
  mci->reg->IDMACTRL  =  SDMMC_IDMA_IDMAEN;

  dctrl = 0U;

  if ((mode & ARM_MCI_TRANSFER_WRITE) == 0) {
    /* Direction: From card to controller */
    mci->info->flags |= MCI_DATA_READ;
    dctrl |= SDMMC_DCTRL_DTDIR;
  }
  else {
    /* Direction: From controller to card */
    mci->info->flags &= ~MCI_DATA_READ;

    if ((SCB->CCR & SCB_CCR_DC_Msk) != 0U) {
      SCB_CleanDCache_by_Addr ((uint32_t *)daddr, (int32_t)(block_count * block_size));
    }
  }

  if (mode & ARM_MCI_TRANSFER_STREAM) {
    /* Stream or SDIO multibyte data transfer enable */
    dctrl |= SDMMC_DCTRL_DTMODE;
  }

  /* Set data block size */
  if (block_size == 512U) {
    sz = 9U;
  }
  else {
    if (block_size > 16384U) {
      return ARM_DRIVER_ERROR_UNSUPPORTED;
    }
    for (sz = 0U; sz < 14U; sz++) {
      if (block_size & (1UL << sz)) {
        break;
      }
    }
  }

  mci->info->dlen   = block_count * block_size;
  mci->info->dctrl  = dctrl | (sz << 4);

  return (ARM_DRIVER_OK);
}


/**
  \fn            int32_t AbortTransfer (void)
  \brief         Abort current read/write data transfer.
  \return        \ref execution_status
*/
static int32_t AbortTransfer (MCI_RESOURCES *mci) {
  int32_t  status;
  uint32_t mask;

  if ((mci->info->flags & MCI_SETUP) == 0U) { return ARM_DRIVER_ERROR; }

  status = ARM_DRIVER_OK;

  /* Disable interrupts */
  mask = mci->reg->MASK;
  mci->reg->MASK = 0U;

  /* Disable IDMA */
  mci->reg->IDMACTRL &= ~(SDMMC_IDMA_IDMAEN);

  /* Flush FIFO */
  mci->reg->DCTRL |= SDMMC_DCTRL_FIFORST;

  /* Clear data transfer bit */
  mci->reg->DCTRL &= ~(SDMMC_DCTRL_DTEN);

  mci->info->status.command_active  = 0U;
  mci->info->status.transfer_active = 0U;
  mci->info->status.sdio_interrupt  = 0U;
  mci->info->status.ccs             = 0U;

  /* Clear pending interrupts */
  mci->reg->ICR = SDMMC_ICR_BIT_Msk;

  /* Enable interrupts */
  mci->reg->MASK = mask;

  return status;
}


/**
  \fn            int32_t Control (uint32_t control, uint32_t arg)
  \brief         Control MCI Interface.
  \param[in]     control  Operation
  \param[in]     arg      Argument of operation (optional)
  \return        \ref execution_status
*/
static int32_t Control (uint32_t control, uint32_t arg, MCI_RESOURCES *mci) {
  GPIO_InitTypeDef GPIO_InitStruct;
  GPIO_TypeDef *port;
  uint32_t val, clkdiv, bps;

  if ((mci->info->flags & MCI_POWER) == 0U) { return ARM_DRIVER_ERROR; }

  switch (control) {
    case ARM_MCI_BUS_SPEED:
      /* Determine clock divider and set bus speed */
      clkdiv = ((mci->info->ker_clk - 1U) / arg) + 1U;
      clkdiv = clkdiv & 0x3FFU;

      val  = mci->reg->CLKCR & ~SDMMC_CLKCR_CLKDIV;
      val |= clkdiv >> 1U;

      /* Set new clock divider */
      mci->reg->CLKCR = val;

      bps = mci->info->ker_clk / clkdiv;

      /* Bus speed configured */
      mci->info->flags |= MCI_SETUP;
      return ((int32_t)bps);

    case ARM_MCI_BUS_SPEED_MODE:
      /* Read clock control register */
      val = mci->reg->CLKCR;
      /* Clear DDR bit */
      val &= ~SDMMC_CLKCR_DDR;

      switch (arg) {
        case ARM_MCI_BUS_DEFAULT_SPEED:
          /* Speed mode up to 25MHz */
        case ARM_MCI_BUS_HIGH_SPEED:
          /* Speed mode up to 50MHz */
        case ARM_MCI_BUS_UHS_SDR12:
          /* SDR12:  up to  25MHz,  12.5MB/s: UHS-I 1.8V signaling */
        case ARM_MCI_BUS_UHS_SDR25:
          /* SDR25:  up to  50MHz,  25  MB/s: UHS-I 1.8V signaling */
          val &= ~SDMMC_CLKCR_BUSSPEED;
          break;

        case ARM_MCI_BUS_UHS_DDR50:
          /* DDR50:  up to  50MHz,  50  MB/s: UHS-I 1.8V signaling */
          val |= SDMMC_CLKCR_DDR;
        case ARM_MCI_BUS_UHS_SDR50:
          /* SDR50:  up to 100MHz,  50  MB/s: UHS-I 1.8V signaling */
        case ARM_MCI_BUS_UHS_SDR104:
          /* SDR104: up to 208MHz, 104  MB/s: UHS-I 1.8V signaling */
          val = mci->reg->CLKCR | SDMMC_CLKCR_BUSSPEED;
          break;

        default: return ARM_DRIVER_ERROR_UNSUPPORTED;
      }
      /* Set new register value */
      mci->reg->CLKCR = val;
      break;

    case ARM_MCI_BUS_CMD_MODE:
      switch (arg) {
        case ARM_MCI_BUS_CMD_OPEN_DRAIN:
          /* Configure command line in open-drain mode */
          val = GPIO_MODE_AF_OD;
          break;
        case ARM_MCI_BUS_CMD_PUSH_PULL:
          /* Configure command line in push-pull mode */
          val = GPIO_MODE_AF_PP;
          break;
        default:
          return ARM_DRIVER_ERROR_UNSUPPORTED;
      }

      GPIO_InitStruct.Mode  = val;
      GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
      GPIO_InitStruct.Pull  = GPIO_PULLUP;

      #if defined(MX_SDMMC1_CMD_Pin)
      if (mci->reg == SDMMC1) {
        port                      = MX_SDMMC1_CMD_GPIOx;
        GPIO_InitStruct.Pin       = MX_SDMMC1_CMD_GPIO_Pin;
        GPIO_InitStruct.Alternate = MX_SDMMC1_CMD_GPIO_AF;
      }
      #endif
      #if defined(MX_SDMMC2_CMD_Pin)
      if (mci->reg == SDMMC2) {
        port                      = MX_SDMMC2_CMD_GPIOx;
        GPIO_InitStruct.Pin       = MX_SDMMC2_CMD_GPIO_Pin;
        GPIO_InitStruct.Alternate = MX_SDMMC2_CMD_GPIO_AF;
      }
      #endif

      HAL_GPIO_Init(port, &GPIO_InitStruct);
      break;

    case ARM_MCI_BUS_DATA_WIDTH:
      val = mci->reg->CLKCR & ~SDMMC_CLKCR_WIDBUS;

      switch (arg) {
        case ARM_MCI_BUS_DATA_WIDTH_1:
          break;
        case ARM_MCI_BUS_DATA_WIDTH_4:
          val |= SDMMC_CLKCR_WIDBUS_0;
          break;
        case ARM_MCI_BUS_DATA_WIDTH_8:
          val |= SDMMC_CLKCR_WIDBUS_1;
          break;
        default:
          return ARM_DRIVER_ERROR_UNSUPPORTED;
      }

      mci->reg->CLKCR = val;
      break;

    case ARM_MCI_CONTROL_CLOCK_IDLE:
      val = mci->reg->CLKCR;
      if (arg) {
        /* Clock generation enabled when idle */
        val &= ~SDMMC_CLKCR_PWRSAV;
      }
      else {
        /* Clock generation disabled when idle */
        val |= SDMMC_CLKCR_PWRSAV;
      }
      mci->reg->CLKCR = val;
      break;

    case ARM_MCI_DATA_TIMEOUT:
      mci->reg->DTIMER = arg;
      break;

    case ARM_MCI_MONITOR_SDIO_INTERRUPT:
      mci->info->status.sdio_interrupt = 0U;
      mci->reg->MASK |= SDMMC_MASK_SDIOITIE;
      break;

    case ARM_MCI_CONTROL_READ_WAIT:
      if (arg) {
        /* Assert read wait */
        mci->info->flags |= MCI_READ_WAIT;
      }
      else {
        /* Clear read wait */
        mci->info->flags &= ~MCI_READ_WAIT;
        mci->reg->DCTRL &= ~SDMMC_DCTRL_RWSTOP;
      }
      break;

    default: return ARM_DRIVER_ERROR_UNSUPPORTED;
  }

  return ARM_DRIVER_OK;
}


/**
  \fn            ARM_MCI_STATUS GetStatus (void)
  \brief         Get MCI status.
  \return        MCI status \ref ARM_MCI_STATUS
*/
static ARM_MCI_STATUS GetStatus (MCI_RESOURCES *mci) {
  return mci->info->status;
}


/* SDMMC interrupt handler */
static void SDMMC_IRQHandler (MCI_RESOURCES *mci) {
  uint32_t sta, icr, event, mask;

  event = 0U;
  icr   = 0U;

  /* Read SDMMC interrupt status */
  sta = mci->reg->STA;

  if (sta & SDMMC_STA_ERR_BIT_Msk) {
    /* Check error interrupts */
    if (sta & SDMMC_STA_CCRCFAIL) {
      icr |= SDMMC_ICR_CCRCFAILC;
      /* Command response CRC check failed */
      if (mci->info->flags & MCI_RESP_CRC) {
        mci->info->status.command_error = 1U;

        event |= ARM_MCI_EVENT_COMMAND_ERROR;
      }
      else {
        /* Ignore CRC error and read the response */
        sta |= SDMMC_STA_CMDREND;
      }
    }
    if (sta & SDMMC_STA_DCRCFAIL) {
      icr |= SDMMC_ICR_DCRCFAILC;
      /* Data block CRC check failed */
      mci->info->status.transfer_error = 1U;

      event |= ARM_MCI_EVENT_TRANSFER_ERROR;
    }
    if (sta & SDMMC_STA_CTIMEOUT) {
      icr |= SDMMC_ICR_CTIMEOUTC;
      /* Command response timeout */
      mci->info->status.command_timeout = 1U;

      event |= ARM_MCI_EVENT_COMMAND_TIMEOUT;
    }
    if (sta & SDMMC_STA_DTIMEOUT) {
      icr |= SDMMC_ICR_DTIMEOUTC;
      /* Data timeout */
      mci->info->status.transfer_timeout = 1U;

      event |= ARM_MCI_EVENT_TRANSFER_TIMEOUT;
    }
  }

  if (sta & SDMMC_STA_CMDREND) {
    /* Command response received */
    icr |= SDMMC_ICR_CMDRENDC;

    if (!(sta & SDMMC_STA_BUSYD0)) {
      /* BusyD0 signal not active */
      event |= ARM_MCI_EVENT_COMMAND_COMPLETE;
    }
  }
  if (sta & SDMMC_STA_BUSYD0END) {
    icr |= SDMMC_ICR_BUSYD0ENDC;
    /* BusyD0 signal deactivated */
    event |= ARM_MCI_EVENT_COMMAND_COMPLETE;
  }

  if (event & ARM_MCI_EVENT_COMMAND_COMPLETE) {
    if (mci->info->response) {
      /* Read response registers */
      if (mci->info->flags & MCI_RESP_LONG) {
        mci->info->response[0] = mci->reg->RESP4;
        mci->info->response[1] = mci->reg->RESP3;
        mci->info->response[2] = mci->reg->RESP2;
        mci->info->response[3] = mci->reg->RESP1;
      }
      else {
        mci->info->response[0] = mci->reg->RESP1;
      }
    }
    if (mci->info->flags & MCI_DATA_XFER) {
      mci->info->flags &= ~MCI_DATA_XFER;

      if (mci->info->flags & MCI_READ_WAIT) {
        mci->info->dctrl |= SDMMC_DCTRL_RWSTART;
      }

      /* Start data transfer */
      mci->reg->DLEN  = mci->info->dlen;
      mci->reg->DCTRL = mci->info->dctrl | SDMMC_DCTRL_DTEN;

      mci->info->status.transfer_active = 1U;
    }
  }
  if (sta & SDMMC_STA_CMDSENT) {
    icr |= SDMMC_ICR_CMDSENTC;
    /* Command sent (no response required) */
    event |= ARM_MCI_EVENT_COMMAND_COMPLETE;
  }
  if (sta & SDMMC_STA_DATAEND) {
    icr |= SDMMC_ICR_DATAENDC;
    /* Data end (DCOUNT is zero) */
    event |= ARM_MCI_EVENT_TRANSFER_COMPLETE;

    if ((SCB->CCR & SCB_CCR_DC_Msk) != 0U) {
      SCB_InvalidateDCache_by_Addr ((uint32_t*)mci->reg->IDMABASE0, (int32_t)mci->info->dlen);
    }
  }
  if (sta & SDMMC_STA_DBCKEND) {
    icr |= SDMMC_ICR_DBCKENDC;
    /* Data block sent/received (CRC check passed) */
  }
  if (sta & SDMMC_STA_SDIOIT) {
    icr |= SDMMC_ICR_SDIOITC;
    /* Disable interrupt (must be re-enabled using Control) */
    mci->reg->MASK &= SDMMC_MASK_SDIOITIE;

    event |= ARM_MCI_EVENT_SDIO_INTERRUPT;
  }

  /* Clear processed interrupts */
  mci->reg->ICR = icr;

  if (event) {
    /* Check for transfer events */
    mask = ARM_MCI_EVENT_TRANSFER_ERROR   |
           ARM_MCI_EVENT_TRANSFER_TIMEOUT |
           ARM_MCI_EVENT_TRANSFER_COMPLETE;
    if (event & mask) {
      mci->info->status.transfer_active = 0U;

      if (mci->info->cb_event) {
        if (event & ARM_MCI_EVENT_TRANSFER_ERROR) {
          (mci->info->cb_event)(ARM_MCI_EVENT_TRANSFER_ERROR);
        }
        else if (event & ARM_MCI_EVENT_TRANSFER_TIMEOUT) {
          (mci->info->cb_event)(ARM_MCI_EVENT_TRANSFER_TIMEOUT);
        }
        else {
          (mci->info->cb_event)(ARM_MCI_EVENT_TRANSFER_COMPLETE);
        }
      }
    }
    /* Check for command events */
    mask = ARM_MCI_EVENT_COMMAND_ERROR   |
           ARM_MCI_EVENT_COMMAND_TIMEOUT |
           ARM_MCI_EVENT_COMMAND_COMPLETE;
    if (event & mask) {
      mci->info->status.command_active = 0U;

      if (mci->info->cb_event) {
        if (event & ARM_MCI_EVENT_COMMAND_ERROR) {
          (mci->info->cb_event)(ARM_MCI_EVENT_COMMAND_ERROR);
        }
        else if (event & ARM_MCI_EVENT_COMMAND_TIMEOUT) {
          (mci->info->cb_event)(ARM_MCI_EVENT_COMMAND_TIMEOUT);
        }
        else {
          (mci->info->cb_event)(ARM_MCI_EVENT_COMMAND_COMPLETE);
        }
      }
    }
    /* Check for SDIO INT event */
    if (event & ARM_MCI_EVENT_SDIO_INTERRUPT) {
      mci->info->status.sdio_interrupt = 1U;

      if (mci->info->cb_event) {
        (mci->info->cb_event)(ARM_MCI_EVENT_SDIO_INTERRUPT);
      }
    }
  }
}


#if defined (MX_SDMMC1)
/* MCI0 Driver wrapper functions */
static ARM_MCI_CAPABILITIES MCI0_GetCapabilities (void) {
  return GetCapabilities (&MCI0_Resources);
}
static int32_t MCI0_Initialize (ARM_MCI_SignalEvent_t cb_event) {
  return Initialize (cb_event, &MCI0_Resources);
}
static int32_t MCI0_Uninitialize (void) {
  return Uninitialize (&MCI0_Resources);
}
static int32_t MCI0_PowerControl (ARM_POWER_STATE state) {
  return PowerControl (state, &MCI0_Resources);
}
static int32_t MCI0_CardPower (uint32_t voltage) {
  return CardPower (voltage, &MCI0_Resources);
}
static int32_t MCI0_ReadCD (void) {
  return ReadCD (&MCI0_Resources);
}
static int32_t MCI0_ReadWP (void) {
  return ReadWP (&MCI0_Resources);
}
static int32_t MCI0_SendCommand (uint32_t cmd, uint32_t arg, uint32_t flags, uint32_t *response) {
  return SendCommand (cmd, arg, flags, response, &MCI0_Resources);
}
static int32_t MCI0_SetupTransfer (uint8_t *data, uint32_t block_count, uint32_t block_size, uint32_t mode) {
  return SetupTransfer (data, block_count, block_size, mode, &MCI0_Resources);
}
static int32_t MCI0_AbortTransfer (void) {
  return AbortTransfer (&MCI0_Resources);
}
static int32_t MCI0_Control (uint32_t control, uint32_t arg) {
  return Control (control, arg, &MCI0_Resources);
}
static ARM_MCI_STATUS MCI0_GetStatus (void) {
  return GetStatus (&MCI0_Resources);
}
void SDMMC1_IRQHandler (void) {
  SDMMC_IRQHandler (&MCI0_Resources);
}

/* MCI0 Driver Control Block */
ARM_DRIVER_MCI Driver_MCI0 = {
  GetVersion,
  MCI0_GetCapabilities,
  MCI0_Initialize,
  MCI0_Uninitialize,
  MCI0_PowerControl,
  MCI0_CardPower,
  MCI0_ReadCD,
  MCI0_ReadWP,
  MCI0_SendCommand,
  MCI0_SetupTransfer,
  MCI0_AbortTransfer,
  MCI0_Control,
  MCI0_GetStatus
};
#endif /* MX_MCI0 */


#if defined (MX_SDMMC2)
/* MCI1 Driver wrapper functions */
static ARM_MCI_CAPABILITIES MCI1_GetCapabilities (void) {
  return GetCapabilities (&MCI1_Resources);
}
static int32_t MCI1_Initialize (ARM_MCI_SignalEvent_t cb_event) {
  return Initialize (cb_event, &MCI1_Resources);
}
static int32_t MCI1_Uninitialize (void) {
  return Uninitialize (&MCI1_Resources);
}
static int32_t MCI1_PowerControl (ARM_POWER_STATE state) {
  return PowerControl (state, &MCI1_Resources);
}
static int32_t MCI1_CardPower (uint32_t voltage) {
  return CardPower (voltage, &MCI1_Resources);
}
static int32_t MCI1_ReadCD (void) {
  return ReadCD (&MCI1_Resources);
}
static int32_t MCI1_ReadWP (void) {
  return ReadWP (&MCI1_Resources);
}
static int32_t MCI1_SendCommand (uint32_t cmd, uint32_t arg, uint32_t flags, uint32_t *response) {
  return SendCommand (cmd, arg, flags, response, &MCI1_Resources);
}
static int32_t MCI1_SetupTransfer (uint8_t *data, uint32_t block_count, uint32_t block_size, uint32_t mode) {
  return SetupTransfer (data, block_count, block_size, mode, &MCI1_Resources);
}
static int32_t MCI1_AbortTransfer (void) {
  return AbortTransfer (&MCI1_Resources);
}
static int32_t MCI1_Control (uint32_t control, uint32_t arg) {
  return Control (control, arg, &MCI1_Resources);
}
static ARM_MCI_STATUS MCI1_GetStatus (void) {
  return GetStatus (&MCI1_Resources);
}
void SDMMC2_IRQHandler (void) {
  SDMMC_IRQHandler (&MCI1_Resources);
}

/* MCI1 Driver Control Block */
ARM_DRIVER_MCI Driver_MCI1 = {
  GetVersion,
  MCI1_GetCapabilities,
  MCI1_Initialize,
  MCI1_Uninitialize,
  MCI1_PowerControl,
  MCI1_CardPower,
  MCI1_ReadCD,
  MCI1_ReadWP,
  MCI1_SendCommand,
  MCI1_SetupTransfer,
  MCI1_AbortTransfer,
  MCI1_Control,
  MCI1_GetStatus
};
#endif /* MX_MCI1 */

/*! \endcond */




回复

使用道具 举报

9

主题

85

回帖

112

积分

初级会员

积分
112
发表于 2022-4-29 16:05:48 | 显示全部楼层
多谢硬汉哥!

这个很有帮助。不过其内部好像还没有封装成 SD_ReadBlocks_DMA 这种上层函数。 目前还在学习中。
我就是非常纳闷,为何这个IDMA中断 申请被屏蔽了。 请教硬汉哥,目前有没有办法通过利用STLINK调试器,去检查某些SDMMC 或者 NVIC寄存器,去找出中断没有触发的原因?

补充下,我发现这个还不是我一个人碰到的问题,好多人都遇到了,最后可能都解决不了,用回查询模式了。 搜了ST官方文档,没有对此说明。 ST社区也无人回答。头痛中。

回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107057
QQ
发表于 2022-4-30 10:40:49 | 显示全部楼层
szjdb 发表于 2022-4-29 16:05
多谢硬汉哥!

这个很有帮助。不过其内部好像还没有封装成 SD_ReadBlocks_DMA 这种上层函数。 目前还在学 ...

多试试,按说这个移植挺简单的。
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-5-16 09:06 , Processed in 0.393738 second(s), 28 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

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