问题是这样的: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;
}
|