Coding challenge: Can you enhance this BMP display? - Embedded.com

Coding challenge: Can you enhance this BMP display?

As you may recall from my recent Quest for fire column, our Caveman Diorama is going to boast a Time Portal, thereby explaining my presence in the scene.


Cardboard prototype of Time Portal (Source: Max Maxfield & Mike Mittlebeeler)

Well, we've finally gotten around to powering up our 2.8″ display from Adafruit and, as usual, there are a few “ups and downs” to ponder. With regard to the display itself, this is a TFT LCD touchscreen on a breakout board with a Micro-SD card socket mounted on the back (we're not planning on using the touchscreen capability). We're currently driving this using an Arduino Uno, but we'll be swapping over to an Arduino Nano when we come to deploy this little scamp in the cave.

As always, Adafruit supplies great support in the form of wiring diagrams and instructions, libraries, and example sketches. The display itself can be driven using a variety of techniques, including a fast 8-bit parallel interface and a slower SPI interface.

In our case, we wish to display a series of BMP files that will be stored on a Micro-SD card plugged into the back of the breakout board. The idea is to alternate between a Stargate mirror effect image and hundreds, perhaps thousands, of random images showing things like alien landscapes, post-apocalyptic scenes, and weird, wonderful, and beautiful visions of the past, present, and future (as you can see, we don’t believe in limiting ourselves).

For some reason, Adafruit only supports the display of BMPs using the SPI interface, which is slower than the 8-bit interface approach. Since observers will be looking downwards towards the Time Portal in the diorama, this means that we want the SPI interface and any associated wires to be on the bottom of the display so as to be minimally visually intrusive.

Based on this, the first question we had was “Which way up will the images be displayed?” If the images were to appear upside down, for example, then we would have to pre-invert them on our host computer before copying them over to the Micro-SD card. Thus, we started out by creating a small 40 x 80 pixel image with different color blocks in diagonally opposite corners and displaying it at X-Y location [0,0] on the display. Happily, this image appeared in the desired location and orientation as illustrated below.


(Source: Max Maxfield & Mike Mittlebeeler)

We had originally envisaged the portal as appearing to be levitating above the floor of the cave. If you look at the image above, however, you will observe a black border around the actual image. This is quite narrow at the sides and the top, but it's pretty significant at the bottom of the display.

This dictates the minimum width of the door frame at the bottom. I was just on the phone to my chum, Adam Carlson (a.k.a. AerospaceEngineer). Adam is creating the 3D printed door frame for the portal. If we made the entire frame as wide as it needs to be at the bottom, then it would be overwhelmingly out of proportion to the actual display area. Thus, we are now thinking of mounting the portal on a small pedestal standing on the floor of the cave with integral steps coming down from the display, thereby disguising the size of the bottom lintel. Adam will be throwing some preliminary sketches together over the weekend and we'll take things from there.

The next step was to see how fast the images can be displayed, so we loaded two full-size (240 wide x 320 high) images onto the card. The first was a Stargate mirror image; the second was of the back of a man sitting on a chair viewing a post-apocalyptic vista as illustrated below.


(Source: Max Maxfield & Mike Mittlebeeler)

We then tweaked the example sketch from Adafruit so as to alternate back and forth between these two images with a one second pause between each reload. The result is shown in this video.

As an aside, Adafruit's libraries require us to use 24-bit color BMPs, which means each image consumes 3 x 240 x 320 = 259,200 bytes. Since there are 1,048,576 bytes in a megabyte (MB), this means we can store four images per megabyte.

I predate the days of 3.5″ floppy disks that could store only 1.44 MB of data, so my knee-jerk reaction was to ruminate on the fact that I would have been able to store only five of our (uncompressed) BMPs on a single floppy. How times have changed.

Looking at this another way, since we can store four images per megabyte, this equates to 4,000 images per gigabyte, which should be more than enough for our needs. So I trotted down to my local Staples store looking for a 1 GB Micro-SD card, only to discover that the smallest card they offer stores 16 GB (I think it cost around $10). This means we can store 64,000 BMPs on our Micro-SD card, which should keep us busy for a while (LOL).

It's not-so-long-ago that 16 GB would have been an almost unimaginable quantity, and the fact the Micro-SD card is about the same size as my fingernail makes things even more surreal, but we digress…

