JPEG picture on Adafruit 3.5" 320x480 Color TFT Touchscreen

Hi all,

I have the Adafruit 3.5" 320x480 Color TFT Touchscreen Breakout.

With the supplied Adafruit_HX8357 library, it wotks well connected on a Mega board (displaying bitmap picture with the spitfbitmap example)

I would like to dispay jpeg picture. Fot that, I try to use the JPEGdecoder library where I chose the TFT_Jpeg example. It works, but the picture is very small as this library was created for the ST7735 Adafruit dispay which is 1.8" - 128x160.

In the code, there is commented lines for using a HX8357 based display (as the Adafruit TFT does) : using TFT_HX8357 library. But it doesnt work with Adafruit TFT, I think due to pinout. I replace the call to library by using Adafruit_HX8357. I also change in the renderJPEG routine the call to setWindow by a call to setAddrWindow as suggested. (setWindows do not exist in Adafruit library)

Finally, the code is well compiled, loaded to the board and it runs (information in the serial monitor) but … no picture !

Hereunder, the code for including the library and creating the class TFTscreen:

// include the necessary libraries
#include <SPI.h>
#include <SD.h>
//#include <TFT.h>  // Arduino LCD library

#include <JPEGDecoder.h>  // JPEG decoder library

// pin definition for the Mega
#define sd_cs  4
#define lcd_cs 10
#define dc     9
#define rst    11

#include <Adafruit_HX8357.h>        // Hardware-specific library
Adafruit_HX8357 TFTscreen = Adafruit_HX8357(lcd_cs, dc); // Invoke custom library

#define TFT_WHITE 0xFFFF
#define TFT_BLACK 0x0000
#define TFT_RED   0xF800

// TFT driver and graphics library
//TFT TFTscreen = TFT(lcd_cs, dc, rst);

