Fast bmp files read from SD card

Hello,

im doing job project on arduino that is reading .bmp pictures on sdcard and writing it on 320x240 tft color display whit ILI9341 driver.

The pictures(even small, like 60x60) load visually slow(line after line), but when writing some complex multicolored shapes of same dimensions(60x60 rainbow, composed by strings) it is almost instantaneous.
So from this i assume that problem is that speed of reading from the SD card is not fast enought to keep up whit writing down the pictures itself on the screen.
Is there anyway to speed up the SD card file read?

I also tried pararell mode instead of SPI mode, the shapes draw even faster, but the .bmp files still draw slowly whit same speed.

In the attachement is bitmap read from SDcard sketch. I use adafruit ili9341+adafruit gfx library.

bmpDraw.ino (2.69 KB)

you should read the BMP file at once into memory as a blob and do the decoding from memory.

Now you are reading one byte at the time and that is very inefficient.

Note that this reading might use quite some RAM.

As sectors on an SD card are typically 512 bytes you could start with a buffer of 512 bytes. And only reread from disk when needed. A buffer of 256 or 128 bytes should improve performance also. Try change BUFFPIXEL to 50.

Never did it on an Arduino, but it was common practice previous century when reading from floppies..

i was thinking about buying a pararell 12MB ram chip, but first i will try this method. Ill post results in a day

klemko:
So from this i assume that problem is that speed of reading from the SD card is not fast enought to keep up whit writing down the pictures itself on the screen.
Is there anyway to speed up the SD card file read?

The solution to speed things up would be: Handle as much bytes as possible in one chunk.

Your TFT is also using SPI, isn't it?

Currently you code does that:

  • switch SPI bus to SD card, read one pixel from SD card
  • switch SPI bus to TFT, push one pixel to TFT
    This is the slowest possibility.

If I'd make a guess, this would speed up things very much:

  • switch SPI bus to SD card, read 20 pixels from SD card in one chunk
  • switch SPI bus to TFT, push 20 pixels to TFT
    I'm guessing this will be possibly 10 times faster than what you are doing now.

Switching the SPI bus from device to device is done in your libraries code, so speeding up your code would mean: Reduce the number of read/write commands and instead of "single byte read/write commands" use "blockread/blockwrite commands" where your libraries allows.

If i raise buffpixel to 50, the time to draw 300x200 picture goes from 4,7 to 4,1sec. If i raise it above 50 the processors runs out of memory and only displays black screen or some random vertical lines.

So i assume i need to wire in and program pararel ram chip if i want to draw faster?

I also thought about modifing the bmpDraw function to ignore black dots(background color) and only read the others. That would reduce the number of dots to read significantly but i dont know if that is possible since dots stil needs to be read for program to see the color. But still if it is black it would not be written to atmegas328 memory.

If i raise buffpixel to 50, the time to draw 300x200 picture goes from 4,7 to 4,1sec.

So the performance bottleneck seems to be elsewhere in the code

Can you do a test run with all Serial.prints disabled (except for the timing measurement)

What is the time if you do set every pixel in a loop (to see what is the fastest possible)

       for (row=0; row<h; row++) { 
          for (col=0; col<w; col++) {
  
            b = 1;
            g = 2;
            r = 3;
            tft.pushColor(tft.color565(r,g,b));

If this is slow it is the library ...

tried removing all serial.print including the setup and no diference.
Also when i set evry pixel in a loop, time goes from 380 to 310.

Im thinking of converting the bmp files to native/rgb code on laptop and then load those files to the sdcard, so i could only call those files from sd card and write directly to display(no need for conversion of 24bit files to rgb that is done on atmega currently and takes long time to do it).
But in that case i need to modifiy my bmpDraw function to call hex code and display it.

What is an option is to gather run lengths of the same colour on a line and then print them with a tft.line command. That would reduce the # tft calls.

I did manage to optimise the spitftbitmap sketch to a point that i can draw pictures 100x100 or smaller in under 100ms and 50x50 under 30ms which is all i needed :stuck_out_tongue:
When i get some time to spare, i will also try to make this library work whit bitmaps in HEX code, that could speed it up, we will see.

Hi klemko,

can you please share your optimized spitftbitmap sketch?
Thanks a lot in advance.

Regards
ZP