打印
[STM32F4]

SDIO设置了硬件流控制发送数据就出现CRC错误,怎么解决?

[复制链接]
3867|9
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
kokoromi|  楼主 | 2017-6-24 14:13 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
    问题是这样的:SD卡的数据传输是使用 DMA方式的。我读取 SD卡数据没问题,但是向 SD卡写入数据每次都提示 CRC错误,奇怪的是如果我关闭了硬件流控制,写入数据就正常了,还有,如果我开启硬件流控制,但是时钟分频大于等于 2(即 SDIO_CK <= 45M/(2 + 2),我的SDIOCLK是 45M),写入数据也是正常的。

    也就是说,在时钟频率低的时候,开启或者关闭硬件流,读写都是正常的,但是如果时钟频率高的时候,开启硬件流,写入数据就出现 CRC错误,而关闭硬件流却正常。

    所以,我怀疑是不是 ST的芯片存在硬件 BUG啊,本来是使能硬件流,却变成了关闭硬件流,所以导致上面的情况,不过感觉这种可能性还是很小的,但是实在不知道是什么原因导致的,调试了好几天,现在决定放弃了,就直接调低频率开启硬件流用了,希望有遇到这个问题的大侠指点一下,不胜感激~


SDIO和DMA的配置如下:

uint8_t BSP_SD_Init()
{
  uint8_t sd_state = 1;

  //设置 DMA2的流 3中断优先级并使能中断
  HAL_NVIC_SetPriority(DMA2_Stream3_IRQn, 15, 0);
  HAL_NVIC_EnableIRQ(DMA2_Stream3_IRQn);
  //设置 SDIO传输时使用的 DMA流 3
  hDMA_SDIO_Tx.Instance = DMA2_Stream3;                             //设置 DMA2的流 3,用于发送数据到 SDIO
  hDMA_SDIO_Tx.Init.Channel = DMA_CHANNEL_4;                        //使用 通道 4
  hDMA_SDIO_Tx.Init.Direction = DMA_MEMORY_TO_PERIPH;               //传输方向为存储器到外设(SDIO)
  hDMA_SDIO_Tx.Init.PeriphInc = DMA_PINC_DISABLE;                   //外设地址不变
  hDMA_SDIO_Tx.Init.MemInc = DMA_MINC_ENABLE;                       //存储器地址增加
  hDMA_SDIO_Tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;      //外设数据为字(字对齐)
  hDMA_SDIO_Tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;         //存储器数据为字节
  hDMA_SDIO_Tx.Init.Mode = DMA_PFCTRL;                              //流控制器为外设(SDIO)
  hDMA_SDIO_Tx.Init.Priority = DMA_PRIORITY_LOW;                    //传输优先级为低
  hDMA_SDIO_Tx.Init.FIFOMode = DMA_FIFOMODE_ENABLE;                 //使能 FIFO
  hDMA_SDIO_Tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;        //FIFO阈值为满
  hDMA_SDIO_Tx.Init.MemBurst = DMA_MBURST_INC16;                    //存储器为 16节拍单次突发传输
  hDMA_SDIO_Tx.Init.PeriphBurst = DMA_PBURST_INC4;                  //外设为 4节拍单次突发传输
  //初始化发送 DMA
  if(HAL_DMA_Init(&hDMA_SDIO_Tx) != HAL_OK) return 1;
  //链接 DMA到 SDIO
  __HAL_LINKDMA(&hSD, hdmatx, hDMA_SDIO_Tx);


  //设置 DMA2的流 6中断优先级并使能中断
  HAL_NVIC_SetPriority(DMA2_Stream6_IRQn, 15, 0);
  HAL_NVIC_EnableIRQ(DMA2_Stream6_IRQn);
  //设置 SDIO传输时使用的 DMA流 6
  hDMA_SDIO_Rx.Instance = DMA2_Stream6;                             //设置 DMA2的流 6,用于从 SDIO接收数据
  hDMA_SDIO_Rx.Init.Channel = DMA_CHANNEL_4;                        //使用通道 4
  hDMA_SDIO_Rx.Init.Direction = DMA_PERIPH_TO_MEMORY;               //传输方向为外设(SDIO)到存储器
  hDMA_SDIO_Rx.Init.PeriphInc = DMA_PINC_DISABLE;                   //外设地址不变
  hDMA_SDIO_Rx.Init.MemInc = DMA_MINC_ENABLE;                       //存储器地址增加
  hDMA_SDIO_Rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;      //外设数据为字(字对齐)
  hDMA_SDIO_Rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;         //存储器数据为字节
  hDMA_SDIO_Rx.Init.Mode = DMA_PFCTRL;                              //流控制器为外设(SDIO)
  hDMA_SDIO_Rx.Init.Priority = DMA_PRIORITY_LOW;                    //传输优先级为低
  hDMA_SDIO_Rx.Init.FIFOMode = DMA_FIFOMODE_ENABLE;                 //使能 FIFO
  hDMA_SDIO_Rx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;        //FIFO阈值为满
  hDMA_SDIO_Rx.Init.MemBurst = DMA_MBURST_INC16;                    //存储器为 16节拍单次突发传输
  hDMA_SDIO_Rx.Init.PeriphBurst = DMA_PBURST_INC4;                  //外设为 4节拍单次突发传输
  //初始化接收 DMA
  if(HAL_DMA_Init(&hDMA_SDIO_Rx) != HAL_OK) return 1;
  //链接 DMA到 SDIO
  __HAL_LINKDMA(&hSD, hdmarx, hDMA_SDIO_Rx);


  //配置 SDIO中断优先级为 14(必须高于 DMA2流 3和流 6,否则无法抢占 DMA2流中断,导致死锁)
  HAL_NVIC_SetPriority(SDIO_IRQn, 14, 0);
  HAL_NVIC_EnableIRQ(SDIO_IRQn);
  //设置 SDIO的初始化参数
  hSD.Instance = SDIO;                                              //指定 SDIO设备
  hSD.Init.ClockEdge = SDIO_CLOCK_EDGE_RISING;                      //上升沿有效
  hSD.Init.ClockBypass = SDIO_CLOCK_BYPASS_DISABLE;                 //禁止旁路模式,使能时钟分频
  hSD.Init.ClockPowerSave = SDIO_CLOCK_POWER_SAVE_ENABLE;           //使能节能模式
  hSD.Init.BusWide = SDIO_BUS_WIDE_1B;                              //设置 SDIO总线为 1位
  hSD.Init.HardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_ENABLE; //使能 SDIO硬件流控制
  hSD.Init.ClockDiv = 0;                                            //时钟分频为 0,即 SDIO_CK = SDIOCLK/(2 + 0)
  //初始化 SD卡
  if(HAL_SD_Init(&hSD, &SDCardInfo) == SD_OK)
  {
    //使能 SD宽总线模式(4线)
    if(HAL_SD_WideBusOperation_Config(&hSD, SDIO_BUS_WIDE_4B) == SD_OK)
      sd_state = 0;
    else
      sd_state = 1;
  }

  return sd_state;
}


