cancel
Showing results for 
Search instead for 
Did you mean: 

Screen tearing in a fixed area, how to avoid it.

Wrend.1
Senior

The screen tearing issue is as below. It looks always appear in the right area:

0693W000006GwEqQAK.gif​The screen is FMC16 bit parallel port, and the parameter is as below:

0693W000006GwKFQA0.pngAnd the screen has TE signal, the TE Interrupt function is an below:

    void TouchGFX_TickHandler(uint8_t PinStatus)
    {
			if (os_inited == true)
			{
				if (PinStatus) /* Raising edge : entering Active Area */
				{
					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 /* Falling edge : exiting active area */
				{
					GPIO::clear(GPIO::VSYNC_FREQ);
					HAL::getInstance()->frontPorchEntered();
				}
			}
    }

Can anyone tell me what caused the screen to tear? And can I avoid it by program.​

6 REPLIES 6
Alexandre RENOUX
Principal

Hello Wrend.1,

Are you sure it is related to FMC ?

What MCU do you use ? Is the white box part of your GUI ?

/Alexandre

I don't know if the FMC related to it.:sad_but_relieved_face:

The MCU is H750VBTx, and the white box is the part of my GUI, I write it for observing the tearing phenomenon.

Alexandre RENOUX
Principal

What is the resolution of your display ?

If your display is an FMC display, it has an embedded GRAM right ?

Do you invalidate the whole screen ? You can check by pressing F2 key on your keyboard when running the simulator.

Tearing effect happens when you have bad synchronization between TouchGFX and your display. It can also happen if the GUI requires too much computing power but this is not the case here.

So actually if your display interface is FMC, you are right to check the parameters for this display. Unfortunately I don't know about your custom display.

Maybe you can refer to the Application Template for L496-DISCO available on TouchGFX Designer. This project uses FMC as a display interface.

/Alexandre

The resolution is 320*170,

it has an embedded GRAM right like this:

namespace {
    // Use the section "TouchGFX_Framebuffer" in the linker to specify the placement of the buffer
    LOCATION_PRAGMA("TouchGFX_Framebuffer")
    uint32_t frameBuf[(320 * 170 * 2 + 3) / 4] LOCATION_ATTRIBUTE("TouchGFX_Framebuffer");
     uint32_t animationStorage[(320 * 170 * 2 + 3) / 4] LOCATION_ATTRIBUTE("TouchGFX_Framebuffer");
}
 
void TouchGFXGeneratedHAL::initialize()
{
    HAL::initialize();
 
    registerEventListener(*(touchgfx::Application::getInstance()));
 
    setFrameBufferStartAddresses((void*)frameBuf, (void*)0, (void*)animationStorage);
    /*
     * Set whether the DMA transfers are locked to the TFT update cycle. If
     * locked, DMA transfer will not begin until the TFT controller has finished
     * updating the display. If not locked, DMA transfers will begin as soon as
     * possible. Default is true (DMA is locked with TFT).
     */
    lockDMAToFrontPorch(true);
}

,and I invalidate the whole screen( I change the white box position and invalidate the screen in a tick event).

I will read the demo of L496-DISCO for some solution, my code is according to F412 demo, there have not much difference.

Hello Wrend.1,

If you don't use LTDC, you should not lock DMA to front Porch. Can you make sure in TouchGFXHAL.cpp in void TouchGFXHAL::initialize() you have the line lockDMAToFrontPorch(false); ?

With a H750 updating an area of 370x170 should be quite easy in terms of computing power, so I believe tearing comes from something else like wrong synchronization between your screen and your MCU.

/Alexandre

Yes, I ​do not lock DMA to front Porch. I change the "lockDMAToFrontPorch(false);" in TouchGFXGeneratedHAL.cpp, the tearing still alive.

And this is the all code of TouchGFXHAL.cpp.

/**
  ******************************************************************************
  * File Name          : TouchGFXHAL.cpp
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under Ultimate Liberty license
  * SLA0044, the "License"; You may not use this file except in compliance with
  * the License. You may obtain a copy of the License at:
  *                             www.st.com/SLA0044
  *
  ******************************************************************************
  */
#include <TouchGFXHAL.hpp>
 
/* USER CODE BEGIN TouchGFXHAL.cpp */
 
#include "stm32h7xx.h"
#include <touchgfx/hal/OSWrappers.hpp>
#include "main.h"
#include "user_voice.h"
#include "st7789v.h"
#include "user_lcd.h"
#include "user_config.h"
#include <touchgfx/hal/GPIO.hpp>
 
#include "FreeRTOS.h"
#include "task.h"
 
 
/* USER CODE END private defines */
 
/* USER CODE BEGIN private variables */
volatile bool firstFrameReadyToDisplay = false;
static uint16_t* currFbBase = 0;
/* USER CODE END private variables */
 
/* USER CODE BEGIN private functions */
 
/* USER CODE END private functions */
 
/* USER CODE BEGIN extern C prototypes */
extern "C"
{
    bool os_inited = false;
	uint32_t display_start,display_tot,display_max = 0;
}
/* USER CODE END extern C prototypes */
 
using namespace touchgfx;
 
void TouchGFXHAL::initialize()
{
    /* USER CODE BEGIN initialize step 1 */
    GPIO::init();
	
//	ST7789V2_Init();
    /* USER CODE END initialize step 1 */
 
    // Calling parent implementation of initialize().
    //
    // To overwrite the generated implementation, omit call to parent function
    // and implemented needed functionality here.
    // Please note, HAL::initialize() must be called to initialize the framework.
 
    TouchGFXGeneratedHAL::initialize();
 
    /* USER CODE BEGIN initialize step 2 */
    lockDMAToFrontPorch(false);
 
    instrumentation.init();
    setMCUInstrumentation(&instrumentation);
    enableMCULoadCalculation(true);
    os_inited = true;
    /* USER CODE END initialize step 2 */
}
 
uint16_t* TouchGFXHAL::getTFTFrameBuffer() const
{
    return currFbBase;
}
 
void TouchGFXHAL::setTFTFrameBuffer(uint16_t* adr)
{
    currFbBase = adr;
}
 
void TouchGFXHAL::configureInterrupts()
{
}
 
void TouchGFXHAL::enableLCDControllerInterrupt()
{
}
 
void TouchGFXHAL::disableInterrupts()
{
}
 
void TouchGFXHAL::enableInterrupts()
{
}
 
// Full refresh
void TouchGFXHAL::flushFrameBuffer()
{
    Rect rect = Rect(0, 0, 320, 170);
    HAL::flushFrameBuffer();
	ST7789V2_SetDisplayWindow(rect.x, rect.y, rect.width, rect.height);
	this->copyFrameBufferBlockToLCD(rect);
}
 
void  TouchGFXHAL::flushFrameBuffer(const Rect& rect)
{
    // Partial framebuffer might be supported for this platform only when Double
    // Buffering is enabled
	display_start = GetSysTs_To_uSec();
//	HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
    this->flushFrameBuffer();
//	HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
	display_tot = GetSysTs_To_uSec() - display_start;
	if(display_tot > display_max)
	{
		display_max = display_tot;
	}
}
 
void TouchGFXHAL::copyFrameBufferBlockToLCD(const Rect rect)
{
    __IO uint16_t* ptr;	
	uint32_t tot;
	
    // Use default implementation (CPU copy!).
    // This can be accelerated using regular DMA hardware
	ptr = getClientFrameBuffer();
	tot = (rect.width - rect.x)*(rect.height - rect.y);
#if 0
	ST7789V2_WriteMultipleData((uint16_t*)ptr, tot);
#else	
	ST7789V2_blockCopy((uint16_t *)ptr,tot);
#endif	
 
}
 
bool TouchGFXHAL::blockCopy(void* RESTRICT          dest,
                            const void* RESTRICT    src,
                            uint32_t            numBytes)
{
    bool retval = true;
 
    // Use default implementation (CPU copy!).
    // This can be accelerated using regular DMA hardware
    retval    = HAL::blockCopy(dest, src, numBytes);
 
    return retval;
}
 
/* USER CODE BEGIN virtual overloaded methods */
bool TouchGFXHAL::beginFrame()
{
    return HAL::beginFrame();
}
 
void TouchGFXHAL::endFrame()
{
    HAL::endFrame();
    if (frameBufferUpdatedThisFrame)
    {
        if (!firstFrameReadyToDisplay)
        {
            firstFrameReadyToDisplay = true;
			/* Backlight control signal assertion */
			BacklightEnable();
//			Voice_Set(0x52);
        }
    }
}
 
/* USER CODE END virtual overloaded methods */
 
/* USER CODE BEGIN extern C functions */
// TODO : Remove this and use BSP/Components/st7789H2 API once fixed
extern "C" {
 
    portBASE_TYPE IdleTaskHook(void* p)
    {
        if ((int)p) //idle task sched out
        {
            touchgfx::HAL::getInstance()->setMCUActive(true);
        }
        else //idle task sched in
        {
            touchgfx::HAL::getInstance()->setMCUActive(false);
        }
        return pdTRUE;
    }
 
    void TouchGFX_TickHandler(uint8_t PinStatus)
    {
		if (os_inited == true)
		{
			if (PinStatus) /* Raising edge : entering Active Area */
			{
				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 /* Falling edge : exiting active area */
			{
				GPIO::clear(GPIO::VSYNC_FREQ);
				HAL::getInstance()->frontPorchEntered();
			}
		}
    }
}
/* USER CODE END extern C functions */
 
/* USER CODE END TouchGFXHAL.cpp */
 
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

Wrong synchronization between your screen and your MCU? Your mean is the TE signal from screen? Or another reason.