cloud_r9yf 发表于 2023-12-9 11:29:43

stm32f407 sdio的硬件流与crc的问题

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

再加一个现象,时钟分频我原来设置的是 0,也就是说 SDIO_CK = 45M/(2+0) = 22.5M,我把分频设置为 1也是不好使,但是我把分频设置到 2或者大于2,发送数据就不会出CRC错了,一切正常了....
这是为什么?难道要使用硬件流控制 SDIO_CK的频率不能太高?感觉像ST芯片的硬件BUG。

数据传输是使用 DMA方式的。现在的问题是,我读取 SD卡数据没问题,但是向 SD卡写入数据每次都提示 CRC错误,奇怪的是如果我关闭了硬件流控制,写入数据就正常了,这是怎么回事?有人遇到过这个问题吗?

eric2013 发表于 2023-12-9 15:53:07

注意这个问题。

F4参考手册的V13版本将SDIO操作SD时钟的0到25MHz删除了,这波操作也是够秀
https://www.armbbs.cn/forum.php?mod=viewthread&tid=94365

cloud_r9yf 发表于 2023-12-14 11:52:23

hSD.Init.ClockDiv = 0;ClockDiv设成0的时候不是没有超过25MHz么,但是会一直进入CRC错误我用正点的例程试了一下,例程的设置是ClockDiv=0,然后硬件流是关闭的,例程跑起来没有问题,但是我用cubemx自己配置了一个工程ClockDiv=0,关闭硬件流跑起来就一直进入下溢和上溢错误,然后我把硬件流使能了程序跑起来又有crc校验的错误把ClockDiv调高了程序才正常读写运行,想请教一下这是什么情况呀

eric2013 发表于 2023-12-15 08:36:48

cloud_r9yf 发表于 2023-12-14 11:52
hSD.Init.ClockDiv = 0;ClockDiv设成0的时候不是没有超过25MHz么,但是会一直进入CRC错误我用正点的例程 ...
找个比较软件,两个工程比较下,锁定下配置差异的地方。

之前H7系列测试过硬件流控制问题,早期的H7的HAL版本开不开都影响,后来的升级版本测试发现开启后才稳定,不开启,经常出错。

cloud_r9yf 发表于 2023-12-15 15:41:39

好的谢谢硬汉哥{:34:}
页: [1]
查看完整版本: stm32f407 sdio的硬件流与crc的问题