Skip to main content
Associate II
April 9, 2025
Solved

16-bit parallel - ILI9325C Display and STM32F401RET6

  • April 9, 2025
  • 2 replies
  • 681 views

Hello,

I am trying to connect an ILI9325C display to an STM32F401RET6 microcontroller Yes this is related to my previous post. After writing the code correctly and connecting the display, it doesn't respond and only has the backlight on (from the power supply). I think my code is correct I compare it to the documentation of my display. Any advice appreciate it.

Display: https://www.waveshare.com/wiki/3.2inch_320x240_Touch_LCD_(C)

My code LCD.C for 16bit-Parrarel

#include "stm32f4xx_hal.h"
#include "stm32f4xx_hal_spi.h"
#include "lcd.h"

SPI_HandleTypeDef hspi1; // SPI do dotyku

// Ustawienie danych na pinach D0–D15
void LCD_SetDataPins(uint16_t data)
{
 // Maska: PB0–PB10, PB12–PB15 (bez PB11 = D11, bo ten jest na PA11)
 uint16_t mask = 0b1111011111111111; // 0xF7FF

 // Najpierw wyczyść i ustaw dane na GPIOB
 GPIOB->ODR = (GPIOB->ODR & ~mask) | (data & mask);

 // Osobno ustaw PA11 (D11)
 if (data & (1 << 11)) {
 HAL_GPIO_WritePin(GPIOA, GPIO_PIN_11, GPIO_PIN_SET);
 } else {
 HAL_GPIO_WritePin(GPIOA, GPIO_PIN_11, GPIO_PIN_RESET);
 }
}

// Wysłanie komendy do LCD
void LCD_WriteCommand(uint16_t cmd) {
 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_1, GPIO_PIN_RESET); // RS = 0
 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_0, GPIO_PIN_RESET); // CS = 0

 LCD_SetDataPins(cmd);

 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_2, GPIO_PIN_RESET); // WR = 0
 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_2, GPIO_PIN_SET); // WR = 1

 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_0, GPIO_PIN_SET); // CS = 1
}

// Wysłanie danych do LCD
void LCD_WriteData(uint16_t data) {
 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_1, GPIO_PIN_SET); // RS = 1
 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_0, GPIO_PIN_RESET); // CS = 0

 LCD_SetDataPins(data);

 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_2, GPIO_PIN_RESET); // WR = 0
 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_2, GPIO_PIN_SET); // WR = 1

 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_0, GPIO_PIN_SET); // CS = 1
}

// Inicjalizacja wyświetlacza LCD
void LCD_Init(void) {
 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_3, GPIO_PIN_RESET); // RST = 0
 HAL_Delay(50);
 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_3, GPIO_PIN_SET); // RST = 1
 HAL_Delay(10);

 LCD_WriteCommand(0x01); // Soft Reset
 HAL_Delay(10);

 LCD_WriteCommand(0x28); // Display OFF
 HAL_Delay(10);

 LCD_WriteCommand(0xCF); // Power control
 LCD_WriteData(0x00);
 LCD_WriteData(0xC1);
 LCD_WriteData(0x30);
}

// Inicjalizacja SPI1 (dla dotyku)
void SPI_Init(void) {
 hspi1.Instance = SPI1;
 hspi1.Init.Mode = SPI_MODE_MASTER;
 hspi1.Init.Direction = SPI_DIRECTION_2LINES;
 hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
 hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
 hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
 hspi1.Init.NSS = SPI_NSS_SOFT;
 hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16;
 hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
 hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
 hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
 hspi1.Init.CRCPolynomial = 10;

 HAL_SPI_Init(&hspi1);
}

// Odczyt danych z kontrolera dotyku
uint16_t Touch_ReadData(uint8_t cmd) {
 uint16_t result = 0;
 uint8_t recv[2] = {0};

 HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET); // TP_CS = 0

 HAL_SPI_Transmit(&hspi1, &cmd, 1, 1000);
 HAL_SPI_Receive(&hspi1, recv, 2, 1000);

 HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET); // TP_CS = 1

 result = ((recv[0] << | recv[1]) >> 4;
 return result;
}

