Skip to content

Working with the screen ​

I received my 2.4" TFT 40pins ILI9341 screen, together with a board with a FPC connector and pins. Let's see how I made it work (I'll save you my tribulations).

TODO: ​

  • [ ] Check with the screen I did not butcher the actual IM0 IM1 IM2 pinout.

Where to buy the screen ? ​

I took it from Aliexpress, it was the only one I found which was working in 3.3 for both VDD and VDDI

Here are the photos of the screen on the website, in case the vendor disapears, so you could try a research by picture?

Screen

Wiring it to the NucleoF446RE ? ​

FPCFUNCTIONSTM32F4
1X- (touch)ignored
2Y- (touch)ignored
3X+ (touch)ignored
4Y+ (touch)ignored
5GNDGND
6VDDI (2.8-3.3V)3.3V
7VDD (2.8-3.3V)3.3V
8NC/FMARK (TE)ignored
9CSX (SPI CS)GND
10DCX (DC,A0)PB8
11WRXPB9
12RDXPB10
13SPI SDI (MOSI)ignored
14SPI SDO (MISO)ignored
15RESX (RESET)PB12
16GNDGND
17DB0PC0
18DB1PC1
19DB2PC2
20DB3PC3
21DB4PC4
22DB5PC5
23DB6PC6
24DB7PC7
25DB8PC8
26DB9PC9
27DB10PC10
28DB11PC11
29DB12PC12
30DB13PC13
31DB14PC14
32DB15PC15
33LED-A3.3V
34LED-Kpulldown 10 ohm
35LED-Kpulldown 10 ohm
36LED-Kpulldown 10 ohm
37GNDGND
38IM03.3V
39IM13.3V
40IM2GND

How to communicate with the screen ? ​

So, as I am using a STM32F4, apparently I could use either DMA (Direct Memory Access) or FSMC(). Claude says FSMC is faster, but he also said I could not use it with my chip (wrong), so I went for DMA, and we'll see annother day if FSMC is faster or not.

The idea is:

  • we send the 2 bytes of data for une pixel via D0-D15
  • we pulse the WRX pin simultaneously
  • we set the DCX pin to 0 for command, 1 for data
  • Usually there would be some bit manipulation to get the right bit on the right pins, but since my mapping is direct PC0 to PC15, I can just write the data directly to the GPIO port.
cpp
void setupPins() {
   // Control pins
   pinMode(TFT_DC, OUTPUT);
   pinMode(TFT_WR, OUTPUT);
   pinMode(TFT_RST, OUTPUT);
   pinMode(TFT_RD, OUTPUT);

   digitalWrite(TFT_WR, HIGH);
   digitalWrite(TFT_RST, HIGH);
   digitalWrite(TFT_RD, HIGH); 

   // Enable GPIO clocks
   RCC->AHB1ENR |= RCC_AHB1ENR_GPIOBEN | RCC_AHB1ENR_GPIOCEN;

   // Set all PC0-PC15 pins to output mode (data bus)
   GPIOC->MODER = 0x55555555;
   // Set all data pins to push-pull, high speed
   GPIOC->OTYPER = 0x0000;     // All push-pull
   GPIOC->OSPEEDR = 0xFFFFFFFF; // All high speed
 }

 inline void pulseWR() {
   GPIOB->BSRR = (1 << (9 + 16));  // WR low (PB9)
   __NOP(); // Small delay
   GPIOB->BSRR = (1 << 9);         // WR high (PB9)
 }

 inline void write16(uint16_t data) {
   // Here there should be some bits manipulation, 
   // but my pinout makes it EASY
   GPIOC->ODR = data;
   pulseWR();
 }

 void setBusToInput() {
   GPIOC->MODER = 0x00000000;
 }

 void setBusToOutput() {
   GPIOC->MODER = 0x55555555;
 }

 void writeCommand(uint8_t cmd) {
   digitalWrite(TFT_DC, LOW);
   write16(cmd);
 }

 void writeData(uint8_t data) {
   digitalWrite(TFT_DC, HIGH);
   write16(data);
 }

 void writeData16(uint16_t data) {
   digitalWrite(TFT_DC, HIGH);
   write16(data);
 }

And that's it, you are ready to communicate ! You can browse the full code here, with the inheritance of the Adafruit_GFX class so that you can draw anything easily.