cancel
Showing results for 
Search instead for 
Did you mean: 

Howto trigger flushFrameBuffer(Rect&)

GEngi.2072
Associate II

Hi all,

we have a STM32F103 MCU with an Epson TFT controller with an internal framebuffer. This framebuffer is attached via FSMC bus and memory-mapped at 0x68000000. We already have an application that draws graphics successfully to our display (using Atollic TrueStudio 9). Now we are evaluating touchGFX as an abstraction layer to create the GUI. What we have achieved so far:

  • created a small demo app with touch designer (background + 1 Button); this runs in windows simulator
  • added the generated code to our Atollic project; compiles and runs
  • use application template from F4 Disco board
  • followed the instructions in MCUs without TFT controller, Running TouchGFX without an operating system and old support thread Porting TouchGFX to 8080-based LCDs
  • from the second link we use the OSWrappers class
  • we have defined an own HAL: class STM32F103HAL : public STM32F4HAL
  • our timer triggers OSWrappers::signalVSync() (verified with debugger)

Most important steps we are doing in pseudo-code:

init_our_hardware();
NoDMA dma;
LCD16bpp display;
NoTouchController tc
touchgfx_init() {
  HAL& hal = touchgfx_generic_init<STM32F103HAL>(dma, display, tc, 320, 240, 0, 0);
  hal.setFrameBufferStartAddress((uint16_t*)frameBuf0, 16, false, false);
  hal.lockDMAToFrontPorch(false);
  // if we uncomment the next two lines we can draw pixels on the TFT via the framebuffer pointer:
  // Rect r(0,0,320,240);
  // hal.flushFrameBuffer(r);
}
create_20hz_timer();
HAL::getInstance()->taskEntry();