// Wypełnianie całego ekranu kolorem
void LCD_FillScreen(uint16_t color) {
 uint32_t i;

 LCD_WriteCommand(0x2A); // Column address set
 LCD_WriteData(0x00);
 LCD_WriteData(0x00);
 LCD_WriteData(0x00);
 LCD_WriteData(0xEF); // 240 columns

 LCD_WriteCommand(0x2B); // Page address set
 LCD_WriteData(0x00);
 LCD_WriteData(0x00);
 LCD_WriteData(0x01);
 LCD_WriteData(0x3F); // 320 rows

 LCD_WriteCommand(0x2C); // Memory write

 for (i = 0; i < 320 * 240; i++) {
 LCD_WriteData(color >> 8); // High byte
 LCD_WriteData(color & 0xFF); // Low byte
 }
}

3. And my pin connection:

display  -- stm
5v-in -- 5v
gnd -- gnd
d0 -- pb0
d1 -- pb1
d2 -- pb2
d3 -- pb3
d4 -- pb4
d5 -- pb5
d6 -- pb6
d7 -- pb7
d8 -- pb8
d9 -- pb9
d10 -- pb10
d11 -- pa11
d12 -- pb12
d13 -- pb13
d14 -- pb14
d15 -- pb15
lcd-cs -- pc0
rs -- pc1
wr -- pc2
rd -- vdd
rst -- pc3
bl-vcc -- 3v
gnd -- gnd
bl-ctrl -- pa5
tp-irq -- pa9
tp-cs -- pa8
tp-sck -- pc10
tp-sdi -- pc12
tp-sdo -- pc11

Thank you in advance!

Best answer by kiwiosek2007

I have made it. Yes that was code issue.
I have wrote code I think that the previous one what I wrote was for ILI9341 what has diffrent commands, but after a long time of debuging and looking for mistakes I have done it and the display is correctly initializating and showing colors.
Here is my code maybe someone will need it, 

#include "stm32f4xx_hal.h"
#include "stm32f4xx_hal_spi.h"
#include "lcd.h"

extern SPI_HandleTypeDef hspi3;

// Ustawienie danych na pinach D0–D15
void LCD_SetDataPins(uint16_t data) {
 uint16_t mask = 0b1111011111111111; // PB0–PB10, PB12–PB15
 GPIOB->ODR = (GPIOB->ODR & ~mask) | (data & mask);

 // PA11 = D11
 HAL_GPIO_WritePin(GPIOA, GPIO_PIN_11, (data & (1 << 11)) ? GPIO_PIN_SET : GPIO_PIN_RESET);
}

// Wysyłanie komend i danych
void LCD_WriteCommand(uint16_t cmd) {
 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_1, GPIO_PIN_RESET); // RS=0
 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_0, GPIO_PIN_RESET); // CS=0
 LCD_SetDataPins(cmd);
 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_2, GPIO_PIN_RESET); // WR=0
 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_2, GPIO_PIN_SET); // WR=1
 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_0, GPIO_PIN_SET); // CS=1
}

void LCD_WriteData(uint16_t data) {
 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_1, GPIO_PIN_SET); // RS=1
 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_0, GPIO_PIN_RESET); // CS=0
 LCD_SetDataPins(data);
 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_2, GPIO_PIN_RESET); // WR=0
 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_2, GPIO_PIN_SET); // WR=1
 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_0, GPIO_PIN_SET); // CS=1
}

// Ustawienie kursora (GRAM address)
void LCD_SetCursor(uint16_t x, uint16_t y) {
 LCD_WriteCommand(0x20);
 LCD_WriteData(x); // kolumna

 LCD_WriteCommand(0x21);
 LCD_WriteData(y); // wiersz

 LCD_WriteCommand(0x22); // RAM write
}

// Wpis danych do pamięci GRAM (jeden piksel)
void LCD_WriteRAM(uint16_t color) {
 LCD_WriteData(color);
}