And the changed code in the renderJPRG routine:

 // draw image block if it will fit on the screen
 if ( ( mcu_x + win_w) <= TFTscreen.width() && ( mcu_y + win_h) <= TFTscreen.height()) {
 // open a window onto the screen to paint the pixels into
 TFTscreen.setAddrWindow(mcu_x, mcu_y, mcu_x + win_w - 1, mcu_y + win_h - 1);
 //TFTscreen.setWindow(mcu_x, mcu_y, mcu_x + win_w - 1, mcu_y + win_h - 1);
 // push all the image block pixels to the screen
 while (mcu_pixels--) TFTscreen.pushColor(*pImg++); // Send to TFT 16 bits at a time

Can somebody help?
Thanks by advance

I don't have an Adafruit HX8357.

I have displayed JPEG with ESP8266, ESP32, STM32, Xmega, Zero,, Due and even a Mega2560.
On a variety of TFT screens.

As far as I know, the Adafruit HX8357 library is a regular GFX compatible library. So it can draw a Pixel.

As always. Quote which libraries, which versions, which example.

David.

Sadly Adafruit clumsily broke their "prime directive" and broke compatibility with many old sketches that use low level writes, this means you have to include startwrite and endwrite functions now or the chip select stays high, see example here.

Hi bodmer,

Thanks for the reply.
You’re right, there is a quite intensive use of startWrite and endWrite in the void bmpDraw of spitftbitmap.ino example (Adafruit_HX8357 library). I did not find any documentation on how to use these routines.
I added startwrite and endwrite around the while loop. Improving, a picture appeared on the screen … but far being perfect!

See result: Picture

Hereunder the code:

  // read each MCU block until there are no more
  TFTscreen.startWrite(); // Start TFT transaction

  while ( JpegDec.read()) {

    // save a pointer to the image block
    pImg = JpegDec.pImage;

    // calculate where the image block should be drawn on the screen
    int mcu_x = JpegDec.MCUx * mcu_w + xpos;
    int mcu_y = JpegDec.MCUy * mcu_h + ypos;

    // check if the image block size needs to be changed for the right and bottom edges
    if (mcu_x + mcu_w <= max_x) win_w = mcu_w;
    else win_w = min_w;
    if (mcu_y + mcu_h <= max_y) win_h = mcu_h;
    else win_h = min_h;

    // calculate how many pixels must be drawn
    uint32_t mcu_pixels = win_w * win_h;

    // draw image block if it will fit on the screen
    if ( ( mcu_x + win_w) <= TFTscreen.width() && ( mcu_y + win_h) <= TFTscreen.height()) {
      // open a window onto the screen to paint the pixels into

      TFTscreen.setAddrWindow(mcu_x, mcu_y, mcu_x + win_w - 1, mcu_y + win_h - 1);
      //TFTscreen.setWindow(mcu_x, mcu_y, mcu_x + win_w - 1, mcu_y + win_h - 1);
      // push all the image block pixels to the screen
      while (mcu_pixels--) TFTscreen.pushColor(*pImg++); // Send to TFT 16 bits at a time
    }

    // stop drawing blocks if the bottom of the screen has been reached
    // the abort function will close the file
    else if ( ( mcu_y + win_h) >= TFTscreen.height()) JpegDec.abort();

  }
     TFTscreen.endWrite(); // End TFT transaction

Some help to better use these statements?
Thanks by advance

No. That is not a good picture !!

Please quote which libraries, which versions, which example.

Few people may have your Adafruit screen. But the beauty of Adafruit_GFX and Adafruit hardware libraries is that they follow a style.

So if a sketch works with v1.2.3 of Adafruit_xxx it will probably work with corresponding version of Adafruit_yyy hardware library.

In simple terms: we can test your JPEG sketch on Adafruit_ILI9341.

David.

Hello,

I have the same issue with the Adafruit 3.5" tft screen and an Arduino Due.

I have downloaded the Adafruit_HX5357 library with the GFX library and I'm using the JPEGDecoder library version 1.8.0 and tried some examples witch I have modified so the Adafruit library's are used.

One example give the same result as seen in your picture, another one gives another result, some don't give any picture on the screen.
So I have tried using the TFT_HX5357_DUE library but with no luck.

So David, did you manage to display a JPEG-file on your screen? And if yes, would you like to share the solution with us?
Thanks!

The IDE Library Manager reports:
Adafruit_HX8357 v1.1.6
Adafruit_GFX v1.5.7
JPEGDecoder v1.8.0

JPEGDecoder uses picojpeg.c which says:

//------------------------------------------------------------------------------
// picojpeg.c v1.1 - Public domain, Rich Geldreich <richgel99@gmail.com>
// Nov. 27, 2010 - Initial release
// Feb. 9, 2013 - Added H1V2/H2V1 support, cleaned up macros, signed shift fixes 
// Also integrated and tested changes from Chris Phoenix <cphoenix@gmail.com>.

I have use “tjpgd.c” from Elm Chan (author of FatFS )
I have used picojpeg.c with my own class JPEGDecoder_kbv

/*
JPEGDecoder_kbv.h

JPEG Decoder for Arduino
Public domain, Makoto Kurauchi <http://yushakobo.jp>

Hacked by kbv from Bodmer for use with a TFT screen

Latest version here:
https://github.com/Bodmer/JPEGDecoder

*/

It is simple enough to render JPEG images from PROGMEM, SD or SPIFFS.
Both decoders require about 3kB of SRAM to work. Which means that you need a Nano EVERY or MEGA2560.

ARM targets e,g. DUE, Teensy3.x, STM32, … have plenty of SRAM and plenty of “PROGMEM” Flash.

PICOJPEG is faster on 8-bit. e.g. Xmega, Mega2560
TJPG is faster on 32-bit ARM. e.g. Due

I can post example programs that render with Adafruit_ILI9341
They should work with Adafruit_HX8357 by simply changing the include and constructor statements.

I have run them with MCUFRIEND_kbv, TFT_eSPI, …

/* show_tjpg_P:   render JPEG image from PROGMEM memory. tiger_jpg */

/* Any Arduino with 8kB SRAM can decode JPEGs
 * tiger.jpg is a typical 320x240 picture
 * NANO-EVERY  @ 16MHz     picojpeg: 3251ms  tjpgd: 4704ms (angry)
 * MEGA2560    @ 16MHz     picojpeg: 5012ms  tjpgd: 6303ms
 * Xmega128a4u @ 62MHz     picojpeg:  806ms  tjpgd:
 * Xmega128a1  @ 46MHz     picojpeg: 1146ms  tjpgd: 1826ms
 * M0_Pro      @ 48MHz     picojpeg: 1160ms  tjpgd: 1061ms
 * Due         @ 84MHz     picojpeg:  715ms  tjpgd:  547ms
 * STM32F103   @ 72mHz     picojpeg:  808ms  tjpgd:  601ms
 * STM32F446   @180mHz     picojpeg:  222ms  tjpgd:  169ms -O1=165 -O2=167 -O3=180
 * STM32F767   @216MHz     picojpeg:  129ms  tjpgd:   92ms
 * ESP32       @240mHz     picojpeg:  224ms  tjpgd:  172ms
 * Teensy3.2   @120mHz     picojpeg:  448ms  tjpgd:  331ms
 */

Do you want to use SD or PROGMEM ?
And on what target?

JPEG rendering time is dependent on the CPU power. TFT library makes little difference.
Rendering from SD is dependent on file size and SD library speed.

David.

Wow, this is a lot of usefull information! Thank you!

I'm using a Due and the SD-card. I'm trying to display the Slideshow data, received from a DAB+ tuner, on to a graphic display. Most of these data result in a JPEG-file that will be stored on the SD card.

I'll read your info carefully and try to implement it.

I'll keep you informed.
Thanks
Staf

I have attached a sketch that uses TJPGD
It loops through every *.jpg file in the /JPEGS directory on SD Card.

I have run it with Adafruit_ILI9341 on an ILI9341 screen.
I hope that it will build and run out of the box with Adafruit_HX8357 on your screen.

It displays landscape JPEGs and portrait JPEGs by changing the rotation to suit.
If the JPEG does not fit, it is scaled smaller.

Please let me know how you get on.
Or if you want a sketch that renders from PROGMEM Flash.

David.

show_tjpgd_SD_8357.zip (13 KB)

Hello David,

It is working!!, even the setRotation is causing no problems with your version.
Wow, thank you very much!
The version where you use the PROGMEM flash, is it much different?
Perhaps it is better to use the memory of the µcontroller, probably it is much faster then file-handling on a sd-card.

Staf

Yes, it goes faster by PROGMEM. But not by much. You can see some times in #6.

It is just the convenience of avoiding a SD card. Or Flash memory chip.

Obviously, you need to compress the JPEGs if you want several in PROGMEM.
And you need to compress to < 32kB if you want to render from PROGMEM on a MEGA2560.

If you want ultimate speed you read RAW files from SD Card on one SPI bus with one DMA channel.
And blit the pixels to the TFT on a different SPI bus with another DMA channel.

Your HX8357 can be used with 8080-8, 8080-16 or SPI interface.

If you use a parallel interface, you only need one SPI bus (for the SD card)

I have only got Teensy3.2
I guess that Teensy3.6 or Teensy4.0 would decode much faster.

David.

That Teensy-development board looks interesting! I think life is going to be too short to discover all these interesting things!

The Teensy performance is impressive. But you need a Sparkfun adapter board if you want to accept regular shields. I made my own adapter from protoboard.

Seriously, you have to think hard about what performance you want to achieve.
i.e. put some real numbers and typical images.

David.

Hi David,

See next video for result with a DAB+ tuner and usage of the code you have shared with me, to display slideshow on the adafruit display;

Your video works well.

You could use FreeFonts for the text. Just remember to draw a fresh background because GFX only prints FreeFonts in transparent mode.

Do you store the JPEGs in Flash or on a SD ?
I presume that you only get text from the DAB broadcast.

David.

Hi David,

Why should I use FreeFonts? Is it better? I have the impression that the used font in this application is very 'readable'.

The DAB+ tuner sends the JPG files in differents data parts. I have to filter the jpg-part of the data and put the jpg-parts back in one file, I use a SD-card for it. With the Teensy I have enough speed for handling the stream of data, storing it on a SD-card and reading it back again for displaying.

I have searched for standard Arduino procedures for storing information into memory but I did not find any usable examples. I'll try to use as much as standaard Arduino functions as possible.

The stationtext that you see on the screen are indeed bytes send by the tuner as ASCII code.

The 7x5 system font looks good in x1. It looks ok in x2 but not as professional as using a Free Font. lt looks very blocky in x3.

Yes, the 7x5 font is very readable. But the FreeFonts look nicer.

Regarding memory storage. Your Teensy4.0 has lots of SRAM. You can store information in variables, arrays or structs.
You can store things on the SD card too (if you want non-volatile storage)

David.