Skip to main content
anonymous.8
Senior II
January 26, 2017
Question

Very slow SDMMC Read performance on STM32F746NGH6

  • January 26, 2017
  • 14 replies
  • 5609 views
Posted on January 26, 2017 at 20:12

Hi all. I am using the

STM32F746NGH6

 on the STM32F7 Discovery board to read from a micro-SD card through FATFS.

I am able to get only around 1MByte/sec read performance when reading blocks of 512 bytes. My application requires at least twice this read speed.

I am accessing a file through Chan's FATFS and the block size is fixed at 512 bytes. My SDMMC driver code is basically bare metal, so all the STD PERIPH and HAL crap has gone. It is pared down to the bone, as it were. I am using the 4 bit mode and the high speed clock mode and DMA mode reads. The clock speed, as verified by my logic analyzer, is indeed around 50MHz.

Given the above configuration, I should get blazing read performance, but the elapsed time to perform the 512 Byte read is sluggish, around 430 - 660 us. This is verified both by a hardware timer and an LED turning on, then off, after the block read and measuring that LED on time with my logic analyzer.

I am using a Class 4 micro-SD card.

I have attached a JPG showing a screen shot of the SD card clock. That image verifies the clock speed as about 50MHz, but interestingly it also shows that the clock comes in bursts of 7 clocks followed by a gap of 120ns. Thus the clock is not clocking in data continuously and therefore is losing about 1/2 of the available time to read the data in.

I have also attached a ZIP file with my SDMMC driver code.

Can anyone shed any light on why my SD MMC clock is so bursty and not continuous, or shed any other light on my poor read performance.

