Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Increase SD card speed #166

Open
Vinschni opened this issue Sep 22, 2019 · 4 comments
Open

Increase SD card speed #166

Vinschni opened this issue Sep 22, 2019 · 4 comments
Labels
enhancement New feature or request

Comments

@Vinschni
Copy link

Vinschni commented Sep 22, 2019

Current status

Current SD card image writing speed is 12 fps and far below capture fps of > 20.
Higher recording speed is required.

Rationale

Recording images to SD is crucial for in-device data collection when building an realtime neural network IoT device. Our algorithm runs with 18 fps currently, but we are not capable of recording images at the same rate, to feed them for in system offline verification into our algorithm to validate our work in the lab.

Things we tried

Writing single JPG images (4.8kB) to SD card with constant speed is possible if for each 100 images a new folder is created.

I achieve 12 fps ==> 57,7 kByte/s speed.

I tried following things to investigate speed or increase it:

  • Checking Maixduino speed for SD-Card writing speed with 4,8kByte files ==> Up to 806 kByte/s in open, write 5200 bytes, close loop.
  • Increased MaixPy SPI freq in sdcard.c
    void SD_HIGH_SPEED_ENABLE(void)
    {
        spi_set_clk_rate(SD_SPI_DEVICE, 20000000);
    }
    
    ==> Did not increase writing speed
  • Implemented small state machine that allows to omit spi_init() called in every sd_write_data | sd_read_data | sd_write_data_dma | sd_read_data_dma in sdcard.c
    ==> Did not increase writing speed
  • Compiled MaixPy with -O2 instead of current -Os ==> Did not help
  • Increasing CPU frequency to 598 MHz ==> Increased SD-Card speed to 67 KByte
  • Writing only dummy data instead of images (which need to be JPG encoded) ==> Does not increase data throughput.

I inspected the STM32 HAL SD card implementation (here) and my conclusion is that we operate in low speed mode.

A switch to a high speed mode, e.g. up to 50 MHz is achieved here.

As a thight loop on maixduino achieves > 10 times higher throughput i assume SD card is not kept busy in MicroPython probably.

Any hints what the bottleneck of the current MaixPy SD card writing implementation is?

@Vinschni
Copy link
Author

Vinschni commented Sep 23, 2019

I retried using Maixduino with following script to test SD card speed.

#include <SPI.h>
#include <SD.h>
#include <Arduino.h>


void setup() {
  // Open serial communications and wait for port to open:
  Serial.begin(460800);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  Serial.print("Initializing SD card...");

  if (!SD.begin(29)) {
    Serial.println("initialization failed!");
    while (1);
  }
  Serial.println("initialization done.");

  SD.remove("test.txt");
  Serial.println("done!");

}
File myFile;
#define dummySize  5200*sizeof(uint8_t)
uint8_t *dummydata = (uint8_t*) malloc(dummySize);
uint64_t lastmillis = millis();
uint32_t countWrites = 0;
void loop() {
  countWrites++;
  if (millis()-lastmillis > 1000) {
    lastmillis = millis();
    Serial.println(countWrites);
    countWrites = 0;
    
  }
  myFile = SD.open("test.txt", FILE_WRITE);

  if (myFile) {
    myFile.write(dummydata,dummySize);
    myFile.close();
  } else {
    Serial.println("error opening test.txt");
  }
}

This gave me at SPI_FULL_SPEED 806kByte/s and with ‭ SPI_HALF_SPEED 374.4 kByte/s.

@anku2424
Copy link

Hello @Vinschni , could you please share the code you used to write image to sd card. I don't seem to get that.

@Vinschni
Copy link
Author

Vinschni commented Dec 8, 2019

