打印
[STM32F4]

CRC错误

[复制链接]
1220|23
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
huanghuac|  楼主 | 2021-5-9 20:20 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
SDIO设置了硬件流控制发送数据就出现CRC错误,怎么解决?

使用特权

评论回复
沙发
chenjunt| | 2021-5-9 20:23 | 只看该作者
什么意思?不是很明白你说的什么,能再解释一下这个现象吗

使用特权

评论回复
板凳
huanghuac|  楼主 | 2021-5-9 20:25 | 只看该作者
SD卡的数据传输是使用 DMA方式的。我读取 SD卡数据没问题,但是向 SD卡写入数据每次都提示 CRC错误,奇怪的是如果我关闭了硬件流控制,写入数据就正常了

使用特权

评论回复
地板
huanghuac|  楼主 | 2021-5-9 20:27 | 只看该作者
还有,如果我开启硬件流控制,但是时钟分频大于等于 2(即 SDIO_CK <= 45M/(2 + 2),我的SDIOCLK是 45M),写入数据也是正常的。

使用特权

评论回复
5
xxmmi| | 2021-5-9 20:30 | 只看该作者
你有什么打算呢?或者你想知道什么?

使用特权

评论回复
6
huanghuac|  楼主 | 2021-5-9 20:32 | 只看该作者
也就是说,在时钟频率低的时候,开启或者关闭硬件流,读写都是正常的,但是如果时钟频率高的时候,开启硬件流,写入数据就出现 CRC错误,而关闭硬件流却正常。

使用特权

评论回复
7
chenjunt| | 2021-5-9 20:34 | 只看该作者
直接调低频率开启硬件流用

使用特权

评论回复
8
wenfen| | 2021-5-9 20:36 | 只看该作者
SDIO和DMA的配置看看

使用特权

评论回复
9
huanghuac|  楼主 | 2021-5-9 20:39 | 只看该作者

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;
}

使用特权

评论回复
10
gongche| | 2021-5-9 20:42 | 只看该作者
必须的要用流控制吗

使用特权

评论回复
11
jiaxw| | 2021-5-9 20:43 | 只看该作者
正常是不会出现CRC错误的。

使用特权

评论回复
12
huanghuac|  楼主 | 2021-5-9 20:48 | 只看该作者
硬件流控制能避免接收FIFO上溢和发送FIFO下溢,不用的话有概率出问题,所以最好还是开启硬件流,比较放心。

使用特权

评论回复
13
huwr| | 2021-5-9 20:49 | 只看该作者
没用过,不知道楼主解决了问题没

使用特权

评论回复
14
happy_10| | 2021-5-9 20:51 | 只看该作者
怀疑可能是开发板布线问题或者硬件问题

使用特权

评论回复
15
huanghuac|  楼主 | 2021-5-9 20:53 | 只看该作者
概率较小

使用特权

评论回复
16
huanghuac|  楼主 | 2021-5-9 20:57 | 只看该作者
采用了关闭硬件流控制的方式实现最高速度,仔细阅读了下文档,发现如果采用DMA方式并且将SDIO作为DMA的流控制器,则SDIO的硬件流是没有作用的,因为SDIO的FIFO数据是DMA根据SDIO的半空半满信号自动进行传输的,等同于流控制了。

使用特权

评论回复
17
chenho| | 2021-5-9 20:59 | 只看该作者
我也遇到类似的问题,开启硬件流控制后,时钟频率低的情况下,sd卡读写都没问题,时钟高了写是没问题,但是读老是出问题。

使用特权

评论回复
18
huanghuac|  楼主 | 2021-5-9 21:02 | 只看该作者
唉,还是没有什么结果,算了,多谢大家啦

使用特权

评论回复
19
木木guainv| | 2021-6-2 16:28 | 只看该作者
请问 什么叫做硬件流啊

使用特权

评论回复
20
八层楼| | 2021-6-2 16:33 | 只看该作者
也就是说还可以通过软件进行控制是吗

使用特权

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

本版积分规则

772

主题

8473

帖子

6

粉丝