Go Down

Topic: Graphics library for NodeMCU (ESP8266), ESP32 and serial+parallel TFT displays (Read 48803 times) previous topic - next topic



Had a look at WifiManager, briefly hoped it would allow me to upload sketches remotely (OTA) and securely, but that is not the purpose...

Have been playing with a fork of the JPEG decoder library here for the ESP8266, it runs quite fast and a neat feature is that it uses the SPIFFS library so JPEGs can be easily stored as file copies in the FLASH chip using the SPIFFS data upload tool. SPIFFS saves a lot of tedious mucking about with arrays or SD cards.

Also found the ESP8266 can be programmed to emulate a WeMo mains switch which can then be controlled with on/off voice commands via the Amazon Echo or an Android AP.



Had a look at WifiManager, briefly hoped it would allow me to upload sketches remotely (OTA) and securely, but that is not the purpose...
WiFi manager is just to set up the ssid and password so you can do it with a browser vs having to re-compile the code.
But there is a s/w bundle for doing OTA updates as well. You have to include some extra code in your code just like with wifi manager but it is pretty cool.

If you google around you can find information on tutorials on Arduino OTA updates.

--- bill


I have updated the TFT_ILI9341 graphics library for the NodeMCU (and ESP8266 variants).  A copy can be found on GitHub.

The 49 Adafruit_GFX Free Fonts have all been added plus two new examples.

The free fonts (as wells as the other resident fonts) can be drawn onto the screen with a background colour and can be drawn relative to a chosen datum, so it easy to right justify text or centre text about a point on the screen (the Adafruit_GFX library lacks these abilities).  The examples show how this works.


I just tried this out, It works perfectly.  Thanks for your hard work and for sharing it!


I have made some performance tweaks to the library, latest version is on GitHub.

With a stock 320x240 display the NodeMCU can now execute all the timed "graphicstest" functions in 0.91s (totalled) and a compatible UTFT_Demo finishes in 0.92s.

Considering these NodeMCU boards sell for only $3 (and have Wifi built in) they are exceptional value if a small powerful processor with wireless connectivity is needed. As they operate at 3.3V they can be wired straight to the display.  Typically the backlight LED benefits from the extra brightness if powered driven from 5V. (Note: some variants of the NodeMCU provide the USB 5V on the Vin pin which is handy).

I have a higher performance ESP32 on order so when the Adruino core libraries are in place for that chip I will see if I can adapt the code for that 240MHz processor though the performance is more dominated by the SPI frequency than the CPU frequency and 80MHz is the limit with the 2.2" ILI9341 display I have.

These are the times reported by the "graphicstest" for different CPU and SPI frequencies:

Code: [Select]
CPU 160MHz, SPI 80MHz
Benchmark                Time (microseconds)
Screen fill              81880
Text                     17484
Lines                    110823
Horiz/Vert Lines         8784
Rectangles (outline)     6683
Rectangles (filled)      168311
Circles (filled)         79768
Circles (outline)        65434
Triangles (outline)      25870
Triangles (filled)       100298
Rounded rects (outline)  30082
Rounded rects (filled)   212347
Done! Total = 0.907055 s

CPU 80MHz, SPI 80MHz
Benchmark                Time (microseconds)
Screen fill              82850
Text                     26730
Lines                    162672
Horiz/Vert Lines         10251
Rectangles (outline)     8617
Rectangles (filled)      170695
Circles (filled)         121724
Circles (outline)        97799
Triangles (outline)      37727
Triangles (filled)       137253
Rounded rects (outline)  43787
Rounded rects (filled)   236197
Done! Total = 1.135728 s

CPU 160MHz, SPI 40MHz
Benchmark                Time (microseconds)
Screen fill              157817
Text                     20258
Lines                    130615
Horiz/Vert Lines         15264
Rectangles (outline)     10667
Rectangles (filled)      323955
Circles (filled)         100700
Circles (outline)        74626
Triangles (outline)      30953
Triangles (filled)       151077
Rounded rects (outline)  36637
Rounded rects (filled)   384025
Done! Total = 1.435837 s

80MHz, 40MHz SPI
Benchmark                Time (microseconds)
Screen fill              161944
Text                     29219
Lines                    179507
Horiz/Vert Lines         16988
Rectangles (outline)     12709
Rectangles (filled)      332815
Circles (filled)         142200
Circles (outline)        106428
Triangles (outline)      42014
Triangles (filled)       189318
Rounded rects (outline)  50262
Rounded rects (filled)   414494
Done! Total = 1.677213 s

160MHz, 20MHz SPI
Benchmark                Time (microseconds)
Screen fill              312993
Text                     26787
Lines                    173766
Horiz/Vert Lines         28570
Rectangles (outline)     18852
Rectangles (filled)      642021
Circles (filled)         145685
Circles (outline)        98588
Triangles (outline)      41397
Triangles (filled)       255954
Rounded rects (outline)  52092
Rounded rects (filled)   735513
Done! Total = 2.531470 s

