Shop OBEX P1 Docs P2 Docs Learn Events
Speed of Reading File from SD card is low — Parallax Forums

Speed of Reading File from SD card is low

chintan_joshichintan_joshi Posts: 135
edited 2023-08-18 08:23 in C/C++

Hello All,
I am trying to read binary file from sd card using P2 Evaluation Board. Below is the cog function to read data from sd card.

I am reading 19200 bytes chunk at a time, Total file size would be 2.5 MB.

But when i measure time of reading 19200 bytes, its showing 4.62 ms(Time between pin 49 high and pin 49 LOW). 4.8 MB/S, So is this default behavior of P2 or i can make it fast read? Appreciate if some one can help me to make this read fast.

Sd card details: class 10, with read speed upto 100MB/S. (https://www.amazon.in/gp/product/B07DJGJ2H1/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&th=1)

P2 is running on 340 MHZ clock frequency.

unsigned char buf_t[19200] = {0};
int bufs = 19200;

void read_sd()
{
     printf("read_Sd cog started\n");
     FILE* fh;
    mount("/sd", _vfs_open_sdcard());
    unsigned char* filename = "/sd/text.dat"; 
    if (fh = fopen(filename, "rb"))
    {
        printf("File opened successfully\n");
    }
    else
    {
        printf("Issue in File open, exiting\n");
        perror("File Open");
        _cogatn(1 << 0);
        return 0;
    }
    data_count = fread(&buf_t, 1, bufs, fh);
    //sending attenuation signal to Main code cog 0
    _cogatn(1 << 0);
    while (true)
    {
        while (_pollatn() == 0);
        //printf("Received Attenuation from printdata\n");
                _pinw(led,1);// Writing High on pin 49 to check time of fread
        data_count = fread(&buf_t, 1, bufs, fh);
                 _pinw(led,0); //Writing LOW on pin 49 to check time of fread
        //printf("data count read_sd= %d\n\n\n\n",data_count);
        if (data_count < 0) {
            break;
        }
    }
}

«13

Comments

  • Wuerfel_21Wuerfel_21 Posts: 4,565
    edited 2023-08-18 08:43

    What do you mean, this is fast! The max. clock for SPI mode SD cards is 50 MHz, so 6.2 MB/s is the theoretical upper limit. You wouldn't be able to reach it on a P2EVAL due to suboptimal board design choices the driver has to work around (not to speak of inherent slowness of some SD controllers).

    Anyways:

    • always read multiples of 512 bytes. This avoids breaking up the read with buffer memcpy shenanigans and allows doing it in one go.
    • cards go to sleep if you don't access them for ~10ms and the next access afterwards will have much increased latency (severity and timing are of course specific to the individual card).
    • The A1/A2 IOPS rating is far more important than crazy UHS speed ratings.
  • evanhevanh Posts: 15,235
    edited 2023-08-18 09:42

    Don't expect card max performance. The driver is electrically limited in a number of ways:

    • The interface used by the built in SD Slot on Eval Board and Edge Card is SPI. This is for low pin count and compatibility with the shared EEPROM on the same pins. This means it's 1-bit serial. 4-bit is not an option without moving to other set of pins.

    • Because of sharing with EEPROM there is an inline current limiting resistor. This limits max clock to 40 MHz (about 5 MB/s). And even this is suspect borderline. The resistor was probably chosen with 25 MHz in mind.

    • UHS modes are not possible. UHS1 is 1.8 volt signalling but the Prop2 pins only support 3.3 volt drive. And of course UHS2+ LVDS signalling is not even close.

    That said, we have dabbled with supporting 4-bit SD interface at 3.3 volt. We have tentatively seen well in excess of 50 MB/s read speed! As mentioned, it needs a separate pin set. Roger Loh has made an Eval Add-On for exactly this - https://forums.parallax.com/discussion/174988/new-sd-mode-p2-accessory-board/p1

  • chintan_joshichintan_joshi Posts: 135
    edited 2023-08-18 10:35

    @evanh and @Wuerfel_21

    Thank you both of you, let me check with read multiple of 512 bytes. Also The idea of using external SPI module is really helpful.
    Because i have checked SD card module with SPI using Arduino and there i can read 19200 bytes in between 1 to 2 ms using Arduino SD library. So i have posted this question why P2 taking more time.

    Will check and post the updates if i found something interesting.

  • @chintan_joshi
    One work around of the current limiting resistor might be to add a second SD card socket onto some other accessory headers. Then you can run at the max speed the SD card allows for any given interface mode. The code can be mapped to an SD card connected to any of the P2 IO pins.

    If a 1-bit interface would suffice, this add-on would be a quick way to experiment: https://www.parallax.com/product/p2-microsd-add-on-board/
    I don't recall if that also includes the resistor (probably does by default at one of the headers)... but if you did go that route just ask and we can share a diagram of how to override the resistor.

  • evanhevanh Posts: 15,235
    edited 2023-08-18 11:20

    @chintan_joshi said:
    Because i have checked SD card module with SPI using Arduino and there i can read 19200 bytes in between 1 to 2 ms using Arduino SD library.

    SPI interface mode is spec'd to only 25 MHz. Less than 3 MB/s. Both are exceeding that.

  • I'm pretty sure 50 MHz "high speed" capability is valid in SPI mode. Though 19200 bytes in 2ms would imply it clocking at excess of 75 MHz, so that's something.

  • @evanh and @Wuerfel_21 , Yes right sorry for the confusion, it was calculation mistake for Arduino, its taking more time than P2. But i have measured P2 time in logic analyser and sure that its taking 4.6 ms to read 19200 bytes.

  • evanhevanh Posts: 15,235

    Maybe it's optional, my experience is that some cards do accept a switch to High Speed in SPI mode but others don't. In reality, Standard Speed clocks as high as High Speed anyway and there is no fixed upper limit on either. But, presumably, older cards will struggle more and peter out at lower frequencies.

  • @VonSzarvas said:
    @chintan_joshi
    One work around of the current limiting resistor might be to add a second SD card socket onto some other accessory headers. Then you can run at the max speed the SD card allows for any given interface mode. The code can be mapped to an SD card connected to any of the P2 IO pins.

    If a 1-bit interface would suffice, this add-on would be a quick way to experiment: https://www.parallax.com/product/p2-microsd-add-on-board/
    I don't recall if that also includes the resistor (probably does by default at one of the headers)... but if you did go that route just ask and we can share a diagram of how to override the resistor.

    @VonSzarvas Thank you, Yes let me order this board.

  • evanhevanh Posts: 15,235

    It has the resistor too! I'm surprised. Well, at least bridging it shouldn't be a problem.

  • @evanh said:
    It has the resistor too! I'm surprised. Well, at least bridging it shouldn't be a problem.

    Provides the same protection as the on-board SD socket.

    I'll post the mod diagram shortly.

  • VonSzarvasVonSzarvas Posts: 3,296
    edited 2023-08-18 15:12

    Here's that diagram, with the resistor in question highlighted green!
    So remove that resistor, and add a solder blob (or bit of wire/etc.. ) across the resistor pads to short them out.
    Then you can run full speed SD!.
    Just don't plug the modified board into the top P2 addon header pins (P56-P63). Any other header pins, no problem!

  • evanhevanh Posts: 15,235

    Easy access on the outside. :) Thanks Von.

  • evanhevanh Posts: 15,235

    chintan,
    To increase the SPI clock frequency for the SD Card edit the value of ck_div at lines 593..596 in file - include/filesys/fatfs/sdmm.cc

                    if( tmr <= 150_000_000 )  ck_div = 0x0002_0004;  // sysclock/4
                    else if( tmr <= 200_000_000 )  ck_div = 0x0002_0005;  // sysclock/5
                    else if( tmr <= 280_000_000 )  ck_div = 0x0002_0006;  // sysclock/6
                    else  ck_div = 0x0003_0008;  // sysclock/8
    

    sysclock/4 is really the fastest the smartpins can do. In particular the tx serial is limited by internal I/O staging latencies that create a lag effect on the tx pin. Any faster has to be implemented using a streamer for tx data.

  • chintan_joshichintan_joshi Posts: 135
    edited 2023-08-21 05:12

    @VonSzarvas said:
    Here's that diagram, with the resistor in question highlighted green!
    So remove that resistor, and add a solder blob (or bit of wire/etc.. ) across the resistor pads to short them out.
    Then you can run full speed SD!.
    Just don't plug the modified board into the top P2 addon header pins (P56-P63). Any other header pins, no problem!

    @VonSzarvas Thank you for the details, i will order the addon board today, it will take minimum 15 days to clear the customs and reach to india.

  • chintan_joshichintan_joshi Posts: 135
    edited 2023-08-21 05:16

    @evanh said:
    chintan,
    To increase the SPI clock frequency for the SD Card edit the value of ck_div at lines 593..596 in file - include/filesys/fatfs/sdmm.cc

                  if( tmr <= 150_000_000 )  ck_div = 0x0002_0004;  // sysclock/4
                  else if( tmr <= 200_000_000 )  ck_div = 0x0002_0005;  // sysclock/5
                  else if( tmr <= 280_000_000 )  ck_div = 0x0002_0006;  // sysclock/6
                  else  ck_div = 0x0003_0008;  // sysclock/8
    

    sysclock/4 is really the fastest the smartpins can do. In particular the tx serial is limited by internal I/O staging latencies that create a lag effect on the tx pin. Any faster has to be implemented using a streamer for tx data.

    @evanh Let me check with this option. Thank you for this suggestion.

    But just a single query

    My code currently setup with this enum

    enum {
        //_xinfreq = 20_000_000,
        _xtlfreq = 20_000_000,
        _clkfreq = 340_000_000,
        DOWNLOAD_BAUD = 230_400,
        DEBUG_BAUD = DOWNLOAD_BAUD,
    
        PINS = 20 | 7 << 6,
        GROUP = 2,
        CLK_PIN = 6,
    
        TX_REGD = 1,
        CLK_REGD = 0,
        CPOL = 1,
        CPHA = 0,
        HEAPSIZE = 80000,
        CLK_DIV = 20,
        M_NCO = 0x8000_0000UL / CLK_DIV + (0x8000_0000UL % CLK_DIV > 0UL ? 1UL : 0UL),    // round up
        //M_LEADIN = X_IMM_32X1_1DAC1 | 7 + CLK_DIV + CLK_REGD - TX_REGD - (1 ^ CPHA) * (CLK_DIV>>1),
    
        M_LEADIN = X_IMM_32X1_1DAC1 | 3 + CLK_DIV + CLK_REGD - TX_REGD - (1 ^ CPHA) * (CLK_DIV >> 1),
    };
    
    

    So Your suggested option will affect this settings?

  • evanhevanh Posts: 15,235

    No, not related. ck_div is a variable in the sdmm.cc source file only. It's not exported. You have to edit it in that file in the includes.

  • @evanh said:
    No, not related. ck_div is a variable in the sdmm.cc source file only. It's not exported. You have to edit it in that file in the includes.

    @evanh i have tried first with ck_div sysclock/4 , but its not able to open file and gives error.

    After that i have changed it to sysclock/5, this can open the file, and read time for 19200 bytes is in between 2.9 ms to 3.6 ms, so its making read fast.

    If i use Addon module that @VonSzarvas suggested, then will it give more read speed? or its still limited to 50 MHZ default MAX speed?

  • Hello All,

    can i use P2 flash memory to write and read files? will it support faster read than Sd card read? because its also showing SPI FLASH.

  • evanhevanh Posts: 15,235
    edited 2023-08-21 09:56

    @chintan_joshi said:
    After that i have changed it to sysclock/5, this can open the file, and read time for 19200 bytes is in between 2.9 ms to 3.6 ms, so its making read fast.

    Good to see success with changes.

    ck_div is value of sysclock divider. If sysclock is 50 MHz then a divider of 5 will make the SPI clock 10 MHz.

    If i use Addon module that @VonSzarvas suggested, then will it give more read speed? or its still limited to 50 MHZ default MAX speed?

    Yes, more speed with that resistor bridged. If sysclock is, say, 240 MHz then a divider of 4 will give 60 MHz SPI clock.

    can i use P2 flash memory to write and read files? will it support faster read than Sd card read? because its also showing SPI FLASH.

    On-board Flash EEPROM doesn't have any inline resistor. Therefore it can go faster than the Eval/Edge SD Slot.

  • The flash can also run in 2-bit mode for more speed. I think this is done in the flash boot stub? Not sure if Chip's current thing uses it. Though of course you can only store 15 MB of data on there.

  • evanhevanh Posts: 15,235

    Chip's flash filesystem doesn't use 2-bit "DualSPI" mode. Good idea though. Maybe merge his earlier boot-loader routine that uses the streamer or pair up two smartpins.

  • @evanh said:

    @chintan_joshi said:
    After that i have changed it to sysclock/5, this can open the file, and read time for 19200 bytes is in between 2.9 ms to 3.6 ms, so its making read fast.

    Good to see success with changes.

    ck_div is value of sysclock divider. If sysclock is 50 MHz then a divider of 5 will make the SPI clock 10 MHz.

    If i use Addon module that @VonSzarvas suggested, then will it give more read speed? or its still limited to 50 MHZ default MAX speed?

    Yes, more speed with that resistor bridged. If sysclock is, say, 240 MHz then a divider of 4 will give 60 MHz SPI clock.

    can i use P2 flash memory to write and read files? will it support faster read than Sd card read? because its also showing SPI FLASH.

    On-board Flash EEPROM doesn't have any inline resistor. Therefore it can go faster than the Eval/Edge SD Slot.

    @evanh, i am currently running P2 with 340 MHZ, so i think Thats why divide by 4 not working. Divide by 5 working but still sometimes it fails to open sd card and gives error. So can't go less than divide by 5. And stuck on read time of 2.9 to 3.6 ms.

    Do we have any sample code to write or read to P2 flash memory using C/C++?

  • @Wuerfel_21 said:
    The flash can also run in 2-bit mode for more speed. I think this is done in the flash boot stub? Not sure if Chip's current thing uses it. Though of course you can only store 15 MB of data on there.

    @Wuerfel_21 , Currently i planning to store only 10 MBs, so storage will not be a problem.

  • evanhevanh Posts: 15,235

    @chintan_joshi said:
    @evanh, i am currently running P2 with 340 MHZ, so i think Thats why divide by 4 not working. Divide by 5 working but still sometimes it fails to open sd card and gives error. So can't go less than divide by 5. And stuck on read time of 2.9 to 3.6 ms.

    You have to bridge out that resistor to get a square wave signal.

    Do we have any sample code to write or read to P2 flash memory using C/C++?

    There's been a few over the years. Latest is Chip's wear-levelling code - https://forums.parallax.com/discussion/175470/on-board-flash-file-system/p1

  • chintan_joshichintan_joshi Posts: 135
    edited 2023-08-23 10:47

    Hello ,

    I am able to mount host file system using _vfs_open_host(). But reading of 19200 bytes from host file system taking more time than sd card read. may be because of serial communication.

    So, I have tried to use Flexprop mount command for P2 Flash,

    mount("/flash",_vfs_open_littlefs_flash(1, 0) );

    But i am getting IO error for mount. This command will not work for P2 Flash or am i missing something?

    Also i have tried to use FlashFileSystem_16MB_Demo,spin2, but this gives lots of warnings and 1 error

    FlashFileSystem_16MB.spin2:213: warning: used tabs for indentation (previous lines used spaces)
    FlashFileSystem_16MB.spin2:214: warning: mixing tabs and spaces for indentation on same line
    FlashFileSystem_16MB.spin2:215: warning: used tabs for indentation (previous lines used spaces)
    FlashFileSystem_16MB.spin2:217: warning: mixing tabs and spaces for indentation on same line
    FlashFileSystem_16MB.spin2:218: warning: used spaces for indentation (previous lines used tabs)
    FlashFileSystem_16MB.spin2:304: warning: used tabs for indentation (previous lines used spaces)
    FlashFileSystem_16MB.spin2:452: warning: used tabs for indentation (previous lines used spaces)
    FlashFileSystem_16MB.spin2:453: warning: mixing tabs and spaces for indentation on same line
    FlashFileSystem_16MB.spin2:454: warning: used spaces for indentation (previous lines used tabs)
    FlashFileSystem_16MB.spin2:455: warning: used tabs for indentation (previous lines used spaces)
    FlashFileSystem_16MB.spin2:456: warning: mixing tabs and spaces for indentation on same line
    FlashFileSystem_16MB.spin2:457: warning: used tabs for indentation (previous lines used spaces)
    FlashFileSystem_16MB.spin2:458: warning: mixing tabs and spaces for indentation on same line
    FlashFileSystem_16MB.spin2:459: warning: used spaces for indentation (previous lines used tabs)
    FlashFileSystem_16MB.spin2:460: warning: used tabs for indentation (previous lines used spaces)
    FlashFileSystem_16MB.spin2:461: warning: mixing tabs and spaces for indentation on same line
    FlashFileSystem_16MB.spin2:462: warning: used spaces for indentation (previous lines used tabs)
    FlashFileSystem_16MB.spin2:585: warning: used spaces for indentation (previous lines used tabs)
    FlashFileSystem_16MB.spin2:510: error: unknown identifier getcrc used in function call

  • evanhevanh Posts: 15,235
    edited 2023-08-23 12:02

    @chintan_joshi said:
    I am able to mount host file system using _vfs_open_host(). But reading of 19200 bytes from host file system taking more time than sd card read. may be because of serial communication.

    That would be correct. It'll be some fraction of 1 MB/s.
    The mount function you're wanting to use with the new add-on is mount("/sd", _vfs_open_sdcardx( clk, ss, di, do ))

    mount("/flash",_vfs_open_littlefs_flash(1, 0) );

    But i am getting IO error for mount. This command will not work for P2 Flash or am i missing something?

    I haven't tried that either. You'll need the "FLASH" dip-switch turned on.

    Also i have tried to use FlashFileSystem_16MB_Demo,spin2, but this gives lots of warnings and 1 error
    FlashFileSystem_16MB.spin2:510: error: unknown identifier getcrc used in function call

    Eric posted a fix. I haven't examined - https://forums.parallax.com/discussion/comment/1552940/#Comment_1552940
    and also updated the compiler. So you'll want to git pull and build the latest Flexspin from https://github.com/totalspectrum/spin2cpp

  • chintan_joshichintan_joshi Posts: 135
    edited 2023-08-24 05:44

    @evanh said:

    @chintan_joshi said:
    I am able to mount host file system using _vfs_open_host(). But reading of 19200 bytes from host file system taking more time than sd card read. may be because of serial communication.

    That would be correct. It'll be some fraction of 1 MB/s.
    The mount function you're wanting to use with the new add-on is mount("/sd", _vfs_open_sdcardx( clk, ss, di, do ))

    mount("/flash",_vfs_open_littlefs_flash(1, 0) );

    But i am getting IO error for mount. This command will not work for P2 Flash or am i missing something?

    I haven't tried that either. You'll need the "FLASH" dip-switch turned on.

    Also i have tried to use FlashFileSystem_16MB_Demo,spin2, but this gives lots of warnings and 1 error
    FlashFileSystem_16MB.spin2:510: error: unknown identifier getcrc used in function call

    Eric posted a fix. I haven't examined - https://forums.parallax.com/discussion/comment/1552940/#Comment_1552940
    and also updated the compiler. So you'll want to git pull and build the latest Flexspin from https://github.com/totalspectrum/spin2cpp

    Yes, my Flash DIP switch is ON.

    All DIP Switch positions are:
    1. ON
    2. ON
    3. OFF
    4. OFF

    Below is the Cog function which is giving error

    void Write_sd()
    {
         printf("WRite_Sd cog started\n");
         FILE* fh;
        mount("/Flash",_vfs_open_littlefs_flash(1, 0));
        //mount("/host",_vfs_open_host());
        perror("Mount:"); // Here i am getting IO error
        unsigned char* filename = "/Flash/text.dat"; //1000x1600, 15pixelcn
    
        if (fh = fopen(filename, "w"))
        {
            printf("File opened successfully\n");
        }
        else
        {
            printf("Issue in File open, exiting\n");
            perror("File Open");
            _cogatn(1 << 0);
            return 0;
        }
        //memset(buf_t, 0, sizeof(buf_t));
        char str[] = "This is flash sample data";
    
        data_count = fwrite(str , 1 , sizeof(str) , fh );
        fclose(fh);
        //sending attenuation signal to Main code cog 0
        _cogatn(1 << 0);
        umount("/Flash");
        _waitms(100);
        printf("Exiting Writesd\n");
    }
    

    And below is the output

    ( Entering terminal mode.  Press Ctrl-] or Ctrl-Z to exit. )                    
    Main start!                                                                     
       clkfreq = 340000000   clkmode = 0x10010fb m_nco = 0x6666667 M_LEADIN = 0x4000
    000c                                                                            
    WRite_Sd cog started                                                            
    Mount:: I/O error                                                               
    Issue in File open, exiting                                                     
    File Open: Function not implemented  
    

    Tried with Latest Flexprop version(6.3.0) and getting same error.

    For Flash test i am using P2 Edge Module Rev D, Hope that may not be the issue.

    Tried with P2 Evaluation Board also and getting same mount IO error.

  • evanhevanh Posts: 15,235
    edited 2023-08-24 07:45

    _vfs_open_littlefs_flash(1,0) is working fine on my Eval Board ... albeit very slow at writes. Less than 100 kB/s on a good day.

    I currently don't have my Prop-Plug so can't easily test my Edge Card.

    EDIT: I've found an old, entirely unused, Prop-Clip ... soldered a Prop-Plug like SIP connector to it ... Testing the EEPROM with _vfs_open_littlefs_flash(1,0) on the EC32MB is fine as well.

    Flexspin version string is Version 6.4.0-beta-v6.3.0-10-gc2eeb269 Compiled on: Aug 24 2023

    EDIT2: Oh, ha, it stops working above 260 MHz! Mounting and file opening still appears okay, but writing data locks up ... same on both boards ...

    EDIT3: Right, yeah, the lag from the I/O stagings has tripped up Nicolas when he coded the SPI smartpin handing. Inverting TX's SmartB input fixes the issue. Err, he's got it slowed to sysclock/8. That should cover the I/O stagings. Must be the added lag from slew propagation then.

    EDIT4: Huh, locking the divider at sysclock/4 and inverting TX SmartB seems to be good up through all frequencies. :)

  • @evanh said:
    _vfs_open_littlefs_flash(1,0) is working fine on my Eval Board ... albeit very slow at writes. Less than 100 kB/s on a good day.

    I currently don't have my Prop-Plug so can't easily test my Edge Card.

    EDIT: I've found an old, entirely unused, Prop-Clip ... soldered a Prop-Plug like SIP connector to it ... Testing the EEPROM with _vfs_open_littlefs_flash(1,0) on the EC32MB is fine as well.

    Flexspin version string is Version 6.4.0-beta-v6.3.0-10-gc2eeb269 Compiled on: Aug 24 2023

    EDIT2: Oh, ha, it stops working above 260 MHz! Mounting and file opening still appears okay, but writing data locks up ... same on both boards ...

    EDIT3: Right, yeah, the lag from the I/O stagings has tripped up Nicolas when he coded the SPI smartpin handing. Inverting TX's SmartB input fixes the issue. Err, he's got it slowed to sysclock/8. That should cover the I/O stagings. Must be the added lag from slew propagation then.

    EDIT4: Huh, locking the divider at sysclock/4 and inverting TX SmartB seems to be good up through all frequencies. :)

    @evanh , So you are able to mount and write/read data to P2 16 MB flash with _vfs_open_littlefs_flash(1,0) command?

    How can i make it work? sysclock/8 and sysclock/4 where they needs to be change?

Sign In or Register to comment.