GIGA Display Shield emWin Guide
Learn how to use the emWin library with the GIGA Display Shield.
Introduction
Segger's emWin is a graphical framework for building powerful UIs, and is fully compatible with the GIGA Display Shield. It allows you to build UIs, using pre-made widgets like buttons, images, loading bars, sliders, checkboxes, etc. It also allows you to fully customize the screenspace on the display. In this guide, we will go through some of the different components, so you can learn how to best implement it in your projects.
Hardware & Software Needed
Downloading the Library and Core
The GIGA R1 core includes the Arduino_H7_Video library that handles the display.
In this guide, we will be using three different libraries:
- Arduino_H7_Video, this one is bundled with the core, so make sure you have the latest version of the Mbed core installed.
- Arduino_GigaDisplayTouch, handles touch on the GIGA Display Shield
- emWin-Arduino-Library
To install them, open the library manager and install the latest version by searching for "emWin" and "Arduino_GigaDisplayTouch".
In the sketch include the emWin library like this:
1#include "DIALOG.h"
There is no need to include the "Arduino_GigaDisplayTouch" library separately, as it is already incorporated within the emWin library.
emWin Library Setup
In this section, we will go through the fundamental elements of an emWin sketch:
- How to define & configure the display,
- how to create a grid layout,
- how to add an object to the grid,
- how to update the display.
emWin Screen Configuration
When creating elements, information about the screen and placement needs to be provided. The provided code initializes the emWin library, configuring display and touch controller settings. It sets the display to landscape mode, enables multi-buffering for the Windows manager, and creates a main window for content rendering.
Full Example:
1void setup() {2 /* Init SEGGER emWin library. It also init display and touch controller */3 GUI_Init();4
5 LCD_ROTATE_SetSel(1); /* Set landscape mode */6 WM_MULTIBUF_Enable(1); /* Enable multi buffering mode for Windows manager */7
8 /* Create the main window. It will include all the sub-windows */9 WM_CreateWindowAsChild(0, 0, LCD_GetXSize(), LCD_GetYSize(), WM_HBKWIN, WM_CF_SHOW, _cbWin, 0);10}
Window Manager
The examples in this tutorial will be using the window manager method. This makes it easier to manage the screen elements and widgets. However, it is also possible to create emWin sketches without the window manager, which will be shown in this section.
Here is an example that sets the screen background color to green and prints the text "Hello world" in red on the screen. Lets first take a look at how this would look without the window manager:
1#include <DIALOG.h>2
3void setup() {4 GUI_Init();5 GUI_MULTIBUF_Begin();6 GUI_SetBkColor(GUI_GREEN);7 GUI_Clear();8 GUI_SetColor(GUI_RED);9 GUI_DispString("Hello world");10 GUI_MULTIBUF_End();11}12
13void loop() {14 GUI_Exec();15}
And to get the same result with a window manager, it would look like this:
1#include "DIALOG.h"2
3static void _cbWin(WM_MESSAGE * pMsg) {4 switch (pMsg->MsgId) {5 case WM_PAINT:6 GUI_SetBkColor(GUI_GREEN);7 GUI_Clear();8 GUI_SetColor(GUI_RED);9 GUI_DispString("Hello world");10 break;11 default:12 WM_DefaultProc(pMsg);13 break;14 }15}16
17void setup() {18 GUI_Init();19 WM_MULTIBUF_Enable(1);20 WM_CreateWindowAsChild(0, 0, LCD_GetXSize(), LCD_GetYSize(), WM_HBKWIN, WM_CF_SHOW, _cbWin, 0);21}22
23void loop() {24 GUI_Exec();25}
Using the window manager method is more complex and require more lines of code, but this method helps with keeping your GUI structured as it gets more elements and widgets to display. For example with the window manager it is impossible to overwrite areas outside a windows designated area. For simpler applications, the window manager may not be needed. Keep this in mind when developing your own emWin solutions! For more information, navigate over to the emWin on Arduino documentation.
Creating a Grid Layout
To create different windows inside our display, use the
WM_CreateWindowAsChild()
function. Here is the function with the parameters that should be given:1WM_CreateWindowAsChild(X-position, Y-position, Height, Width, ParentWindow, VisibilityFlag, WindowsCallback, AdditionalBytes);
This is how it would look to use emWin to create a 2x2 grid layout inside the main window:
Full Example:
1static void _cbWin(WM_MESSAGE * pMsg) {2 switch (pMsg->MsgId) {3 case WM_CREATE:4 /* [0, 0] - Image */5 WM_CreateWindowAsChild(20, 20, 370, 210, pMsg->hWin, WM_CF_SHOW, _cbChildWinImg, 0);6
7 /* [1, 0] - Slider */8 WM_CreateWindowAsChild(20, 210+20*2, 370, 210, pMsg->hWin, WM_CF_SHOW, _cbChildWinSlider, 0);9
10 /* [0, 1] - Checkbox, button and labels */11 WM_CreateWindowAsChild(370+20*2, 20, 370, 210, pMsg->hWin, WM_CF_SHOW, _cbChildWinChkBtn, 0);12
13 /* [1, 1] - Progress bar */14 WM_CreateWindowAsChild(370+20*2, 210+20*2, 370, 210, pMsg->hWin, WM_CF_SHOW, _cbChildWinPgrBar, 0);15 break;16 case WM_PAINT:17 GUI_SetBkColor(0x03989e); /* Background color set to: R(0x03),G(0x98),B(0x9E) */18 GUI_Clear();19 break;20 default:21 WM_DefaultProc(pMsg);22 break;23 }24}
Update Loop
In the loop of any emWin sketch, the bare minimum that needs to be called is
GUI_Exec()
. This will keep the engine alive, handle touch events for the rest of the sketch among other things.1void loop(){2 GUI_Exec();3}
Visual Elements
Image
To be able to display an image it first needs to be defined. bmarduinologo is the filename of the image. The image file needs to be in the same folder as the sketch. The image needs to be referenced like this:
1extern GUI_CONST_STORAGE GUI_BITMAP bmarduinologo; /* Image bitmap structure (see img_arduinologo_emwin.c in attach) */
To convert images into the emWin format, you can use the emWin Bitmap Converter tool.
Now the image can be drawn by specifying the image file along with the x and y position. Like this:
1GUI_DrawBitmap(&bmarduinologo, X-position, Y-position);
Full Example:
Remember that the image file needs to be in the same folder as the sketch, use the image that comes with the full demo (File > Examples > Arduino_H7_Video > emWinDemo).
1#include "DIALOG.h"2
3extern GUI_CONST_STORAGE GUI_BITMAP bmarduinologo; /* Image bitmap structure (see img_arduinologo_emwin.c in attach) */4
5static void _cbWin(WM_MESSAGE * pMsg) {6 switch (pMsg->MsgId) {7 case WM_CREATE:8 break;9 case WM_PAINT:10 GUI_SetBkColor(GUI_WHITE);11 GUI_Clear();12 /* Draw image */13 GUI_DrawBitmap(&bmarduinologo, 85, 35);14 break;15 default:16 WM_DefaultProc(pMsg);17 break;18 }19}20
21void setup() {22 /* Init SEGGER emWin library. It also init display and touch controller */23 GUI_Init();24
25 LCD_ROTATE_SetSel(1); /* Set landscape mode */26 WM_MULTIBUF_Enable(1); /* Enable multi buffering mode for Windows manager */27
28 /* Create the main window.*/29 WM_CreateWindowAsChild(0, 0, LCD_GetXSize(), LCD_GetYSize(), WM_HBKWIN, WM_CF_SHOW, _cbWin, 0);30}31
32void loop() {33 /* Keep emWin alive, handle touch and other stuff */34 GUI_Exec();35}
Text
Most widgets have label functions attached to them. However if you want to print something independent of a widget you can use the
GUI_DispString("")
function. This will display any text put in as a parameter.Calling
GUI_SetColor()
before the text print will allow you to change the color of the text that is then printed. Here you can find the colors available.For changing the font size, use
GUI_SetFont(&GUI_Font16_1);
, this call will set the font size to 16.Full Example:
1#include "DIALOG.h"2
3static void _cbWin(WM_MESSAGE * pMsg) {4 switch (pMsg->MsgId) {5 case WM_PAINT:6 GUI_SetBkColor(GUI_GREEN);7 GUI_Clear();8 GUI_SetColor(GUI_RED);9 GUI_SetFont(&GUI_Font16_1);10 GUI_DispString("Hello world");11 break;12 default:13 WM_DefaultProc(pMsg);14 break;15 }16}17
18void setup() {19 GUI_Init();20 WM_MULTIBUF_Enable(1);21 WM_CreateWindowAsChild(0, 0, LCD_GetXSize(), LCD_GetYSize(), WM_HBKWIN, WM_CF_SHOW, _cbWin, 0);22}23
24void loop() {25 GUI_Exec();26}
Functional Elements
Checkbox
Like with other widgets this line creates the checkbox widget:
1hBox = CHECKBOX_CreateEx(X-position, Y-position, Height, Width, pMsg->hWin, WM_CF_SHOW, 0, GUI_ID_CHECK0);
If we want a label next to the checkbox, use
CHECKBOX_SetText(hBox, "Check");
. Where you specify the checkbox the text belongs to and what the text should say. The font and color can then be set for the text with the following lines of code:1CHECKBOX_SetText(hBox, "Check");2 CHECKBOX_SetTextColor(hBox, GUI_BLACK);3 CHECKBOX_SetFont(hBox, &GUI_Font16_1);
Then for the state of the checkbox the number of states and where it should start will be determined by these lines:
1CHECKBOX_SetNumStates(hBox, 3);2 CHECKBOX_SetState(hBox, 1);
Full Example:
1#include "DIALOG.h"2
3static void _cbChildWinCheck(WM_MESSAGE * pMsg) {4 static WM_HWIN hBox;5 BUTTON_Handle hButton;6 int NCode, Id;7 char acBuffer[32];8 int State;9 static int Clicked, Released;10
11 switch(pMsg->MsgId) {12 case WM_CREATE:13 /* Create CHECKBOX widget */14 hBox = CHECKBOX_CreateEx((LCD_GetXSize()/2), (LCD_GetYSize()/2), 80, 40, pMsg->hWin, WM_CF_SHOW, 0, GUI_ID_CHECK0);15 /* Edit widget properties */16 CHECKBOX_SetText(hBox, "Check");17 CHECKBOX_SetTextColor(hBox, GUI_BLACK);18 CHECKBOX_SetFont(hBox, &GUI_Font16_1);19 /* Set number of possible states to 3 (if needed). The minimum number of states is 2 and the maximum is 3 */20 CHECKBOX_SetNumStates(hBox, 3);21 /* Manually set the state */22 CHECKBOX_SetState(hBox, 1);23 break;24 case WM_PAINT:25 GUI_SetBkColor(GUI_WHITE);26 GUI_Clear();27
28 /* Display current CHECKBOX state */29 State = CHECKBOX_GetState(hBox);30 sprintf(acBuffer, "State of checkbox: %d", State);31 GUI_DispStringAt(acBuffer, 10, 60);32 break;33
34 case WM_NOTIFY_PARENT:35 /* Get Id of sender window and notification code */36 Id = WM_GetId(pMsg->hWinSrc);37 NCode = pMsg->Data.v;38
39 switch (Id) {40 case GUI_ID_CHECK0:41 switch(NCode) {42 case WM_NOTIFICATION_VALUE_CHANGED:43 /* When the value of the checkbox changed, redraw parent window to update the display of the state */44 WM_InvalidateWindow(pMsg->hWin);45 break;46 }47 break;48 }49 break;50 default:51 WM_DefaultProc(pMsg);52 }53}54
55void setup() {56 /* Init SEGGER emWin library. It also init display and touch controller */57 GUI_Init();58
59 LCD_ROTATE_SetSel(1); /* Set landscape mode */60 WM_MULTIBUF_Enable(1); /* Enable multi buffering mode for Windows manager */61
62 /* Create the main window. It will include all the sub-windows */63 WM_CreateWindowAsChild(0, 0, LCD_GetXSize(), LCD_GetYSize(), WM_HBKWIN, WM_CF_SHOW, _cbChildWinCheck, 0);64}65
66void loop() {67 /* Keep emWin alive, handle touch and other stuff */68 GUI_Exec();69}
Slider
Like the other widgets this line of code creates it:
1hSlider = SLIDER_CreateEx(X-position, Y-position, Height, Width, pMsg->hWin, WM_CF_SHOW, SLIDER_CF_HORIZONTAL, GUI_ID_SLIDER0);
The specifications of the slider, such as range, number of ticks marks, value and width of the marker are set by the following lines:
1SLIDER_SetRange(hSlider, 0, 100);2 SLIDER_SetNumTicks(hSlider, 10);3 SLIDER_SetValue(hSlider, 20);4 SLIDER_SetWidth(hSlider, 20);
If you want to display the sliders value adjacent to the slider, use the following lines:
1Value = SLIDER_GetValue(hSlider);2 sprintf(acBuffer, "Value: %d", Value);3 GUI_DispStringAt(acBuffer, 110, 120);
sprintf()
will print the value as text and GUI_DispStringAt()
will decide where the text is printed.The GUI will also have to be re-drawn when the value changes so the display stays accurate. This can be achieved with:
1case WM_NOTIFICATION_VALUE_CHANGED:2 WM_InvalidateWindow(pMsg->hWin);3 break;4 }5 break;
Full Example:
1#include "DIALOG.h"2
3static void _cbChildWinSlider(WM_MESSAGE * pMsg) {4 static WM_HWIN hSlider;5 int NCode, Id;6 int Value;7 char acBuffer[32];8
9 switch(pMsg->MsgId) {10 case WM_CREATE:11 /* Create horizonzal slider */12 hSlider = SLIDER_CreateEx(300, 180, 200, 50, pMsg->hWin, WM_CF_SHOW, SLIDER_CF_HORIZONTAL, GUI_ID_SLIDER0);13 /* Set range of slider */14 SLIDER_SetRange(hSlider, 0, 100);15 /* Set number of tick marks */16 SLIDER_SetNumTicks(hSlider, 10);17 /* Set value of slider */18 SLIDER_SetValue(hSlider, 20);19 /* Set width of thumb */20 SLIDER_SetWidth(hSlider, 20);21 break;22 case WM_PAINT:23 GUI_SetBkColor(GUI_WHITE);24 GUI_Clear();25 GUI_SetFont(&GUI_Font16B_1);26 GUI_SetColor(GUI_BLACK);27
28 /* Display slider value */29 Value = SLIDER_GetValue(hSlider);30 sprintf(acBuffer, "Value: %d", Value);31 GUI_DispStringAt(acBuffer, 300, 240);32 break;33 case WM_NOTIFY_PARENT:34 Id = WM_GetId(pMsg->hWinSrc);35 NCode = pMsg->Data.v;36
37 switch(Id) {38 case GUI_ID_SLIDER0:39 switch(NCode) {40 case WM_NOTIFICATION_VALUE_CHANGED:41 /* Redraw the window when a value has changed so the displayed value will be updated */42 WM_InvalidateWindow(pMsg->hWin);43 break;44 }45 break;46 }47 break;48 default:49 WM_DefaultProc(pMsg);50 }51}52
53void setup() {54 /* Init SEGGER emWin library. It also init display and touch controller */55 GUI_Init();56
57 LCD_ROTATE_SetSel(1); /* Set landscape mode */58 WM_MULTIBUF_Enable(1); /* Enable multi buffering mode for Windows manager */59
60 /* Create the main window. It will include all the sub-windows */61 WM_CreateWindowAsChild(0, 0, LCD_GetXSize(), LCD_GetYSize(), WM_HBKWIN, WM_CF_SHOW, _cbChildWinSlider, 0);62}63
64void loop() {65 /* Keep emWin alive, handle touch and other stuff */66 GUI_Exec();67}
Progress Bar
Creating the progress bar is similar to the other widgets:
1PROGBAR_Handle hProg;2hProg = PROGBAR_CreateEx(X-position, Y-position, Height, Width, pMsg->hWin, WM_CF_SHOW, PROGBAR_CF_HORIZONTAL, GUI_ID_PROGBAR0);
The progress bar needs a callback function that will handle the calculation and animation of the progress that is being displayed. The progress bar and callback function that should be linked are defined in the
WM_SetCallback()
function, like so:1WM_SetCallback(hProg, _cbProgbar);
To display the progress on the progress bar, a rectangle will have to be drawn inside of the existing progress bar, like this:
1WM_GetClientRect(&Rect);2 GUI_SetColor(GUI_BLACK);3 GUI_AA_DrawRoundedRectEx(&Rect, 3);
The progress bars value, or the progress of it can be calculated and displayed with these lines:
1Value = PROGBAR_GetValue(pMsg->hWin);2 ValueF = Value / 100.0F;3 sprintf(acBuffer, "Progress: %d%%", Value);
In the
void loop()
of the sketch the calculation of time for the animation needs to be defined. Here the reset of the progress bar will also be set. Using PROGBAR_SetValue(progressbar, progressbarcount)
the value of the progress bar can be set from the loop()
. Then it can be redrawn to show how it updates.1if (millis() - previousMillis >= 100) {2 previousMillis = millis();3 progbarCnt++;4 if (progbarCnt > 100) {5 progbarCnt = 0;6 }7 PROGBAR_SetValue(hProg, progbarCnt);8 WM_InvalidateWindow(hProg); /* Make sure the entire PROGBAR gets redrawn */9 }
Full Example:
1#include "DIALOG.h"2
3PROGBAR_Handle hProg;4
5static void _cbChildWinPgrBar(WM_MESSAGE * pMsg) {6 GUI_RECT Rect;7 float ValueF;8 int Value;9 char acBuffer[16];10
11 switch (pMsg->MsgId) {12 case WM_CREATE:13 hProg = PROGBAR_CreateEx(250, 150, 200, 30, pMsg->hWin, WM_CF_SHOW, PROGBAR_CF_HORIZONTAL, GUI_ID_PROGBAR0);14 WM_SetCallback(hProg, _cbProgbar);15 break;16 case WM_PAINT:17 GUI_SetBkColor(GUI_WHITE);18 GUI_Clear();19 break;20 default:21 WM_DefaultProc(pMsg);22 break;23 }24}25
26static void _cbProgbar(WM_MESSAGE * pMsg) {27 GUI_RECT Rect;28 float ValueF;29 int Value;30 char acBuffer[16];31
32 switch (pMsg->MsgId) {33 case WM_PAINT:34 GUI_SetBkColor(GUI_WHITE);35 GUI_Clear();36 /* Draw progress bar */37 WM_GetClientRect(&Rect);38 GUI_SetColor(GUI_BLACK);39 GUI_AA_DrawRoundedRectEx(&Rect, 3);40 Value = PROGBAR_GetValue(pMsg->hWin);41 ValueF = Value / 100.0F;42 sprintf(acBuffer, "Progress: %d%%", Value);43 Rect.x0 += 2;44 Rect.y0 += 2;45 Rect.x1 -= 2;46 Rect.y1 -= 2;47 Rect.x1 = Rect.x1 * (ValueF);48 GUI_SetColor(GUI_GRAY_9A);49 GUI_AA_FillRoundedRectEx(&Rect, 1);50 WM_GetClientRect(&Rect);51 Rect.x0 += 2;52 Rect.y0 += 2;53 Rect.x1 -= 2;54 Rect.y1 -= 2;55 GUI_SetColor(GUI_BLACK);56 GUI_SetTextMode(GUI_TM_TRANS);57 GUI_SetFont(&GUI_Font16B_1);58 GUI_DispStringInRect(acBuffer, &Rect, GUI_TA_HCENTER | GUI_TA_VCENTER);59 break;60 default:61 PROGBAR_Callback(pMsg);62 break;63 }64}65
66int progbarCnt = 0;67unsigned long previousMillis = 0;68
69void setup() {70 /* Init SEGGER emWin library. It also init display and touch controller */71 GUI_Init();72
73 LCD_ROTATE_SetSel(1); /* Set landscape mode */74 WM_MULTIBUF_Enable(1); /* Enable multi buffering mode for Windows manager */75
76 /* Create the main window. It will include all the sub-windows */77 WM_CreateWindowAsChild(0, 0, LCD_GetXSize(), LCD_GetYSize(), WM_HBKWIN, WM_CF_SHOW, _cbChildWinPgrBar, 0);78}79
80void loop() {81 /* Update progress bar value */82 if (millis() - previousMillis >= 100) {83 previousMillis = millis();84 progbarCnt++;85 if (progbarCnt > 100) {86 progbarCnt = 0;87 }88 PROGBAR_SetValue(hProg, progbarCnt);89 WM_InvalidateWindow(hProg); /* Make sure the entire PROGBAR gets redrawn */90 }91
92 /* Keep emWin alive, handle touch and other stuff */93 GUI_Exec();94}
Button
Like the other widgets, this one is created with:
1hButton = BUTTON_CreateEx(10, 100, 80, 20, pMsg->hWin, WM_CF_SHOW, 0, ID_BUTTON);
And to set the text on the button, use:
1BUTTON_SetText(hButton, "Click me");
To check for the button being pressed, you can use two integers,
Clicked
and Released
. Then simply put these inside the if()
statements to make them trigger whenever the button is pressed or released.1static int Clicked, Released;2
3if(Clicked) {4 sprintf(acBuffer, "Button was clicked at: %d.", Clicked);5 GUI_DispStringAt(acBuffer, 10, 130);6}7if(Released) {8 sprintf(acBuffer, "Button was released at: %d.", Released);9 GUI_DispStringAt(acBuffer, 10, 150);10}
Full Example:
1#include "DIALOG.h"2
3#define ID_BUTTON 14
5static void _cbChildWinBtn(WM_MESSAGE * pMsg) {6 static WM_HWIN hBox;7 BUTTON_Handle hButton;8 int NCode, Id;9 char acBuffer[32];10 int State;11 static int Clicked, Released;12
13 switch(pMsg->MsgId) {14 case WM_CREATE:15 /* Create a button */16 hButton = BUTTON_CreateEx(300, 150, 120, 80, pMsg->hWin, WM_CF_SHOW, 0, ID_BUTTON);17 BUTTON_SetText(hButton, "Click me");18 break;19 case WM_PAINT:20 GUI_SetBkColor(GUI_WHITE);21 GUI_Clear();22 GUI_SetFont(&GUI_Font16_1);23 GUI_SetColor(GUI_BLACK);24
25 /* Check button state and print info on labels */26 if(Clicked) {27 sprintf(acBuffer, "Button was clicked at: %d.", Clicked);28 GUI_DispStringAt(acBuffer, 300, 240);29 }30 if(Released) {31 sprintf(acBuffer, "Button was released at: %d.", Released);32 GUI_DispStringAt(acBuffer, 300, 260);33 }34 break;35 case WM_NOTIFY_PARENT:36 /* Get Id of sender window and notification code */37 Id = WM_GetId(pMsg->hWinSrc);38 NCode = pMsg->Data.v;39
40 switch (Id) {41 case ID_BUTTON:42 switch(NCode) {43 case WM_NOTIFICATION_CLICKED:44 Clicked = GUI_GetTime();45 WM_InvalidateWindow(pMsg->hWin);46 break;47 case WM_NOTIFICATION_RELEASED:48 Released = GUI_GetTime();49 WM_InvalidateWindow(pMsg->hWin);50 break;51 }52 break;53 break;54 }55 break;56 default:57 WM_DefaultProc(pMsg);58 }59}60
61void setup() {62 /* Init SEGGER emWin library. It also init display and touch controller */63 GUI_Init();64
65 LCD_ROTATE_SetSel(1); /* Set landscape mode */66 WM_MULTIBUF_Enable(1); /* Enable multi buffering mode for Windows manager */67
68 /* Create the main window. It will include all the sub-windows */69 WM_CreateWindowAsChild(0, 0, LCD_GetXSize(), LCD_GetYSize(), WM_HBKWIN, WM_CF_SHOW, _cbChildWinBtn, 0);70}71
72void loop() {73 /* Keep emWin alive, handle touch and other stuff */74 GUI_Exec();75}
Conclusion
This guide went through the building blocks of the different components that can be implemented with emWin. To see these examples in a full running example sketch go to File > Examples > Arduino_H7_Video > emWinDemo.
This demo sketch will show the different components using a screen manager in a 2x2 grid.
Next Step
emWin is a comprehensive library and GUI framework that has a lot of customizability, if you are interested in playing around more with it, you can find many different examples and widgets on the official website for Segger® emWin. The code on the website can easily be adapted into a sketch for the GIGA Display Shield.
Suggest changes
The content on docs.arduino.cc is facilitated through a public GitHub repository. If you see anything wrong, you can edit this page here.
License
The Arduino documentation is licensed under the Creative Commons Attribution-Share Alike 4.0 license.