cancel
Showing results for 
Search instead for 
Did you mean: 

Exact steps to configure TouchGFX

VLau
Associate III

Hey!

I've been struggling to understand TouchGFX engine. I tried Discovery board and examples provided by TouchGFX Designer - everything works out of the box.

However playing with high level app software on discovery boards won't help me on the product boards, so I tried build project from scratch and failed. After that I reduced my task to pick small I2C B/W display, working LCD driver and draw a square on it with TouchGFX framework. Just to see that engine "ticks" as expected. Still no luck.

Things I tried so far:

  • follow https://support.touchgfx.com scenario on SPI interface
  • NUCLEO-G071 board example
  • some guy's blog who was able to run TouchGFX with SPI display
  • without/with RTOS

Maybe anyone saw EXACT steps on how connect TouchGFX framework to hardware. Like what signals/interrupts framework needs, which file to put it (ex. step 1: you should provide this instruction here for this and this flag there for that). I guess I'm talking about "Touch AL" layer which seems to be the hardest part. Theoretically I kinda understand what is rendering, when flushing buffer takes place and such things, yet no able to run it.

For now I always stuck at

    virtual void backPorchExited()
    {
        swapFrameBuffers();
        tick();   // <- here
    }

Worth mention that tried I provide Vsync flag with Timer interrupt. I tried different timer rates and different places to start it, also tried to emulate Vsync flag.

extern "C" void touchgfx_signalVSyncTimer(void)
{
  HAL::getInstance()->vSync();
  touchgfx::OSWrappers::signalVSync();
}

Any suggestions appreciated! Thanks

1 ACCEPTED SOLUTION

Accepted Solutions
N. SANTINI
ST Employee

Hi,

Thanks for sharing indeed !

If I can give my 2 cents on the single frame buffer issue : I got a similar issue recently (double frame buffer strategy is fine while single frame buffer is not), the root was the DMA2D synchronization that can be enabled by default when selecting double frame buffer and remains there when switching to single frame buffer.

You could try to disable it by adding the following line to void TouchGFXHAL::initialize() method after mother class initialize() call) : lockDMAToFrontPorch(false);

Best regards,

Nicolas

View solution in original post

10 REPLIES 10
Romain DIELEMAN
ST Employee

Hi,

It is a bit complicated to know what exactly you are struggling with and guide you accordingly without more details, especially since I guess you have already looked a bit everywhere from what you wrote 😅 But maybe this video from another user (HP) can help you for some of the steps. For the blog I guess you are referring to that one ?

/Romain

Thanks for response!

Yeah I was refering to that link and example with NUCLEO-G071 & X-NUCLEO-GFX01M1. Both used partial buffer strategy.

Found somewhat similar problem in this thread https://community.st.com/s/question/0D53W000004nFAu/touchgfx-with-spi-tft.

I was using single buffering also. Changed it to double buffering in CubeMX and now I was able to run engine freely without stuck at backPorchExited(), my display finally draw me something. Not sure if it was a bug or did I missed something during setting project up.

For now I want to keep this thread for a while since I would likely need help with double buffering strategy. My display showed only half of the image, with other half filled with random pixels.

N. SANTINI
ST Employee

Hi,

For your information a new video has just been released from our TouchGFX Development team, focused on board bring-up.

I think it should be of great help in your case,

Board Bring-up

TouchGFX Board bring up introduction

Abstraction Layer:

TouchGFX Abstration layer development introduction

Best regards,

Nicolas

Thanks for the videos!

After days and days I finally had some success. I bought DISCOVERY-F429 board with ili93141-based display which supports RGB interface.

Now I have 4 working projects made from scratch: with/without SDRAM, with/without RTOS.

If someone needs help here's what I did:

  • start empty CubeIDE project;
  • enable modules in CubeMX: FMC for SDRAM, I2C for touch panel, LTDC for display and SPI for configuring display;
  • add drivers from discovery examples for this board (drivers kinda bloated and confusing at first glance, what you really need is files ili93141.c/.h, stmpe811.c/.h and a layer to connect them to your hardware);
  • write some modules initialization code. Fill SDRAM with anything and make sure that all modules work as expected.
  • all above was "Board bring-up" step;
  • back to CubeMX, enable TouchGFX framework with following config: No OS, double buffer strategy, buffer location by address. Generate code;
  • within CubeIDE open TouchGFX Designer and make simple UI. Generate code;
  • important step to add missing line (IMO) in file TouchGFXConfiguration.cpp:
