Hello,
I'm currently developing a µGFX based GUI on ATSAMG55J19 running FreeRTOS, with a ILI9431 controller in SPI 4-wire mode. I've started prototyping the GUI in baremetal first to split the development into smaller problems. I'll integrate it in a FreeRTOS task later once I'm happy with the result.
The application has multiple screens, for which I'm using containers. Not relevant to my current question but maybe worth mentioning is that I have a sidebar that uses a unique instance of a container that doesn't need to be refreshed when changing pages, while the pages themselves are implemented in the remaining 230x240 portion of the screen (which is 320x240). Option #2 of this this answer was helpful in deciding how to implement this static sidebar without duplicating the widgets and it works fine. I'm also using this trick to make clickable zones over multiple widgets within the sidebar as I didn't want simple buttons but rather a combination of icons and dynamic labels in each clickable area. Again, not completely relevant to what I want to ask next.
The issue I'm facing is that although the page transitions are functional, the refresh of the screen is done twice. Since refresh operations are not very fast, this is quite an annoying glitch and I'm trying to figure out what could be causing two refreshes. The total wait time is actually 4 page loads, because the pages are first cleared before displaying a new one. I can clearly see that the page displays all widgets correctly after the first clear + redraw, but it gets cleared and re-drawn a second time.
Here is are the relevant portions of the code, you'll notice I used a uGFX Studio-generated project as initial template. I tried removing as much noise as possible to limit this post's length:
/* Called from mainloop after other platform initialisations
* and a call to gfxInit();
*/
int ugfx_test(void){
gdispSetBacklight(100);
gdispSetContrast(100);
geventListenerInit(&glistener);
gwinAttachListener(&glistener);
guiCreate();
while (1) {
guiEventLoop();
}
}
void guiCreate(void)
{
GWidgetInit wi;
// Prepare fonts
dejavu_sans_16 = gdispOpenFont("DejaVuSans16");
dejavu_sans_24 = gdispOpenFont("DejaVuSans24");
dejavu_sans_32 = gdispOpenFont("DejaVuSans32");
// GWIN settings
gwinWidgetClearInit(&wi);
gwinSetDefaultFont(dejavu_sans_16);
gwinSetDefaultStyle(&white, FALSE);
gwinSetDefaultColor(white_studio);
gwinSetDefaultBgColor(white_studio);
/* Create 6 pages */
createPage00_standby();
createPage01_main();
createPage02_important();
createPage03_info();
createPage04_measure_menu();
createPage05_measure_pressure();
/* Create the sidebar in a unique container */
create_sidebar();
/* Display page 0 at the start */
guiShowPage(0);
gwinShow(ghContainer_sidebar);
}
void guiShowPage(unsigned pageIndex)
{
// Hide all pages
gwinHide(ghContainer00_standby);
gwinHide(ghContainer01_main);
gwinHide(ghContainer02_important);
gwinHide(ghContainer03_info);
gwinHide(ghContainer04_measure_menu);
gwinHide(ghContainer05_measure_pressure);
// Show page selected page
switch (pageIndex) {
case 0:
gwinShow(ghContainer00_standby);
break;
case 1:
gwinShow(ghContainer01_main);
break;
/* etc... cases 2 to 5 also handled here for remaining pages */
/* ... */
default:
break;
}
}
void guiEventLoop(void)
{
GEvent* pe;
while (1) {
// Get an event
pe = geventEventWait(&glistener, 10);
switch (pe->type) {
case GEVENT_GWIN_BUTTON:
if ( ((GEventGWinButton*)pe)->gwin == ghButton1) {
guiShowPage(1);
} else if ( ((GEventGWinButton*)pe)->gwin == ghButton2) {
guiShowPage(2);
}
/* etc, same thing for other pages */
/* ... */
break;
}
}
}
I left out the createPagexx functions as they are quite long, but the general idea for all of them is pretty much identical to what uGFX generates in a typical display page, for example:
static void createPage01_main(void)
{
GWidgetInit wi;
gwinWidgetClearInit(&wi);
// create container widget: ghContainer01_main
wi.g.show = FALSE;
wi.g.x = 0;
wi.g.y = 0;
wi.g.width = 230;
wi.g.height = 240;
wi.g.parent = 0;
wi.text = "Container";
wi.customDraw = 0;
wi.customParam = 0;
wi.customStyle = 0;
ghContainer01_main = gwinContainerCreate(0, &wi, 0);
// Create label widget: ghLabel_1_date
wi.g.show = TRUE;
wi.g.x = 10;
wi.g.y = 10;
wi.g.width = 100;
wi.g.height = 20;
wi.g.parent = ghContainer01_main;
wi.text = "12/03/2016";
wi.customDraw = gwinLabelDrawJustifiedCenter;
wi.customParam = 0;
wi.customStyle = 0;
ghLabel_1_date = gwinLabelCreate(0, &wi);
gwinLabelSetBorder(ghLabel_1_date, FALSE);
gwinSetFont(ghLabel_1_date, dejavu_sans_16);
gwinRedraw(ghLabel_1_date);
/* Other child widgets of ghContainer01_main here, not shown */
/* ... */
}
I'm trying to understand the source of the double refresh:
Could be due to the actual button event being generated twice due to some sort of button debounce problem, althoughit seems unlikely. As I understand it, there is no queue for events so if multiple events are fired all subsequent events will be dropped until we come back to a blocking wait in geventEventWait(...).
Could be due to some child widgets needing to be redrawn after the initial redraw of the page. Could child widgets needing to be redraw trigger a redraw of the parent container? Seems unlikely again, especially since I get this with even the most basic container with a single label as child.
Brain fart from my part, highly likely
Thanks for the great software and tools you are putting together, and for any support on this matter.
By the way, are there any plans to open source the uGFX Studio? I'm willing to contribute some minor bugfixes.
Have a nice day
Sébastien