stm32plus: ILI9327 TFT driver

The code presented in this article requires a minimum of version 3.0.0 of my stm32plus library.

The TFT panel

The ILI9327 is a driver IC for 432×240 (WQVGA) panels. The panels are typically found in mobile phones; LG went through a phase of producing lots of phones with resolutions close to this as did several other manufacturers.

I got one of these panels on ebay. It came attached to a handy breakout board, though I have seen others that come with just the FPC tail if you’re feeling adventurous. This particular board seems to have the tail soldered directly to it somewhere underneath the panel.


The front of the board


The back of the board

There’s also an ADS7843-compatible touch screen driver and an SD card cage. This is a configuration we often see on development boards sourced from China.

Pinout

The seller included the pinout for the display. It’s a familiar 16-bit 8080 interface that is easily connected to the FSMC of the STM32 microcontroller. There’s no sign of a step-up DC-DC converter on the board so the white LED’s that make up the backlight must be in a parallel configuration.


The pinout

The touch screen is compatible with the ADS7843 controller and that can be hooked up to my stm32plus driver. I’ve had varying luck with the touch screens attached to these cheap boards. The ADS7843 is an A-D converter which means that the board should be carefully designed to minimise noise and it seems that not all of them are that well thought out.

Panel details

This panel is slightly unusual in that its resolution is 400×240 which is less than the full 432×240 supported by the ILI9327. How does that manifest itself? Well, the co-ordinates from 0-31 are not visible. That is, you can write to them but nothing will appear on the screen. Therefore we have to make allowances for that in the stm32plus driver and you will see how in the demo code.

My demo sequence exercises some of the common functions used in graphics operations such as rectangle, line and ellipse drawing as well as text rendering and hardware scrolling when the panel supports it (the ILI9327 does support hardware scrolling in portrait and landscape modes).

The datasheet for the ILI9327 is readily available on the internet. It’s written to the high standard that I’ve come to expect from ILITek making the job of writing a driver really straightforward.

The panel supports 16 bit colour (5-6-5 format) and 18-bit colour (6-6-6 format). The STM32F103 can easily drive either colour format at a fast pace. I’ve come to realise that the observable difference between 64K and 262K colours is pretty low and generally I’ll use 64K for the extra speed that it offers.




Data transfer protocol for the 16-bit interface (click for larger)

Using a 16-bit interface we can transfer a 64K colour pixel in one operation. A 262K colour pixel costs an extra transfer per-pixel and therefore halves the speed just for those extra 2 bits.

STM32 wiring

Here’s the wiring mapping table that you’re going to need if you intend to hook one of these up to an STM32 MCU. You’re free to change the address line that you use for RS, the bank selector that you use for /CS and the GPIO pin for RESET.

In my example code for this panel I’m using SRAM bank 1 and A16 for RS (register select). This configuration is compatible with the 100 and 144 pin STM32F103 devices.

LCD signal STM32 port port function
D0 PD14 FSMC_D0
D1 PD15 FSMC_D1
D2 PD0 FSMC_D2
D3 PD1 FSMC_D3
D4 PE7 FSMC_D4
D5 PE8 FSMC_D5
D6 PE9 FSMC_D6
D7 PE10 FSMC_D7
D8 PE11 FSMC_D8
D9 PE12 FSMC_D9
D10 PE13 FSMC_D10
D11 PE14 FSMC_D11
D12 PE15 FSMC_D12
D13 PD8 FSMC_D13
D14 PD9 FSMC_D14
D15 PD10 FSMC_D15
/WR PD5 FSMC_nWE
/RD PD4 FSMC_nOE
/CS PD7 FSMC_nE1
/RESET PE1 GPIO
RS (D/CX) PD11 FSMC_A16

stm32plus driver

stm32plus 2.0.0 comes with an updated ILI9327 demo application. Here’s an extract from the source code that shows how to set it up.

#include "config/stm32plus.h"
#include "config/display/tft.h"

using namespace stm32plus;
using namespace stm32plus::display;

class ILI9327Test {

	protected:
		typedef Fsmc16BitAccessMode<FsmcBank1NorSram1> LcdAccessMode;
		typedef ILI9327_400x240_Portrait_262K<LcdAccessMode> LcdPanel;

		LcdAccessMode *_accessMode;
		LcdPanel *_gl;
		Font *_font;

