GxTFT library - modifying it to work on other STM32 boards

Using ZinggJM library GxTFT on a STM32F407, I managed to run LVGL with a 7" SSD1963 display.

Recently ZinnggJM updated the library to work with the official STM32 core.
I am very impressed with the library and like how it is all separated with the controller, IO & Display, its also got a nice selection of tft that it is compatible with.

I wanted to migrate over to a more powerful board with bigger flash memory, one of the boards I have is a Nucleo 144-F767ZI using the STM32duino core on Arduino, since I had it running on a STM32F407 I thought I could possibly port it over to the Nucleo Board more easily as most of the F7 series are pin-to-pin compatible with the F4 series.

I did attempt to reassign the pins to more easily accessible ones on the Nucleo 144, studied how the F4 pins were assigned (see attached) on GxTFT but think I was going wrong with the GPIO registers, I tried several combinations but unfortunately could not get it to work.

I decided it was best to stick with the code that works on the F407 first and try to get that to work with 16bit bitbashing on the Nucleo board.
Wired it up exactly the same pins but again could not get it to display anything just a blank screen.

Now because I have a working example with F407, I am waiting on a cheapy logic analyser (its only 8bit) I purchased to arrive, I can hopefully compare the two boards on pin level.

Does anyone have any suggestions with things I should consider and the basics I should look in to first?

The F407 is 168Mhz
The F7 is 216Mhz

Nucleo_144.cpp (13.8 KB)

Nucleo_144.h (1.14 KB)

@RGarrett93, Hi,

I have a directory on my notebook where I store code downloads, named NewbieCodes.
It felt a bit strange to add RGarrett93 there to put your Nucleo_144.h and Nucleo_144.cpp.

The concept to separate aspects of TFT driver code into separate classes still seems a good idea.
But the implementation in GxTFT is a bit clumsy.

Having a graphics base class on top of the inheritance tree, such as Adafruit_GFX and Adafruit_SPITFT looks better.
But trying to handle parallel IF TFTs like SPI TFT doesn't look clean.
And to add cross-dependencies between libraries is a total mess in my view.

I found a way to add parallel IF specializations sideways to the inheritance tree in GFX_TFT.
But this is work in (trickle slow) progress.

I see that you paid attention to pulse length of read and write pulses in Nucleo_144.cpp.
Maybe you need to add pinMode() for the pins you use with digitalRead() and digitalWrite().
digitalWrite() might be no-op-ed if pinMode() is not set.


Hi Jean-Marc,

Thanks for your reply.

What I particularly like about having seperate classes in GxTFT, it lays a good foundation for adding new hardware.

I've not yet had a proper look at GFX_TFT but will have a explore and test it. I'm looking forward to trying the epaper library you've been working on too.

You've given me food for thought and I'll check out pinMode with the relating pins used, I assumed the MODER registers covered that though.

I will post back here, if I make any progress with it.


I've put on pause the Nucleo_144.cpp until I get a better understanding why its not working.

What I don't get is that the code that works with the F407VE should in theory work with F767ZI if I use the exact same GPIO. The registers should be the exact same.
I tested it with GxIO_STM32F407V_P16, removed the ifdef but still nothing.

ICache & DCache on the F7 is used, so I have disabled that to keep it matching the F4.

I just remember that I have a similar issue pending.

I have two pairs of nearly identical boards, but with different processors.
I think it is STM32F407VET6 and STM32F407VGT6 and STM32F103VE and STM32F103VG.
The VE versions work with GxTFT, but the VG don’t (yet).
But I put them aside and don’t have it at hand right now.
I do have some STM32F767, but not used yet.

This just to say there may be subtle differences, maybe with alternate functions.

The STM32F767 is faster than the F407 so you may need to extend the write strobe high and low periods to provide a longer data setup and hold time.

I found I had to tune the write strobe timing for different STM32 processors and displays, see example here otherwise the displays remained blank.

In that particular case direct register writes are used to set/reset I/O pins, but if you use digitalWrite you may find the pin toggling is slow enough to avoid extending the strobe.

You just have to watch the write cycle timing. (and read cycle)

