1. Abstract¶
The emWin embedded graphics library developed by SEGGER Microcontroller is now offered by Dialog Semiconductor in library form for free commercial use with the SmartBond® DA1469x wireless microcontrollers. The software bundle offered by Dialog Semiconductor includes the emWin Color basic package, the Window Manager/Widgets module including the GUI Builder, the Memory Devices module for flicker-free animation, the Antialiasing module for smooth display of curves, lines and fonts and the Font Converter. The emWin can be used in any application from battery-powered single chip products with basic graphic needs, to high-end embedded systems that demand ultra-high performance, and sophisticated animations.
2. Figures¶
Fig. 1 Graphics Display Interface (GDI) Layer
Fig. 2 GDI File Structure - GDI Sub-Folder
Fig. 3 GDI File Structure - SEGGER Sub-Folder
Fig. 4 Common Memory Layout Schemes
Fig. 5 colour Conversion Scheme
Fig. 6 Display Initialization Sequence Diagram
Fig. 7 Display Update Sequence Diagram
Fig. 8 Read Touch Event Sequence Diagram
Fig. 9 Creating GDI Configuration File
Fig. 10 SmartSnippets Studio - Starting New Session
Fig. 11 SmartSnippets Studio - Switching to QSPI Partition Table Window
Fig. 12 SmartSnippets Studio - Opening Partition Table
Fig. 13 SmartSnippets Studio - Loading XBF data
Fig. 14 SmartSnippets Studio - Burning XBF Data
Fig. 15 SmartSnippets Studio - Identifying Occupied Memory Space
Fig. 16 Converting Images to Bitmap Datastream (Phase 1)
Fig. 17 Converting Images to Bitmap Datastreams (Phase 2)
Fig. 18 SmartSnippets Studio - Loading Bitmap Datastream
Fig. 19 SmartSnippets Studio - Burning Bitmap Datastream
Fig. 20 External Resources - Memory Overview
Fig. 21 Adafruit Capacitive Shield - Enabling the SPI Interface
Fig. 22 Adafruit Capacitive Shield - Enabling Backlight Control
Fig. 23 Adafruit Resistive Shield - Enabling Backlight Control
Fig. 24 DA1469x Pro DevKit - Soldering Pin Headers on Arduino Socket
Fig. 25 DA1469x Pro DevKit - Adding Support for External QSPI RAM
Fig. 26 DA1469x Pro DevKit - Connecting an Adafruit LCD Shield
Fig. 27 DA1469x Pro DevKit - Arduino Socket Pins Diagram
Fig. 28 Identifying the Address of the RTT Control Block
Fig. 29 Opening a J-Link RTT Viewer Window
Fig. 30 Getting Display Log Messages on the J-Link RTT Viewer Window
Fig. 31 Getting Touch Log Messages on the J-Link RTT Viewer Window
Fig. 32 Application Description #1
Fig. 33 Application Description #2
3. Tables¶
4. Terms and definitions¶
CS Chip Select
DMA Direct Memory Access
DevKit Development Kit
FPS Frame Per Second
GDI Graphics Display Interface
HW Hardware
I/O Input Output
ICSP In-Circuit Serial Programming
LCD Liquid Crystal Display
LLD Low-Level Driver
PC Personal Computer
PSRAM Pseudo Static Random Access Memory
QSPI Quad Serial Peripheral Interface
RAM Random Access Memory
RGB Red Green Blue
RTOS Real Time Operating System
RTT Real Time Transfer
SDK Software Development Kit
SMD Surface Mount Device
SoC System on Chip
SW Software
TFT Thin Film Transistor
USB Universal Serial Bus
WM Window Manager
5. Prerequisites¶
SmartSnippets™ Studio Package
Dialog Semiconductor SmartSnippets™ DA1469x SDK
Operating System (Windows or Linux)
DA1469x Pro DevKit and USB Cable
Segger’s J-Link Software Package
Adafruit 2.8’’ TFT Touch Shield
0.1’’ Female Pin Headers
Soldering
APS6404L-SQ-SN PSRAM IC (Optional)
R1005 SMD Resistor - 10-12 kohm (Optional)
6. Graphics Display Interface (GDI)¶
As wearable devices evolve and become more sophisticated, LCD interfaces become more and more an integral part of wearable devices. LCDs designed for wearable systems follow a wide range of interfaces as well as color depths and resolutions. This makes it very challenging for an MCU to support all various combinations and signals without some form of hardware acceleration. The DA1469x family of devices integrates an LCD controller capable of supporting the most commonly used interfaces and color depths. Furthermore, there is a dedicated DMA engine used to fetch pixel data from frame buffers and to transfer that data to the LCD controller, with image geometry and color format awareness. This means that the frame buffers used to accommodate pixel data can be of any size and any supported color format, regardless of the actual output interface and color format.
Icons, graphs and animations are some of the most common ways to communicate events and data towards the end user of a product. Typically, these operations require some kind of data processing by invoking either a hardware accelerator or graphics library. The DA1469x family of devices does not feature any form of graphics acceleration and so, a software approach is used. In this context, the GDI implementation is delivered along with the emWin graphics library provided by SEGGER. This library is designed to provide an efficient, processor- and display controller-independent graphical user interface for any application that operates with a graphical display.
This document aims to provide an in-depth analysis of the Graphics Display Interface (GDI) layer, part of the displays support. Fig. 1 illustrates the whole idea of the GDI entity.
The GDI entity is an intermediate layer that links the graphics library used, in our case this is the emWin solution, with the LCDC adapters. The LCDC adapters are considered an intermediate layer, placed on top of the LCD low lever drivers, which provides multi-thread awareness and guarantees that the system remains awake for as long as the LCD controller is in use, and a drawing operation is in progress. A display-specific configuration file determines the behavior of the GDI layer and because of that there is no need for the developer to modify the GDI layer in case a different display should be supported. To facilitate users, the GDI solution comes with a number of configuration files that support some of the most commonly used LCD displays. However, and in case a different display should be employed, the user should be able to support their displays by creating the appropriate configuration file. A detailed explanation on the contents of a configuration file is given later on in this document.
Table 1 lists all out-of-the-box LCD models along with the integrated display controllers.
Part. No |
Resolution |
Interface |
Controller |
---|---|---|---|
DT280QV10CT |
240x320 |
SPI4 |
ILI9341 |
PSP27801 |
96x96 |
SPI4 |
SSD1351 |
LS013B7DH03 |
128x128 |
Serial Sharp |
|
LS013B7DH06 |
128x128 |
Serial Sharp |
|
LPM012M134B |
240x240 |
JDI Parallel |
|
HM80160A090 |
80x160 |
SPI4 |
ST7735S |
T1D3BP006 |
240x240 |
SPI4 |
ST7789V2 |
T1D54BP002 |
240x240 |
SPI3 |
ST7789V2 |
MCT024L6W240320PML |
240x320 |
SPI4 |
ILI9341 |
E1394AA65 |
468x454 |
SPI4 |
RM69330 |
LPM013M091A |
320x300 |
SPI4 |
NT35350 |
NHD43480272EFASXN |
480x272 |
RGB |
ST7282T2 |
7. GDI File Structure¶
This section briefly tells the file tree of the delivered GDI implementation. The GDI layer has two software components. The first component includes sample code that
demonstrates the GDI layer in combination with the emWin graphics library provided by SEGGER. The second component has two sub-folders called gdi
and segger
.
The gdi
sub-folder hosts the implementation of the GDI layer as well as a number of configuration files that support common LCD displays for out-of-the-box use.
The segger
sub-folder has all emWin-related files as shown in Fig. 3
The
config
folder (1) has all the files that emWin needs to communicate with the DA1469x LCD Controller. All functionality is already configured and because of that the developer does not have to modify anything.The
emwin
folder (2) has the documentation of the emWin graphics library, sample code that demonstrate common emWin features as well as a some emWin tools that can speed up the development of an emWin-based application.The
libemwin
folder (3) has the emWin API and the underlying emWin graphics library.The terms and conditions (4) under which the
emWin
graphics library is released.
8. GDI Configurations¶
Typical GDI configurations include the amount of memory allocated, the amount of memory used by the graphics library, as well as the color format used to represent pixel data.
In specific, emWin
requires some heap memory for its internal operations as well as memory (frame buffers) used to accommodate intermediate pixel data and to display the
image. Typical emWin-based drawing operations require about 9 KB
of heap memory and two frame buffers. The size of a frame buffer depends on the display resolution and
color depth. For instance, a display of 240x320
resolution and RGB565
color depth requires a frame buffer capable of accommodating 240x320x2 = 153,600 bytes
. The
memory that the graphics library allocates can be part of either the system RAM or an external QSPI RAM. To facilitate users further, there is the possibility to put heap
memory and frame buffers in different memory locations. By default, all memory allocated by the graphics library is part of the system RAM.
For color format, there are two different configurations to be taken into consideration. The first configuration concerns the color depth used by the graphics library to
process the various pixel data with the help of the frame buffers. The second configuration concerns the output color depth used by the LCD controller. Note that both the
emWin graphics library and LCD controller can perform color conversions from one format to another. For more information on the color conversion capabilities please see the
corresponding datasheet/user manuals. For instance, and as illustrated in Fig. 5, a static image of RGBA8888
color depth, stored in the
Flash memory, can be converted by emWin to RGB565
color mode. Then, the image stored in the frame buffer can be converted on-the-fly and with zero latency by the LCD
controller to RGB332
color mode.
Table 2 explains all macros that can be used by the developer to customize the GDI layer.
Macro Name |
Default Value |
Description |
---|---|---|
GDI_SINGLE_FB_NUM |
2 |
Number of frame buffers allocated for the various drawing operations. When the multiple buffer feature is used, |
GDI_FB_USE_QSPI_RAM |
dg_configUSE_HW_QSPI2 |
If set to |
GDI_GUI_HEAP_SIZE |
0 |
Size of heap memory, expressed in bytes, allocated by the graphics library. Typical |
GDI_HEAP_USE_QSPI_RAM |
0 |
If set to |
GDI_QSPI_RAM_OFFSET |
0 |
Offset, expressed in bytes, added to the base address of PSRAM before allocating memory. If not defined, memory allocation will start at the base address of QSPI2 controller. |
GDI_PWMLED_BACKLIGHT |
0 |
If set to |
GDI_PWMLED_DUTY_CYCLE_1 |
0 |
Duty cycle of white LED1. This macro is valid only if the LED driver is enabled via |
GDI_PWMLED_DUTY_CYCLE_2 |
0 |
Duty cycle of white LED2. This macro is valid only if the LED driver is enabled via |
GDI_USE_CONTINUOUS_MODE |
0 |
If set to |
GDI_USE_OS_TIMER |
0 |
If set to |
GDI_LCDC_CONFIG |
Not defined |
LCD controller configurations. Typically, this is a structure (adapter level) that holds the settings required to access the target display controller. |
GDI_DISP_OFFSETX |
0 |
Horizontal offset, expressed in pixels, of the top-left pixel of the display’s memory (GRAM). This macro is useful in cases where the first pixel on the display panel does not correspond to the first column of the display’s controller. |
GDI_DISP_OFFSETY |
0 |
Vertical offset, expressed in pixels, of the top-left pixel of the display’s memory (GRAM). This macro is useful in cases where the first pixel of the display panel does not correspond to the first row of the display’s controller. |
GDI_DISP_PRE_DRAW |
Not defined |
Routine to execute before a drawing operation is done (display update). Note that, the declared routine must match specific function declaration (input/output arguments). This macro is useful in cases where a custom display is to be used. |
GDI_DISP_POST_DRAW |
Not defined |
Routine to execute after a drawing operation is done (display update). Note that, the routine declared must match specific function declaration (input/output arguments). This macro is useful in cases where a custom display is to be used. |
GDI_DISP_SET_PARTIAL_UPDATE |
Not defined |
Routine to execute for target display configuration to support partial updates. Note that, the routine declared must match specific function declaration (input/output arguments). This macro is useful in cases where a custom display is to be used. |
GDI_TOUCH_ENABLE |
0 |
If set to 1, touch support is enabled. Otherwise, touch operations cannot be done. |
GDI_TOUCH_INTERFACE |
GDI_TOUCH_INTERFACE_I2C |
The serial interface required to communicate to the touch controller. Currently, two serial interfaces are supported: I2C and SPI. |
GDI_TOUCH_INIT |
Not defined |
Routine to initialize the touch controller the very first time GDI is initialized. Note that, the routine declared must match specific function declaration (input/output arguments). |
GDI_TOUCH_READ_EVENT |
Not defined |
Routine to read touch events from the touch controller. Note that, the routine declared must match specific function declaration (input/output arguments). |
GDI_TOUCH_CONFIG |
Not defined |
Serial controller configurations. Typically, this is a structure (adapter level) that holds the settings required to access the target touch controller. |
USE_COLOR_FORMAT |
CF_NATIVE_AUTO |
Color format used by the graphics library. The default value (native) requires that the preferred color format is defined in the configuration file of the target display. By design, three input colour formats are supported by the GDI layer, that is |
HW_LCDC_FIFO_PREFETCH_LVL |
44 bytes |
Number of bytes that should be received in the internal FIFO of the LCD controller, by the deticated DMA, before the controller starts outputting them towards the target display. Valid values can be selected from the |
GDI_MULTIPLEX_TOUCH_DISPLAY |
0 |
This macro must be set to |
9. Analysing the Contents of a Configuration File¶
This section analyses the typical structure of a configuration file. It provides a thorough description of the default LCD model, that is DT280QV10CT
, as well as
peculiarities encountered on some LCD interfaces.
Initially, the configuration file should include all configurations of the LCD controller, which are mainly split into two structures. The first structure concerns the
driver of the target display. Typical settings are the LCD interface, output color format, LCD interface speed, the resolution of the target display as well as various
timing parameters required to communicate to the controller of the display. The second structure deals with the I/O pins used by the LCD controller to output pixel data
as well as timing signals. This structure is put in a separate source file, named platform_devices.c
. To facilitate the user, a copy of the LCD-related I/O pins is
found on top of each configuration file.
static const ad_lcdc_driver_conf_t dt280qv10ct_drv = {
.hw_init.phy_type = HW_LCDC_PHY_MIPI_SPI4,
.hw_init.format = GDI_DISP_colour,
.hw_init.cfg_extra_flags = 0,
.hw_init.mode = HW_LCDC_MODE_DISABLE,
.hw_init.iface_freq = LCDC_FREQ_48MHz,
.ext_clk = HW_LCDC_EXT_CLK_OFF,
.te_enable = false,
.te_polarity = HW_LCDC_TE_LOW,
.display.resx = GDI_DISP_RESX,
.display.resy = GDI_DISP_RESY,
.display.fpx = 0,
.display.fpy = 0,
.display.bpx = 0,
.display.bpy = 0,
.display.blx = 2, //! Min. timing parameters required by LCDC */
.display.bly = 1, //! Min. timing parameters required by LCDC */
};
static const ad_lcdc_controller_conf_t dt280qv10ct_cfg = {
.io = &dt280qv10ct_io,
.drv = &dt280qv10ct_drv,
};
Note
There are a minimum of timing parameters required for the correct operation of the LCD controller; even if this is not required by the target display model and LCD interface.
Note
If the Tearing Effect (TE) is enabled, then make sure that the target display supports that functionality.
Next, the configuration file should determine the behavior of the LCD controller/GDI for various display-related operations. For instance:
Power on the display. Typically, this step involves enabling the backlight and/or the
EN
signal of the display.
/*
* Define LCDC commands that should be executed to power ON the target display.
*/
static const uint8_t screen_power_on_cmds[] = {
LCDC_GPIO_SET_ACTIVE(DT280QV10CT_BL_PORT, DT280QV10CT_BL_PIN),
};
Initialize the display. Typically, this step involves a hardware and software reset, setting the color mode and frame rate, enable/disable the tearing effect of the display, as well as various display-specific configurations.
/*
* Define LCDC commands that should be executed to initialize the target display.
*/
static const uint8_t screen_init_cmds[] = {
LCDC_GPIO_SET_INACTIVE(DT280QV10CT_RST_PORT, DT280QV10CT_RST_PIN),
LCDC_DELAY_MS(10),
LCDC_GPIO_SET_ACTIVE(DT280QV10CT_RST_PORT, DT280QV10CT_RST_PIN),
LCDC_DELAY_MS(120),
LCDC_MIPI_SW_RST(),
...
LCDC_MIPI_SET_MODE(0x55), // Set colour mode to RGB565
LCDC_MIPI_SET_TEAR_ON(0x00),
LCDC_MIPI_CMD(0xB1), LCDC_MIPI_DATA(0x00), LCDC_MIPI_DATA(0x1F),
LCDC_MIPI_CMD(0xB5), LCDC_MIPI_DATA(0x5F), LCDC_MIPI_DATA(0x60),
LCDC_MIPI_DATA(0x1F), LCDC_MIPI_DATA(0x1F),
LCDC_MIPI_SET_POSITION(0, 0, GDI_DISP_RESX - 1, GDI_DISP_RESY - 1),
};
Enable the display. Typically, this step involves exiting the display from low power mode and configure for active mode.
/*
* Define LCDC commands that should be executed to enable the target display.
*/
static const uint8_t screen_enable_cmds[] = {
LCDC_MIPI_CMD(HW_LCDC_MIPI_DCS_EXIT_SLEEP_MODE),
LCDC_DELAY_MS(120),
LCDC_MIPI_CMD(HW_LCDC_MIPI_DCS_SET_DISPLAY_ON),
LCDC_DELAY_MS(80),
};
Note
In an emWin application, the display is enabled with LCD_On()
. This triggers that the LCDC commands are done written in screen_enable_cmds[]
.
Fig. 6 shows the sequence of events done when emWin initializes.
The next piece of information deals with the amount of pixel information sent to the display following a drawing operation. The way
emWin
is configured will result in returning only the pixel data that have been changed compared to a previous frame update operation. Updating part of the display panel requires that the display itself supports partial update operations. The demonstrated display shield supports partial updates and so, no further actions should be done following a drawing event.
__STATIC_INLINE void screen_set_partial_update_area(hw_lcdc_frame_t *frame)
{
/*
* Define the area that is to be updated on the display panel.
*/
(void)frame; //! Just to suppress compiler warnings
}
In cases where the target display does not support partial update operations, for instance for parallel RGB interfaces, here is what the routine should look like:
__STATIC_INLINE void screen_set_partial_update_area(hw_lcdc_frame_t *frame)
{
/* RGB interface does not support partial update */
frame->startx = 0;
frame->starty = 0;
frame->endx = GDI_DISP_RESX - 1;
frame->endy = GDI_DISP_RESY - 1;
}
The configuration file should also include information about how the display should be disabled, cleared and powered off.
/*
* Define LCDC commands that should be executed to disable the target display.
*/
static const uint8_t screen_disable_cmds[] = {
LCDC_MIPI_CMD(HW_LCDC_MIPI_DCS_SET_DISPLAY_OFF),
LCDC_DELAY_MS(50),
LCDC_MIPI_CMD(HW_LCDC_MIPI_DCS_ENTER_SLEEP_MODE),
LCDC_DELAY_MS(120),
};
/*
* Define LCDC commands that should be executed to power OFF the target display.
*/
static const uint8_t screen_power_off_cmds[] = {
LCDC_GPIO_SET_INACTIVE(DT280QV10CT_BL_PORT, DT280QV10CT_BL_PIN),
};
/*
* Define LCDC commands that should be executed to clear the target display.
*/
static const uint8_t screen_clear_cmds[] = {
};
Note
In an emWin application, call LCD_Off()
to disable the target display. This will trigger to do the LCDC commands written in screen_disable_cmds[]
.
Note
If no actions are required after a specific event/operation, the corresponding structure should be left empty.
The DA1469x SDK can also support display models that do not follow any standard, e.g. like the MIPI DBI interface, in the way they operate. Usually, such display models support a standard LCD interface; however the commands required to communicate to the display controller are device specific. In this context, the GDI layer has a number of macros/routines that the developer can use. The following code snippets are part of the
PSP27801
display model delivered with the GDI implementation.
Pre-drawing operations to be done before a drawing operation. Typically, this step involves sending a device-specific command that designates to the display controller the advent of a frame update.
#define GDI_DISP_PRE_DRAW (screen_pre_draw)
/*
* Define code to be executed prior to performing a display update operation.
*/
__STATIC_INLINE void screen_pre_draw(gdi_t *gdi, ad_lcdc_handle_t dev,
const hw_lcdc_layer_t *layer)
{
(void)gdi; //! Just to suppress compiler warnings
(void)dev;
(void)layer;
hw_lcdc_mipi_cmd(HW_LCDC_MIPI_CMD, SSD1351_CMD_WRITE_MEMORY_START);
}
Note
The declared routine must match that specific function definition (input/output arguments).
Post-drawing operations that to be done after a drawing operation is done.
#define GDI_DISP_POST_DRAW (screen_post_draw)
/*
* Define code to be executed after performing a display update operation.
*/
__STATIC_INLINE void screen_post_draw(gdi_t *gdi, ad_lcdc_handle_t dev,
const hw_lcdc_layer_t *layer)
{
}
Note
The declared routine must match that specific function definition (input/output arguments).
Operations to do to enable the partial update mode of the target display.
#define GDI_DISP_SET_PARTIAL_UPDATE (screen_set_partial_update)
/*
* Define code required to configure the target display to support partial update
*/
__STATIC_INLINE void screen_set_partial_update(gdi_t *gdi, ad_lcdc_handle_t dev,
hw_lcdc_frame_t *frame)
{
(void)gdi; //! Just to suppress compiler warnings
(void)dev;
hw_lcdc_mipi_cmd(HW_LCDC_MIPI_CMD, SSD1351_CMD_SET_COLUMN_ADDRESS);
hw_lcdc_mipi_cmd(HW_LCDC_MIPI_DATA, frame->startx + GDI_DISP_OFFSETX);
hw_lcdc_mipi_cmd(HW_LCDC_MIPI_DATA, frame->endx + GDI_DISP_OFFSETX);
hw_lcdc_mipi_cmd(HW_LCDC_MIPI_CMD, SSD1351_CMD_SET_PAGE_ADDRESS);
hw_lcdc_mipi_cmd(HW_LCDC_MIPI_DATA, frame->starty + GDI_DISP_OFFSETY);
hw_lcdc_mipi_cmd(HW_LCDC_MIPI_DATA, frame->endy + GDI_DISP_OFFSETY);
}
Note
The declared routine must match that specific function definition (input/output arguments).
9.1. Adding Support for Touch Operations¶
In the current GDI implementation, touch support is encapsulated along with display support. All touch-related configurations should be added in the same configuration file used for display support. Thus, making the whole process easier to the end user.
This section explains all the steps required to enable and support touch operations using code snippets of the demonstrated LCD shield, that is DT280QV10CT
.
Initially, the configuration file should include the macro that enables touch support as well as the macro that defines the interface required to communicate to the target touch controller.
#define GDI_TOUCH_ENABLE (1)
#define GDI_TOUCH_INTERFACE (GDI_TOUCH_INTERFACE_I2C)
Next, the configuration file should include all configurations of the selected serial controller (e.g. I2C), which are mainly split into two structures. The first structure concerns the
driver of the target touch controller and the second structure deals with the I/O pins used to physically connect to the touch controller. The latter, is put in a
separate source file, named platform_devices.c
. To facilitate the user, a copy of the I/O pins is found on top of each driver structure.
/* I2C driver configurations */
static const ad_i2c_driver_conf_t ft6206_drv = {
I2C_DEFAULT_CLK_CFG,
.i2c.speed = HW_I2C_SPEED_STANDARD, /* 100kb/s */
.i2c.mode = HW_I2C_MODE_MASTER,
.i2c.addr_mode = HW_I2C_ADDRESSING_7B,
.i2c.address = FT6206_I2C_ADDRESS,
.dma_channel = HW_DMA_CHANNEL_2
};
/* I2C controller configurations */
static const ad_i2c_controller_conf_t ft6206_cfg = {
.id = HW_I2C1,
.drv = &ft6206_drv,
.io = &ft6206_io
};
Then, a user-defined callback function that initializes the touch controller should be defined. This routine is called the very first time GDI is initialized.
/* User-defined routine used by GDI to initialize the target touch controller */
__STATIC_INLINE void ft6206_init(void *dev)
{
uint8_t write_addr[] = { FT6206_REG_FOCALTECH_ID };
uint8_t read_buf[1];
ad_i2c_write_read(dev, (const uint8_t *)write_addr, sizeof(write_addr), read_buf, sizeof(read_buf),
HW_I2C_F_ADD_STOP);
if (read_buf[0] == 0x11) {
}
else {
OS_ASSERT(0);
}
}
Note
The declared routine must match that specific function definition (input/output arguments).
The next piece of information deals with the routine that performs the actual touch read operations. This routine is called by GDI, following a valid touch event, to read and store touch data.
/* User-defined routine used by GDI to read touch events */
__STATIC_INLINE void ft6206_read_event(void *dev, gdi_touch_data_t *touch_data)
{
uint8_t write_addr[] = { FT6206_REG_GEST_ID };
uint8_t read_buf[6];
uint16_t touch_x, touch_y;
ad_i2c_write_read(dev, (const uint8_t *)write_addr, sizeof(write_addr), read_buf, sizeof(read_buf),
HW_I2C_F_ADD_STOP);
/* Get and exercise event flag */
switch(FT6206_GET_EVENT_FLAG(read_buf[2])) {
case FT6206_EVENT_FLAG_PRESS_DOWN:
touch_data->pressed = 1;
break;
case FT6206_EVENT_FLAG_LIFT_UP:
touch_data->pressed = 0;
break;
case FT6206_EVENT_FLAG_CONTACT:
touch_data->pressed = 1;
break;
case FT6206_EVENT_FLAG_NO_EVENT:
touch_data->pressed = 0;
break;
default:
/* Invalid status */
OS_ASSERT(0);
break;
}
touch_x = FT6206_GET_XY_COORDINATE(read_buf[2], read_buf[3]);
touch_y = FT6206_GET_XY_COORDINATE(read_buf[4], read_buf[5]);
/* Convert touch data to display coordinates */
touch_data->x = ft6206_map_touch_to_display(touch_x, 0, GDI_DISP_RESX, GDI_DISP_RESX, 0);
touch_data->y = ft6206_map_touch_to_display(touch_y, 0, GDI_DISP_RESY, GDI_DISP_RESY, 0);
}
Note
The declared routine must match that specific function definition (input/output arguments).
The last piece of information concerns the way GDI is notified once a valid touch event is generated by the touch controller. Typically, a touch controller toggles a pin if a valid touch
is detected. This pin can be connected to the DA1469x WKUP controller, so the system can react on the touch event. Currently, the DA1469x SDK does not have adapters for
controlling the WKUP controller and so, it is user’s responsibility to handle the controller. In the current GDI implementation, and once the WKUP controller is up and running,
a call to the gdi_touch_event()
routine should be performed following a touch event. Note that this function can be called either directly within
an Interrupt Service Routine (ISR) or within an RTOS task.
#define TOUCH_INT_PIN_MASK (1 << TOUCH_INT_PIN)
/* WKUP P0 interrupt handler (ISR) */
static void _wkup_gpio_cb(void)
{
uint32_t status;
/* Clear the WKUP interrupt flag!!! (mandatory) */
hw_wkup_reset_interrupt();
/*
* Get port status of the last wake-up event.
*
* \note: The status is returned as BITMASK, meaning that each bit reflects
* the corresponding pin state.
*/
status = hw_wkup_get_status(TOUCH_INT_PORT);
/*
* Clear the interrupt latch status!!! (mandatory).
*/
hw_wkup_clear_status(TOUCH_INT_PORT, status);
/*
* If interrupt is produced by the touch controller, then notify the GDI task.
*/
if (status & TOUCH_INT_PIN_MASK) {
gdi_touch_event();
} else {
/* Otherwise, notify other tasks (if needed) */
}
}
10. Adding Support for New Displays¶
This section lists the required steps to add support for new display models (not supported by default). Do the following steps:
In
/config/custom_config_xxx.h
, declare a macro used to select the target display. For instance:
#define dg_configUSE_DT280QV10CT ( 0 )
#define dg_configUSE_HM80160A090 ( 0 )
#define dg_configUSE_LPM012M134B ( 0 )
...
#define dg_configUSE_MY_CUSTOM_LCD ( 1 )
Note
If the display supports touch functionality, declare a macro used to select the target touch controller.
In
/config/peripheral_setup.h
, declare macros for the LCD I/O pins used to connect/communicate to the target display. For instance:
#if dg_configUSE_MY_CUSTOM_LCD
/*
* Add macro definitions that reflect the LCD I/O pins of the target display.
*/
#define MY_CUSTOM_LCD_SDI_PORT HW_GPIO_PORT_1
#define MY_CUSTOM_LCD_SDI_PIN HW_GPIO_PIN_13
#define MY_CUSTOM_LCD_SCL_PORT HW_GPIO_PORT_1
#define MY_CUSTOM_LCD_SCL_PIN HW_GPIO_PIN_17
...
#endif
Note
If the display supports touch functionality, declare macros for the I/O pins used to connect/communicate to the target touch controller.
In
platform_devices.c
, declare all I/O pins that the LCD controller needs to communicate with the target display. For instance:
#elif dg_configUSE_MY_CUSTOM_LCD
static const ad_io_conf_t my_custom_lcd_gpio_cfg[] = {
{ MY_CUSTOM_LCD_SCL_PORT, MY_CUSTOM_LCD_SCL_PIN, { HW_GPIO_MODE_OUTPUT, HW_GPIO_FUNC_LCD_SPI_CLK, true }, { HW_GPIO_MODE_OUTPUT, HW_GPIO_FUNC_GPIO, true }},
{ MY_CUSTOM_LCD_SDI_PORT, MY_CUSTOM_LCD_SDI_PIN, { HW_GPIO_MODE_OUTPUT, HW_GPIO_FUNC_LCD_SPI_DO, true }, { HW_GPIO_MODE_OUTPUT, HW_GPIO_FUNC_GPIO, true }},
...
};
const ad_lcdc_io_conf_t my_custom_lcd_io = {
.voltage_level = HW_GPIO_POWER_VDD1V8P,
.io_cnt = sizeof(my_custom_lcd_gpio_cfg) / sizeof(my_custom_lcd_gpio_cfg[0]),
.io_list = my_custom_lcd_gpio_cfg,
};
Note
If the display supports touch functionality, declare all I/O pins that the serial controller (e.g. I2C) needs to communicate with the target touch controller.
In
/config/platform_devices.h
, declare an external variable that has the previously defined structure (I/O pins configurations). For instance:
#if dg_configLCDC_ADAPTER
#if dg_configUSE_HM80160A090
extern const ad_lcdc_io_conf_t hm80160a090_io;
#elif dg_configUSE_E1394AA65A
extern const ad_lcdc_io_conf_t e1394aa65a_io;
...
#elif dg_configUSE_MY_CUSTOM_LCD
extern const ad_lcdc_io_conf_t my_custom_lcd_io;
#endif
#endif /* dg_configLCDC_ADAPTER */
Note
If the display supports touch functionality, declare an external variable that has the previously defined structure that holds the I/O pins for connecting to the touch controller.
In
main.c
, declare the default LCD controller’s I/O pins configurations. These configurations are applied when the device initializes and should be put inprvSetupHardware()
. For instance:
static void prvSetupHardware( void )
{
...
#if dg_configLCDC_ADAPTER
#if dg_configUSE_HM80160A090
ad_lcdc_io_config(&hm80160a090_io, AD_IO_CONF_OFF);
#elif dg_configUSE_E1394AA65A
ad_lcdc_io_config(&e1394aa65a_io, AD_IO_CONF_OFF);
...
#elif dg_configUSE_MY_CUSTOM_LCD
ad_lcdc_io_config(&my_custom_lcd_io, AD_IO_CONF_OFF);
#endif
#endif /* dg_configLCDC_ADAPTER */
...
}
Note
If the display supports touch functionality, declare the default serial controller’s I/O pins configurations.
Create a configuration file for the target display. To do so, make a copy of an existing configuration file and make the necessary changes to support the target display. For instance:
7. In /ui/gdi/inc/gdi_config.h
, declare the configuration file to use once the target display is selected. For instance:
#if dg_configUSE_HM80160A090
#include "hm80160a090.h"
#elif dg_configUSE_E1394AA65A
#include "e1394aa65a.h"
...
#elif dg_configUSE_MY_CUSTOM_LCD
#include "my_custom_lcdc.h"
#endif
11. Using External Resources¶
There might be cases where an image or font should be stored in a dedicated area in the flash memory used. Currently, the DA1469x SDK defines a mechanism that divides the
flash memory area into logical areas, named partitions. For instance, the bitmap data of an image could be stored in NVMS_LOG_PART
. A custom font type could also be stored
in the same or separate partition in the flash memory. The emWin graphics library does support streamed bitmaps and other mechanisms for fetching data stored in an
external medium. The delivered demonstration example comes with a simple API that supports both XBF format and streamed bitmaps. The corresponding API can be found under
/ui/ExternalResources.h
.
11.1. Burning External Resources in FLASH¶
This section explains the steps required to write bitmap streams and XBF data in the flash memory via the SmartSnippets Studio.
Open the SmartSnippets Studio and execute the following steps:
Select New to create a new project (1). In the New Project window, enter a name for the project (2). This step is optional if a project has already been created.
Choose the newly created or an available project (4).
Choose a communication interface (3) and a port (5). To achieve faster communication this should be the
JTAG
interface.Select the family of devices to use (in our use case this should be the DA1469x-00 option) (6).
Open the selected project (7).
Write the external resources in the flash memory:
Switch to the
QSPI Partition Table
window:
Open the partition table:
In the Partition Table area, click Connect (1) and wait for the cursor to stop rotating.
Then, click Read (2). All the partition entries should now be displayed.
Load the XBF data. This information can be generated using the font tools provided by emWin.
In the QSPI Partition Table area, click Browse (1).
In the pop-up window select All Files in the Files of type section (2). Then, search for and select the XBF file (.xbf).
Click Open (3). The contents of the selected file should now be displayed under the QSPI Partition Table area (4).
Note
An XBF file (.xbf) should start with a magic word. The very first time emWin attempts to initialize XBF fonts will try to identify that specific sequence of characters. If it fails, then the whole procedure will be aborted.
Burn the XBF data into the flash device used:
In the Partition Tasks area, select the partition that XBF data should be stored to (1) as well as an offset relative to the partition start address (2). In this demonstration,
NVMS_LOG_PART
and zero offset are selected.Click Burn (3) and wait for the cursor to stop rotating. To make sure that the writing operation has been executed successfully, click Verify (4).
Identify the memory space occupied by XBF information. This is required so the next external resource is stored in a free and clean area.
The next step involves converting an image into bitmap datastream format. To do so, the bitmap converter tool, provided by emWin, can be used.
Open the tool and drag and drop an image of your choice on the white area. The image should now be displayed.
From the menu bar, select Image –> Scale… (1).
In the pop-up window select the new dimensions of the image and click Ok (2). The scaled image should now be displayed (3).
From the menu bar, select File –> Save as… (1)
In the pop-up window select the appropriate format (.dta) (2) and then select Save (3).
In the pop-up window select the color format of the selected image and click Ok (4).
Load the previously generated bitmap datastream data.
In the QSPI Partition Table area, click Browse (1).
In the pop-up window select All Files in the Files of type section (2). Then, search for and select the bitmap datastream file (.dta).
Click Open (3). The contents of the selected file should now be displayed under the QSPI Partition Table area (4).
Note
A bitmap datastream file (.dat) should start with a magic word. The very first time emWin attempts to fetch bitmap datastream, will try to identify that specific sequence of characters. If it fails, then the whole procedure will be aborted.
Burn the bitmap datastream into the flash device used:
In the Partition Tasks area, select the partition that bitmap datastream should be stored to (1) as well as an offset relative to the partition start address (2). In this demonstration,
NVMS_LOG_PART
and0x1AE0
offset are selected.Click Burn (3) and wait for the cursor to stop rotating. To make sure that the writing operation has been executed successfully, click Verify (4).
For this demonstration the contents of the log partition should look like this:
11.2. Setting External Resources in Application¶
As mentioned at the start of this section, the delivered demonstration example comes with a simple API that supports both XBF fonts and bitmap data streaming.
To use the resources written in the flash memory, the following macros should be set accordingly. All macros should be defined in ExternalResources.h
.
#define PARTITION_ID_XBF_FONT NVMS_LOG_PART
#define XBF_FONT_TYPE GUI_XBF_TYPE_PROP
#define PARTITION_OFFSET_XBF_FONT 0x00
#define PARTITION_ID_BITMAP_DATASTREAM NVMS_LOG_PART
#define PARTITION_OFFSET_BITMAP_DATASTREAM 0x1AE0
Go to the main application task, that is MainTask.c
and set the following macros:
#define USE_XBF_FONT 1
#define USE_BITMAP_DATASTREAM 1
Dialog’s logo icon should now be replaced with the image stored in FLASH and the text of the first page should be drawn based on the XBF font data.
Note
For the delivered sample code, the size of the newly defined image should not exceed the dimensions of the Dialog’s logo icon, that is 54x80.
12. Running the Demonstration Example¶
This section describes the necessary steps to prepare the Pro DevKit and other tools to successfully run the demonstration example. In this sample code, the Adafruit 2.8’’ TFT
touch shield is demonstrated. A DT280QV10CT
display model, 0.1” female pin headers, some soldering and an RTT Viewer provided by SEGGER are required to test and check if
the target application behaves correctly. If QSPI RAM is to be used, an APS6404L-SQ-SN
IC package and an R1005 SMD resistor of 10-15 kΩ are required as well. Note that, the
demonstrated LCD shield comes in two flavors: a resistive and a capacitive touch shield. Both are demonstrated in this section.
12.1. Preparing and Connecting to the LCD Shield¶
This step is required only for the capacitive version of the LCD shield. By default, the SPI interface used to communicate to the display, is available through the ICSP header. On the back of the shield, find and solder the SPI pads as shown in Fig. 21
Note
This step is not required if the resistive version is used, because the SPI interface is available through the header pins of the shield.
Note
Optionally, and for the capacitive version, use a sharp knife or razor to cut the traces of the ICSP pads.
Both the resistive and capacitive versions can dim or completely enable/disable the backlight. On the capacitive touch shield solder the jumper labelled
#5
. Then, the backlight can be controlled via thePORT1.8
pin.
On the resistive touch shield solder the jumper labelled
#3
. Then, the backlight can be controlled via thePORT1.3
pin.
Solder 0.1’’ female pin headers on the Pro DevKit, (J13, J11, J14 and J12) to take advantage of the Arduino socket. See Fig. 24
On the Pro DevKit (motherboard) solder a zero Ohm resistor in
R307
so the display is powered through the USB hub of the motherboard. Alternatively, connect a USB cable to the DA1469x Daughter Board (J3).
Fig. 27 shows the pins diagram of the Arduino sockets. R307
is marked with orange color.
12.2. Connecting External QSPI RAM¶
This section is optional and intended in cases where external QSPI RAM should be used to allocate memory. Note that the supplied Pro DevKit does not have PSRAM and so, user should solder PSRAM on their own. Currently, the SDK supports three PSRAM models which can be used out of the box. The system also needs a 10-12 kΩ resistor that connects the Chip Select (CS) line of PSRAM to the V18 power rail.
12.3. Building and Running the Source Code¶
Use the Arduino socket to connect the Adafruit TFT shield to the Pro DevKit as shown in Fig. 26
Use the USB1 port of the motherboard to connect the target device to your PC. This port is used to supply power to and communicate with the DA1469x SoC. For this demonstration a Pro DevKit is used.
Download the demonstration example and then import it into the working directory.
Note
Make sure that the python_scripts
folder is imported.
This step is needed if the resistive version of the LCD shield is used. In
/config/peripheral_setup.h
, change the I/O pin that is used to control the backlight of the display:
/*
* \note For the resistive touch shield the backlight is routed on P1.5
*/
#define DT280QV10CT_BL_PORT HW_GPIO_PORT_1
#define DT280QV10CT_BL_PIN HW_GPIO_PIN_5
Note
Out-of-the-box touch support is not currently provided for the resistive version of the target Adafruit LCD shield.
Build the project either in Debug_QSPI or Release_QSPI mode and download the generated image into the chip.
Note
A folder, named emwin_lib
, should now be created accommodating the gdi
and segger
sub-folders.
Note
The gdi
and segger
folders can also be downloaded from the support website. If this is the case, the emwin_lib
folder should manually be created and accommodate the gdi
and segger
sub-folders (downloaded from the support website).
Press the RESET button on Pro DevKit to have the chip executing its firmware.
12.3.1. Printing LOG Messages on RTT Console¶
Go to
/emwin_lib/gdi/inc/gdi_config.h
and setGDI_CONSOLE_LOG
to 1Re-build the project and download the generated image into the chip. Then press RESET.
Open a J-Link RTT Viewer to get the log messages.
Open the generated
.map
file, calledemwin_demo.map
, and find the address of the RTT Control Block. To do so, pressCtrl+F
on keyboard and search for the address of the_SEGGER_RTT
symbol.
Open a J-Link RTT Viewer window and continue with the configurations as shown in Fig. 29
The window should now shows the log messages:
The actual frame rate (FPS) (1)
The time it takes for a new image to update (2)
The time it takes for a frame buffer to be sent to the display (3)
Note
The displayed values reflect latencies introduced by the application itself.
If touch operations are enabled, you should expect to get the following extra information:
Note
Enabling log messages will adversely affect the whole GDI performance.
12.4. Application Description¶
Having executed the steps above, the LCD should now display moveable objects along with static control buttons displayed at the bottom side of the visual plane. By default, two control buttons are displayed as shown in Fig. 32.
Play/Pause: used to start/stop the animation which consists of two moveable objects (Dialog Logo, QR). Based on the animation state, that is active or paused, the appropriate icon is displayed. Note that the displayed icon shows the action that is going to be performed.
Reset: used to re-position the moveable objects to their default locations. This control button has effect only when the animation is paused and a moveable object has been moved from its original position.
Speed Slider: used to change the speed of the animation. This control widget is only displayed when the animation is paused. To change the animation speed swipe up/down the slider as shown in Fig. 33. Note that, the speed change is reflected the next time the animation is re-started.
User can re-position moveable objects at any location on the visible plane as shown in Fig. 34. The new positions are reflected the next time the animation is re-restarted. Note that, re-positioning objects is only allowed when the animation is stopped.
User can also transits from the home page (animation) to other pages by swiping up/down as shown in Fig. 35. By default, two more pages should be displayed:
The first page displays the name of the target project
The second page displays information on the target chip and TFT shield.
13. Revision history¶
Revision |
Date |
Description |
---|---|---|
1.0 |
8-Oct-2019 |
First released version |
1.1 |
3-Feb-2020 |
Enabling (emWin) touch functionality, Adding support for external resources |
14. Status definitions¶
Status |
Definition |
---|---|
DRAFT |
The content of this document is under review and subject to formal approval, which may result in modifications or additions. |
APPROVED or unmarked |
The content of this document has been approved for publication. |
15. Disclaimer¶
Information in this document is believed to be accurate and reliable. However, Dialog Semiconductor does not give any representations or warranties, expressed or implied, as to the accuracy or completeness of such information. Dialog Semiconductor furthermore takes no responsibility whatsoever for the content in this document if provided by any information source outside of Dialog Semiconductor.
Dialog Semiconductor reserves the right to change without notice the information published in this document, including without limitation the specification and the design of the related semiconductor products, software and applications.
Applications, software, and semiconductor products described in this document are for illustrative purposes only. Dialog Semiconductor makes no representation or warranty that such applications, software and semiconductor products will be suitable for the specified use without further testing or modification. Unless otherwise agreed in writing, such testing or modification is the sole responsibility of the customer and Dialog Semiconductor excludes all liability in this respect.
Customer notes that nothing in this document may be construed as a license for customer to use the Dialog Semiconductor products, software and applications referred to in this document. Such license must be separately sought by customer with Dialog Semiconductor.
All use of Dialog Semiconductor products, software and applications referred to in this document are subject to Dialog Semiconductor’s Standard Terms and Conditions of Sale, unless otherwise stated.
© Dialog Semiconductor. All rights reserved.
Contacting Dialog Semiconductor |
||
---|---|---|
United Kingdom (Headquarters) Dialog Semiconductor PLC Phone: +44 1793 757700 Germany Dialog Semiconductor GmbH Phone: +49 7021 805-0 The Netherlands Dialog Semiconductor B.V. Phone: +31 73 640 8822 |
North America Dialog Semiconductor Inc. Phone: +1 408 845 8500 Japan Dialog Semiconductor K. K. Phone: +81 3 5425 4567 Taiwan Dialog Semiconductor Taiwan Phone: +886 281 786 222 |
Singapore Dialog Semiconductor Singapore Phone: +65 64 849929 China Dialog Semiconductor China Phone: +86 21 5178 2561 Korea Dialog Semiconductor Korea Phone: +82 2 3469 8291 |
Email: |
Web site: www.dialog-semiconductor.com |