沙发
wahahaheihei| | 2017-6-24 19:18 | 只看该作者
必须的要用流控制吗

使用特权

评论回复
板凳
kokoromi|  楼主 | 2017-6-27 19:50 | 只看该作者
wahahaheihei 发表于 2017-6-24 19:18
必须的要用流控制吗

硬件流控制能避免接收FIFO上溢和发送FIFO下溢,不用的话有概率出问题,所以最好还是开启硬件流,比较放心。

使用特权

评论回复
地板
wahahaheihei| | 2017-7-6 18:23 | 只看该作者
没用过,不知道楼主解决了问题没

使用特权

评论回复
评论
kokoromi 2017-8-16 13:56 回复TA
没解决,现在仍然采用降速使用的方式。 
5
hotpower| | 2017-7-11 17:37 | 只看该作者
6
kokoromi|  楼主 | 2017-8-19 12:54 | 只看该作者
这个问题始终没解决,怀疑可能是开发板布线问题或者硬件问题(概率较小),最终采用了关闭硬件流控制的方式实现最高速度,仔细阅读了下文档,发现如果采用DMA方式并且将SDIO作为DMA的流控制器,则SDIO的硬件流是没有作用的,因为SDIO的FIFO数据是DMA根据SDIO的半空半满信号自动进行传输的,等同于流控制了。

使用特权

评论回复
7
zx1360425739| | 2017-9-26 21:56 | 只看该作者
楼主现在解决了吗

使用特权

评论回复
8
我的心里只有你| | 2017-11-3 19:28 | 只看该作者
楼主解决了吗?我也遇到类似的问题,开启硬件流控制后,时钟频率低的情况下,sd卡读写都没问题,时钟高了写是没问题,但是读老是出问题。

使用特权

评论回复
9
hotpower| | 2017-12-24 20:43 | 只看该作者
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

111

主题

344

帖子

3

粉丝