打印
[应用相关]

【转】stm32 3.5固件库带sdio版本V4.5.0 bug修改

[复制链接]
649|3
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
风萧寒|  楼主 | 2016-10-16 21:02 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 风萧寒 于 2016-10-16 21:05 编辑

写的很详细

1:SD_WaitReadOperation()函数或者SD_WaitWriteOperation()函数进入死循环
原因:数据传输错误导致传输中断,无法满足退出等待的判断条件。

代码分析:
SD_Error SD_WaitReadOperation(void)
{
  SD_Error errorstatus = SD_OK;
  while ((SD_DMAEndOfTransferStatus() == RESET) && (TransferEnd == 0) && (TransferError == SD_OK))
  {}
  if (TransferError != SD_OK)
  {
    return(TransferError);
  }
  return(errorstatus);
}


代码中用了while()是导致死循环的原因。TransferEnd ,TransferError 这两个参数是在中断中修改的, SD_DMAEndOfTransferStatus() 的结束条件是DMA传输结束。
看中断例程:
SD_Error SD_ProcessIRQSrc(void)
{
  if (StopCondition == 1)
  {
    SDIO->ARG = 0x0;
    SDIO->CMD = 0x44C;
    TransferError = CmdResp1Error(SD_CMD_STOP_TRANSMISSION);
  }
  else
  {
    TransferError = SD_OK;
  }

  SDIO_ClearITPendingBit(SDIO_IT_DATAEND);
  SDIO_ITConfig(SDIO_IT_DATAEND, DISABLE);
  TransferEnd = 1;
  return(TransferError);
}

中断配置为数据传输结束中断SDIO_ITConfig(SDIO_IT_DATAEND, ENABLE);
数据传输出错导致传输中断的情况下,SD_DMAEndOfTransferStatus的判断为false,TransferEnd 和TransferError 的状态也不会改变,导致while循环无法退出。
解决:
中断配置为SDIO_ITConfig(SDIO_IT_RXOVERR|SDIO_IT_DTIMEOUT|SDIO_IT_DCRCFAIL|SDIO_IT_DATAEND, ENABLE);
中断例程修改:
SD_Error SD_ProcessIRQSrc(void)
{
if (SDIO_GetFlagStatus(SDIO_FLAG_DTIMEOUT) != RESET)
{
  SDIO_ClearFlag(SDIO_FLAG_DTIMEOUT);
  TransferError = SD_DATA_TIMEOUT;
}
else if (SDIO_GetFlagStatus(SDIO_FLAG_DCRCFAIL) != RESET)
{
  SDIO_ClearFlag(SDIO_FLAG_DCRCFAIL);
  TransferError = SD_DATA_CRC_FAIL;
}
else if (SDIO_GetFlagStatus(SDIO_FLAG_RXOVERR) != RESET)
{
  SDIO_ClearFlag(SDIO_FLAG_RXOVERR);
  TransferError = SD_RX_OVERRUN;
}

else if (SDIO_GetFlagStatus(SDIO_FLAG_STBITERR) != RESET)
{
  SDIO_ClearFlag(SDIO_FLAG_STBITERR);
  TransferError = SD_START_BIT_ERR;
}

else
{
  if (StopCondition == 1)
  {
  SDIO->ARG = 0x0;
  SDIO->CMD = 0x44C;
  TransferError = CmdResp1Error(SD_CMD_STOP_TRANSMISSION);
  }
else
  {
  TransferError = SD_OK;
  }
}
  SDIO_ITConfig(SDIO_IT_RXOVERR|SDIO_IT_DTIMEOUT|SDIO_IT_DCRCFAIL|SDIO_IT_DATAEND, DISABLE);
  TransferEnd = 1;
  return(TransferError);
}

这么做的作用是发生错误时也会进入中断,即使dma没有结束,也能退出while循环。

沙发
风萧寒|  楼主 | 2016-10-16 21:03 | 只看该作者

2:sd_init()过程失败
可能性1:按照SD规范,初始化之前需要有74个或更多个clock让sd卡同步,例程中把clock开起来后直接发送cmd0,没有同步clock,所以先修改SD_PowerON函数内SDIO_ClockCmd(ENABLE);调用之后增加200us延时。
可能性2:发生SDIO_FLAG_DCRCFAIL错误。
修改SDIO_TRANSFER_CLK_DIV 来修改数据传输速率。
按照ST例程的注释,数据传输速率不能超过25M,但是原先配置SDIO_TRANSFER_CLK_DIV=0,按照72M主频计算的话传输速度达到72/2=36M,不出错就怪了。
我现在配置SDIO_TRANSFER_CLK_DIV=2后正常。
可能性3:固件库使用不正确。使用V4.5的例程,固件库需要用V3.5.0的,试过3.2的固件库会失败。

3:SD_DMAEndOfTransferStatus函数内没有清标志位,按照datasheet,标志位是由手动清除的。

4:SD_ReadBlock()发生SDIO_FLAG_DCRCFAIL错误。
一开始是实践发现,先执行一下SD_ReadMultiBlocks函数,以后再执行SD_ReadBlock就正常了。很奇怪的现象吧。后来查阅了一些资料,发现SD卡的block大小并不是固定的,可以配置为512,1024等,于是怀疑是block大小配置不正确导致。检查发现SD_ReadBlock操作之前没有设置sd卡block大小,也就是cmd16,加入这个代码就像行了
  /*!< Set Block Size for Card */
  SDIO_CmdInitStructure.SDIO_Argument = (uint32_t) BlockSize;
  SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SET_BLOCKLEN;
  SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
  SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
  SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
  SDIO_SendCommand(&SDIO_CmdInitStructure);
  errorstatus = CmdResp1Error(SD_CMD_SET_BLOCKLEN);

  if (SD_OK != errorstatus)
  {
    return(errorstatus);
  }

其实这个操作并不是每次读操作都要执行的,如果中途不改变block大小,只要初始化的时候设置一次就可以了。

使用特权

评论回复
板凳
four_zhg| | 2016-10-16 22:11 | 只看该作者
不错,路过收藏了

使用特权

评论回复
地板
风萧寒|  楼主 | 2016-10-22 00:24 | 只看该作者
four_zhg 发表于 2016-10-16 22:11
不错,路过收藏了

不客气,尽管拿走

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

68

主题

134

帖子

3

粉丝