芯片:STM32F427
芯片配置软件:STM32CubeMx 5.6.0
配置了FATFS
卡时钟(SDIO_CK ):每个时钟周期在命令和数据线上传输 1 位命令或数据。对于多媒体卡 V3.31 协议,时钟频率可以在 0MHz 至 20MHz 间变化;对于多媒体卡 V4.0/4.2 协议,时钟频率可以在 0MHz 至 48MHz 间变化;对于 SD 或 SD I/O 卡,时钟频率可以在 0MHz 至 25MHz间变化。
SDIO适配器时钟( SDIOCLK ):该时钟用于驱动 SDIO 适配器,其频率等于 AHB 总线频率( HCLK ),并用于产生 SDIO_CK 时钟。
AHB 总线接口时钟( HCLK/2 ):该时钟用于驱动 SDIO 的 AHB 总线接口,其频率为HCLK/2 。
前面提到,我们的SD 卡时钟( SDIO_CK ),根据卡的不同,可能有好几个区间,这就涉及到时钟频率的设置, SDIO_CK 与 SDIOCLK 的关系为:
SDIO_CK=SDIOCLK/(2+CLKDIV)
其中,SDIOCLK 为 HCLK ,一般是 72Mhz(F103系列),而 CLKDIV 则是分配系数,可以通过 SDIO
的 SDIO_CLKCR 寄存器进行设置(确保 SDIO_CK 不超过卡的最大操作频率)。
这里要提醒大家,在SD 卡刚刚初始化的时候,其时钟频率( SDIO_CK )是不能超过 400Khz的,
否则可能无法完成初始化。在初始化以后,就可以设置时钟频率到最大了(但不可超过 SD卡的最大操作时钟频率)。
按上面的公式配置了SD:
测试代码:
// mount SD卡
retSD = f_mount(&SDFatFS, SDPath, 1);
if(retSD)
{
printf("mount error : %d \r\n",retSD);
return -1;
}
else
{
printf("mount sucess!!! \r\n");
}
int8_t SDWrite_test()
{
static char testFileName[] = "test.txt";
int32_t testVal = 123456;
// 创建并写入文件
FIL fl;
retSD = f_open(&fl, testFileName, FA_CREATE_ALWAYS | FA_WRITE);
if(FR_OK == retSD)
{
UINT bw = 0;
if(FR_OK != f_write(&fl, (void*)&testVal , sizeof(int32_t ), &bw))
{
f_close(&fl);
printf("f_write file(%s) error : %d\r\n", testFileName, retSD);
return -1;
}
retSD = f_close(&fl);
if(retSD)
{
printf("close(%s) error!!! %d\r\n", testFileName, retSD);
}
else
{
//printf("close(%s) sucess!!! \r\n", testFileName);
}
return 0;
}
else
{
printf("w open file(%s) error : %d\r\n", testFileName, retSD);
return -1;
}
}
// 读取文件测试
int8_t SDRead_test()
{
static char testFileName[] = "test.txt";
int32_t testVal = 0;
FIL fl;
// 打开文件
retSD = f_open(&fl, testFileName, FA_READ);
if(retSD)
{
printf("open file(%s) error : %d\r\n", testFileName, retSD);
return -1;
}
else
{
//printf("open file(%s) sucess\r\n", testFileName);
}
if(f_size(&fl) != sizeof(int32_t))
{
f_close(&fl);
printf("file(%s) len(%d) err\r\n", testFileName, (uint32_t)f_size(&fl));
return -1;
}
uint32_t bytesread = 0; // 读文件计数
// 读取文件
retSD = f_read(&fl, &testVal , sizeof(int32_t), (UINT*)&bytesread);
if(retSD)
{
f_close(&fl);
printf("read(%s) error!!! %d\r\n", testFileName, retSD);
return -1;
}
else
{
//printf("read(%s) sucess!!! \r\n", testFileName);
}
// 关闭文件
retSD = f_close(&fl);
if(retSD)
{
printf("close(%s) error!!! %d\r\n", testFileName, retSD);
}
else
{
//printf("close(%s) sucess!!! \r\n", testFileName);
}
printf("testVal :%d \r\n", testVal);
return 0;
}
写入SD卡返回了成功,但是当我执行SD卡读取代码时发现,文件不存在,读取失败了,取了SD卡放到电脑也发现文件没创建
如果写入文件后立刻读取失败则重写文件,一般写第二次就会成功,查看了SD卡的优先级,基本已经都是最高的
之后尝试调整SDIOCLK clock devide factor的值,基本上SD有问题都是这个问题,尝试了加大和减小这个值,发现设置为0-2都可以一次写入文件成功
按公式,如果设置SDIOCLK clock devide factor为0,SD卡的时钟频率就应该会超了才对,然而发现SD卡是能正常的,还是说是高速模式,没搞清楚
在使用STM32CubeMX 6.12.0和STM32F427ZGT6芯片时,发现SDIO中Mode选择为SD 4 bits Wide bus时,f_mount会返回错误3,对比以前的工程发现,同样的SD 4 bits Wide bus配置STM32F427VGT6芯片生成的工程代码不一样,改成hsd.Init.BusWide = SDIO_BUS_WIDE_1B;就能正常mount SD卡
所以使用STM32CubeMX配置SDIO为SDIO_BUS_WIDE_4B时,需要将MX_SDIO_SD_Init中的hsd.Init.BusWide = SDIO_BUS_WIDE_4B改为hsd.Init.BusWide = SDIO_BUS_WIDE_1B,否则f_mount会报错误3,可以在USER CODE BEGIN SDIO_Init 2区域内添加hsd.Init.BusWide = SDIO_BUS_WIDE_1B;
在使用STM32CubeMX配置SDIO为SDIO_BUS_WIDE_4B后,工程内部会自动调用HAL_SD_ConfigWideBusOperation(&hsd, SDIO_BUS_WIDE_4B),如果配置为SDIO_BUS_WIDE_1B则不会
所以应该需要使用SDIO_BUS_WIDE_1B初始化,然后再配置为SDIO_BUS_WIDE_4B