We had originally hoped to be able to have the default Stargate mirror image somehow “rippling” on the screen. We had also hoped to be able to perform some sort of crossover-fade effect from the mirror image to the scene images, and vice versa.

As you can see in the above video, however, it actually takes about four seconds to present each new image onto the display. This occurs as a slow “wipe” starting at the top of the display and working its way to the bottom. The image below shows the “Man on Chair” image (top) in the process of being “wiped” over the “Stargate Mirror” image (bottom).


(Source: Max Maxfield & Mike Mittlebeeler)

On the one hand, we can certainly live with this; on the other hand, it would nice if we could do it better (e.g., smoother, faster, more interesting transitions).

This is where you come in. We've reached the limit of our programming skills. This time-portal-stuff.zip file contains the two 240 x 320 BMPs we've been playing with, the Adafruit_GFX (graphics) library, the Adafruit_ILI9341 (display) library, and the Time_Portal_01 sketch, which is based on Adafruit's SPI BMP display example sketch.

In the case of the rippling mirror effect, could we achieve this by drawing expanding circles using the graphics library rather than by displaying BMP images? Alternatively could we start off by displaying the BMP, and then “tweak” individual pixels using the graphics library to provide some sort of visual interest? Any suggestions here would be very much appreciated.

Furthermore, in the case of transitioning to a new BMP image, is there anything we can do to speed things up? Looking at Adafruit's sketch, it seems that there's a lot of error-checking to make sure the BMP files are of the right size and format and suchlike. Since we know our BMPs are all going to be guaranteed to be 240 x 320 x 24-bits, and they will all be generated in exactly the same way from Paint.net, can we strip out a lot of this error checking and — if we do so — will this speed things up?

It may be that we are fundamentally speed-limited by the fact that the Arduino Uno (and Arduino Nano) has only 2 KB of SRAM. As we've already discussed, each of our BMPs is 3 x 240 x 320 = 259,200 bytes in size. This means that we have to bounce back and forth streaming small groups of pixels from the Micro-SD card and writing these pixels to the display.

If we do have this fundamental limit, it may be that we can still achieve a more interesting image-to-image transition effect. We don’t know how BMP files represent their data, but let's visualize it as being something like the following:



(Source: Max Maxfield & Mike Mittlebeeler)

It would be nice if we could read out pixel data from any specified [Row, Col] location from the BMP file and write that data to any specified [Row, Col] location on the display. However, our understanding is that we can do the latter, but not the former. That is, we think that when we open the file on the Micro-SD card and start reading pixel data, this data is presented to us (something like) in the order [0,0], [0,1], [0,2] … [0,238], [0,239], [1,0], [1,1], [1,2] … [1,238], [1,239] … [319,238], [319,239].

But what if we created a simple pre-processor program on the PC that could take our original BMP file, “shuffle” its contents in some way, and generate a modified BMP file as output?



(Source: Max Maxfield & Mike Mittlebeeler)

If our sketch running on the Arduino “knows” that the data will be presented in this way, it could read Row 0 from the file and write it to Row 159 on the display, read Row 1 from the file and write it to Row 160 on the display, and so forth. This would mean that the new image would “wipe” over the old image starting from the center and working outwards, which — we think — would offer a much better effect.

Maybe we could go even more sophisticated than this — starting at the center of the display and working outwards in all dimensions. What do you think? Is this possible and — if so — can you help us to achieve it?