80MHz, 20MHz SPI
Benchmark                Time (microseconds)
Screen fill              315007
Text                     35582
Lines                    221512
Horiz/Vert Lines         30092
Rectangles (outline)     20778
Rectangles (filled)      646544
Circles (filled)         186471
Circles (outline)        129292
Triangles (outline)      52337
Triangles (filled)       292740
Rounded rects (outline)  65204
Rounded rects (filled)   761167
Done! Total = 2.756191 s


Is there some way to make the clock on your Clock_TFT_NTP sketch display local time? I un commented the line for it and in the serial window it displays the correct time but not on the display itself.


Hi Stan,

The attached should do what you want but it is a "work in progress" and therefore not fully finished/tested. It uses a worldwide DST correction library, see comments in sketch.

Things to be aware of:
1. It also uses a SI7021 sensor to display temperature and humidity, so comment out those bits
2. It uses a NTP pool lookup, so I get faster responses from a UK NTP server, your mileage may vary
3. It takes a couple of minutes to show the correct time due to an uncorrected bug :-)

You can set your time zone and display different time zones on the analogue and digital clock displayed. You will need to read the TimeZone library documentation to see how to edit the sketch to do what you want.

Link to the libraries needed are in the sketch header.

Have fun.


Thank you! I have one of the gy21 sensors and loaded the sketch, it works perfectly. I am reading the documentation to figure out the time zone part.
All your hard work is greatly appreciated from a beginner like me.


Hi Stan,

The good news is that I have attached an improved NTP time sketch with comments that show you where/how to change the time zones for the analogue and/or digital clocks!

The bad news is that I have taken out the SI7021 (GY-21 board) code... so if you want that back in there you still have something else to do!

If you get stuck or find it has a coding bug then post back.


The latest sketch works great, with your well written & commented coding it was easy to figure out how to change the time zone. The new feature with the day & date is better than the temp & humidity I think.

Thanks again for your contribution :-)



Hi Stan,

Thanks for the feedback, I appreciate your appreciation!

I expect you have noticed there is an indicator shown on the top right corner, this shows the NTP reply status:

 Green: NTP message received in last minute
Amber: No NTP message for 1-15 minutes
Red:     No NTP message for more than 15 minutes

If it goes red then the time will drift from the real time due to the accuracy of the local clock.

"All your hard work is greatly appreciated from a beginner like me."

As a beginner you are the one that is doing the hard stuff by having to clicmb that steep learning curve to get new things working! I have a lot of code and hardware experience, so now it is like building software with Lego and is no longer hard work.  In fact I rather like it when things don't work, as I have something interesting to investigate and find a solution!


I wondered what the green dot was, This is loaded with all the features you could want.
I have had it running without a problem for about 24 hours now and it is my favorite desktop toy.


Hi Stan,

You will have to wait and see if the DST time is automatically applied on the correct day for your time zone :-)


This might please David  :) , I have added 8+16+32 bit reads to the library with indexing so arbitrary register bytes can be read rather than a simple sequence. This also helps when the are dummy, "don't care" undefined values in the register that can be skipped. Github has been updated.

These new functions only work with ILI9341 displays configured for SPI Interface II which reply with data on the SPI MISO line.  Some displays are configured for SPI Interface I and have a bi-directional SDA (aka MOSI) line.

There are two example sketches added that will indicate which interface you have on your display, one of these will give good values including the 9341 ID of the driver:

TFT_Read_Reg example uses the TFT_ILI9341_ESP member functions for Interface II displays

is a stand-alone sketch that tries to read a Interface I display with a bidirectional data line

Just because you have 2 identical looking displays does not mean you have 2 of the same Interface type as the configuration is done at PCB level via hidden links (i.e. configuration pins IM [3:0] are "1110" for Interface II).


Hi Rowboteer

Thank you very much for all your contributions.

Support for ESP8266 is highly welcome; this system is very usable for IoT kind of applications, and to be able to add a display to the network with just one inexpensive "Arduino" is interesting. I use quite many of these.

May I suggest a simple fix to your code?

The member variable

Code: [Select]
           SPIClass *_SPI;

at line 433 does not get initialized. Line 60 in .cpp is commented out:

Code: [Select]
  //_SPI = SPIdev;

and should be

Code: [Select]
  _SPI = &SPI;

Fortunately no method of SPIClass is virtual, so calls zero instance pointer work.
Why access to the only member variable useHwSpi does not cause exceptions is unclear to me.

I prefer references instead of pointers as member variables, then the compiler forces me to initialize them.

No personal message please; any question may be useful for other users. Use code tags for code. Make links clickable with URL tags. Provide links to the product in question.

Go Up