Stm32f429 + ili9341 spi

Finally I make port :grinning: :sweat_smile:

Didn’t make any optimization except at compilation option
Look very smooth. Isn it?


Schematic have some mistake with audio chip but display working well basically

Buffer is half of frame in RAM. So, what yours opinion?
Planning run Doom :upside_down_face:

2 Likes

Looks good! Something looks wrong with the colors (RGB swapped?), but it is running very smoothly.

Hmm, I change swap RGB option its become blue colorized. I think its like color Themes but not. CPU is loaded on 100% most of time. Its normal behavior for that test?
I will check one more time Clock configuration prescaller settings

Looks very smooth scrolling.

How fast is your SPI clock ? Does it use DMA ?

I found the SPI HAL driver very slow on the STMcube. I assume you don’t use the HAL driver ?

No DMA use


I send buffer to SPI bus in lvgl callback the HAL_SPI_Transmit(&hspi, (unsigned char*)buffer, size*2, 10);
Before set coordinates ILI9341_Set_Address(x1,y1,x2,y2);
I can share my solution on github if you interesting. Little messy but working code

So, I created the repository


Also, try using SPI over DMA. didn’t notice any significant improvement. Speed of SPI 45 Mbit. As I know it is a huge overclock for ili9341 but the display working stable!


Thank you for the advice.

I was using writeRect() and that was calling the SPI HAL two byte at a time, that is why it was so slow.

Now I’ve changed it to:
HAL_SPI_Transmit(&hspi1, (unsigned char*)color_p, widthheight2, 10);

It is now much faster. :slight_smile:

My board is the STM32G474 and the SPI clock is 40MHz. The scrolling is pretty smooth.

1 Like

I connected SDRAM and using a buff
#define SDRAM_BANK_ADDR ((uint32_t)0xC0000000)

lv_disp_buf_init(&disp_buf, (uint16_t*)SDRAM_BANK_ADDR, NULL, LV_HOR_RES_MAX * LV_VER_RES_MAX); - There is artifact. Half of screen not rendered!

I see half of the screen updated. But if I reduce the buffer to half all again working perfectly. What it can be?
lv_disp_buf_init(&disp_buf, (uint16_t*)SDRAM_BANK_ADDR, NULL, LV_HOR_RES_MAX * LV_VER_RES_MAX/2); - No artifact!

Black label with test info rendered good despite its position in the bottom right corner

I tried to make an offset SDRAM_BANK_ADDR + NNN to be sure memory is not affected. The same result

With the full-frame buffer, performance jump to 40 FPS+ but the artifact comes

Also, keys optimization of compilation somehow affected on rendering
I hope I did all right

/Initialize the display/
lv_disp_drv_t disp_drv;
lv_disp_drv_init(&disp_drv);
disp_drv.hor_res = LV_HOR_RES_MAX;
disp_drv.ver_res = LV_VER_RES_MAX;
disp_drv.flush_cb = my_disp_flush;
disp_drv.buffer = &disp_buf;
lv_disp_drv_register(&disp_drv);

I change frequency of SPI, system bus and MCU. Play with lvgl config. All the same

Your buffer setting (NULL, LV_HOR_RES_MAX * LV_VER_RES_MAX) is too high (as you already noticed by yourself :wink:).

Normally the buffer is set around to be LV_HOR_RES_MAX * 20 (or 40, or more or less).
You are using DMA. DMA in STM32F4/7 or STM32FH7 can only handle up buffer length up to 16 bit (means 65535 bytes).

You set your buffer to LV_HOR_RES_MAX * LV_VER_RES_MAX. For a 320 x 240 that is 76 800.
As you have a 16-bit color values, it means 76800 * 2 = 153600 bytes. That’s more than double of that what the DMA can handle at once.
As only less than a half of the necessary data is transferred to the display, frame rate gets more than doubled.

This is true if lvgl is updating the entire (or nearly the entire) display at once.
When only smaller parts of the display will be redrawn everthing is ok. As the used buffer is smaller (less than the 16-bit limit of DMA).

You can of course change your flush function to split the display transfer into smaller parts,
but that will not change the overall time you need for transfer all the display data over SPI.
The bottleneck is SPI.

But with the method to have the buffer within the SDRAM (external memory), I think you will slow down lvgl.

Using the external SDRAM would make sense only when using it as a real frame buffer for display, in the case the STM32F4/7 would use it directly for (parallel) display driving.

Thanks for clarifying about DMA. But I try to do it without DMA
HAL_SPI_Transmit(&hspi1, (unsigned char*)color_p, wh2, 30);
The same effect coming.

There is a port where is using SDRAM for full-frame but with a different approach. Its


static lv_color_t buf[TFT_HOR_RES * 48];
static lv_color_t buf2[TFT_HOR_RES * 48];
static lv_disp_buf_t disp_buf;
lv_disp_buf_init(&disp_buf, buf, buf2, TFT_HOR_RES * 48);
As I see code is proving your words :thinking:
But buffers located not in SDRAM

I will try to play with 65535 bytes value

When you use HAL_SPI_Transmit the size is also limited to 16-bit.

HAL_StatusTypeDef HAL_SPI_Transmit (SPI_HandleTypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout);

I don’t know what kind of IDE and compiler you use, but it would make me wonder if there wouldn’t be a warning about it.