Finally we have two issues that are not clear to us / that do not work:

  1. our flushFrameBuffer(Rect&) is never called by touchgfx main loop (can't be the bug mentioned in the third linked support thread, we use 4.10.0); when we uncomment the lines 10&11 in above code, our STM32F103HAL::flushFrameBuffer(Rect&) *is* called; And:
  2. we have declared the frame buffer start address to touchgfx (line 7), so in our flushFrameBuffer function we just call the base implementation ("STM32F4HAL::flushFrameBuffer(rect);"); but touchgfx doesn't generate any output, the display remains dark (as mentioned, via the frame buffer pointer we manually can draw pixels, so the hardware is set up);

When trying to address problem 1 we already fiddled with Model::tick() and HAL::tick() but without success.

Thanks in advance for any ideas!

10 REPLIES 10
Martin KJELDSEN
Chief III

You do not need to call flushFrameBuffer() manually.

It is called by TouchGFX hal after

endFrame();

What you do then to get the framebuffer pointer is to call:

HAL::getInstance()->lockFrameBuffer();

Based on Rect calculate where to go in the frame bufferand what to start transferring. Typically:

fbPtr += rect.y * lcd().framebufferStride() + rect.x * (bpp/8); //for 8/16/24bpp

Transfer data using your driver, considering:

rect.width;
rect.height;

You can use lcd().framebufferStride() to get the pointer to the next row.

If using DMA to transfer data you need additional synchronization like a semaphore to ensure that flushFrameBuffer(Rect& rect) does not return before transfer is completed.

When done call:

HAL::getInstance()->unlockFrameBuffer();

/Martin

GEngi.2072
Associate II

Hello Martin,

thanks for the info. The manual calling of flushFrameBuffer was just a test to make sure our hardware works (as suggested in one of the linked threads). And indeed, calling flushFrameBuffer manually we can draw a pixel pattern to frameBuf0 in that function. So hardware setup should be OK. But flushFrameBuffer it is not called by touchGFX main loop. As described above, our application is generated via touch Designer. Maybe there is a link missing, because we don't have an OS, see below:

This currently is working (checked by stepping via debugger):

In our hw timer irq -> "touchgfx::HAL::getInstance()->vSync(); touchgfx::OSWrappers::signalVSync();"

Then, because we don't have an OS, we have stripped down the main loop to this code:

#if TRY_WITH_DESIGNER_CODE
    // from tutorials/01_hello_world
    Bitmap::registerBitmapDatabase(BitmapDatabase::getInstance(),
        BitmapDatabase::getInstanceSize(), 0, 0);
 
    Texts texts;
    TypedText::registerTexts(&texts);
    Texts::setLanguage(0); // Change '0' to the initial language, e.g. 'GB'
 
    //The Keyboard uses the FontManager to get at FontProvider.
    ApplicationFontProvider fontProvider;
    FontManager::setFontProvider(&fontProvider);
 
// (*) if we uncomment the next two lines, program crashes:
//    FrontendHeap& heap = FrontendHeap::getInstance();
//    (void) heap; // we need to obtain the reference above to initialize the frontend heap.
    HAL::getInstance()->registerEventListener(*(Application::getInstance()));
    // --------------- end from tutorials/01_hello_world
#endif
 
    // suggestion from https://touchgfx.zendesk.com/hc/en-us/articles/204887741
    // instead of "HAL::getInstance()->taskEntry();" do it manually:
    HAL::getInstance()->enableLCDControllerInterrupt();
    HAL::getInstance()->enableInterrupts();
    while(1)
    {
      OSWrappers::waitForVSync();
      HAL::getInstance()->backPorchExited();
    }

Via the timer, backPorchExited() is called regularly. There, we call:

virtual void backPorchExited() {
        swapFrameBuffers();
        HAL::getInstance()->endFrame();
}

but nothing happens, none of both flushFrameBuffer functions is ever called.

The first code snippet we can compile with TRY_WITH_DESIGNER_CODE defined or not defined - no change. If we define it and uncomment the two lines below the "// (*)" comment the program crashes, but at least from the call stack we can see that touchGFX tries to Screen::draw() something! To me it looks as if there is some initial setup missing:

Thread #1 57005 (Suspended : Signal : SIGTRAP:Trace/breakpoint trap)	
	HardFault_Handler() at stm32f1xx_it.cpp:77 0x8004ae6	
	<signal handler called>() at 0xfffffff9	
	touchgfx::Screen::draw() at 0x802c676	
	touchgfx::Application::Application() at 0x802b978	
	touchgfx::MVPApplication::MVPApplication() at MVPApplication.hpp:58 0x8017cac	
	FrontendApplicationBase::FrontendApplicationBase() at FrontendApplicationBase.cpp:20 0x8017eac	
	FrontendApplication::FrontendApplication() at FrontendApplication.cpp:4 0x8018710	
	FrontendHeap::FrontendHeap() at FrontendHeap.hpp:68 0x80173e8	
	FrontendHeap::getInstance() at FrontendHeap.hpp:56 0x801731e	
	touchgfx_main() at main.cpp:157 0x80174ce	
	main() at main.cpp:1.300 0x802475e

Thanks and greetings!

GEngi.2072
Associate II

Hi there,

unfortunately we still don't see an output from our Designer code (for the first test this simply should be a colored background with a rectangle in a different color in the center). Via the simulator we see this test. Here is the current pseudo-code with some remarks:

hardware_init()
 
// touchgfx init:
HAL& hal = touchgfx_generic_init<STM32F103HAL>(dma, display, tc, 120, 80, 0, 0)
hal.setFrameBufferStartAddress((uint16_t*)frameBuf0, 16, true, false)
 
//[1] Designer App init (?):
Bitmap::registerBitmapDatabase()
TypedText::registerTexts()
FontManager::setFontProvider()
//[2] FrontendHeap& heap = FrontendHeap::getInstance()
HAL::getInstance()->registerEventListener(*(Application::getInstance()))
HAL::getInstance()->enableLCDControllerInterrupt()
HAL::getInstance()->enableInterrupts()
HAL::getInstance()->unlockFrameBuffer()
 
while (1) {
  OSWrappers::waitForVSync()  //[2] waits for our timer
  swapFramebuffers()
  endFrame()
  //[3] uint16_t* fbPtr = HAL::getInstance()->lockFrameBuffer()
  //[3] *fbPtr = 0xffff
  //[3] HAL::getInstance()->unlockFrameBuffer();
}

The hardware init and tgfx init seem to work fine, because when commenting out the last three lines ("//[3]") we can see the white dot on our TFT. Where we are not sure about is the section below "//[1]": what is missing to trigger the touchGFX draw() functions? Apart from the dot the screen just remains black. (Maybe this posting's subject now is misleading: initially we thought flushFrameBuffer() somehow triggers the Designer generated elements to call their draw() function...)

If we remove the comment "//[2]" we still get the stacktrace from our last comment. Is this related to the issue discussed in HardFault when upgrading TouchGFX 4.9.3 to 4.10.0? But for our STM32F103 there is no __HAL_RCC_CRC_CLK_ENABLE.

Thanks and greetings!

GEngi.2072
Associate II

Short follow-up, in case anybody hits this thread. Issue solved, our test-app is running. Finally it was two things:

  1. we had to enable CRC (wasn't needed in our legacy setup and touchGFX doesn't run without it!)
  2. remove all unneeded code from our legacy setup (in our previous project we had a couple of libraries that somehow still were included during touchGFX port...)

Greetings!

Martin KJELDSEN
Chief III

Thanks for the update. Do you still need me to take a look at something or are you good? Seems like you're calling a lot of functions manually, and i'd have to think about how that impacts the internals of the main event loop, etc.

flushFrameBuffer(Rect& rect) is only called if there's something to transfer. So, depending on your application, at least once.

/Martin

GEngi.2072
Associate II

Hi Martin,

the test app currently runs fine with our display hardware, so no further help on this topic needed. Next step is to connect some digital inputs (our hardware buttons, the display doesn't have touch!) to the event loop. Maybe there new questions will be arising ... Side note: as you can see from the "timing" of my messages this is a test project (how to port our projects to touchGFX) that runs in parallel to daily work...

Gxun.1
Associate

have started the CRC,But it still cannot go into the flushFrameBuffer().I've tried a lot. Am I missing something?Or is there any other possibility

Check out the article i wrote on using external events as triggers in the designer https://support.touchgfx.com/docs/development/board-bring-up/example-gpio

And check out the webinar i did on this topic: Connecting hardware to your UI.

/Martin

Could you start a new topic about your issue?