// Reset i inicjalizacja
void LCD_Init(void) {
 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_3, GPIO_PIN_RESET); // RST = 0
 HAL_Delay(150);
 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_3, GPIO_PIN_SET); // RST = 1
 HAL_Delay(150);

 // Inicjalizacja ILI9325 — wybrane rejestry (skrót wersji)
 LCD_WriteCommand(0x00E5); LCD_WriteData(0x78F0);
 LCD_WriteCommand(0x0001); LCD_WriteData(0x0100);
 LCD_WriteCommand(0x0002); LCD_WriteData(0x0700);
 LCD_WriteCommand(0x0003); LCD_WriteData(0x1030); // BGR=1, Scan direction
 LCD_WriteCommand(0x0004); LCD_WriteData(0x0000);
 LCD_WriteCommand(0x0008); LCD_WriteData(0x0202);
 LCD_WriteCommand(0x0009); LCD_WriteData(0x0000);
 LCD_WriteCommand(0x000A); LCD_WriteData(0x0000);
 LCD_WriteCommand(0x000C); LCD_WriteData(0x0000);
 LCD_WriteCommand(0x000D); LCD_WriteData(0x0000);
 LCD_WriteCommand(0x000F); LCD_WriteData(0x0000);

 // Power On
 LCD_WriteCommand(0x0010); LCD_WriteData(0x0000);
 LCD_WriteCommand(0x0011); LCD_WriteData(0x0007);
 LCD_WriteCommand(0x0012); LCD_WriteData(0x0000);
 LCD_WriteCommand(0x0013); LCD_WriteData(0x0000);
 HAL_Delay(200);
 LCD_WriteCommand(0x0010); LCD_WriteData(0x17B0);
 LCD_WriteCommand(0x0011); LCD_WriteData(0x0037);
 HAL_Delay(50);
 LCD_WriteCommand(0x0012); LCD_WriteData(0x0138);
 HAL_Delay(50);
 LCD_WriteCommand(0x0013); LCD_WriteData(0x1700);
 LCD_WriteCommand(0x0029); LCD_WriteData(0x000D);
 HAL_Delay(50);

 // Gamma
 LCD_WriteCommand(0x0030); LCD_WriteData(0x0001);
 LCD_WriteCommand(0x0031); LCD_WriteData(0x0606);
 LCD_WriteCommand(0x0032); LCD_WriteData(0x0003);
 LCD_WriteCommand(0x0035); LCD_WriteData(0x0206);
 LCD_WriteCommand(0x0036); LCD_WriteData(0x0008);
 LCD_WriteCommand(0x0037); LCD_WriteData(0x0504);
 LCD_WriteCommand(0x0038); LCD_WriteData(0x0007);
 LCD_WriteCommand(0x0039); LCD_WriteData(0x0000);
 LCD_WriteCommand(0x003C); LCD_WriteData(0x0007);
 LCD_WriteCommand(0x003D); LCD_WriteData(0x0000);

 // Window
 LCD_WriteCommand(0x0050); LCD_WriteData(0x0000);
 LCD_WriteCommand(0x0051); LCD_WriteData(0x00EF);
 LCD_WriteCommand(0x0052); LCD_WriteData(0x0000);
 LCD_WriteCommand(0x0053); LCD_WriteData(0x013F);

 LCD_WriteCommand(0x0060); LCD_WriteData(0xA700);
 LCD_WriteCommand(0x0061); LCD_WriteData(0x0001);
 LCD_WriteCommand(0x006A); LCD_WriteData(0x0000);

 // Display ON
 LCD_WriteCommand(0x0007); LCD_WriteData(0x0133);
 HAL_Delay(50);
}

// Wypełnienie całego ekranu kolorem
void LCD_FillScreen(uint16_t color) {
 LCD_SetCursor(0, 0);
 uint32_t i;
 for (i = 0; i < 320 * 240; i++) {
 LCD_WriteRAM(color);
 }
}

Thanks to @Ozone @Andrew Neil for advices and trying to help.

2 replies

Andrew Neil
Super User
April 9, 2025

