health 发表于 2026-1-18 15:29:53

SPI读取SD卡速度测试

STC32G144K246 SPI接口读取TF卡测试,FATFS读取TF卡上一个2MB多文件,每次读取8KB,直至文件结束。
直接读到RAM缓冲区不做任何处理。

原始demo程序,SPI时钟频率10MHz,增加如下代码测量速度。
void speedTest(const char *rootPath)
{
        uint16_t br;
        uint32_t total, time;

        f_open(&file, str_concat(rootPath, "/test.dat"), FA_READ);
        printf("打开文件并读取文件内容\n");
       
        sec = 0;
        Timer1_Init();
       
        total = 0;
        LED = 1;
        do
        {
                f_read(&file, testbuf, 8192, &br);
                total += br;
        }while(br == 8192);
        LED = 0;
       
        TR1 = 0;
        ET1 = 0;
        time = (((TH1*256+TL1) - 151) * 1000UL)/(65536UL - 151);
        time += sec*1000;       

        f_close(&file);       
        printf("file read %ld byte : %ld ms.\n", total, time);
}
测量结果如下
文件大小2124765字节,耗时5.078秒,平均速度约408KB/S。



神农鼎 发表于 2026-1-18 15:43:57

SPI可以 放到 30MHz ~ 45MHz

神农鼎 发表于 2026-1-18 15:44:42

MP3音乐播放器【FatFs+SD/TF卡+I2S-DAC】@STC32G144K246,实时解码MP3 - STC32G144K246 测试版块,PGA/运放,DAC,CAN-FD,主频100MHz以下 国芯人工智能技术交流网站 - AI32位8051交流社区

health 发表于 2026-1-18 16:23:50

SPI时钟速度提升至17MHz后,读取同样文件耗时为4.298秒,平均速度约480KB/S。

health 发表于 2026-1-18 16:27:30

SD规范规定SPI模式下最大时钟频率25MHz,初始化时时钟最大400KHz。

尝试设置SPI时钟24.75MHz,初始化时钟保持300多KHz不变,读卡失败。
失败时的打印信息如下

开始发送至少74个时钟周期的空闲信号...
空闲信号发送完成。
发送CMD0,尝试让SD卡进入空闲状态...
SD卡已成功进入空闲状态,CMD0响应:0x01
发送CMD8,检查SD卡是否支持2.0协议...
SD卡支持2.0协议,CMD8响应:0x01
读取CMD8的4字节响应...
CMD8的4字节响应读取完成。
发送CMD58,读取OCR寄存器...
成功发送CMD58,开始读取OCR寄存器的4字节...
OCR寄存器的4字节读取完成。
SDSC卡容量:503316480 字节,c_size:3839,read_bl_len:9,c_size_mult:6
SDSC卡容量:503316480 字节,c_size:3839,read_bl_len:9,c_size_mult:6
SD卡初始化成功。
挂载磁盘失败,13
初始化失败.
文件系统初始化失败

health 发表于 2026-1-18 17:06:05

测试结果极限就是17MHz,再高一点就失败。17.5MHz也不行。

PLL输出408MHz,SYSCLK 102MHz,SPI时钟408 /2 /3 /4 = 17MHz。

health 发表于 2026-1-19 17:17:18

SPI时钟17MHz查询方式,文件读取速度480KB/S,此时SPI传输字节间隔较大。
精简SPI读写函数,
void SPI_WriteByte(u8 dat)//SPI发送一个字节数据
{
    if(ESPI)
    {
      B_SPI_Busy = 1;
      SPDAT = dat;
      while(B_SPI_Busy);//中断模式
    }
    else
    {
      SPDAT = dat;
      while(!(SPIF));        //查询模式
      SPI1_ClearFlag();    //清除SPIF和WCOL标志
    }
}
改为宏定义
#define SPI_WriteByte(dat)SPDAT = (dat);while(!SPIF);SPI1_ClearFlag()

u8 SPI_ReadByte(void)
{
    SPDAT = 0xff;
    if(ESPI)
    {
      B_SPI_Busy = 1;
      while(B_SPI_Busy);//中断模式
    }
    else
    {
                while(!(SPIF));        //查询模式
      SPI1_ClearFlag();        //清除SPIF和WCOL标志
       
    }
    return (SPDAT);
}
这个有返回值,不太好用宏定义替代,直接在调用处替换代码。
SPDAT = 0xff;while(!SPIF);*buffer++ = SPDAT;SPI1_ClearFlag();

上述处理后,读文件速度飙升至715KB/S。

health 发表于 2026-1-19 17:22:58

启动SPI DMA,彻底消除SPI字节间隔时间。

实测开启SPI DMA但未开启FIFO,速度还不如CPU查询方式。

开启FIFO并启用SPI DMA后,速度达到798KB/S。此时用示波器观察波形,SPI CLK近乎连续,但字节间仍有很小的间断。

_奶咖君_ 发表于 2026-1-20 10:12:56

health 发表于 2026-1-19 17:22
启动SPI DMA,彻底消除SPI字节间隔时间。

实测开启SPI DMA但未开启FIFO,速度还不如CPU查询方式。


SPI通讯不连续,一直都是他们家的问题。

_奶咖君_ 发表于 2026-1-20 10:17:40



我用的单片机相对旧,没有太多的功能(FIFO)。这个是梁工的回复。

https://www.stcaimcu.com/forum.php?mod=redirect&goto=findpost&ptid=7892&pid=73870
页: [1] 2
查看完整版本: SPI读取SD卡速度测试