Otherwise it is just a question of accessing different PORT pins. For example the Arduino pins are different on Nucleo-144 versus Nucleo-64


The F407 is 168Mhz
The F767 is 216Mhz

Sounds like possibly a timing issue, I was hoping it would mostly be compatible but of course I can’t get away with that being too easy.

I will have a look at your strobe timing @bodmer, see if I can replicate that.

It’s worth comparing the two boards with a logic analyser just to get a bit of a picture too.
Won’t be able to have a look till the next few days but will report back my findings.

Feel like getting somewhere with it, appreciate all the suggestions.


Just add large delays to start with. Don't worry about fast performance.

Then you can reduce the delays until you get to the datasheet limits e.g. 66ns tWC for most controllers.

Think about it. 216MHz means 4.63ns per machine cycle. i.e. 15 machine cycles for the complete TFT Write Cycle.

TFT controllers vary e.g.

SSD1289  tWC =100ns  tWRH = 50ns  tRCFM =1000ns  tRC =1000ns (tWCFM= 238ns)
SSD1963  tWC = 26ns  tWRH = 13ns  tRCFM = 110ns  tRC =  72ns
ST7789V  tWC = 66ns  tWRH = 15ns  tRCFM = 450ns  tRC = 160ns
ST7793   tWC = 75ns  tWRH = 25ns  tRCFM = 450ns  tRC = 450ns


Some more advice, first things first:

  • check that RST is not stuck low. I once lost a day until I noticed.

  • measure voltage on the control lines while example is running. They should fluctuate.

  • if the interface has a control line for parallel selection (Waveshare board), make sure it is correct.

  • and of course check VCC and GND connections (for inexperienced readers only).



After some digging I think I found the box with the pending issues:

There is a STM32F407VET6 board with matching "DevEBox" 3.2" ILI9341 Display that works.

There is a slightly bigger STM32F407ZET6 board with similar matching 3.2" ILI9341 Display that doesn't work.
Looks like I need to check if different pins are used for control, data pins should be same FSMC.

There is a blue STM32F103ZET6 board with the same (2nd) matching 3.2" ILI9341 Display that runs the pre-loaded Demo code.

My memory doesn't work too well, but its about half a year that I stored these away.

In a second box there is a STM32F407ZGT6 M4 DEMO board with matching 3.5" ILI9486 Display that works.

So after all my issue may just be a wiring question.

Okay so good news, I have managed to get it to display on my nucleo.

Using all of your advice and after several tests, going back and forth with testing pins, I decided to write it all again from scratch.