@kiwiosek2007 wrote:

Yes this is related to my previous post.


You mean this:

https://community.st.com/t5/others-stm32-mcus-related/problem-with-ili9325c-display-and-stm32f401ret6/td-p/788495

 


@kiwiosek2007 wrote:

I think my code is correct I compare it to the documentation of my display.


What about when you look at the actual interface lines; eg, with a logic analyser?

A complex system that works is invariably found to have evolved from a simple system that worked.A complex system designed from scratch never works and cannot be patched up to make it work.
Associate II
April 9, 2025

Yes and I have changed the spi to the 16bit-parrarel. 
I don't have right now the analyzer. When I'll get back I'll test it, but also my anaylzer don't have so much channels to get all pins to checked.
When i was in debug my display doesn't response the connection in neither way. I thought that is problem with my code. 

Andrew Neil
Super User
April 9, 2025

@kiwiosek2007 wrote:

my anaylzer don't have so much channels to get all pins to checked. 


At least start by looking at a selection of lines - the control lines and as many data lines as you can.

 


@kiwiosek2007 wrote:

I thought that is problem with my code. 


A logic analyser will be the easiest way to see what your code is actually doing.

Knowing what it's actually doing, you can then compare that to what it should be doing.

That should lead you to the part(s) of your code that are not working correctly.

It may, of course, show that you (also) have hardware problem(s)...

A complex system that works is invariably found to have evolved from a simple system that worked.A complex system designed from scratch never works and cannot be patched up to make it work.
kiwiosek2007AuthorBest answer
Associate II
April 10, 2025

I have made it. Yes that was code issue.
I have wrote code I think that the previous one what I wrote was for ILI9341 what has diffrent commands, but after a long time of debuging and looking for mistakes I have done it and the display is correctly initializating and showing colors.
Here is my code maybe someone will need it, 

#include "stm32f4xx_hal.h"
#include "stm32f4xx_hal_spi.h"
#include "lcd.h"

extern SPI_HandleTypeDef hspi3;

// Ustawienie danych na pinach D0–D15
void LCD_SetDataPins(uint16_t data) {
 uint16_t mask = 0b1111011111111111; // PB0–PB10, PB12–PB15
 GPIOB->ODR = (GPIOB->ODR & ~mask) | (data & mask);

 // PA11 = D11
 HAL_GPIO_WritePin(GPIOA, GPIO_PIN_11, (data & (1 << 11)) ? GPIO_PIN_SET : GPIO_PIN_RESET);
}

// Wysyłanie komend i danych
void LCD_WriteCommand(uint16_t cmd) {
 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_1, GPIO_PIN_RESET); // RS=0
 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_0, GPIO_PIN_RESET); // CS=0
 LCD_SetDataPins(cmd);
 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_2, GPIO_PIN_RESET); // WR=0
 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_2, GPIO_PIN_SET); // WR=1
 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_0, GPIO_PIN_SET); // CS=1
}

void LCD_WriteData(uint16_t data) {
 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_1, GPIO_PIN_SET); // RS=1
 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_0, GPIO_PIN_RESET); // CS=0
 LCD_SetDataPins(data);
 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_2, GPIO_PIN_RESET); // WR=0
 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_2, GPIO_PIN_SET); // WR=1
 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_0, GPIO_PIN_SET); // CS=1
}

// Ustawienie kursora (GRAM address)
void LCD_SetCursor(uint16_t x, uint16_t y) {
 LCD_WriteCommand(0x20);
 LCD_WriteData(x); // kolumna

 LCD_WriteCommand(0x21);
 LCD_WriteData(y); // wiersz

 LCD_WriteCommand(0x22); // RAM write
}

// Wpis danych do pamięci GRAM (jeden piksel)
void LCD_WriteRAM(uint16_t color) {
 LCD_WriteData(color);
}