Thanks for any help you may be able to give.
    This topic has been closed for replies.

    14 replies

    Nemui Trinomius
    Associate II
    January 30, 2017
    Posted on January 30, 2017 at 01:34

    Dear David Harrison,

    Disable clock powersave mode,and obtain read/write buffer(about 16kByte or avobe) at DTCM region.

    Best Regards,

    Nemui.
    anonymous.8
    Senior II
    January 30, 2017
    Posted on January 30, 2017 at 21:34

    I don't think disabling the SD bus clock power save mode will do anything at all. All it means is that the SD bus clock will be running all the time, even when there is no bus activity.

    Tesla DeLorean
    Guru
    January 30, 2017
    Posted on January 30, 2017 at 03:40

    Don't read/write single blocks, the command overhead will eat you. I benchmark with 32KB of blocks. Find a sweet-spot that balances the speed you want and the memory you have to spare, try 4KB, 8KB, 16KB and 32KB

    Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
    anonymous.8
    Senior II
    January 30, 2017
    Posted on January 30, 2017 at 22:21

    Yes, indeed. When I Increase the buffer size to just 4KBytes, I get a raw SDReadBlocks access of 10MBytes/sec and through FATFS f_read of about 6MBytes/sec. However I can't directly using this size buffer without redesigning other parts of the system since that large buffer size currently causes large latencies elsewhere.

    Thanks for reminding me of the huge SD card overheads in reading data.

    dttworld
    Associate II
    January 30, 2017
    Posted on January 30, 2017 at 03:49

    Nothing wrong with the ST HAL libraries. I am getting 5 MB/s write speeds using a class 10 micro SD with the ST HAL libraries using DMA. That was not a typo, 5 mega bytes per second write speeds! This test was done on an STM32F7-DISCO board. Test was also done on an STM32F405 chip. I haven't done read speed tests since my application requires the files to be read by a PC but clearly you can get better read speeds than 1 MB/s.

    anonymous.8
    Senior II
    January 30, 2017
    Posted on January 30, 2017 at 19:43

    Actually my code originated from the STM32F7 HAL SDMMC driver. I simply stripped out all the unecessary HAL clutter and reduced it to direct register access. But the algorithm and SD card read access process is exactly the same.

    After looking at the problem some more, I have discovered that the issue is not bus bandwidth or memory bandwidth. I see very little change in overall read access time for a 512 byte block whether I use a1 bit bus, 4 bit bus, DMA or polled or standard speed or high speed Therefore I can only come to the conclusion that the bottleneck is not the code or the bus bandwidth but the SD card itself.

    Here is where Clive's comment comes in - yes, I do remember that there is an overhead for any SD card access but I am surprised at how much that is. I am about to do more measurements to try and quantify it.

    I have reasons for wanting a small buffer size and accessing 512 bytes at a time since a large buffer size creates latency elsewhere in the system. But I may to rethink my whole SD card access and sample processing strategy to allow larger SD card accesses but retain smaller DMA buffer dumps to my DAC.

    I will post some result later after some measurements.

    Akos Miklos
    Visitor II
    February 7, 2018
    Posted on February 07, 2018 at 18:16

    Hello David,

    I am working with the same STM32F7 Discovery board. I am using all the STD PERIPH and HAL. I also experienced the unexpected low speed at writing with DMA, although in polling mode I could reach 3-5MBps. So it does not lie on the card.

    By debugging and benchmarking I found that there is a large overhead somewhere between two writes of clusters (Chan's FATfs splits the data according to the card's cluster size). So increasing the cluster size by formatting the SD card can help instantly, tough it is not the ultimate solution. By the way, it is not a solution if you HAVE to read/write 512byte blocks.

    Remark: if I stopped the execution by breakpoints in some cases (when stopping at sending WRITE_MULT_BLOCK command) the overhead has gone. It seems that the annoying something has happened while pausing execution.

    If somebody knows what exactly slows down the process, I would be very happy to learn it.

    Best regards

    Akos

    Tesla DeLorean
    Guru
    February 7, 2018
    Posted on February 07, 2018 at 19:52

    There is a special SD Card formatter that takes into account the underlying erase block size, and the alignment of structures/clusters with that. Avoiding spanning these blocks, the card hides this management from you, but it slows things down.

    For the L4R9 SDMMC implementation special casing single sector writes using SINGLE vs MULTI command made the performance significantly more robust.

    For the F7 one needs to be cognisant of caching, using the 64KB SRAM at 0x20000000 for buffering helps there. I need to pull the current benchmarks for the STM32F746-DISCO implementation, but it is not slow, and doesn't stall or require pauses. One needs to be aware that DMA will complete before the FIFO clears, and some of the error call-backs, oddly, occur in normal operation.

    Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
    AVI-crak
    Senior
    February 8, 2018
    Posted on February 08, 2018 at 09:21

    Many thanks for the program code on direct access to the registers. This code is flexible enough for further processing with a sledgehammer.

    As for the speed of the SD card.

    Modern SD cards have two sets of instructions: standard and advanced user functions. Standard instructions have high-quality documentation, they are easy to use.

    Advanced user functions do not have a standard, every SD card manufacturer has its own set of fast commands. And this is the problem. Access to documentation is limited, or difficult in search mode.

    But there is another solution - card reader drivers for Linux. If you try hard - you can get the codes of the manufacturer's id and command sets.

    All additional commands are reduced to an asynchronous transfer mode. When the card responds with a significant delay about the success of operations, without interrupting the main data stream.
    AVI-crak
    Senior
    February 8, 2018
    Posted on February 09, 2018 at 00:34

    Harrison.David.002

    Function SDLowLevelDMARxConfig, DMA2_Stream3-> CR = DMA_Channel_4

    Function SDLowLevelDMATxConfig, DMA2_Stream3-> CR = DMA_Channel_6

    That is how it should be?

    Poonam Deoghare
    Associate II
    March 21, 2018
    Posted on March 21, 2018 at 12:49

    Hi folks,

    I have read/written in to micro sd card using sdmmc driver and polling mode on stm32f4 disco kit.

    Now I am trying to read/write using DMA mode. I am able to read write 1 block[ 512 bytes] successfully but when I am trying to read/write more thatn one block, it's not working without printf. If I add delay of 1 msec, then it works fine but I dont want to add delay.

    Below is my code snippet to read/write 10 blocks . Please let me know what is going wrong.

     MX_DMA_Init();

    ....

    void SD_Write_Data(void)

    {    

           for(int i = 0; i<10; i++)

        {

        while(HAL_SD_GetCardState(&hsd) != HAL_SD_CARD_TRANSFER)

        {}

        //printf(' Write_addr is 0x%x \n' ,addr);    

        //    HAL_Delay(1);    

          HAL_SD_WriteBlocks_DMA(&hsd, Tx, addr, 1);

            addr += 0x200;     

      }

        CardState = HAL_SD_GetCardState(&hsd);

        printf('\n CardState after write is %d \n', CardState);

    }

    void SD_Read_Data(void)

    {    

        static int k =0;

         for( k = 0; k<10; k++)

        {

        while(HAL_SD_GetCardState(&hsd) != HAL_SD_CARD_TRANSFER)

        {}

        HAL_SD_ReadBlocks_DMA(&hsd, Rx, read_addr, 1);

            read_addr += 0x200;    

          printf('\n RX is %s , k is %d \n',Rx,k);        

            }   

        CardState = HAL_SD_GetCardState(&hsd);

        printf('\n CardState after read is %d \n', CardState);     

    }   

    Thanks,

    Poonam

    Tesla DeLorean
    Guru
    March 21, 2018
    Posted on March 21, 2018 at 17:14

    >>

    Please let me know what is going wrong.

    You need code to spin on DMA completion.

    \STM32Cube_FW_F4_V1.19.0\Projects\STM32F412G-Discovery\Applications\USB_Host\AUDIO_Standalone\Src\sd_diskio_dma.c

    Also want to read/write as many sectors as possible, writing 10 sectors 1 at a time will be the slowest possible method, a lot of command/interaction overhead.

    If you don't like polling loops, you're going to need to use a multi-threaded approach.

    Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..