Its slow because I am using purely pinMode/ digitalWrite/ digitalRead but with no delays: I have had to write it slightly different but what this should allow me to do, is work backwards and start rewriting it with the correct registers
(I thought my Nucleo_144.cpp was correct but I could only get a small flicker/ line on the bottom of the screen, so I will recheck it all again to make sure I've not mistyped one of the bitmasks)

I've attached the files (GxTFT_MCU_Tester.cpp & GxTFT_MCU_Tester.h) here, in theory it should work with any MCU that uses the arduino framework: you just have to redefine the pins below with your pins instead...

So the next bit for me, is to improve the performance/ speed of it running on the Nucleo_144.

This has been very educational for me and I appreciate all the help and advice given so far.

I've got a question, so why is using pinMode, digitalWrite slow because in theory its calling the exact registers I would call but one at a time?
Is it because each pin is set individually whereas when using the registers instead, you can set multiple pins all at once/ together?


GxTFT_MCU_Tester.h (1.39 KB)

GxTFT_MCU_Tester.cpp (8.29 KB)

I've got a question, so why is using pinMode, digitalWrite slow because in theory its calling the exact registers I would call but one at a time?

These methods use the HAL (Hardware Abstraction Layer) code of the STMicroelectronics package.
I didn't look at the code of this package, it may be less complicated, but the code of the Roger Clark package is very complicated, near to not understandable. This is because the hardware is very flexible and complicated, e.g. because of the set of alternate functions of each pin.

BTW, I got my STM32F407ZET6 working now, just RS and CS are on different pins.


Awesome that's good to hear the STM32F407ZET6 is now working.

I'm using the official STM32 Core but I believe it is based on Roger Clark's core which also uses HAL

I reckon if I spend a bit of time carefully I should be able to get the correct registers and take in to consideration with what has been mentioned on here with timing and therefore increase the performance.

There are functions for the registers that might help but I would have to experiment with them, just something I came across within the core pins_arduino.h

portSetRegister(digitalPinToPort(P)); //BSRR

I have ordered a Nucleo 144-F767ZI from Digi-Key: NUCLEO-F767ZI. Should arrive quite soon.

Less expensive than available from all those unknown shops on AliExpress (I know ACELEX), and faster.

Disadvantage of the Nucleo board is that I will need to add a proto board as shield, with FSMC pins on a display connector.

I already have a small STM32H750 board with 0.96" TFT I have not yet used. Time to learn something new.
STM32H7 core board STM32H750VBT6 development board compatible with openmv minimum system board



How do Distributors operate in Switzerland?

In the UK I can order the Nucleo from Farnell before 18.00 and it arrives at my front door at about 11.00 the following morning.
My packet would probably come from the UK Warehouse but sometimes from Belgium.

I have heard conflicting reports that some European Distributors will not sell to the general public.
But UK companies don't mind who they sell to. As long as they get their money.

Yes, I have noticed that regular ST Evaluation Boards are sold by Chinese companies on Ebay at extortionate prices. When you can buy from the official Distributor in your own country.



How do Distributors operate in Switzerland?

I don't have much experience ordering from distributors, except for consumer electronics.
For consumer electronics it is easy, there are several good choices, I have to decide for each order.
For hobby electronics components it is a bit more difficult to find out who has what at which price.
Component prices are often considerably higher than from AliExpress shops.

One shop I order from time to time is conrad.ch (also known conrad.de).
My first Arduino was a "Pretzelboard" Arduino Nano - ESP-01 board in a IoT - Adventskalender from Conrad.
Delivery is a bit slow, some days, unless you order express delivery.

I think Distrelec is a well-known distributor in Switzerland.

But I rarely think of ordering from a local distributor, as I am so much used to look on AliExpress.
AliExpress delivery currently is rather slow and varies considerably, because of COVID-19. Usual was 3 weeks.
Lithium Accus are extremely slow, up to 3 months, because only PostNL transports them.

I have heard conflicting reports that some European Distributors will not sell to the general public.

One reason is that they need an agreement with swiss customs to collect and deliver VAT.
An other reason may be that factories prefer to force higher prices through retailers in Switzerland.



I just received my Nucleo-144 boards (STM32F767ZIT6 and STM32F746ZGT6) from Digi-Key.
So delivery is quite fast from this distributor. It arrived by UPS.
I bought 2 boards to have free shipping delivery. Price paid in SFr. through PayPal, with VAT already added.


Next step is study the pins, find where the FSMC data pins are, and then create a shield for my (FSMC) TFTs.
This will take some time, from experience double row connectors take time with me, especially when on different side of the proto board.



Apologies only just saw your reply (I'm not receiving notification alerts), that's great to hear you have received the nucleo boards.
So things to note, on the STM32F767ZIT6 there is no FSMC but instead it's now known as FMC, all the FSMC stuff just needs to be renamed but it should work much the same.

The STM32F767 FMC pins are exactly the same as the STMF4 FSMC pins, so you should be able to use the exact same registers.

Two of the FMC pins (PD8 & PD9) conflict with the STlink board at the top of the Nucleo, as it is used for virtual serial comms when you plug your nucleo to you PC.
They are easily disconnected via two solder bridge, this can be done by removing SB5 & SB6 link resistors which are in the middle of the Nucleo board.

Most of the pins will be on the morpho connectors, see below.


thank you for your valuable input! This will help me get started faster.

I just finished my proto-shield.
It was trickier than expected, as most pins are available on the ST Zio connectors, but not all.
I hope I didn't introduce too many errors.
My first test with the bit-bashed driver just failed, so I need to do some checks.
The FSMC/FMC version will come afterwards, so I didn't notice the name change yet.

From your post it is unclear to me if you got it already working with GxTFT.