2025-08-06 2:15 AM - edited 2025-08-07 2:42 AM
hello , T。T
I’m developing a GUI using TouchGFX on the STM32F469I-DISCO board.
In the handleTickEvent() function, I add 5 points to a dynamic data graph each time it is called. However, when doing this, the frequency of handleTickEvent() drops significantly, and the display performance becomes very poor.
In comparison, an older project based on the demo uses MIPI DSI in command mode and configures LTDC as 480×200×4, and it performs noticeably better than my current setup where LTDC is configured as 480×800 and DSI is set to video mode.
The scan is 480 * 800 .
static void MX_LTDC_Init(void)
{
/* USER CODE BEGIN LTDC_Init 0 */
/* USER CODE END LTDC_Init 0 */
LTDC_LayerCfgTypeDef pLayerCfg = {0};
/* USER CODE BEGIN LTDC_Init 1 */
/* USER CODE END LTDC_Init 1 */
hltdc.Instance = LTDC;
hltdc.Init.HSPolarity = LTDC_HSPOLARITY_AH;
hltdc.Init.VSPolarity = LTDC_VSPOLARITY_AH;
hltdc.Init.DEPolarity = LTDC_DEPOLARITY_AL;
hltdc.Init.PCPolarity = LTDC_PCPOLARITY_IPC;
hltdc.Init.HorizontalSync = 1;
hltdc.Init.VerticalSync = 1;
hltdc.Init.AccumulatedHBP = 2;
hltdc.Init.AccumulatedVBP = 2;
hltdc.Init.AccumulatedActiveW = 202;
hltdc.Init.AccumulatedActiveH = 482;
hltdc.Init.TotalWidth = 203;
hltdc.Init.TotalHeigh = 483;
hltdc.Init.Backcolor.Blue = 0;
hltdc.Init.Backcolor.Green = 0;
hltdc.Init.Backcolor.Red = 0;
if (HAL_LTDC_Init(&hltdc) != HAL_OK)
{
Error_Handler();
}
pLayerCfg.WindowX0 = 0;
pLayerCfg.WindowX1 = 200;
pLayerCfg.WindowY0 = 0;
pLayerCfg.WindowY1 = 480;
pLayerCfg.PixelFormat = LTDC_PIXEL_FORMAT_RGB565;
pLayerCfg.Alpha = 255;
pLayerCfg.Alpha0 = 0;
pLayerCfg.BlendingFactor1 = LTDC_BLENDING_FACTOR1_CA;
pLayerCfg.BlendingFactor2 = LTDC_BLENDING_FACTOR2_CA;
pLayerCfg.FBStartAdress = 0xC0000000;
pLayerCfg.ImageWidth = 200;
pLayerCfg.ImageHeight = 480;
pLayerCfg.Backcolor.Blue = 0;
pLayerCfg.Backcolor.Green = 0;
pLayerCfg.Backcolor.Red = 0;
if (HAL_LTDC_ConfigLayer(&hltdc, &pLayerCfg, 0) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN LTDC_Init 2 */
__HAL_LTDC_DISABLE(&hltdc);
DSI_LPCmdTypeDef LPCmd;
HAL_DSI_Start(&hdsi);
NT35510_Init(NT35510_FORMAT_RBG565, LCD_ORIENTATION_LANDSCAPE);
HAL_DSI_ShortWrite(&hdsi, 0, DSI_DCS_SHORT_PKT_WRITE_P1, NT35510_CMD_DISPOFF, 0x00);
LPCmd.LPGenShortWriteNoP = DSI_LP_GSW0P_DISABLE;
LPCmd.LPGenShortWriteOneP = DSI_LP_GSW1P_DISABLE;
LPCmd.LPGenShortWriteTwoP = DSI_LP_GSW2P_DISABLE;
LPCmd.LPGenShortReadNoP = DSI_LP_GSR0P_DISABLE;
LPCmd.LPGenShortReadOneP = DSI_LP_GSR1P_DISABLE;
LPCmd.LPGenShortReadTwoP = DSI_LP_GSR2P_DISABLE;
LPCmd.LPGenLongWrite = DSI_LP_GLW_DISABLE;
LPCmd.LPDcsShortWriteNoP = DSI_LP_DSW0P_DISABLE;
LPCmd.LPDcsShortWriteOneP = DSI_LP_DSW1P_DISABLE;
LPCmd.LPDcsShortReadNoP = DSI_LP_DSR0P_DISABLE;
LPCmd.LPDcsLongWrite = DSI_LP_DLW_DISABLE;
HAL_DSI_ConfigCommand(&hdsi, &LPCmd);
HAL_LTDC_SetPitch(&hltdc, 800, 0);
__HAL_LTDC_ENABLE(&hltdc);
/* USER CODE END LTDC_Init 2 */
}
this is the comparison I’ve observed.
1. How can I improve the performance of my graph display?
2. Why is the example project configured this way for LTDC? What are the advantages? Why is its configuration different from what's stated in the datasheet?
3. If I use video mode, will this kind of configuration provide any optimization?
2025-08-18 5:40 AM
I will start with the complicated answer to 2), since the solution for you may just be to revert to the supplied Board setup.
Basically, the reason it is handled in this way is that the display is a portrait display. This means that the scan line, as mounted on the DK, moves from left to right, rather than from the top to the bottom, regardless of how the registers in the controller are setup - it's a hardware limitation.
This means that data sent to the display are stored internally and drawn when the scanline reaches the desired point. Since the framebuffer is transferred in landscape orientation, this leads to an undesired tearing effect, where the data for the bottom of the framebuffer are update last, but the scan line started consuming the stored data from the beginning.
This has been solved in a rather unintuitive way, by splitting the screen into four parts and updating them one at a time. This way, the "bottom" of the first quarter is ready when the display TE safe area ends, and the remaining three parts can be transferred fast enough that they are ready once the scan line reaches them.
You can see the code in TouchGFXHAL.cpp.
If you want to change the configuration, you should remove that code. You should set the frame buffer to 480x800, initialize the display in portrait mode and rotate the GUI in TouchGFX.
If you want inspiration for how to handle this, the F469DK and F769DK board setups available wit TouchGFX have been updated to behave this way, although they are still in DSI command mode and the TE signal as source for VSYNC events, which in turn triggers the tick event.
I will note in general, though, that the graph widget is generally not very fast.
2025-08-21 2:24 AM
thx , mathiasmarkussen
1.If I configure the LTDC and screen mode on the STM32F469I-Disco, when LTDC and touchgfx setting the resolution to 800 * 480, the ET scanning direction will be from top to bottom; if configuring it to 480 * 800, the ET scanning direction will be from left to right.
2. Have you ever tested the performance of scroll-dynamic graphs using the DSI video mode on the STM32F469I-Disco?
2025-08-21 2:38 AM - edited 2025-08-21 2:39 AM
1) The actual scan line of the display will always move from one short edge to the other. You can show this by, for example, making a UI that moves a colored bar across the screen at some increment every frame. If you define your display as 800x480 and it is updated at 60 hz, you will see that the bar will tear at a certain position with a slanted line at the top. This will be the position where the scan line catches up to the data copy to the display.
2) I have not done any measurements, but if it works well for you with the original board setup, I would not imagine this being your problem.
2025-08-21 5:15 AM
1. If i want to change text int main_screen in other task. How to do ?
2025-08-21 5:53 AM
I'm not sure I understand your question, but If you want to change text inside your application at runtime, you can watch this video:
2025-08-21 6:36 PM - edited 2025-08-22 12:12 AM
1. add point
This is my touchgfx task,
/* creation of TouchGFXTask */
TouchGFXTaskHandle = osThreadNew(TouchGFX_Task, NULL, &TouchGFXTask_attributes);
If i want to change my
If I need add a point in graph in other task(maybe AddPoint_Task)
audio_dynamicGraph.addDataPoint(10)
2. I use dsi-video model and add a point every handletichevent.
My screen refresh rate will down to 3 hz
int8_t tmp_cnt = -127;
void main_screenView::handleTickEvent()
{
if(time_cnt_1ms - start_cnt_1ms > 1000)
{
start_cnt_1ms = time_cnt_1ms;
monitor_frame.current_frame = monitor_frame.cnt_frame;
monitor_frame.skip_frame = 0;
monitor_frame.cnt_frame = 0;
}
if (HAL::getInstance()->getLCDRefreshCount() > 1)
{
monitor_frame.skip_frame++;
}
else
{
monitor_frame.cnt_frame++;
}
audio_dynamicGraph.addDataPoint(tmp_cnt);
tmp_cnt = tmp_cnt + 20;
}
2025-08-22 1:11 AM
1) I would use message queues to pass data between threads. The intended way to handle that is using the model-view-presenter pattern and read the message queue in the model, but I suppose you can do it directly in the screen if you prefer.
Model-View-Presenter Design Pattern | TouchGFX Documentation
There are a few board specific demos that handle communication with external stuff in TouchGFX, you could take inspration from them. I've attached a screenshot, do not mind the red boxes - you're probably more interested in intertask communication or multitask communication.
2) how do you get vsync signal? How do you transfer data to the display?
2025-08-22 1:55 AM
thx,
extern "C"
{
void HAL_LTDC_LineEventCallback(LTDC_HandleTypeDef* hltdc)
{
if (!HAL::getInstance())
{
return;
}
if (LTDC->LIPCR == lcd_int_active_line)
{
//entering active area
HAL_LTDC_ProgramLineEvent(hltdc, lcd_int_porch_line);
HAL::getInstance()->vSync();
OSWrappers::signalVSync();
// Swap frame buffers immediately instead of waiting for the task to be scheduled in.
// Note: task will also swap when it wakes up, but that operation is guarded and will not have
// any effect if already swapped.
HAL::getInstance()->swapFrameBuffers();
GPIO::set(GPIO::VSYNC_FREQ);
}
else
{
//exiting active area
HAL_LTDC_ProgramLineEvent(hltdc, lcd_int_active_line);
// Signal to the framework that display update has finished.
HAL::getInstance()->frontPorchEntered();
GPIO::clear(GPIO::VSYNC_FREQ);
}
}
}
2025-08-22 2:25 AM - edited 2025-08-22 2:26 AM
So this is in TouchGFXGeneratedHAL.cpp, right?
What is your tickrate if you do not add datapoints to your graph?
If you'd like to share your project, I have access to a board to experiment a bit on myself.