void touchgfx_taskEntry()
{
	/*
	 * Main event loop will check for VSYNC signal, and then process next frame.
	 *
	 * Note This function returns immediately if there is no VSYNC signal.
	 */
	if (OSWrappers::isVSyncAvailable())
	{
		OSWrappers::signalRenderingDone(); //// <- ADD THIS TO RESET VSYNC FLAG
		hal.backPorchExited();
	}
}
  • compile & see everything is working
  • it is useful to provide pin handle in file TouchGFXGPIO.cpp for signals VSYNC_FREQ, RENDER_TIME, FRAME_RATE. Use logic analyzer to see what's going on, waveforms should make sense;
  • back to CubeMX. TouchGFX config: change to single buffer strategy, buffer location by Allocation. Now our framebuffer would be in MCU's RAM. You can completely disable SDRAM if you want. Generate code;
  • add missing line in TouchGFXConfiguration.cpp since this file is regenerated as I recall;
  • compile & see everything is working;
  • back to CubeMX. Add FreeRTOS with TouchGFX_Task, TouchGFX config: change to CMSIS_RTOS_V2. Generate code;
  • IIRC, nothing more should be done. Compile & see everything is working.

However my SPI-display based approach does not work as expected. Single buffer strategy doesn't work at all. With double buffer strategy I can see my UI screens, but waveforms acquried with logic analyzer are complete mess. I definately missed some flags somewhere.

Thanks for sharing 👍

Just out of curiosity did you also try the partial framebuffer strategy with the SPI display approach ? What is the issue with the single framebuffer ? Nothing is displayed or a hardfault in the initialization ?

/Romain

VLau
Associate III

No didn't try.

With single framebuffer I can't even make it to flushFrameBuffer() part, engine dies at backPorchExited() in HAL.hpp file.

With double buffer strategy engine "ticks" and my UI screens are displayed, yet something is wrong too. I attached waveforms just in case (VSYNCS are set by 60 Hz timer, MOSI & SCK - actual "flushing" framebuffer to display).

extern "C" void touchgfx_signalVSyncTimer(void)
{
	GPIO::set(GPIO::VSYNC_FREQ);
	/* VSync has occurred, increment TouchGFX engine vsync counter */
	touchgfx::HAL::getInstance()->vSync();
	/* VSync has occurred, signal TouchGFX engine */
	touchgfx::OSWrappers::signalVSync();
	GPIO::clear(GPIO::VSYNC_FREQ);
}
void TouchGFXHAL::flushFrameBuffer(const touchgfx::Rect &rect)
{
	// Calling parent implementation of flushFrameBuffer(const touchgfx::Rect& rect).
	//
	// To overwrite the generated implementation, omit call to parent function
	// and implemented needed functionality here.
	// Please note, HAL::flushFrameBuffer(const touchgfx::Rect& rect) must
	// be called to notify the touchgfx framework that flush has been performed.
	ssd1306_FlushFrameBuffer(getClientFrameBuffer());
	//TouchGFXGeneratedHAL::flushFrameBuffer(rect);
}

As I understand flushFrameBuffer() should be called after RENDER_TIME is done, since it makes sense. In my case it is called twice and during RENDER_TIME. So something else I should provide.

N. SANTINI
ST Employee

Hi,

Thanks for sharing indeed !

If I can give my 2 cents on the single frame buffer issue : I got a similar issue recently (double frame buffer strategy is fine while single frame buffer is not), the root was the DMA2D synchronization that can be enabled by default when selecting double frame buffer and remains there when switching to single frame buffer.

You could try to disable it by adding the following line to void TouchGFXHAL::initialize() method after mother class initialize() call) : lockDMAToFrontPorch(false);

Best regards,

Nicolas

Ok, thanks!

Now it works with single buffer too.

But flushFrameBuffer is called twice in one vsync period, so SPI actually sends same data twice to display.

Another question, do I have to implement anything else except actual sending pixel data into TouchGFXHAL::flushFrameBuffer() ?

void TouchGFXHAL::flushFrameBuffer(const touchgfx::Rect &rect)
{
	// Calling parent implementation of flushFrameBuffer(const touchgfx::Rect& rect).
	//
	// To overwrite the generated implementation, omit call to parent function
	// and implemented needed functionality here.
	// Please note, HAL::flushFrameBuffer(const touchgfx::Rect& rect) must
	// be called to notify the touchgfx framework that flush has been performed.
	mydriver_FlushFrameBuffer(getClientFrameBuffer());
        HAL::flushFrameBuffer(rect);      // <- does this line needed? seems no influence at all
}

N. SANTINI
ST Employee

Hi,

This may not have a direct influence in your case but I think the "HAL::flushFrameBuffer(rect);" call is preferable as it updates some internal states of the TouchGFX library.

Best regards,

Nicolas