2025-08-14 3:27 AM
Hello,
I’m running a TouchGFX application on LTDC Layer 2 with pixel format ARGB8888.
Underneath it, on LTDC Layer 1, I have a simple colored rectangle as a background.
I have configured the LTDC blending factors for per-pixel alpha, and the blending works — for example, when I set Layer 2’s constant alpha to zero, I can see Layer 1 correctly.
However, even when using images with transparent areas in TouchGFX, the “transparent” parts appear as solid black on the screen and completely block Layer 1. It seems that TouchGFX is filling those pixels with an opaque color (alpha 255) instead of leaving them transparent (alpha 0).
What I expect is that transparent parts of the UI would allow Layer 1 to show through, but instead they are rendered as black.
Is this the expected behavior for TouchGFX? If so, is there a supported way to make untouched areas of the framebuffer remain transparent so that hardware blending between Layer 2 and Layer 1 works as intended?
Thanks in advance.
2025-08-15 1:25 AM
Hello,
TouchGFX is primarily designed to be used as a "stand-alone" LTDC layer. What is your use case for multible LTDC layers?
When generating code in TouchGFX Designer, it will insert a black background box to ensure that all pixels are written. You can see this in the generate code for your view like this:
You can try hiding this black background by adding this code the following code to the setupScreen method in our user code file:
2025-08-15 1:36 AM - edited 2025-08-15 1:37 AM
Thanks for your reply. Actually, I’m not using TouchGFX as a two-layer setup. Instead of rendering on LTDC layer 0, I made it render on LTDC layer 1. I want to put a camera feed on LTDC layer 0, and I plan to do this manually.
Now, I tried using __background.setVisible(false);, but instead of making the background transparent, it showed the leftover image from the previous screen.
I want to have some small UI elements on top of the camera feed.
2025-08-15 2:00 AM
Ok. The behavior is a bit different depending our your rendering method (software, DMA2D or GPU2D). What MCU are you working on?
You can try keeping the background box visible but setting it to transparent, with this code line instead of the previous suggestion:
2025-08-15 2:38 AM
I’m using a DMA2D on an F7 series MCU, and the __background.setColor(0); method still seems to produce a black color.
2025-08-15 6:03 AM
Ok. It will take some mere investigation then.
Another option you could consider is integrate the camera feed in TouchGFX and thereby only have a single solid LTDC layer. You can do this by creating a Dynamic bitmap in TouchGFX and writing your camera frames here. This can then be set as a background image in your TouchGFX application. More information about this here: https://support.touchgfx.com/docs/development/ui-development/touchgfx-engine-features/dynamic-bitmaps
2025-08-19 10:48 PM
Actually, I started in a similar way to using a dynamic bitmap, but instead I used a PixelDataWidget. I was successful with that. However, when I try to increase the camera clock frequency to get a higher frame rate from the camera, the system crashes. At the moment, I can run it at around 9 fps. But if I feed the camera image into the LTDC framebuffer with my own methods, I can achieve much higher fps. At this point, my question is: PixelDataWidget may not be using elements like DMA2D, so could that be why it is slower? Maybe DynamicBitmap would give better results. What approach should be taken here? The camera provides data in 565 format. If TouchGFX is working in 888 format, should I use DMA2D to perform the conversion myself? To avoid screen tearing, I want to use a double-buffering method where I capture the entire frame at once.
2025-08-21 10:58 PM
I would really appreciate your help.
2025-08-22 2:29 AM
I am not familiar with the PixelDataWidget, but if you integrate it in TouchGFX as an Image pointing to dynamic bitmaps, DMA2D will do the needed color conversion. But to ensure completely glitch-free video playback, you will need to triple buffer the video, by rendering it to three different dynamic bitmaps. I have attached an example project, where we decode an L8 format video in a separate thread and shows it as an image in TouchGFX.
Alternatively, I can also investigate how render transparent pixels on F7, if you can share your CubeMX LTDC Layer configuration with me.
2025-08-22 2:57 AM - edited 2025-08-22 4:50 AM
I’m sharing my LTDC layer settings. Unfortunately, I won’t be able to work on this project for a while. However, I’d like to ask this question: Are we using the triple buffer method in the following way: one buffer for the raw DCMI output, and the other two buffers acting as a double buffer where the data from the raw buffer is converted into the ideal format? And the DynamicBitmap switches between these two buffers in a cyclic manner.
Lastly, I want to ask one more thing: We are currently not using an RTOS in the system. Was not using an RTOS a wrong choice from the beginning for a system like this?
hltdc.Instance = LTDC;
hltdc.Init.HSPolarity = LTDC_HSPOLARITY_AL;
hltdc.Init.VSPolarity = LTDC_VSPOLARITY_AL;
hltdc.Init.DEPolarity = LTDC_DEPOLARITY_AL;
hltdc.Init.PCPolarity = LTDC_PCPOLARITY_IPC;
hltdc.Init.HorizontalSync = 0;
hltdc.Init.VerticalSync = 0;
hltdc.Init.AccumulatedHBP = 43;
hltdc.Init.AccumulatedVBP = 12;
hltdc.Init.AccumulatedActiveW = 523;
hltdc.Init.AccumulatedActiveH = 284;
hltdc.Init.TotalWidth = 525;
hltdc.Init.TotalHeigh = 285;
hltdc.Init.Backcolor.Blue = 255;
hltdc.Init.Backcolor.Green = 0;
hltdc.Init.Backcolor.Red = 255;
if (HAL_LTDC_Init(&hltdc) != HAL_OK)
{
Error_Handler();
}
pLayerCfg.WindowX0 = 0;
pLayerCfg.WindowX1 = 480;
pLayerCfg.WindowY0 = 0;
pLayerCfg.WindowY1 = 272;
pLayerCfg.PixelFormat = LTDC_PIXEL_FORMAT_ARGB8888;
pLayerCfg.Alpha = 255;
pLayerCfg.Alpha0 = 255;
pLayerCfg.BlendingFactor1 = LTDC_BLENDING_FACTOR1_CA;
pLayerCfg.BlendingFactor2 = LTDC_BLENDING_FACTOR2_CA;
pLayerCfg.FBStartAdress = 0xD014A000;
pLayerCfg.ImageWidth = 480;
pLayerCfg.ImageHeight = 272;
pLayerCfg.Backcolor.Blue = 0;
pLayerCfg.Backcolor.Green = 0;
pLayerCfg.Backcolor.Red = 255;
if (HAL_LTDC_ConfigLayer(&hltdc, &pLayerCfg, 0) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN LTDC_Init 2 */
pLayerCfg.WindowX0 = 80;
pLayerCfg.WindowX1 = 400;
pLayerCfg.WindowY0 = 16;
pLayerCfg.WindowY1 = 256;
pLayerCfg.ImageWidth = 320;
pLayerCfg.ImageHeight = 240;
pLayerCfg.FBStartAdress = 0xD014A000;
if (HAL_LTDC_ConfigLayer(&hltdc, &pLayerCfg, 0) != HAL_OK)
{
Error_Handler();
}
pLayerCfg1.WindowX0 = 0;
pLayerCfg1.WindowX1 = 480;
pLayerCfg1.WindowY0 = 0;
pLayerCfg1.WindowY1 = 272;
pLayerCfg1.PixelFormat = LTDC_PIXEL_FORMAT_ARGB8888;
pLayerCfg1.Alpha = 255;
pLayerCfg1.Alpha0 = 0;
pLayerCfg1.BlendingFactor1 = LTDC_BLENDING_FACTOR1_PAxCA;
pLayerCfg1.BlendingFactor2 = LTDC_BLENDING_FACTOR2_PAxCA;
pLayerCfg1.FBStartAdress = 0xD0000000;
pLayerCfg1.ImageWidth = 480;
pLayerCfg1.ImageHeight = 272;
pLayerCfg1.Backcolor.Blue = 50;
pLayerCfg1.Backcolor.Green = 255;
pLayerCfg1.Backcolor.Red = 255;
if (HAL_LTDC_ConfigLayer(&hltdc, &pLayerCfg1, 1) != HAL_OK)
{
Error_Handler();
}