I wrote following class to allow continuous recording of jpg files at ~12 fps with MaixPy to SD.`
It creates a hirachy of folders with four levels the circumvent the performance drops of FAT32 access to folders.
If file count within folder increases above 50 or file name is longer than 8 characters slowdown of FAT32 code in MaixPy is sugnificant and introduces fps drops every dozen frames.

I assume porting LittleFS to MaixPy or repairing recording of binary files would make MaixPy a valid platform for recording frames at a decend speed > 15 fps @qvga RGB. (see https://github.com/sipeed/MaixPy/issues/164)

class Vid:
    def __init__(self, name,):
        self.name = name
        self.count = 0
        self.fLim = 50
        self.countLvl1 = 0
        self.lsDir = ""
        try:
            os.mkdir('/sd/v')
        except:
            pass
        try:
            os.mkdir('/sd/v/'+name)
        except:
            pass

    def add_frame(self,img, fn_postifx):
        if self.count % self.fLim == 0:
            self.__handleFolder()
        fp = self.currentFolder + '/' + str(self.count) + '_' + fn_postifx + '.jpg'
        #print(fp)
        img.save(fp)
        self.count += 1

    def next_frame_path(self):
        if self.count % self.fLim == 0:
            self.__handleFolder()
        for f in self.lsDir:
            if f.startswith(str(self.count)):
                fileName = f
                break
        #fpath = self.currentFolder + '/' + str(self.count) +  '.jpg'
        fpath = self.currentFolder + '/' + fileName
        print(f)
        self.count += 1
        return fpath

    def __handleFolder(self):
        # Folders on lvl 3
        if self.count % (self.fLim * self.fLim * self.fLim * self.fLim) == 0:
            # Create new folder                                     lvl 1
            self.currentFolder = self.currentFolder = '/sd/v/' + self.name + '/' + str(int(self.count / (self.fLim * self.fLim * self.fLim * self.fLim)))
            try:
                os.mkdir(self.currentFolder)
            except:
                pass
        # Folders on lvl 2
        if self.count % (self.fLim * self.fLim * self.fLim) == 0:
            # Create new folder                                     lvl 1
            self.currentFolder = self.currentFolder = '/sd/v/' + self.name + '/' + str(int(self.count / (self.fLim * self.fLim * self.fLim * self.fLim))) + '/' + str(int(self.count / (self.fLim * self.fLim * self.fLim)))
            try:
                os.mkdir(self.currentFolder)
            except:
                pass
        # Folders on lvl 1
        if self.count % (self.fLim * self.fLim) == 0:
            # Create new folder                                     lvl 1
            self.currentFolder = self.currentFolder = '/sd/v/' + self.name + '/' + str(int(self.count / (self.fLim * self.fLim * self.fLim * self.fLim))) + '/' + str(int(self.count / (self.fLim * self.fLim * self.fLim))) + '/' + str(int(self.count / (self.fLim * self.fLim)))
            try:
                os.mkdir(self.currentFolder)
            except:
                pass
        # Folders on lvl 0
        if self.count % self.fLim == 0:
            # Create new folder
            self.currentFolder = self.currentFolder = '/sd/v/' + self.name + '/' + str(int(self.count / (self.fLim * self.fLim * self.fLim * self.fLim))) + '/' + str(int(self.count / (self.fLim * self.fLim * self.fLim))) + '/' + str(int(self.count / (self.fLim * self.fLim))) + '/' + str(int(self.count / self.fLim))
            try:
                os.mkdir(self.currentFolder)
            except:
                self.lsDir = os.listdir(self.currentFolder) # Cache content of current folder for offline processing
                pass

@ZSYAD
Copy link

ZSYAD commented Dec 25, 2019

@

Current status

Current SD card image writing speed is 12 fps and far below capture fps of > 20.
Higher recording speed is required.

Rationale

Recording images to SD is crucial for in-device data collection when building an realtime neural network IoT device. Our algorithm runs with 18 fps currently, but we are not capable of recording images at the same rate, to feed them for in system offline verification into our algorithm to validate our work in the lab.

Things we tried

Writing single JPG images (4.8kB) to SD card with constant speed is possible if for each 100 images a new folder is created.

I achieve 12 fps ==> 57,7 kByte/s speed.

I tried following things to investigate speed or increase it:

* Checking Maixduino speed for SD-Card writing speed with 4,8kByte files ==> Up to 806 kByte/s in open, write 5200 bytes, close loop.

* Increased MaixPy SPI freq in `sdcard.c`
  ```
  void SD_HIGH_SPEED_ENABLE(void)
  {
      spi_set_clk_rate(SD_SPI_DEVICE, 20000000);
  }
  ```
  
  
  ==> Did not increase writing speed

* Implemented small state machine that allows to omit `spi_init()` called in every `sd_write_data` | `sd_read_data` | `sd_write_data_dma` | `sd_read_data_dma` in  `sdcard.c`
  ==> Did not increase writing speed

* Compiled MaixPy with `-O2` instead of current `-Os` ==> Did not help

* Increasing CPU frequency to 598 MHz ==> Increased SD-Card speed to 67 KByte

* Writing only dummy data instead of images (which need to be JPG encoded) ==> Does not increase data throughput.

I inspected the STM32 HAL SD card implementation (here) and my conclusion is that we operate in low speed mode.

A switch to a high speed mode, e.g. up to 50 MHz is achieved here.

As a thight loop on maixduino achieves > 10 times higher throughput i assume SD card is not kept busy in MicroPython probably.

Any hints what the bottleneck of the current MaixPy SD card writing implementation is?

I have seen a strange code in sdcard.c :
static void sd_lowlevel_init(uint8_t spi_index)
{
gpiohs_set_drive_mode(SD_CS_PIN, GPIO_DM_OUTPUT);
spi_set_clk_rate(SD_SPI_DEVICE, 200000); /set clk rate/
}

Maybe the speed of SDCard are limited by this code.
i want to change this code and rebuild to verify my assumion, but i can not rebuild it, could you please help me ? change this code and rebuild it , Thank you very much.

@Neutree Neutree added the enhancement New feature or request label Aug 7, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

4 participants