Jump to content

uGFX + FreeRTOS (on STM32F746-Disco)


Simon

Recommended Posts

I've been trying to get uGFX running with FreeRTOS on an STM32F746-Discovery board.

I've got uGFX working and I've got FreeRTOS working, however, I cannot get them to work together.

I understand that gfxInit has to be run in a non-looping task that is defined before the scheduler is started. However, gfxInit never returns so the GUI task never gets created. If I define the GUI task before starting the scheduler it doesn't execute either.

I have 

#define GFX_USE_OS_FREERTOS                          TRUE

defined in gfxconf.h and my code is:

int main(int argc, char* argv[])
{
	(void)argc;
	(void)argv;
	// Create the initialization task
	xTaskCreate(uGFXInit, "uGFXInit", 1024, 0, 1, uGFXInitHandle);
	// Start the scheduler.
	vTaskStartScheduler();
	/* We should never get here as control is now taken by the scheduler */
	for(;;);
}
static void uGFXInit(void* pvParameters)
{
	(void)pvParameters;
    gfxInit();
    /* Create GUI task */
    xTaskCreate(GUIThread, "GUI_Thread", 16384, 0, 1, 0);
    vTaskDelete(uGFXInitHandle);
}
static void GUIThread(void* pvParameters)
{
	(void)pvParameters;
	gdispSetBacklight(100);
	gdispSetContrast(100);
	vTaskDelay( 200 );
	geventListenerInit(&glistener);
	gwinAttachListener(&glistener);

	guiCreate();
  /* Gui background Task */
  while(1) {
	guiEventLoop();
  }
}

I am thinking that I need to use GFX_OS_CALL_UGFXMAIN but cannot work out how to specifically. The behaviour I am seeing is that gfxInit gets called but never returns and it looks like the FreeRTOS idle task is running continuously after this point.

As the FreeRTOS page on the wiki says that the "FreeRTOS port works out of the box without any modifications" I may be way off track here but would appreciate advice on the correct way to get FreeRTOS and uGFX to work together.

Link to comment
Share on other sites

Hello @Simon,

Did you make sure that you use the latest version of the µGFX library? There have been a few changes/improvements in the last release.

gfxInit() not returning indicates that some part of the initialization failed. The easiest way to track it down is by stepping through the code.
One other think you can try is forcing the usage of the built-in memory manager that comes with µGFX. You can do that by setting GFX_OS_HEAP_SIZE to a non-zero value. All µGFX heap allocation calls are then managed by µGFX internally. If it's set to 0, the memory manager of the underlying system will be used (in this case FreeRTOS). There are different heap managers that you can use with FreeRTOS and this test would certainly help to find out whether there might be a problem with that. But I'd recommend you to get started by stepping through the gfxInit() code to find the source of the problem.

Your code looks good in general - nothing rings the alarm bells right now.

EDIT: One thing that just came to my mind: Are you sure that you want to call the GUIThread from the uGFXInit() thread? It has been quite a while since I worked with FreeRTOS the last time but I could imagine that that is a problem due to nested stack spaces (eg. uGFXInit would need all its stack + the stack of the new thread) and probably also scopes. Did you try following the example given in the wiki?

Link to comment
Share on other sites

There are two running models with uGFX...

1. gfxInit (optionally) initialises the OS, the display, heap manager etc and then returns. Your application then runs its own event loop etc.

2. gfxInit does the same initialisation as above and then calls uGFXMain(). You put your event loop etc in uGFXMain().

With FreeRTOS the operating system initialisation never returns to the caller thus option 1 is not possible if uGFX is required to initialise the os. It should actually give you a compile error if you try this.

The solution is to either tell uGFX not to initialise the OS as you will do it yourself in your main() or to alternatively use option 2. Option 2 is also the preferred methodology for all uGFX programs from V3.x (when it is released) as this works nicely with OS's like FreeRTOS and with systems like Arduino.

From memory setting GFX_OS_CALL_UGFXMAIN to TRUE is the way to use option 2. In your main() just call gfxInit - it will never return. Define function uGFXMain() which contains the body of your application. No need to explicitly initialise FreeRTOS, uGFX will do it for you.

Link to comment
Share on other sites

Hi @inmarket,

do you mean something like this:

int main(int argc, char* argv[])
{
	(void)argc;
	(void)argv;
	gfxInit();

}
 void uGFXMain()
{
    /* Create GUI task */
    xTaskCreate(GUIThread, "GUI_Thread", 16384, 0, 1, 0);
}
static void GUIThread(void* pvParameters)
{
	(void)pvParameters;
	gdispSetBacklight(100);
	gdispSetContrast(100);
	vTaskDelay( 200 );
	geventListenerInit(&glistener);
	gwinAttachListener(&glistener);

	guiCreate();
  /* Gui background Task */
  while(1) {
	guiEventLoop();
  }
}

In this instance gfxInit does not try to initialise FreeRTOS and so when it executes the gfxSleepMilliseconds, which expands to the FreeRTOS command of vTaskDelay, it eventually fails and goes into the infinite loop default handler.

