A short video showing creation of GUI pages and how to integrate these into a MaaXBoard RT embedded application is available on-demand (link below)
- Project detailed procedure : http://avnet.me/maaxRT-gui
- Project source files (github) : http://avnet.me/maaxRT-gui-workshop
- Project on-demand video : http://avnet.me/maaxRT-gui-workshop-video
MaaXBoard RT is a low-cost dual-purpose, NXP i.MX RT1176 based single board computer optimized for use as a low-cost development board and to embed in OEM products.
This article will provide a step-by-step guide to creating a GUI application running on the MaaXBoard RT. The GUI design and implementation is done using the free GUI Guider tool from NXP.
2. GUI GuiderGUI Guider is a WYSIWYG (What You See Is What You Get) designer IDE supporting UI design by drag and drop. GUI Guider enables the rapid development of high quality displays with the open-source LVGL graphics library.
2.1. Download GUI GuiderFrom the GUI Guider main page, download and install a copy of the GUI Guider application. An NXP account is required for the download.
3. Creating a GUI projectOnce GUI Guider is installed, launch the application. In the welcome window perform the following:
- Select the LVGL version, in this example we are using LVGL7
- Pick a name for the project
- Select a project directory
Next, we need to specify the hardware details, this is simplified through selecting the correct board template which in this case is an MIMXRT1176xxxxx.
GUI Guider provides several templates that can be used as a starting point for the design. We will select the EmptyUI template since we are creating our own design.
Once all the fields are completed and templates selected, press the Create button to create the project.
The designer window will now be available with a blank page.
We will now explore some of the GUI Guider features that will be used in this article. For additional information, refer to the GUI Guider v1.3.0 User's Guide from NXP.
4.1. WidgetsGUI Guider provides a variety of graphical widgets that are used in creating a rich user interface. These widgets are available from the Widget tab.
Once screens are created and widgets are placed, these resources would be shown in the Resource tab.
Graphics and images used in the project are imported into the workspace and can be found in the Import tab.
Widgets can be customized in a variety of ways and each widget type has unique properties that define the widget’s visual design and behavior. These properties can be accessed from the right side of the screen. Once a widget is selected by clicking on it, all the properties of that widget will be displayed in the Widget tab.
Widget action can be customized to integrate into the project, actions are defined in the Event tab. In the this example, the button widget event will be triggered upon release and will call the “openAVScreen();” function defined in the MCUXpresso project. A header file can also be added in the include window that defines the function that is used for the event.
In this guide we will be creating three pages that will provide a good starting point to implementing more complex user interfaces. The three pages are the following
- Main menu
- LED Control
- Audio Graph
Since the MCUXpresso project will need to interact with the graphical object created in GUI Guider, it is critical to keep the naming of these objects consistent otherwise the compilation of the MCUXpresso project will fail due to missing variables. The names of the objects will be provided for each screen, so take great care in defining the object names as provided.
5.2. The Main Menu pageClick on the Resource tab an select the "screen" page. From the right side of the IDE, click the Widget tab. Use the background slider to set the opaque setting to 100% i.e., no transparency. Here you may also change the background color but in this example, we will stick with a white background. The required names of the objects on this screen are as follows:Page name – main_screenLED screen navigation button – led_screen_btnAudio screen navigation button – audio_screen_btn
From the Widgets tab, locate the button widget and drag and drop two buttons onto the page.
Click on each button and adjust their visual properties from the Widget tab on the right side of the IDE. In this area, you can rename the button change its dimensions and position on the screen. We labeled the buttons LED CONTROL and AUDIO GRAPH respectively.
Similarly, other widgets like images and labels can be added to the page for a rich user experience. The images and labels are not accessed from the MCUXpresso source code so the names of these objects are not critical and default names are acceptable.
Once the main page is completed, you may like to see how the design would look on the display and check for functionality. The GUI Guider provides a simulator feature that allows the user to view and test their GUI design. To run the simulator, press the Run Simulator button on the top of the IDE and select C.
The built-in compiler will compile, build and launch the generated code in the simulator window.
In the Resource tab press the [+] button which will create a new screen. Choose a name for the screen and press submit. The newly created screen will be visible in the Resource tab. Navigate between screens by clicking on the screen name.
Click on the newly created screen and then switch to the Widgets tab. Add 3 buttons and 3 LEDs to the page. These buttons will be used to control the onboard LEDs and the LEDs on the screen will mimic the physical onboard LED statuses.The required names of the objects on this screen are as follows: Page name – led_screenRed LED – red_ledGreen LED – green_ledBlue LED - blue_ledRed LED button – red_led_btnGreen LED button – green_led_btnBlue LED button - blue_led_btnHome button - home_btn_1
As before, size, label and position the widgets on the page using the Widget tab on the right. Modify the LED color properties. This is done by selecting the LED and changing its color properties. The shape and style of the LED can also be modified in the Widget tab to produce an esthetically pleasing widget. Do this for the remaining two LEDS using green and blue to represent the onboard RGB LED.
Create a new screen as shown earlier, this screen will be the Audio Graph page. Once the screen is created, add a chart and four checkboxes to this page. Size and label these widgets as desired.
Once multiple screens are added, navigation between screens becomes necessary. A home button is the simplest way to go back to the main menu screen from where the user can navigate to a different page. Let's add a graphical home button to both the LED Control page and the Audio Graph page. From the Widgets tab, drag and drop an image button widget and assign it a graphic of your choice as shown below.
Now that the three pages have been created, we need to provide a way to navigate between them. This is accomplished in the widget Event tab.
1. Select the widget that you would like to add an event to2. Press the [+] button to add an event3. Select the event trigger, in this case we use the clicked event4. Select the target widget, in this case we will select the LED Control page5. select the action to perform which in this case is a Load Screen action
We perform the same steps to the Audio Graph button except we now select the target widget to be the Audio Graph screen.
The home button on each of the other screens needs to be also assigned an event that would load the Home Screen once pressed. It is recommended for non-button widgets to use the released trigger event to perform an action. In the case of the home button, the screen will switch once the user removes their finger from the touchscreen.
Once all the navigation buttons have been assigned events, launch the simulator as described earlier and test the screen navigation buttons.
GUI Guider provides mechanisms to incorporate C or Python code into the design. This provides flexibility and better integration with the embedded project code. Only C code will be used in this guide.
7.1. Connecting the navigation buttons to the embedded applicationThere are several ways to implement GUI integration with the embedded application. This guide will provide a method for reference using Customer Code events, feel free to implement the interface in a different way to better fit your own application.
Starting with the main screen
1. Click on the LED Control button to select it2. Press the [+] button in the Event tab to add a new event.3. Select the event trigger, in this case we use the clicked event4. The target widget must be set to NULL since this will be a C code event5. Select the action to perform which in this case is a Customer Code action6. Code type is C code7. Add the custom.h header file by adding the line #include "custom.h"8. Add the function that needs to be called when the event is triggered our function is called NavigateToLEDScreen();
Repeat these steps for the remaining navigation buttons on all the screens. The predefined navigation functions in this guide are the following:
1. Navigate to LED screen - NavigateToLEDScreen();2. Navigate to Audio screen - NavigateToAudioScreen();3. Home Button - NavigateToHomeScreen();
7.2 Adding clicked events to the LED buttonsFor each of the LED control buttons create a clicked event with Customer Code action as shown previously. In the Code section add the following code to each of the buttons.
Red button
LEDRedState = !LEDRedState;
ToggleLEDState(eLEDRed, LEDRedState);
Green button
LEDGreenState = !LEDGreenState;
ToggleLEDState(eLEDGreen, LEDGreenState);
Blue button
LEDBlueState = !LEDBlueState;
ToggleLEDState(eLEDBlue, LEDBlueState);
Essentially what this code is doing is toggling a flag representing the state of the LED and calling an update function to execute the physical LED state change.
7.3 Adding clicked events to the microphone checkboxesSimilarly, to the LED buttons, we create events for each of the microphones on the audio page, the events however are Value Changed event types. In the Code section add the following code to each of the checkboxes.
MIC1
MIC1Checked = !MIC1Checked;
ToggleMicState(1, MIC1Checked);
MIC2
MIC2Checked = !MIC2Checked;
ToggleMicState(2, MIC2Checked);
MIC3
MIC3Checked = !MIC3Checked;
ToggleMicState(3, MIC3Checked);
MIC4
MIC4Checked = !MIC4Checked;
ToggleMicState(4, MIC4Checked);
At this stage, the GUI design is complete however the project will not compile or run in the simulator until we define the flags and functions that we added.
8. The GUI Guider folder structureBelow is an outline of the typical folder structure of a GUI Guider project. Locate and explore the directory of your project, we will need some of these resources later in this guide.
Locate the custom.c and custom.h files located in the custom folder of your project. These files key to successfully integrating the GUI logic with the embedded logic.
Copy and paste the below code in the respective files. You may recognize the flags and functions in these files since they were used in the previous steps.
custom.h
/*
* custom.h
*
* Created on: July 29, 2020
* Author: nxf53801
*/
#ifndef __CUSTOM_H_
#define __CUSTOM_H_
#include "gui_guider.h"
typedef enum
{
eLEDRed = 0,
eLEDGreen,
eLEDBlue,
}eLED;
void custom_init(lv_ui *ui);
void NavigateToLEDScreen();
void NavigateToAudioScreen();
void NavigateToHomeScreen();
void ToggleLEDState(eLED led, bool state);
void ToggleMicState(int mic, bool state);
extern volatile bool LEDRedState;
extern volatile bool LEDGreenState;
extern volatile bool LEDBlueState;
extern volatile bool MIC1Checked;
extern volatile bool MIC2Checked;
extern volatile bool MIC3Checked;
extern volatile bool MIC4Checked;
#endif /* EVENT_CB_H_ */
custom.c
/**
* @file custom.c
*
*/
/*********************
* INCLUDES
*********************/
#include <stdio.h>
#include "lvgl/lvgl.h"
#include "custom.h"
#if (LV_USE_GUIDER_SIMULATOR != 1)
#include "lvgl_demo.h"
#include "demo_common.h"
#endif
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC VARIABLES
**********************/
volatile bool LEDRedState;
volatile bool LEDGreenState;
volatile bool LEDBlueState;
volatile bool MIC1Checked;
volatile bool MIC2Checked;
volatile bool MIC3Checked;
volatile bool MIC4Checked;
/**
* Create a demo application
*/
void custom_init(lv_ui *ui)
{
/* Add your codes here */
}
#if (LV_USE_GUIDER_SIMULATOR == 1)
void NavigateToLEDScreen()
{
}
void NavigateToAudioScreen()
{
}
void NavigateToHomeScreen()
{
}
void ToggleLEDState(eLED led, bool state)
{
}
void ToggleMicState(int mic, bool state)
{
}
#else
void NavigateToLEDScreen()
{
openLEDScreen();
}
void NavigateToAudioScreen()
{
openAVScreen();
}
void NavigateToHomeScreen()
{
openMenuScreen();
}
void ToggleLEDState(eLED led, bool state)
{
switch (led)
{
case eLEDRed:
set_red_led(state);
break;
case eLEDGreen:
set_green_led(state);
break;
case eLEDBlue:
set_blue_led(state);
break;
default:
break;
}
}
void ToggleMicState(int mic, bool state)
{
enableMic(mic, state);
}
#endif
10. Separating Simulator code from Embedded codeIt is important to note that some of the functions, variables and header files in the custom.c and custom.h files may not be available when using the simulator therefore the GUI project will fail the compilation and the simulator becomes unusable. One way to resolve this issue is to create dummy variables and functions that will only be used under simulation, this may be useful if you would like to add specialized code to only run during simulation for testing etc.
Conditional compilation can be used to separate simulator code from embedded code. The LV_USE_GUIDER_SIMULATOR define can be used to achieve this. The LV_USE_GUIDER_SIMULATOR define is at the bottom of the lv_conf.h file which is located in the source folder of the embedded project.
lv_conf.h
#define LV_USE_GUIDER_SIMULATOR 0
11. Compiling the final GUI projectAt this point the GUI project is ready and can be compiled and tested in the simulator. At the top of the IDE press the Generate Code button and verify that there are no errors displayed in the Log Information pane.
The required resources to integrate the GUI design into an MCUXpresso project are the following.
1. custom folder which contains logic we implemented2. generate folder containing all required fonts, graphics, screens an so on3. lvgl folder which is the lvgl library source files4. lv_conf.h file used to configure the lvgl library for the project
To generate the required resources to be used within the MCUXpresso project, from the file menu select File->Export Code->MCUxCode. The "Select Export Path window" will open. Navigate to a desired temporary folder location and press "Select folder" to save. Note: it is important to choose file paths that do not contain spaces.
Download the GUI Demo lite project as a zip file from the project repo page and import it into MCUXpresso. The steps to import a project to MCUXpresso are documented in the README file of the project repo. The below image shows the project structure and identifies required GUI Guider resource locations. A sample GUI Guider project is included for reference.
Note: It is strongly recommended to compile and run the project on the hardware prior to making changes to validate the setup.
Once a test run of the original MCUXpresso project is performed, substitute the numbered resources above with the ones that were exported in the previous step. The lvgl folder is not exported and can be either kept unaltered or copied directly from the GUI Guider workspace folder. Rebuild the project and run it on the MaaXBoard RT. Your design should now be running and visible on the display.
Note: Don't forget to verify the LV_USE_GUIDER_SIMULATOR define at the bottom of the lv_conf.h is set to 0.
#define LV_USE_GUIDER_SIMULATOR 0
Note: MCUXpresso will sometimes exclude folders from the build when they are deleted and then replaced while the project is open in the IDE. To resolve this issue, right click on the above-mentioned folders and make sure that the exclude from build checkbox is unchecked.
Functions that interface with the GUI are located in two files, lvgl_demo.c and demo_common.c. The functions below were called from the custom.c file described earlier in this guide, these functions are used for the GUI events such as navigation, toggling of LEDs and enabling specific microphones.
lvgl_demo.c functions
//
//GUI Event functions
//
void openMenuScreen()
void openLEDScreen()
void openAVScreen()
void enableMic(int mic, bool state)
//
//Functions to change LED state on the GUI
//
void setLedRedImgState(bool state)
void setLedGreenImgState(bool state)
void setLedBlueImgState(bool state)
//
//Function to change to enable and disable a specific microphone on the GUI
//
void enableInactiveMicCheckboxes(bool state)
//
//Function to update the audio graph with the enabled microphone data
//
void addMicData(int mic, int16_t value)
demo_common.c functions
//
//GUI Event functions
//
void set_red_led(bool state)
void set_green_led(bool state)
void set_blue_led(bool state)
12.3 LVGL Library APIsSome of the functions above will call LVGL library APIs, the details of these APIs are well documented and beyond the scope of this guide. Please refer to the LVGL README document in the lvgl folder and online.
13. ConclusionThis guide illustrates a subset of the GUI Guider capabilities, please refer to the GUI Guider page for more information. Hopefully you find this guide helpful. If you have questions, comments, or suggestions, please leave them in the Comments section. Thank you.
Note!In absence of a MaaXBoard RT board or it's 7-inch MIPI DSI display, your custom GUI pages can still be exercised using GUI Guider's built-in simulator. Refer to the 30 minute video for a brief introduction to creating pages in GUI Guider and what is possible with MaaXBoard RT:http://avnet.me/maaxRT-gui-workshop-video
Comments
Please log in or sign up to comment.