// Reset i inicjalizacja
void LCD_Init(void) {
 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_3, GPIO_PIN_RESET); // RST = 0
 HAL_Delay(150);
 HAL_GPIO_WritePin(GPIOC, GPIO_PIN_3, GPIO_PIN_SET); // RST = 1
 HAL_Delay(150);

 // Inicjalizacja ILI9325 — wybrane rejestry (skrót wersji)
 LCD_WriteCommand(0x00E5); LCD_WriteData(0x78F0);
 LCD_WriteCommand(0x0001); LCD_WriteData(0x0100);
 LCD_WriteCommand(0x0002); LCD_WriteData(0x0700);
 LCD_WriteCommand(0x0003); LCD_WriteData(0x1030); // BGR=1, Scan direction
 LCD_WriteCommand(0x0004); LCD_WriteData(0x0000);
 LCD_WriteCommand(0x0008); LCD_WriteData(0x0202);
 LCD_WriteCommand(0x0009); LCD_WriteData(0x0000);
 LCD_WriteCommand(0x000A); LCD_WriteData(0x0000);
 LCD_WriteCommand(0x000C); LCD_WriteData(0x0000);
 LCD_WriteCommand(0x000D); LCD_WriteData(0x0000);
 LCD_WriteCommand(0x000F); LCD_WriteData(0x0000);

 // Power On
 LCD_WriteCommand(0x0010); LCD_WriteData(0x0000);
 LCD_WriteCommand(0x0011); LCD_WriteData(0x0007);
 LCD_WriteCommand(0x0012); LCD_WriteData(0x0000);
 LCD_WriteCommand(0x0013); LCD_WriteData(0x0000);
 HAL_Delay(200);
 LCD_WriteCommand(0x0010); LCD_WriteData(0x17B0);
 LCD_WriteCommand(0x0011); LCD_WriteData(0x0037);
 HAL_Delay(50);
 LCD_WriteCommand(0x0012); LCD_WriteData(0x0138);
 HAL_Delay(50);
 LCD_WriteCommand(0x0013); LCD_WriteData(0x1700);
 LCD_WriteCommand(0x0029); LCD_WriteData(0x000D);
 HAL_Delay(50);

 // Gamma
 LCD_WriteCommand(0x0030); LCD_WriteData(0x0001);
 LCD_WriteCommand(0x0031); LCD_WriteData(0x0606);
 LCD_WriteCommand(0x0032); LCD_WriteData(0x0003);
 LCD_WriteCommand(0x0035); LCD_WriteData(0x0206);
 LCD_WriteCommand(0x0036); LCD_WriteData(0x0008);
 LCD_WriteCommand(0x0037); LCD_WriteData(0x0504);
 LCD_WriteCommand(0x0038); LCD_WriteData(0x0007);
 LCD_WriteCommand(0x0039); LCD_WriteData(0x0000);
 LCD_WriteCommand(0x003C); LCD_WriteData(0x0007);
 LCD_WriteCommand(0x003D); LCD_WriteData(0x0000);

 // Window
 LCD_WriteCommand(0x0050); LCD_WriteData(0x0000);
 LCD_WriteCommand(0x0051); LCD_WriteData(0x00EF);
 LCD_WriteCommand(0x0052); LCD_WriteData(0x0000);
 LCD_WriteCommand(0x0053); LCD_WriteData(0x013F);

 LCD_WriteCommand(0x0060); LCD_WriteData(0xA700);
 LCD_WriteCommand(0x0061); LCD_WriteData(0x0001);
 LCD_WriteCommand(0x006A); LCD_WriteData(0x0000);

 // Display ON
 LCD_WriteCommand(0x0007); LCD_WriteData(0x0133);
 HAL_Delay(50);
}

// Wypełnienie całego ekranu kolorem
void LCD_FillScreen(uint16_t color) {
 LCD_SetCursor(0, 0);
 uint32_t i;
 for (i = 0; i < 320 * 240; i++) {
 LCD_WriteRAM(color);
 }
}

Thanks to @Ozone @Andrew Neil for advices and trying to help.

Ozone
Principal
April 10, 2025

I had done the same thing about 10 years ago, although for another MCU.
And also without scope or logic analyser.

A bit of persistence and a proper incremental approach are helpful...