Skip to main content
Associate III
September 11, 2025
Solved

LTDC Rotation 180 degres

  • September 11, 2025
  • 12 replies
  • 1212 views

Hello i'm using touch GFX with STM32H7RS-DK And i need to evaluate for a future product if display rotation is possible.

I tried this implementation but drawCacheEnabled isn't reconize by software so i removed it and the widget is working but the screen flicker betwen 0 and 180° . Is there a more actual way of rotate a screen . 

 // Force redrawing entire screen
 virtual void draw(Rect& rect)
 {
 if (drawCacheEnabled)
 {
 // Invalidate entire screen instead of requested rect.
 Rect r(0, 0, HAL::DISPLAY_WIDTH, HAL::DISPLAY_HEIGHT);
 Application::draw(r);
 }
 else
 {
 // Use original rect if we are *actually* drawing and not just invalidating.
 Application::draw(rect);
 }
 }

 Thanks

Best answer by LouisB

Hello @Hamady,

You are welcome, the project doesn't contain such a button, but it's implementation will mainly consist of a bypassing all the additional code (as rotations can be done in realtime). If the project answers your question, please mark it as best answer so other users can access it easily.

BR,

12 replies

ST Employee
September 11, 2025

Hello @Hamady,


We do not support 180 rotation, usually for a product, the whole screen itself is rotated. Also some screen support rotation by setting some bits.
It's possible to achieve rotation, by rotating a copy of the framebuffer that you then send to the screen. You can use the GPU to do that with better performances.

May I ask, how did you come up with this code, I dont see how you can have a rotation with just that ?

BR,

HamadyAuthor
Associate III
September 12, 2025

Hello,

Thanks for the quick response 

I got the code from here : https://community.st.com/t5/stm32-mcus-touchgfx-and-gui/repost-change-lcd-orientation-in-180-degree/m-p/376534

Do you have a sampling code or a tuto to achieve this via GPU.

Thanks !

ST Employee
September 12, 2025

Hello @Hamady,

This code is from an old version, that is why the "drawCacheEnabled" wasn't working.
I can guide you on how this can be achieved but,I need to know what are the specs for your custom board project (screen resolution, amount of ram, ...) ?

BR,

HamadyAuthor
Associate III
September 12, 2025

Thanks @LouisB 

Screen :https://newhavendisplay.com/3-5-inch-ips-tft-without-touchscreen/

Interface RGB 24bit (No acces to rotation pin and command like GRAM screen i suppose )

Resolution 320x240
Ram 256MB (same as DK board).
Thanks for the help.

ST Employee
September 12, 2025

And the chip will be the same as DK board ?

HamadyAuthor
Associate III
September 12, 2025

exactly the same ! 

HamadyAuthor
Associate III
September 15, 2025

Hello,

@LouisB any news about the solution for the GPU2D

Thanks !

ST Employee
September 17, 2025

Hello @Hamady,

We are working on a solution internally that uses GPU2D, I will get back to you when I have something.

BR,

ST Employee
September 22, 2025

Hello @Hamady,

Here's an example of 180 degrees rotation with GPU2D to summarize we use the NemaGFX to produce a rotated image that is updated, only in the requested areas (it doesn't invalidate the whole screen every frames). I provide a PowerPoint with some additional explanations.

Feel free to ask questions,

BR,

Visitor II
October 8, 2025

Dear @LouisB , 

Thanks you for your work, this is exactly what I was also looking for.

I have tried to integrate your work and adapt it to our project wich is based on the 24bpp example, with ARGB888 format, but I still have some difficulties to make it work as it should.

Would you mind having a look if I send you the complete project?

Thanks for your help

HamadyAuthor
Associate III
September 22, 2025

Hi, 

A big thanks for you hard work ,

Is there a toogle in the code to rotate the screen with user interaction (to show the rotation )

Thanks !!!

LouisBBest answer
ST Employee
September 23, 2025

Hello @Hamady,

