{"id":2528,"date":"2024-05-18T13:21:18","date_gmt":"2024-05-18T13:21:18","guid":{"rendered":"https:\/\/blog.embeddedexpert.io\/?p=2528"},"modified":"2024-05-18T13:21:22","modified_gmt":"2024-05-18T13:21:22","slug":"getting-started-with-lvgl-v9-with-stm32f429-disco-part3-lvgl-integration","status":"publish","type":"post","link":"https:\/\/blog.embeddedexpert.io\/?p=2528","title":{"rendered":"Getting Started with LvGL V9 with STM32F429-disco Part3: LvGL Integration"},"content":{"rendered":"\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"300\" height=\"95\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/logo_lvgl-2.png\" alt=\"\" class=\"wp-image-2529\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/logo_lvgl-2.png 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/logo_lvgl-2-250x79.png 250w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/figure><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>In this guide, we shall integrate LvGL and initialize the LCD, touch LvGL itself.<\/p>\n\n\n\n<p>In this guide, we shall cover the following:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>TFT integration.<\/li><li>Touch integration.<\/li><li>LvGL integration.<\/li><li>Code download.<\/li><li>Results.<\/li><\/ul>\n\n\n\n<p>List of the previous parts:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><a rel=\"noreferrer noopener\" href=\"https:\/\/blog.embeddedexpert.io\/?p=2509\" data-type=\"URL\" data-id=\"https:\/\/blog.embeddedexpert.io\/?p=2509\" target=\"_blank\">Part 1<\/a><\/li><li><a href=\"https:\/\/blog.embeddedexpert.io\/?p=2521\" data-type=\"URL\" data-id=\"https:\/\/blog.embeddedexpert.io\/?p=2521\" target=\"_blank\" rel=\"noreferrer noopener\">Part 2<\/a><\/li><\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">1. TFT Integration:<\/h2>\n\n\n\n<p><\/p>\n\n\n\n<p>Create new source and header file with name of LCDController.c and LCDController.h respectively,<\/p>\n\n\n\n<p>Within the header file:<\/p>\n\n\n\n<p>The contents of the header can be found <a href=\"https:\/\/github.com\/lvgl\/lvgl\/blob\/master\/examples\/porting\/lv_port_disp_template.h\" target=\"_blank\" rel=\"noreferrer noopener\">here<\/a>.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">#ifndef INC_LCDCONTROLLER_H_\n#define INC_LCDCONTROLLER_H_\n\n\n#ifdef __cplusplus\nextern &quot;C&quot; {\n#endif\n\n\/*********************\n *      INCLUDES\n *********************\/\n\n#include &quot;lvgl.h&quot;\n\n\/*********************\n *      DEFINES\n *********************\/\n\n\/**********************\n *      TYPEDEFS\n **********************\/\n\n\/**********************\n * GLOBAL PROTOTYPES\n **********************\/\n\/* Initialize low level display driver *\/\nvoid lv_port_disp_init(void);\n\n\/* Enable updating the screen (the flushing process) when disp_flush() is called by LVGL\n *\/\nvoid disp_enable_update(void);\n\n\/* Disable updating the screen (the flushing process) when disp_flush() is called by LVGL\n *\/\nvoid disp_disable_update(void);\n\n\/**********************\n *      MACROS\n **********************\/\n\n#ifdef __cplusplus\n} \/*extern &quot;C&quot;*\/\n#endif\n\n\n\n#endif \/* INC_LCDCONTROLLER_H_ *\/\n<\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>In the source file which can be found <a href=\"https:\/\/github.com\/lvgl\/lvgl\/blob\/master\/examples\/porting\/lv_port_disp_template.c\" target=\"_blank\" rel=\"noreferrer noopener\">here<\/a>.<\/p>\n\n\n\n<p>The content of the source file as following:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">\/*********************\n *      INCLUDES\n *********************\/\n#include &quot;LCDController.h&quot;\n#include &lt;stdbool.h&gt;\n#include &quot;ILI9341.h&quot;\n#include &quot;stm32f4xx.h&quot;\n#include &quot;stdint.h&quot;\n#include &quot;LCD_Pins.h&quot;\n\/*********************\n *      DEFINES\n *********************\/\n#define MY_DISP_HOR_RES 240\n\n\n#define MY_DISP_VER_RES 320\n\n\n\/**********************\n *      TYPEDEFS\n **********************\/\n\n\/**********************\n *  STATIC VARIABLES\n **********************\/\nlv_display_t * disp;                        \/*Descriptor of a display driver*\/\n\nlv_color_t buf_1[MY_DISP_HOR_RES *64];      \/*A buffer for 10 rows*\/\n\n\/**********************\n *  STATIC PROTOTYPES\n **********************\/\nstatic void disp_init(void);\n\nstatic void disp_flush(lv_display_t * disp, const lv_area_t * area, lv_color_t * color_p);\n\n\n\/**********************\n *      MACROS\n **********************\/\n\n\n\/**********************\n *   GLOBAL FUNCTIONS\n **********************\/\n\nvoid lv_port_disp_init(void)\n{\n    \/*-------------------------\n     * Initialize your display\n     * -----------------------*\/\n    disp_init();\n\n    \/*-----------------------------\n     * Create a buffer for drawing\n     *----------------------------*\/\n    disp=lv_display_create(MY_DISP_HOR_RES,MY_DISP_VER_RES);\n\n    \t\/*Set the display flush callback*\/\n    lv_display_set_flush_cb(disp, &amp;disp_flush);\n\n\n      \/* display buffer initialization *\/\n    lv_display_set_buffers(disp, &amp;buf_1, NULL, sizeof(buf_1), LV_DISPLAY_RENDER_MODE_PARTIAL);\n}\n\n\/**********************\n *   STATIC NCTIONS\n **********************\/\n\n\/*Initialize your display and the required peripherals.*\/\nstatic void disp_init(void)\n{\n    ILI9341_Init();\n    ILI9341_setRotation(3);\n\n\n}\n\nvolatile bool disp_flush_enabled = true;\n\n\/* Enable updating the screen (the flushing process) when disp_flush() is called by LVGL\n *\/\nvoid disp_enable_update(void)\n{\n    disp_flush_enabled = true;\n}\n\n\/* Disable updating the screen (the flushing process) when disp_flush() is called by LVGL\n *\/\nvoid disp_disable_update(void)\n{\n    disp_flush_enabled = false;\n}\n\n\nstatic void disp_flush(lv_display_t * disp, const lv_area_t * area, lv_color_t * color_p)\n{\n\n\tsetAddrWindow(area-&gt;x1, area-&gt;y1, area-&gt;x2, area-&gt;y2);\n\tint height = area-&gt;y2 - area-&gt;y1 + 1;\n\tint width = area-&gt;x2 - area-&gt;x1 + 1;\n\n\tILI9341_DrawBitmap(width, height, (uint8_t *)color_p);\n\n\n    \/*IMPORTANT!!!\n     *Inform the graphics library that you are ready with the flushing*\/\n\n}\n\nvoid SPI5_TX_Finished(void)\n{\n\n\tlv_disp_flush_ready(disp);\n\tLCD_CS_HIGH();\n}\n<\/pre><\/div>\n\n\n\n<p>Explanation:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">#include &quot;LCDController.h&quot;\n#include &lt;stdbool.h&gt;\n#include &quot;ILI9341.h&quot;\n#include &quot;stm32f4xx.h&quot;\n#include &quot;stdint.h&quot;\n#include &quot;LCD_Pins.h&quot;<\/pre><\/div>\n\n\n\n<p>These includes are needed to make the lcd works.<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">#define MY_DISP_HOR_RES 240\n\n\n#define MY_DISP_VER_RES 320<\/pre><\/div>\n\n\n\n<p>Our display resolution.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">lv_display_t * disp;                        \/*Descriptor of a display driver*\/\n\nlv_color_t buf_1[MY_DISP_HOR_RES *64];      \/*A buffer for 10 rows*\/<\/pre><\/div>\n\n\n\n<p>Display driver and the LCD buffer.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">static void disp_init(void);\n\nstatic void disp_flush(lv_display_t * disp, const lv_area_t * area, lv_color_t * color_p);<\/pre><\/div>\n\n\n\n<p>Static declaration of function prototype.<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">void lv_port_disp_init(void)\n{\n    \/*-------------------------\n     * Initialize your display\n     * -----------------------*\/\n    disp_init();\n\n    \/*-----------------------------\n     * Create a buffer for drawing\n     *----------------------------*\/\n    disp=lv_display_create(MY_DISP_HOR_RES,MY_DISP_VER_RES);\n\n    \t\/*Set the display flush callback*\/\n    lv_display_set_flush_cb(disp, &amp;disp_flush);\n\n\n      \/* display buffer initialization *\/\n    lv_display_set_buffers(disp, &amp;buf_1, NULL, sizeof(buf_1), LV_DISPLAY_RENDER_MODE_PARTIAL);\n}\n\n\/**********************\n *   STATIC NCTIONS\n **********************\/\n\n\/*Initialize your display and the required peripherals.*\/\nstatic void disp_init(void)\n{\n    ILI9341_Init();\n    ILI9341_setRotation(3);\n\n\n}<\/pre><\/div>\n\n\n\n<p>This shall initialize the LCD and LvGL buffer.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">volatile bool disp_flush_enabled = true;\n\n\/* Enable updating the screen (the flushing process) when disp_flush() is called by LVGL\n *\/\nvoid disp_enable_update(void)\n{\n    disp_flush_enabled = true;\n}\n\n\/* Disable updating the screen (the flushing process) when disp_flush() is called by LVGL\n *\/\nvoid disp_disable_update(void)\n{\n    disp_flush_enabled = false;\n}\n<\/pre><\/div>\n\n\n\n<p>Here is to enable flush of the buffer after the data has been drawn.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">static void disp_flush(lv_display_t * disp, const lv_area_t * area, lv_color_t * color_p)\n{\n\n\tsetAddrWindow(area-&gt;x1, area-&gt;y1, area-&gt;x2, area-&gt;y2);\n\tint height = area-&gt;y2 - area-&gt;y1 + 1;\n\tint width = area-&gt;x2 - area-&gt;x1 + 1;\n\n\tILI9341_DrawBitmap(width, height, (uint8_t *)color_p);\n\n\n    \/*IMPORTANT!!!\n     *Inform the graphics library that you are ready with the flushing*\/\n\n}\n\nvoid SPI5_TX_Finished(void)\n{\n\n\tlv_disp_flush_ready(disp);\n\tLCD_CS_HIGH();\n}\n<\/pre><\/div>\n\n\n\n<p>This for the display flush.<\/p>\n\n\n\n<p>It shall first set the region to be drawn by the LvGL, push the data to the LCD using SPI in DMA mode then SPI5_TX_Finished shall be called once the data has been sent.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>For more information, please refer to <a href=\"https:\/\/docs.lvgl.io\/master\/porting\/display.html\" target=\"_blank\" rel=\"noreferrer noopener\">this<\/a>.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">2. Touch Integration:<\/h2>\n\n\n\n<p>Create new source and header file with name of TouchController.c and TouchController.h respectively.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>Within the header file:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">#ifndef TOUCHCONTROLLER_H_\n#define TOUCHCONTROLLER_H_\n\n\/*********************\n *      INCLUDES\n *********************\/\n#include &quot;lvgl.h&quot;\n\n\/*********************\n *      DEFINES\n *********************\/\n\n\/**********************\n *      TYPEDEFS\n **********************\/\n\n\/**********************\n * GLOBAL PROTOTYPES\n **********************\/\nvoid lv_port_indev_init(void);\n\n\n\/**********************\n *      MACROS\n **********************\/\n\n\n\n#endif \/* TOUCHCONTROLLER_H_ *\/\n<\/pre><\/div>\n\n\n\n<p>In the source file:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">\/*********************\n *      INCLUDES\n *********************\/\n#include &quot;lvgl.h&quot;\n#include &quot;TouchController.h&quot;\n#include &quot;STMPE811.h&quot;\n#include &quot;ILI9341.h&quot;\n\/*********************\n *      DEFINES\n *********************\/\n#define GUI_WIDTH 240\n#define GUI_HEIGHT 320\n\/**********************\n *      TYPEDEFS\n **********************\/\n\n\n\/**********************\n *  STATIC PROTOTYPES\n **********************\/\n\nstatic void touchpad_init(void);\nstatic void touchpad_read(lv_indev_t * indev_drv, lv_indev_data_t * data);\nstatic bool touchpad_is_pressed(void);\nstatic void touchpad_get_xy(lv_coord_t * x, lv_coord_t * y);\n\n\n\/**********************\n *  STATIC VARIABLES\n **********************\/\nlv_indev_t * indev_touchpad;\n\nstruct {\n\tlv_coord_t x;\n\tlv_coord_t y;\n}get_xy;\n\nuint16_t intx, inty;\n\n\n\n\/**********************\n *      MACROS\n **********************\/\n\n\/**********************\n *   GLOBAL FUNCTIONS\n **********************\/\n\nvoid lv_port_indev_init(void)\n{\n\n    \/*------------------\n     * Touchpad\n     * -----------------*\/\n\n    \/*Initialize your touchpad if you have*\/\n    touchpad_init();\n\n    \/*Register a touchpad input device*\/\n    indev_touchpad = lv_indev_create();\n    lv_indev_set_type(indev_touchpad, LV_INDEV_TYPE_POINTER);\n    lv_indev_set_read_cb(indev_touchpad, touchpad_read);\n\n\n}\n\n\/*Initialize your touchpad*\/\nstatic void touchpad_init(void)\n{\n\tSTMPE811_Touch_Enable();\n}\n\n\n\nuint8_t ret_value;\nstatic int32_t _x = 0, _y = 0;\nint16_t xDiff, yDiff, xr, yr;\nuint16_t x_raw, y_raw;\n\n\/*Return true is the touchpad is pressed*\/\nstatic bool touchpad_is_pressed(void)\n{\n\n\n\n\tif(isToched()==no_touch)\n\t{\n\t\tret_value=false;\n\t}\n\telse\n\t{\n\t\t\tgetTouchValue(&amp;x_raw,&amp;y_raw);\n\t\t\t\/* Y value first correction *\/\n\t\t\ty_raw -= 300;\n\n\t\t\t\/* Y value second correction *\/\n\t\t\tyr = y_raw \/ 11;\n\n\t\t\t\/* Return y_raw position value *\/\n\t\t\tif(yr &lt;= 0) yr = 0;\n\t\t\telse if (yr &gt; GUI_HEIGHT) yr = GUI_HEIGHT - 1;\n\n\t\t\ty_raw = yr;\n\n\t\t\t\/* X value first correction *\/\n\t\t\tif(x_raw &lt;= 3720) x_raw = 3770 - x_raw;\n\t\t\telse  x_raw = 3770 - x_raw;\n\n\t\t\t\/* X value second correction *\/\n\t\t\txr = x_raw \/ 15;\n\n\t\t\t\/* Return X position value *\/\n\t\t\tif(xr &lt;= 0) xr = 0;\n\t\t\telse if (xr &gt; GUI_WIDTH) xr = GUI_WIDTH - 1;\n\n\t\t\tx_raw = xr;\n\t\t\tif(x_raw&gt;_x){xDiff=x_raw - _x;}\n\t\t\telse {xDiff=_x - x_raw;}\n\n\t\t\tif(y_raw&gt;_y){yDiff=y_raw - _y;}\n\t\t\telse {yDiff=_y - y_raw;}\n\n\n\t\t\t\/\/xDiff = x_raw &gt; _x? (x_raw - _x): (_x - x_raw);\n\t\t\t\/\/yDiff = y_raw &gt; _y? (y_raw - _y): (_y - y_raw);\n\n\t\t\tif (xDiff + yDiff &gt; 5)\n\t\t\t{\n\t\t\t\t_x = x_raw;\n\t\t\t\t_y = y_raw;\n\t\t\t}\n\n\t\t\tget_xy.x = GUI_WIDTH-_x;\n\t\t\tget_xy.y = GUI_HEIGHT-_y;\n\t\t\tret_value= true;\n\t}\n\treturn ret_value;\n}\n\n\/*Will be called by the library to read the touchpad*\/\nstatic void touchpad_read(lv_indev_t * indev_drv, lv_indev_data_t * data)\n{\n\n    \/*Save the pressed coordinates and the state*\/\n    if(touchpad_is_pressed()) {\n\n        data-&gt;state = LV_INDEV_STATE_PR;\n\n    }\n    else {\n        data-&gt;state = LV_INDEV_STATE_REL;\n    }\n\n    \/*Set the last pressed coordinates*\/\n    data-&gt;point.x = get_xy.x;\n    data-&gt;point.y = get_xy.y;\n}\n\n\n\/*Get the x and y coordinates if the touchpad is pressed*\/\nstatic void touchpad_get_xy(lv_coord_t * x, lv_coord_t * y)\n{\n    \/*Your code comes here*\/\n\n    (*x) = 0;\n    (*y) = 0;\n}\n\n\n\n<\/pre><\/div>\n\n\n\n<p>Please refer to <a rel=\"noreferrer noopener\" href=\"https:\/\/github.com\/lvgl\/lvgl\/blob\/master\/examples\/porting\/lv_port_indev_template.c\" data-type=\"URL\" data-id=\"https:\/\/github.com\/lvgl\/lvgl\/blob\/master\/examples\/porting\/lv_port_indev_template.c\" target=\"_blank\">this<\/a> and <a rel=\"noreferrer noopener\" href=\"https:\/\/docs.lvgl.io\/master\/porting\/indev.html\" data-type=\"URL\" data-id=\"https:\/\/docs.lvgl.io\/master\/porting\/indev.html\" target=\"_blank\">this<\/a> for more details about the touch integration.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">3. LvGL Integration:<\/h2>\n\n\n\n<p>First, head to this <a rel=\"noreferrer noopener\" href=\"https:\/\/github.com\/lvgl\/lvgl\/tree\/release\/v9.1\" data-type=\"URL\" data-id=\"https:\/\/github.com\/lvgl\/lvgl\/tree\/release\/v9.1\" target=\"_blank\">github repository<\/a>.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>Then:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"632\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/2024-05-18_15-55-06-1024x632.jpg\" alt=\"\" class=\"wp-image-2530\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/2024-05-18_15-55-06-1024x632.jpg 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/2024-05-18_15-55-06-300x185.jpg 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/2024-05-18_15-55-06-768x474.jpg 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/2024-05-18_15-55-06-1536x948.jpg 1536w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/2024-05-18_15-55-06-2048x1264.jpg 2048w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/2024-05-18_15-55-06-1150x710.jpg 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/2024-05-18_15-55-06-750x463.jpg 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/2024-05-18_15-55-06-400x247.jpg 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/2024-05-18_15-55-06-250x154.jpg 250w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>Make sure to select the latest version (V9.1 when this guide is written) and download as zip file.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>After the download, extract the zip file and rename it to be lvgl only.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>In STM32CubeIDE. create new folder with name of Drivers as following:<\/p>\n\n\n\n<p><\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"526\" height=\"572\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/2024-05-18_15-35-09.jpg\" alt=\"\" class=\"wp-image-2531\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/2024-05-18_15-35-09.jpg 526w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/2024-05-18_15-35-09-276x300.jpg 276w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/2024-05-18_15-35-09-400x435.jpg 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/2024-05-18_15-35-09-250x272.jpg 250w\" sizes=\"(max-width: 526px) 100vw, 526px\" \/><\/figure><\/div>\n\n\n\n<p>Copy the lvgl folder to the driver folder.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>Create new header file within the driver folder with name of lv_conf.h.<\/p>\n\n\n\n<p>Copy the content of <a href=\"https:\/\/github.com\/lvgl\/lvgl\/blob\/release\/v9.1\/lv_conf_template.h\" data-type=\"URL\" data-id=\"https:\/\/github.com\/lvgl\/lvgl\/blob\/release\/v9.1\/lv_conf_template.h\" target=\"_blank\" rel=\"noreferrer noopener\">this header<\/a> to lv_conf.h.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>In the header file, enable LvGL by setting this to 1 (line 15):<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">#if 1 \/*Set it to &quot;1&quot; to enable content*\/<\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>In line 30, set the color depth to 16:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">#define LV_COLOR_DEPTH 16<\/pre><\/div>\n\n\n\n<p>In line 946, enable widget demo:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">#define LV_USE_DEMO_WIDGETS 1<\/pre><\/div>\n\n\n\n<p>Save the header file.<\/p>\n\n\n\n<p>Now, we shall include the lvgl to the project<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"521\" height=\"1024\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/2024-05-18_16-01-28-521x1024.jpg\" alt=\"\" class=\"wp-image-2532\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/2024-05-18_16-01-28-521x1024.jpg 521w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/2024-05-18_16-01-28-153x300.jpg 153w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/2024-05-18_16-01-28-750x1474.jpg 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/2024-05-18_16-01-28-400x786.jpg 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/2024-05-18_16-01-28-250x491.jpg 250w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/2024-05-18_16-01-28.jpg 756w\" sizes=\"(max-width: 521px) 100vw, 521px\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>Right click on the project and select Properties.<\/p>\n\n\n\n<p>Then:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"891\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/2024-05-18_16-08-15-1024x891.jpg\" alt=\"\" class=\"wp-image-2533\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/2024-05-18_16-08-15-1024x891.jpg 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/2024-05-18_16-08-15-300x261.jpg 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/2024-05-18_16-08-15-768x668.jpg 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/2024-05-18_16-08-15-1536x1336.jpg 1536w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/2024-05-18_16-08-15-1150x1000.jpg 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/2024-05-18_16-08-15-750x652.jpg 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/2024-05-18_16-08-15-400x348.jpg 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/2024-05-18_16-08-15-250x217.jpg 250w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/2024-05-18_16-08-15.jpg 1750w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>And:<\/p>\n\n\n\n<p><\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"891\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/2024-05-18_16-09-06-1024x891.jpg\" alt=\"\" class=\"wp-image-2534\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/2024-05-18_16-09-06-1024x891.jpg 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/2024-05-18_16-09-06-300x261.jpg 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/2024-05-18_16-09-06-768x668.jpg 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/2024-05-18_16-09-06-1536x1336.jpg 1536w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/2024-05-18_16-09-06-1150x1000.jpg 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/2024-05-18_16-09-06-750x652.jpg 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/2024-05-18_16-09-06-400x348.jpg 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/2024-05-18_16-09-06-250x217.jpg 250w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/05\/2024-05-18_16-09-06.jpg 1750w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>Click on apply and close.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>Now, in delay.c source file:<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>Include the lvgl.h header file:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">#include &quot;lvgl.h&quot;<\/pre><\/div>\n\n\n\n<p>Within the systick interrupt handler, call lv_tick_inc(1) which means increase the lv tick by 1ms:<\/p>\n\n\n\n<p><\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">lv_tick_inc(1);<\/pre><\/div>\n\n\n\n<p>In main.c file:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-csrc&quot;,&quot;theme&quot;:&quot;dracula&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:false,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;&quot;,&quot;language&quot;:&quot;C&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;c&quot;}\">#include &quot;LCD_Pins.h&quot;\n#include &quot;ILI9341.h&quot;\n#include &quot;i2c3.h&quot;\n#include &quot;STMPE811.h&quot;\n#include &quot;LCDController.h&quot;\n#include &quot;demos\/lv_demos.h&quot;\n#include &quot;TouchController.h&quot;\n\n\n\nint main(void)\n{\n\tdelay_init(180000000);\n\n\ti2c3_init();\n\n\tLCD_Pin_Init();\n\tLCD_SPI_Init();\n\tlv_init();\n\tlv_port_disp_init();\n\tlv_port_indev_init();\n\tlv_demo_widgets();\n\n\twhile(1)\n\t{\n\t\tlv_timer_handler();\n\t\tdelay(5);\n\n\t}\n}\n<\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">3. Code Download:<\/h2>\n\n\n\n<p>You may download the entire project from here:<\/p>\n\n\n\n<div class=\"wp-block-file\"><a href=\"https:\/\/blog.embeddedexpert.io\/9c5abad1-cccb-4c62-ba73-167db6e228cd\" class=\"wp-block-file__button\" download>Download<\/a><\/div>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">4. Demo:<\/h2>\n\n\n\n<p><\/p>\n\n\n\n<figure class=\"wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" title=\"LvGL V9 Demo on STM32F429\" width=\"1170\" height=\"658\" src=\"https:\/\/www.youtube.com\/embed\/sGsvpj9oM6Q?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>Happy coding \ud83d\ude09 <\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this guide, we shall integrate LvGL and initialize the LCD, touch LvGL itself. In this guide, we shall cover the following: TFT integration. Touch integration. LvGL integration. Code download. Results. List of the previous parts: Part 1 Part 2 1. TFT Integration: Create new source and header file with name of LCDController.c and LCDController.h [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-2528","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/2528"}],"collection":[{"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=2528"}],"version-history":[{"count":1,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/2528\/revisions"}],"predecessor-version":[{"id":2535,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/2528\/revisions\/2535"}],"wp:attachment":[{"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2528"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2528"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2528"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}