	public:
		void run() {

			// reset is on PE1 and RS (D/CX) is on PD11

			GpioE<DefaultDigitalOutputFeature<1> > pe;
			GpioD<DefaultFsmcAlternateFunctionFeature<11>> pd;

			// set up the FSMC with RS=A16 (PD11)

#if defined(STM32PLUS_F1)
			Fsmc8080LcdTiming fsmcTiming(0,2);
#elif defined(STM32PLUS_F4)
			Fsmc8080LcdTiming fsmcTiming(4,10);
#endif
			_accessMode=new LcdAccessMode(fsmcTiming,16,pe[1]);

			// declare a panel

			_gl=new LcdPanel(*_accessMode);

			// apply gamma settings

			ILI9327Gamma gamma(0,0x10,0,0,3,0,0,1,7,5,5,0x25,0,0,0);
			_gl->applyGamma(gamma);

			// clear to black while the lights are out

			_gl->setBackground(0);
			_gl->clearScreen();

			// create the backlight on timer4, channel2 (PD13)

			DefaultBacklight backlight;

			// fade up to 100% in 4ms steps

			backlight.fadeTo(100,4);

			// create a font

			_font=new Font_VOLTER__28GOLDFISH_299;
			*_gl << *_font;

Let’s look at the code in a little more detail.

Includes and namespaces

#include "config/stm32plus.h"
#include "config/display/tft.h"

using namespace stm32plus;
using namespace stm32plus::display;

Firstly we need to include the headers that define the classes we’re going to use. Secondly, since all of stm32plus lives either in the stm32plus namespace or a sub-namespace (in this case stm32plus::display) we will import them into the global namespace to make the declarations of the objects less clumsy looking.

FSMC access mode and reset

typedef Fsmc16BitAccessMode<FsmcBank1NorSram1> LcdAccessMode;
typedef ILI9327_400x240_Portrait_262K<LcdAccessMode> LcdPanel;

LcdAccessMode *_accessMode;
LcdPanel *_gl;
Font *_font;

  public:
    void run() {

      // reset is on PE1 and RS (D/CX) is on PD11

      GpioE<DefaultDigitalOutputFeature<1> > pe;
      GpioD<DefaultFsmcAlternateFunctionFeature<11>> pd;

      // set up the FSMC with RS=A16 (PD11)

#if defined(STM32PLUS_F1)
      Fsmc8080LcdTiming fsmcTiming(0,2);
#elif defined(STM32PLUS_F4)
      Fsmc8080LcdTiming fsmcTiming(4,10);
#endif
      _accessMode=new LcdAccessMode(fsmcTiming,16,pe[1]);

We use an ‘access-mode’ class to control how we communicate with the panel. Here we initialise it to use the FSMC in 16-bit mode with A16 as the RS line (PD11). We will also be wiring up the panel’s RESET line to PE1.

We declare an Fsmc8080Lcdtiming object that takes care of the timing details. The two parameters are the address setup and data setup times in HCLK cycles. At full speed the STM32F1 has a 36MHz FSMC bus and the STM32F4 has a 60MHz bus. Therefore the timings may be different for each MCU if the bus is faster than the panel.

To determine the value of these parameters you need your panel’s data sheet and the equations in the ST Microelectronics application note AN2790 (google it). Alternatively you can just start with some large-ish numbers and decrease until the timings get too tight and the panel doesn’t respond!

Declare a panel

// declare a panel

_gl=new LcdPanel(*_accessMode);

Now that we have an access mode we can declare the panel. The constructor will ask the access mode class to reset the panel and then it will do the initialisation sequence.

Our example initialises it in portrait mode, 18 bit colour (262K). If you take a look at TftInterfaces.h you will see that following modes are available:

ILI9327_400x240_Portrait_64K
ILI9327_400x240_Landscape_64K
ILI9327_400x240_Portrait_262K
ILI9327_400x240_Landscape_262K

The predefined drivers are just C++ typedefs that bring together the necessary combination of template instantiations to create a coherent graphics library. If you have an ILI9327 panel that is not 400×240 then you can support it by supplying your own ILI9327400x240PanelTraits class. See the code for details.

Gamma correction

      // apply gamma settings

      ILI9327Gamma gamma(0,0x10,0,0,3,0,0,1,7,5,5,0x25,0,0,0);
      _gl->applyGamma(gamma);

Gamma correction involves the manual adjustment of the panel’s response to different shades of grey to compensate for differences in the manufacturing process. Every panel will be slightly different.

Setting up the tweaks to the gamma curve are optional, a reasonable display will be obtained by using the default linear curve but if true-to-life colours are a requirement then a custom gamma curve is essential.

stm32plus includes an interactive gamma adjustment application, and that will be introduced in a future blog post. For now, you can just use the default settings and maybe come back to it later.

Backlight

// create the backlight on timer4, channel2 (PD13)

DefaultBacklight backlight;

// fade up to 100% in 4ms steps

backlight.fadeTo(100,4);

stm32plus comes with a PWM backlight controller template class, and a subclass of that called DefaultBacklight that assumes you can connect the backlight regulator to PD13.

This PWM output should be used to drive the base of suitable transistor, or the ‘enable’ pin of a constant current backlight driver. It should not be used to directly power the backlight because it’s likely to draw too much current from the MCU pin.

The fadeTo method allows smooth transitioning of the backlight between levels to give a pleasing user experience.

Font selection

// create a font

_font=new Font_VOLTER__28GOLDFISH_299;
*_gl << *_font;

stm32plus (as of 1.2.0) now supports the very convenient stream ‘<<' operator to output text and numbers to the display. To do this the operator needs to know which font to use, and we do that by using the << operator with the font object as the operand.

Get the source code

Updated source code is in stm32plus 2.0.0 (or later) available from my downloads page.

Watch the videos

I’ve uploaded a pair of short videos that shows the demo code in action. Firstly, here it is on the STM32F103.


Secondly, here it is on the STM32F4 Discovery board.

  • Tim

    Nice! Great job Andy.
    Site looks great too.

  • ian

    hi,
    what would you suggest as a simple tool chain to get the code into the device,
    I have a stm32 development board with 2.8 inch screen from ebay…
    but it has code in chinese. i have a clone jtag uploader.
    many thanks my email new@ianmoore.org
    Ian

  • ian

    Hi….
    thanks for helping….. okay i have eclipse and gnu arm….
    ive done lots of avr programming with BASOM basic compiler…. and am happy to get in there and edit a c++ example…. however to start from scratch… do i put all the c files header files etc in one folder? then how do i 'register' them in the editor?
    do i just load all the files one at a time…. then edit the main c file ?
    this the board and tft i have: http://www.ebay.co.uk/itm/STM32F103RBT6-Developme

    and i have this jtag clone programmer….. http://www.ebay.co.uk/itm/USB-Mini-JTAG-ARM-Debug

    ive managed to connect using the jtag and errased the chip….
    but not managed to upload or create any program suitable for the3 screen.
    I managed to upload a hex file that blinks an led…
    or erase the chip…to stop blinking the led.

    this is daft….. ive been programming for 10 years!… but this has baffled me! :o)
    I'd really appreciate your help to
    download a graphics routine/demo
    put it into eclipse…. somehow… folders(?) .h and .c files
    compile it
    upload it….
    I can then EDIT the demo…… I'm away with the whole world infront of me! :o)

    many thanks
    Love your site
    Best wishes
    Ian

  • jafaryn

    Do you still have the link on ebay for this lcd module?

    • It was seller "emartee2009" but it looks like he doesn't have any at the moment.

  • it wonderful post….i liked it…thanks for sharing!

  • Ramucho

    Hello Andy,

    I have a 5" TFT 800×480 display and I'm not able to make the calibration working correctly. My 3.2" TFT 320×240 works correctly with it. Both of them use the same ADS7846 or XPT2046, they're compatible. Is it a problem with the calculation of the matrix ? I've heard that it should work for a maximum resolution of 512×512. Is it right ? I'm sure that's not a hardware problem because I can draw on the screen without using the calibration but using a simple calculation. Do you have an idea about this problem ? By the way, very nice job 😉
    Thanks.

    • It's worth checking your driver code to make sure that the matrix calcs don't overflow the datatype being used. I don't see anything in the touch screen protocol that would affect you. The default ADC accuracy is 12 bits – plenty for your screen size.

  • Ramucho

    Hi,

    Thanks for your fast answer. Tracking an overflow somewhere is exactly what I'm doing since 2-3 days but with no results for the moment 😉 I can't see what else it could be… Wait and see.
    Regards.

  • Ramucho

    Hi,

    I got it work ! The problem is I have to change the variables declaration : from int32_t to int64_t in the matrix calculation 🙂 And now it's ok ! Cool. I can go on now. Thanks for you help. Just a question, do use 150 ohm resistors between the display and the discovery board ? Do you use a 5V to 3.3V DC-DC converter for the display ? Mine is powered by the discovery 3V but I don't think it is sufficient for the display, I still have some instability sometimes (maybe the FSMC config is not correct).
    Regards.

    • I use the 3V pins on the discovery board for power. The displays themselves tend to draw very little current. The backlight LEDs are by far the biggest current drain – there must be quite a lot of them on a 5 inch display. In general I have found it much harder to get the FSMC timings correct on the F4 than the F1 and when you get them wrong it's unstable.

      • Rastislav

        Hi,

        could you please give an estimation of power consumption during the demo with STM32F4Discovery (I suppose its running at 168MHz) and the ratio of what consumes F4 compared to the display.

        Many thanks.

  • BO LI

    i think this driver's pins are almost the same sequences of S6D1121 from the one i bought. Are the registers also the same?
    So just want to ask another naive question, is the transmission from the stm to lcd affected by the baud rate?

    • Hi, What do you mean by "baud rate" ? If you are referring to the CPU clock frequency then the answer is yes. The FSMC timings are all defined in terms of HCLK's where HCLK is the CPU clock.

      • BO LI

        i see.
        For the System.c file from your library, it says 168MHZ for hclk, really?