You are welcome, the project doesn't contain such a button, but it's implementation will mainly consist of a bypassing all the additional code (as rotations can be done in realtime). If the project answers your question, please mark it as best answer so other users can access it easily.

BR,

ST Employee
October 10, 2025

Hello @bluespark,

Since my project was made with a H7RS, and it doesnt support 24Bits Nema natively, check this thread GPU2D trouble on STM32H7S78-DK - STMicroelectronics Community and the doc TouchGFX on NeoChrom/NeoChromVG | TouchGFX Documentation before hand.

From a 16 bits to 24bits, you have to do few modifications as below from the project I gave:

in TouchGFXHAL.cpp:

// this 
LOCATION_PRAGMA_NOLOAD("TouchGFX_Framebuffer")
uint32_t animationBuffer[(800 * 480 * 2 + 3) / 4] LOCATION_ATTRIBUTE_NOLOAD("TouchGFX_Framebuffer");
LOCATION_PRAGMA_NOLOAD("TouchGFX_Framebuffer")
uint32_t ltdcFrameBuf1[(800 * 480 * 2 + 3) / 4] LOCATION_ATTRIBUTE_NOLOAD("TouchGFX_Framebuffer");
LOCATION_PRAGMA_NOLOAD("TouchGFX_Framebuffer")
uint32_t ltdcFrameBuf2[(800 * 480 * 2 + 3) / 4] LOCATION_ATTRIBUTE_NOLOAD("TouchGFX_Framebuffer");
// becomes
LOCATION_PRAGMA_NOLOAD("TouchGFX_Framebuffer")
uint32_t animationBuffer[(800 * 480 * 3 + 3) / 4] LOCATION_ATTRIBUTE_NOLOAD("TouchGFX_Framebuffer");
LOCATION_PRAGMA_NOLOAD("TouchGFX_Framebuffer")
uint32_t ltdcFrameBuf1[(800 * 480 * 3 + 3) / 4] LOCATION_ATTRIBUTE_NOLOAD("TouchGFX_Framebuffer");
LOCATION_PRAGMA_NOLOAD("TouchGFX_Framebuffer")
uint32_t ltdcFrameBuf2[(800 * 480 * 3 + 3) / 4] LOCATION_ATTRIBUTE_NOLOAD("TouchGFX_Framebuffer");

Change all the NEMA_RGB565 to NEMA_RGB24 in the TouchGFXHAL.cpp.


Here in the example the screen is 800*480 so readapt the size to yours.

In CubeMX you have to put single frame buffer strategy.

I'm using a custom TouchGFXgeneratedhal also, you need to do the same in your project, in my project the custom code add is the below :

uint16_t* otherLTDCFB;
uint16_t* framebufferLTDC1;
uint16_t* framebufferLTDC2;
uint16_t* currentLTDCFB;
void initializeLTDCFB(uint32_t* framebuff,uint32_t* framebuff2) {
 framebufferLTDC1 = (uint16_t*)framebuff;
 framebufferLTDC2 = (uint16_t*)(framebuff2);
 currentLTDCFB = framebufferLTDC1;
 otherLTDCFB = framebufferLTDC2;
}


void swapLTDCFrameBuffer() {
 otherLTDCFB = currentLTDCFB;
 if (currentLTDCFB == framebufferLTDC1)
 {
 currentLTDCFB = framebufferLTDC2;
 }
 else{
 currentLTDCFB = framebufferLTDC1;

 }
}
[...]
 // 180 Rotation
 // We swap the ltdc framebuffers so the one we drew is shown
 if (swapLTDC)
 {
 swapLTDCFrameBuffer();
 LTDC_Layer1->CFBAR = (uint32_t)currentLTDCFB;
 
 /* Reload immediate */
 LTDC->SRCR = (uint32_t)LTDC_SRCR_IMR;
 swapLTDC = false;
 }
 // 180 Rotation


Since this file is regenerated each time we do a code generation, you can do the same as the example I gave where, In designer Config->Build->Post generate target command, I do a copy of my custom file to the generated one.

BR,