33 thoughts on “Coding challenge: Can you enhance this BMP display?

  1. “First to answer the question of stripping out the error checking. Yes you could strip out the checks but you won't gain much since the checks only run when you first open the file.nnThe two things that are likely to be slowing things down are the necess

    Log in to Reply
  2. “It's a pity I can't use the SPI interface to read the data from the Micro-SD card and then use the parallel interface to write it to the display…nnI'm sure this would be possible for someone who had a clue what they were doing…”

    Log in to Reply
  3. “If it makes you feel any better, their library code is not exactly easy to understand….nnThey added too many #ifdef statements to make it universal without documenting what products they apply to…nn#ifdef statements make the code hard to follow in

    Log in to Reply
  4. “I'm a little confused as to why you cannot use the 8-bit interface. They have a driver for it on github:nnhttps://github.com/adafruit/TFTLCD-LibrarynnAs for speeding up data retrieval, you can attempt converting the color scheme of your BMPs from

    Log in to Reply
  5. “OK… I looked at the code again and can see the pin conflicts between the SPI and the 8-bit interface. There might be a way to tweak their macros found in the pin_magic.h file of the TFTLCD library… but I'll need to look into it tomorrow.”

    Log in to Reply
  6. “The rate is highly dependent on the operating mode of SPI. nu0421heck the settings of flags modes, for example SPI_HAS_TRANSACTION, USE_FAST_PINIO and others. “

    Log in to Reply
  7. “I see quite a bit of room for improvement in the interface, though the real improvement would actually be using the 8 bit parallel line.nn1) Convert all your bitmaps to 16 bit rgb565 format, store as raw (no header). I'm pretty sure ImageMagick can do t

    Log in to Reply
  8. “serial LCD (with external controller) should has scroll area, you should write second image on different display buffer area (not overlapping it with first image), once it's finished switch the scroll pointer to new area”

    Log in to Reply
  9. “My problem is limited coding savvy — the only BMP example they show (as far as I know) uses the SPI interface — but I will try to look into this further”

    Log in to Reply
  10. “I would love to reduce the BMPs from 24 to 16 bits (I've not started processing them yet so this would be easy to do while I'm resizing/cropping)– however moving from 3 bytes to 2 bytes reduces the data I need to pull/push around by 33%, not 50% (not t

    Log in to Reply
  11. “If the controller supports double buffering I would love to use it — but I don't know if it has it and, if it does, I don't know how to use it. Apart from that, I'm totally on top of the situation LOL”

    Log in to Reply
  12. “I love option (2) — I've been thinking along these lines myself — the problem here is that we would have to transmit X-Y-Data for each pixel rather than X-Y-data-data-data-…”

    Log in to Reply
  13. “Looking at the datasheet, it seems it has only enough memory for one single image. There is a scroll function, but I think it's only to create a scrolling transition effect on the display.”

    Log in to Reply
  14. “The 8-bit interface code uses the same kind of commands as the SPI interface driver code, so changing to the new driver shouldn't cause much pain.nnAs for the pin conflicts, I think if you change the pins used to D7-D0, that would free up the dedicated

    Log in to Reply
  15. “I think there is a lot of room for improvement so, it would hardly take more cpu cycles. It will take even less IO if you don't use full color RGB bitmaps, but just raw RGB565.nnI did not get everything to work with ImageMagick, so I wrote a Python 2.7

    Log in to Reply
  16. “Hi Vincent — wow, thanks for creating this Python script (what is Pillow?)nnI didn't profile the code because I don't know how to do so with an Arduino — I think the best way to go will be to read the raw image via SPI and write it to the display via

    Log in to Reply
  17. “Hi Max – Pillow is a python image library. If you install python 2.7, and set the correct path such that PIP.exe is on the path (C:\Python27\Scripts), you can install it using 'pip install pillow' from the command line. (I'm assuming Windows here, but w

    Log in to Reply
  18. “”Anyway it seems there is a choice: slow and simple or fast and not-so-simple”nnWell, I'm a simple man, but I would like my Time Portal to live in the fast lane LOL”

    Log in to Reply
  19. “I know the fun of keeping things simple, and doing a lot with minimal hardware, but in this case I'm afraid the fast-lane consists of a raspberry PI, VGA TFT and VLC media player. :-O”

    Log in to Reply
  20. “I'm all in favor of trying new things, but I think you may be unnecessarily reinvenintg the wheel here.nWhy not use an inexpensive “digital picture frame” like you can get at Wal-Mart for a few bucks. Mnay of them support full motion video plus a numbe

    Log in to Reply
  21. “Reinventing the wheel is what I do best LOLnnA couple of thoughts are that (a) I don't think they make digital picture frames as small as I would need it and (b) I may want to show different images at different times under program control.nnRe the slo

    Log in to Reply
  22. “But I'm an Arduino man — the challenge is to use the capabilities provided by the Arduino and make the thing work … watch this space :-)”

    Log in to Reply
  23. “You've asked a bunch of engineers so you're going to get the engineering solutions, some of which are great, but in the interest of time and true simplicity I suggest focusing on the “art” (not the bitmap art, but the story you are telling). I'd suggest

    Log in to Reply
  24. “All of these are great suggestions. In fact, all of the effects (the light sin the fire, pool, tunnel, roof) are going to have a variety of selectable modes/options, so we coudl do the same with the time portal.”

    Log in to Reply

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.