The first part of my gfxconf.h file contains:

#define GFX_USE_OS_FREERTOS                      TRUE
#define GFX_CPU                                  GFX_CPU_CORTEX_M7_FP
#define GFX_OS_HEAP_SIZE                         16384
#define GFX_OS_CALL_UGFXMAIN                     TRUE

So, I suspect they key question is how do I get gfxInit to initialise FreeRTOS. BTW, I cloned the git repository last night so I am using an up-to-date version. FreeRTOS is v9.0.0 supplied with STM32Cube v 1.8.0 (latest version).

Link to comment
Share on other sites

Yes using the latest version is a requirement for FreeRTOS as the FreeRTOS support before V2.8 was very buggy.

Yes your example code is close, just put the contents of GUIThread into uGFXMain. There is no need to create a seperate task for it as uGFX sets up a task to run uGFXMain. Returning from uGFXMain (as your code does now) is not supported and in some OS's may even cause a panic.

There is a gfxconf.h setting that determines if the OS is initialised automatically. By default it is and it requires an explicit define to turn that off. I can't remember off the top of my head the setting but it should start with GFX_OS_...

Link to comment
Share on other sites

Actually, the problem arises before uGFX initialises FreeRTOS. During the board init the BSP_SDRAM_Initialization_sequence routine is called. In the version of stm32f746g_discovery_sdram.c included with uGFX the call to HAL_Delay(1) included in the ST version of this file is replaced with gfxSleepMilliseconds(1), which actually runs the FreeRTOS command vTaskDelay, but because FreeRTOS has not been initialised at this point it eventually fails and goes into default error handler.

I'll have a deeper look later today but in the meantime if anyone know a fix please let me know :-)

Link to comment
Share on other sites

Not for FreeRTOS it doesn't. vTaskStartScheduler is called from function _gosPostInit (in gos_freertos.c) right at the end of gfxInit.

I notice that in gos_chibios.c and gos_cmsis.c the OS is initialised at the start of gfxInit so I presume this is a simple mis-placement of code. I'll look at it tonight or tomorrow and see if moving the initialisation of the OS to _gosInit resolves the issue.

 

Link to comment
Share on other sites

39 minutes ago, Simon said:

I'll look at it tonight or tomorrow and see if moving the initialisation of the OS to _gosInit resolves the issue.

I doubt that will work as vTaskStartScheduler never returns. So all the other initialization functions will never execute.

Link to comment
Share on other sites

Yep, @cpu20 is correct. That's the reason why the FreeRTOS looks different from the ChibiOS port.

Are you sure that you are doing everything exactly as shown in the wiki article? The FreeRTOS port is used by dozens of commercial customers, hundreds of makers and even quite a few Universities. There shouldn't be any fundamental problem with that. I used it myself without any problems about half a year ago.

Link to comment
Share on other sites

55 minutes ago, Simon said:

It is quite likely that my configuration is at fault so my next step is to take a working FreeRTOS demo and add uGFX to it. 

I personally don't think your configuration is wrong, but the problem lies in the gfxSleepMilliseconds used before vTaskStartScheduler is called.

FreeRTOS doesn't initialize the scheduler until you explicitly call vTaskStartScheduler. So that means that any call of vTaskDelay before the scheduler is initialized will result in a HardFault (or a hangup). A simple thing you can try to see if this is indeed the problem is to use the HAL_Delay() function again. (Make sure the HAL SysTick is initialized and running by calling HAL_Init and putting the SysTick handler in the stm32fxxx_it.c)

Link to comment
Share on other sites

Hi @cpu20, as you predicted using HAL_Init and setting up the RCC clock and changing gfxSleepMilliseconds to look like this:

void gfxSleepMilliseconds(delaytime_t ms)
{
	HAL_Delay(ms);
}

...works as no FreeRTOS commands are used until the OS is initialised. However, using uGFX to initialise FreeRTOS still doesn't work so I have set GFX_OS_NO_INIT to TRUE and initialised it myself.

The touchscreen doesn't work but that's a problem for the weekend.

Link to comment
Share on other sites

7 hours ago, Simon said:

like the attached file but I get a compile error when I try to include this.

Are the SCB_EnableICache() functions giving errors? I think to use those you also need to add #include "stm32f4xx.h"

8 hours ago, Simon said:

However, using uGFX to initialise FreeRTOS still doesn't work

I have no idea what could still be going wrong. When I got some spare time, I will try to setup a project and see what could be wrong.

Link to comment
Share on other sites

After creating a program in SW4STM32 and experimenting a bit, it is clear that the method using the uGFXMain() will never work. As stated here no delays are possible before the scheduler is started.

The Init function you were using in your first post and starting the scheduler yourself will be the way to go.

While trying to get a project up and running it took me quite some tries to get everything right to work together and I bounced into a problem in the board_stm32ltdc.h
The stm32f7xx_hal_rcc.h and stm32f7xx_gpio.h need to be replaced with stm32f7xx_hal.h to work properly with the latest HAL libraries. Anyway here is the result if anyone would be interested.

STM32F746-Disco-FreeRTOS.zip

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...