基于STM32的SDIO用4位总线24MHZDMA模式操作SHDC卡。

    很蛋疼的发现网上很多所谓的SDIO操作SHDC无意例外都是官方的那个烂玩意,完全没有修改过,所以很多时候根本无法初始化SHDC,我也在网上看到很多人关于这部分的疑问,虽然STM32的SDIO的确是可以这样操作。但是很佩服那群人,什么都没改就发上来,把哥我害惨了。。。。
经过查资料,追踪,最后运气可佳。我发现自己的金士顿4GSD卡(class4)不能初始化跟用4位总线dma操作的原因。。各位也可以上网去找别人的试试,很多人都说不能用4位总线操作,而且用1位总线也只能是在低速率以及开启流控的情况下。而且经常出错。而4位总线总是提示没有检测到起始位。
但是他们都只会问,都没有去想象为什么,我也是。。但是后来发现。STM32的SDIO是完全没问题的,可以读写SHDC,用4位总线24MHZ工作在DMA模式,大家看我修改出来的例程就知道了。看我改过的地方,对比下官方的。
首先:
在配置的时候, 一开始的时候sd卡需要有至少发74个时钟使它自己初始话,这是2.0规范要求的,但是你们自己看看官方的,完全没有这个,我一直追踪,发先在电源初始化那里就已经卡住了- -|||。

于是我在那里面加入了一个发送74个时钟的小代码。

SD_Error SD_PowerON(void)
{
  SD_Error errorstatus = SD_OK;
  uint32_t response = 0, count = 0;
  bool validvoltage = FALSE;
  uint32_t SDType = SD_STD_CAPACITY;
  int16_t i = 0;
  /* Power ON Sequence -------------------------------------------------------*/
  /* Configure the SDIO peripheral */
  SDIO_InitStructure.SDIO_ClockDiv = SDIO_INIT_CLK_DIV; /* HCLK = 72MHz, SDIOCLK = 72MHz, SDIO_CK = HCLK/(178 + 2) = 400 KHz */
  SDIO_InitStructure.SDIO_ClockEdge = SDIO_ClockEdge_Rising;
  SDIO_InitStructure.SDIO_ClockBypass = SDIO_ClockBypass_Disable;
  SDIO_InitStructure.SDIO_ClockPowerSave = SDIO_ClockPowerSave_Disable;
  SDIO_InitStructure.SDIO_BusWide = SDIO_BusWide_1b;
  SDIO_InitStructure.SDIO_HardwareFlowControl = SDIO_HardwareFlowControl_Disable;
  SDIO_Init(&SDIO_InitStructure);

  /* Set Power State to ON */
  SDIO_SetPowerState(SDIO_PowerState_ON);

  /* Enable SDIO Clock */
  SDIO_ClockCmd(ENABLE);

  /* CMD0: GO_IDLE_STATE -------------------------------------------------------*/
  /* No CMD response required */
  SDIO_CmdInitStructure.SDIO_Argument = 0x0;
  SDIO_CmdInitStructure.SDIO_CmdIndex = SDIO_GO_IDLE_STATE;
  SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_No;
  SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
  SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
  for(;i < 74; i++)
  {
    SDIO_SendCommand(&SDIO_CmdInitStructure);
  CmdError();
 }

看到没有,就是画线的那个,这个用37也可以了。但是规范点用74、

接下来,自己初始化可以通过了,因为上电正确一般是可以初始化正常的,这个没什么问题,到了这个函数就开始有问题了。

status = SD_SelectDeselect((u32) (SDCardInfo.RCA << 16));
  if (status != SD_OK)
  {
   rt_kprintf("SD_SelectDeselect is  error./n");
   goto __return;
  }
  rt_kprintf("SD set to transfer mode./n");
  status = SD_EnableWideBusOperation(SDIO_BusWide_4b);

就是这个函数,使能四位总线模式的函数。事实上,在经过上一次的操作后,配置总线的时候我是这么配置的:

  SDIO_InitStructure.SDIO_ClockDiv = SDIO_TRANSFER_CLK_DIV +5 ;
  SDIO_InitStructure.SDIO_ClockEdge = SDIO_ClockEdge_Rising;
  SDIO_InitStructure.SDIO_ClockBypass = SDIO_ClockBypass_Disable;
  SDIO_InitStructure.SDIO_ClockPowerSave = SDIO_ClockPowerSave_Disable;
  SDIO_InitStructure.SDIO_BusWide = SDIO_BusWide_1b;
  SDIO_InitStructure.SDIO_HardwareFlowControl = SDIO_HardwareFlowControl_Enable;
  SDIO_Init(&SDIO_InitStructure);

我发现加入流控是必须 的,避免出现数据出错,因为这个模式很不稳定,很多时候会出现overrun的错误,或者crc错误。这时候我们可以先不要调用SD_EnableWideBusOperation(SDIO_BusWide_4b);

这样的话,其实我们是可以直接操作读写SHDC的,但是会发现不仅速度低,而且经常出错。这就是我为什么拼命要搞出四位总线的原因。

所以首先要SD_SelectDeselect((u32) (SDCardInfo.RCA << 16));命令选择SD为传送模式后,要再调用SD_EnableWideBusOperation(SDIO_BusWide_4b)配置总线为四位总线模式;这是为了能够以更快的速度读取SHDC卡。事实上这个函数是有问题的。传送是命令是没有问题的,但是判断依据问题不小。

大家看我的代码

  • 10
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 28
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 28
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值