{"id":2274,"date":"2024-01-13T14:06:35","date_gmt":"2024-01-13T14:06:35","guid":{"rendered":"https:\/\/blog.embeddedexpert.io\/?p=2274"},"modified":"2024-01-17T04:34:41","modified_gmt":"2024-01-17T04:34:41","slug":"getting-started-with-lvgl-part-1-introduction-and-environment-setup","status":"publish","type":"post","link":"https:\/\/blog.embeddedexpert.io\/?p=2274","title":{"rendered":"Getting Started with LvGL Part 1: Introduction and environment setup"},"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\/01\/logo_lvgl.png\" alt=\"\" class=\"wp-image-2275\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/01\/logo_lvgl.png 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/01\/logo_lvgl-250x79.png 250w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/figure><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>In this new guide series, we shall take a look at LvGL and develop driver to display LvGL and touch control.<\/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>What is LvGL.<\/li><li>Required hardware.<\/li><li>TFT connection.<\/li><li>Environment setup.<\/li><li>Essential drivers.<\/li><\/ul>\n\n\n\n<p><\/p>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">1. What is LvGL:<\/h2>\n\n\n\n<p>LvGL is a free and open-source graphics library that allows you to create beautiful and versatile user interfaces for any embedded device, such as microcontrollers, microprocessors, and displays. It has many features, such as widgets, styles, layouts, fonts, animations, and events. It also has a professional UI editor tool, called SquareLine Studio, that lets you design and develop your UIs with drag and drop. LvGL is supported by many vendors and projects, such as Arm, STM32, NXP, Espressif, Arduino, and more. You can learn more about LvGL on its <a href=\"^1^\">website<\/a> or <a href=\"^2^\">GitHub<\/a> page.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>In simple terms, it is Light versatile Graphics Library.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">2. Required Hardware:<\/h2>\n\n\n\n<p>First we shall use STM32F767ZI Nucleo-144 board as shown in figure below:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"640\" height=\"640\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/01\/NUCLEO-F767ZI.jpg\" alt=\"\" class=\"wp-image-2276\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/01\/NUCLEO-F767ZI.jpg 640w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/01\/NUCLEO-F767ZI-300x300.jpg 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/01\/NUCLEO-F767ZI-150x150.jpg 150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/01\/NUCLEO-F767ZI-400x400.jpg 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/01\/NUCLEO-F767ZI-250x250.jpg 250w\" sizes=\"(max-width: 640px) 100vw, 640px\" \/><\/figure><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>Also, we need 2.4 ILI9341 Touch screen as shown in figure:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"612\" height=\"612\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/01\/12f28942-feeb-445f-bcaf-e8927a6c2824.1b07a5935ffb6219e5dccd5006eb9a50.jpeg.webp\" alt=\"\" class=\"wp-image-2277\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/01\/12f28942-feeb-445f-bcaf-e8927a6c2824.1b07a5935ffb6219e5dccd5006eb9a50.jpeg.webp 612w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/01\/12f28942-feeb-445f-bcaf-e8927a6c2824.1b07a5935ffb6219e5dccd5006eb9a50.jpeg-300x300.webp 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/01\/12f28942-feeb-445f-bcaf-e8927a6c2824.1b07a5935ffb6219e5dccd5006eb9a50.jpeg-150x150.webp 150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/01\/12f28942-feeb-445f-bcaf-e8927a6c2824.1b07a5935ffb6219e5dccd5006eb9a50.jpeg-400x400.webp 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/01\/12f28942-feeb-445f-bcaf-e8927a6c2824.1b07a5935ffb6219e5dccd5006eb9a50.jpeg-250x250.webp 250w\" sizes=\"(max-width: 612px) 100vw, 612px\" \/><\/figure><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">3. TFT Connection:<\/h2>\n\n\n\n<p>The connection of TFT with STM32 (display only) as following:<\/p>\n\n\n\n<figure class=\"wp-block-table is-style-regular\"><table><tbody><tr><td class=\"has-text-align-center\" data-align=\"center\">2.4 TFT SPI<\/td><td class=\"has-text-align-center\" data-align=\"center\">STM32F767ZI-Nucleo144<\/td><\/tr><tr><td class=\"has-text-align-center\" data-align=\"center\">Vcc<\/td><td class=\"has-text-align-center\" data-align=\"center\">5V<\/td><\/tr><tr><td class=\"has-text-align-center\" data-align=\"center\">GND<\/td><td class=\"has-text-align-center\" data-align=\"center\">GND<\/td><\/tr><tr><td class=\"has-text-align-center\" data-align=\"center\">CS<\/td><td class=\"has-text-align-center\" data-align=\"center\">PF3<\/td><\/tr><tr><td class=\"has-text-align-center\" data-align=\"center\">RESET<\/td><td class=\"has-text-align-center\" data-align=\"center\">PF10<\/td><\/tr><tr><td class=\"has-text-align-center\" data-align=\"center\">D\/C<\/td><td class=\"has-text-align-center\" data-align=\"center\">PF5<\/td><\/tr><tr><td class=\"has-text-align-center\" data-align=\"center\">MOSI<\/td><td class=\"has-text-align-center\" data-align=\"center\">PA7<\/td><\/tr><tr><td class=\"has-text-align-center\" data-align=\"center\">SCK<\/td><td class=\"has-text-align-center\" data-align=\"center\">PA5<\/td><\/tr><tr><td class=\"has-text-align-center\" data-align=\"center\">LED<\/td><td class=\"has-text-align-center\" data-align=\"center\">3V3<\/td><\/tr><tr><td class=\"has-text-align-center\" data-align=\"center\">MISO<\/td><td class=\"has-text-align-center\" data-align=\"center\">Not needed<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">4. Environment setup:<\/h2>\n\n\n\n<p>In order to prepare STM32CubeIDE to work with register level programming, we need to setup it up in such way, it allows us to do.<\/p>\n\n\n\n<p>Follow the instruction in this guide <a rel=\"noreferrer noopener\" href=\"https:\/\/blog.embeddedexpert.io\/?p=1255\" data-type=\"URL\" data-id=\"https:\/\/blog.embeddedexpert.io\/?p=1255\" target=\"_blank\">here<\/a>.<\/p>\n\n\n\n<p>Replace STM32F4 with STM32F7<\/p>\n\n\n\n<p>Also, we shall put the header file into folder named driver.<\/p>\n\n\n\n<p>Hence, the project structure looks like this:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"604\" height=\"704\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/01\/Screenshot-2024-01-13-at-4.35.53\u202fPM.png\" alt=\"\" class=\"wp-image-2278\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/01\/Screenshot-2024-01-13-at-4.35.53\u202fPM.png 604w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/01\/Screenshot-2024-01-13-at-4.35.53\u202fPM-257x300.png 257w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/01\/Screenshot-2024-01-13-at-4.35.53\u202fPM-400x466.png 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/01\/Screenshot-2024-01-13-at-4.35.53\u202fPM-250x291.png 250w\" sizes=\"(max-width: 604px) 100vw, 604px\" \/><\/figure>\n\n\n\n<p>Paths:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"312\" src=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/01\/Screenshot-2024-01-13-at-4.39.25\u202fPM-1024x312.png\" alt=\"\" class=\"wp-image-2279\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/01\/Screenshot-2024-01-13-at-4.39.25\u202fPM-1024x312.png 1024w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/01\/Screenshot-2024-01-13-at-4.39.25\u202fPM-300x91.png 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/01\/Screenshot-2024-01-13-at-4.39.25\u202fPM-768x234.png 768w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/01\/Screenshot-2024-01-13-at-4.39.25\u202fPM-1150x350.png 1150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/01\/Screenshot-2024-01-13-at-4.39.25\u202fPM-750x228.png 750w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/01\/Screenshot-2024-01-13-at-4.39.25\u202fPM-400x122.png 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/01\/Screenshot-2024-01-13-at-4.39.25\u202fPM-250x76.png 250w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/01\/Screenshot-2024-01-13-at-4.39.25\u202fPM.png 1466w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Symbol should be:<\/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;}\">STM32F767xx<\/pre><\/div>\n\n\n\n<p>Or simply, download the correct project setup from here:<\/p>\n\n\n\n<div class=\"wp-block-file\"><a href=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/01\/LvGL-1.zip\">LvGL-1<\/a><a href=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/01\/LvGL-1.zip\" class=\"wp-block-file__button\" download>Download<\/a><\/div>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">5. Essential Drivers:<\/h2>\n\n\n\n<p>First, we need to push the STM32F767 to maximum speed of 216MHz, refer to <a rel=\"noreferrer noopener\" href=\"https:\/\/blog.embeddedexpert.io\/?p=531\" data-type=\"URL\" data-id=\"https:\/\/blog.embeddedexpert.io\/?p=531\" target=\"_blank\">this guide<\/a> for how push the core frequency to maximum.<\/p>\n\n\n\n<p>We start by creating new source file with name of sys_init.c:<\/p>\n\n\n\n<p>Within the source file:<\/p>\n\n\n\n<p>Include the following header:<\/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;stm32f7xx.h&quot;<\/pre><\/div>\n\n\n\n<p>Declare the following function:<\/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 SystemInit(void) \/\/set the core frequency to 216MHz<\/pre><\/div>\n\n\n\n<p>Within the function:<\/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 PLL_M      4\n#define PLL_N      216\n#define PLL_P      2\n\n\t__IO uint32_t StartUpCounter = 0, HSEStatus = 0;\n\n\n\tRCC-&gt;CR |= ((uint32_t)RCC_CR_HSEON);\n\n\tdo\n\t{\n\t\tHSEStatus = RCC-&gt;CR &amp; RCC_CR_HSERDY;\n\t\tStartUpCounter++;\n\t} while((HSEStatus == 0) &amp;&amp; (StartUpCounter != 3000));\n\n\n\tif ((RCC-&gt;CR &amp; RCC_CR_HSERDY) != RESET)\n\t{\n\t\tHSEStatus = (uint32_t)0x01;\n\t}\n\telse\n\t{\n\t\tHSEStatus = (uint32_t)0x00;\n\t}\n\n\tif (HSEStatus == (uint32_t)0x01)\n\t{\n\n\t\tRCC-&gt;APB1ENR |= RCC_APB1ENR_PWREN;\n\t\tPWR-&gt;CR1 &amp;= (uint32_t)~(PWR_CR1_VOS);\n\n\n\t\tRCC-&gt;CFGR |= RCC_CFGR_HPRE_DIV1;\n\n\n\t\tRCC-&gt;CFGR |= RCC_CFGR_PPRE2_DIV2;\n\n\n\t\tRCC-&gt;CFGR |= RCC_CFGR_PPRE1_DIV4;\n\n\n\t\tRCC-&gt;PLLCFGR = PLL_M | (PLL_N &lt;&lt; RCC_PLLCFGR_PLLN_Pos) | (((PLL_P &gt;&gt; 1) -1) &lt;&lt; RCC_PLLCFGR_PLLP_Pos) |\n\t\t\t\t(RCC_PLLCFGR_PLLSRC_HSE);\n\n\n\t\tRCC-&gt;CR |= RCC_CR_PLLON;\n\n\n\t\twhile((RCC-&gt;CR &amp; RCC_CR_PLLRDY) == 0)\n\t\t{\n\t\t}\n\n\t\t\/* Configure Flash prefetch, Instruction cache, Data cache and wait state *\/\n\t\tFLASH-&gt;ACR = FLASH_ACR_LATENCY_7WS;\n\n\t\t\/* Select the main PLL as system clock source *\/\n\t\tRCC-&gt;CFGR &amp;= (uint32_t)((uint32_t)~(RCC_CFGR_SW));\n\t\tRCC-&gt;CFGR |= RCC_CFGR_SW_PLL;\n\n\t\t\/* Wait till the main PLL is used as system clock source *\/\n\t\twhile ((RCC-&gt;CFGR &amp; (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL)\n\t\t{;}\n\t\t}\n\telse\n\t{ \t\/* If HSE fails to start-up, the application will have wrong clock\n\t\t\tconfiguration. User can add here some code to deal with this error *\/\n\t}<\/pre><\/div>\n\n\n\n<p>After the core has been set to maximum, we need to enable the floating point hardware and enable cell compensation to improve the speed of the GPIOs 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;}\">\t\/*Enable float point hardware*\/\n\tSCB-&gt;CPACR |= ((3UL &lt;&lt; 10*2)|(3UL &lt;&lt; 11*2));\n\n\t\/*Enable cell compensation*\/\n\tRCC-&gt;APB2ENR|=RCC_APB2ENR_SYSCFGEN ;\n\tSYSCFG-&gt;CMPCR|=SYSCFG_CMPCR_CMP_PD;\n\twhile(!((SYSCFG-&gt;CMPCR)&amp;(SYSCFG_CMPCR_READY))){;}<\/pre><\/div>\n\n\n\n<p>Note: This function will be called upon system boot and doesn&#8217;t need to be called anywhere else.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>Next, LEDs. <\/p>\n\n\n\n<p>Since STM32F767ZI Nucleo-144 features 3-LED, we can create functions to set the state of them.<\/p>\n\n\n\n<p>For more information about the LEDs and how to enable them, please refer to <a href=\"https:\/\/blog.embeddedexpert.io\/?p=514\" data-type=\"URL\" data-id=\"https:\/\/blog.embeddedexpert.io\/?p=514\" target=\"_blank\" rel=\"noreferrer noopener\">this guide<\/a>.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>Create new source and header file with name of LEDs.c and LEDs.h respectively.<\/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 LEDS_H_\n#define LEDS_H_\n\n#include &quot;stdint.h&quot;\n\ntypedef enum\n{\n\tGreen=0,\n\tBlue=1,\n\tRed=2\n}LEDs;\n\ntypedef enum\n{\n\tOFF=0,\n\tON=1\n}LEDState;\n\nvoid LEDs_Init(void);\n\nvoid LED_Write(LEDs led, LEDState state);\n\n#endif \/* LEDS_H_ *\/<\/pre><\/div>\n\n\n\n<p>Within 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;}\">#include &quot;LEDs.h&quot;\n#include &quot;stm32f7xx.h&quot;\n\nvoid LEDs_Init(void)\n{\n\tRCC-&gt;AHB1ENR|=RCC_AHB1ENR_GPIOBEN;\n\n\tGPIOB-&gt;MODER|=GPIO_MODER_MODER0_0|GPIO_MODER_MODER7_0|GPIO_MODER_MODER14_0;\n\tGPIOB-&gt;MODER&amp;=~(GPIO_MODER_MODER0_1|GPIO_MODER_MODER7_1|GPIO_MODER_MODER14_1);\n}\n\nvoid LED_Write(LEDs led, LEDState state)\n{\n\tswitch (led)\n\t{\n\t\tcase Green:\n\t\t\tif(state==OFF)\n\t\t\t{\n\t\t\t\tGPIOB-&gt;BSRR=GPIO_BSRR_BR0;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tGPIOB-&gt;BSRR=GPIO_BSRR_BS0;\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase Blue:\n\t\t\tif(state==OFF)\n\t\t\t{\n\t\t\t\tGPIOB-&gt;BSRR=GPIO_BSRR_BR7;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tGPIOB-&gt;BSRR=GPIO_BSRR_BS7;\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase Red:\n\t\t\tif(state==OFF)\n\t\t\t{\n\t\t\t\tGPIOB-&gt;BSRR=GPIO_BSRR_BR14;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tGPIOB-&gt;BSRR=GPIO_BSRR_BS14;\n\t\t\t}\n\t\t\tbreak;\n\n\t\tdefault : break;\n\n\t}\n\n}\n<\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>Also, we need time base for our system, hence, we shall use SysTick.<\/p>\n\n\n\n<p>Create new source and header file with name of time_base.c and time_base.h respectively.<\/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 TIME_BASE_H_\n#define TIME_BASE_H_\n\n#include &quot;stdint.h&quot;\n\n\/*\n * @brief This function will initialize SysTick\n * to generate 1ms interrupt.\n * @param freq source frequency of SysTick.\n * @return nothing.\n * @see Generic ARM CortexM4 user guide.\n * *\/\n\nvoid Time_Base_Init(uint32_t freq);\n\n\/*\n * @brief This function will return the current millis.\n *\n * @param nothing.\n * @return current time in millis.\n * *\/\nuint64_t Tick_Get();\n\n\n\/*\n * @brief This function will spin lock the CPU to delay for the required\n * amount\n * @param time to be delayed in milliseconds.\n * @return nothing.\n * *\/\nvoid delay(uint32_t time);\n\n\n#endif \/* TIME_BASE_H_ *\/\n<\/pre><\/div>\n\n\n\n<p>Within the source file:<\/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;}\">#include &quot;stm32f7xx.h&quot;\n#include &quot;time_base.h&quot;\n\n\n\n#define\tCTRL_ENABLE\t\t\t\t\t(1U&lt;&lt;0) \/*Enable SysTick Timer*\/\n#define CTRL_CLKSRC\t\t\t\t\t(1U&lt;&lt;2) \/*Clock source selection*\/\n#define CTRL_COUNTFLAG\t\t\t\t(1U&lt;&lt;16) \/*Count flag bit*\/\n#define CTRL_TICKINT\t\t\t\t(1U&lt;&lt;1) \/*Interrupt enable bit*\/\n\n\nvolatile uint64_t mil; \/*volatile variable to hold the ms counter*\/\n\n\n\n\nvoid Time_Base_Init(uint32_t  freq)\n{\n\t\/*Disable global interrupt*\/\n\t__disable_irq();\n\n\t\/*Set period to be 1ms*\/\n\tSysTick-&gt;LOAD=(freq\/1000)-1;\n\n\t\/*Reset the systick value*\/\n\tSysTick-&gt;VAL=0;\n\n\t\/*Enable systick and select internal clk src*\/\n\tSysTick-&gt;CTRL = CTRL_ENABLE | CTRL_CLKSRC ;\n\n\t\/*Enable systick interrupt*\/\n\tSysTick-&gt;CTRL  |= CTRL_TICKINT;\n\n\t\/*Enable global interrupt*\/\n\t__enable_irq();\n}\n\nuint64_t Tick_Get(void)\n{\n\t__disable_irq(); \/*Disable global interrupt*\/\n\n\tuint64_t ml=mil; \/*Get the current millis values and store in ml*\/\n\n\t__enable_irq(); \/*Enable global interrupt*\/\n\n\treturn ml;\t\t\/*Return the stored value*\/\n}\n\n\n\/*Spin lock the CPU to delay*\/\nvoid delay(uint32_t time)\n{\n\n\tuint64_t start=Tick_Get();\n\twhile((Tick_Get() - start) &lt; (time+1));\n}\n\n\/*Interrupt handler of SysTick*\/\nvoid SysTick_Handler(void)\n{\n\t\/*Increment the counter with every interrupt*\/\n\tmil++;\n\n}\n<\/pre><\/div>\n\n\n\n<p>Next, we shall use SPI1 to transmit data to the TFT using DMA for LvGL and polling for the initialization sequence.<\/p>\n\n\n\n<p>For more information to transmit data over DMA, please refer to<a href=\"https:\/\/blog.embeddedexpert.io\/?p=2257\" data-type=\"URL\" data-id=\"https:\/\/blog.embeddedexpert.io\/?p=2257\" target=\"_blank\" rel=\"noreferrer noopener\"> this guide<\/a>.<\/p>\n\n\n\n<p>For the polling mode from <a href=\"https:\/\/blog.embeddedexpert.io\/?p=739\" data-type=\"URL\" data-id=\"https:\/\/blog.embeddedexpert.io\/?p=739\" target=\"_blank\" rel=\"noreferrer noopener\">here<\/a>.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>Create new source and header file with name of SPI1.c and SPI1.h respectively.<\/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 SPI1_H_\n#define SPI1_H_\n\n#include &quot;stdint.h&quot;\n\nvoid SPI1_Pins_Init(void);\n\nvoid SPI1_DMA_Init(void);\n\nvoid SPI1_TX(uint8_t *data,uint32_t size);\n\nvoid SPI1_TX_DMA(uint8_t *data,uint16_t len);\n\n\n#endif \/* SPI1_H_ *\/<\/pre><\/div>\n\n\n\n<p>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;}\">#include &quot;stm32f7xx.h&quot;\n\n#include &quot;SPI1.h&quot;\n#include &quot;time_base.h&quot;\n\n#define AF05 0x05\n\n#define CH3 0x03\n\n\nvoid SPI1_Pins_Init(void)\n{\n\t\/\/enable clock for GPIOA\n\tRCC-&gt;AHB1ENR|=RCC_AHB1ENR_GPIOAEN;\n\n\t\/\/set PA5, PA6 and PA7 to alternate function mode\n\tGPIOA-&gt;MODER|=GPIO_MODER_MODER5_1|GPIO_MODER_MODER6_1|GPIO_MODER_MODER7_1;\n\n\tGPIOA-&gt;MODER&amp;=~(GPIO_MODER_MODER5_0|GPIO_MODER_MODER6_0|GPIO_MODER_MODER7_0);\n\n\tGPIOA-&gt;AFR[0]|=(AF05&lt;&lt;GPIO_AFRL_AFRL5_Pos)|(AF05&lt;&lt;GPIO_AFRL_AFRL6_Pos)|(AF05&lt;&lt;GPIO_AFRL_AFRL7_Pos);\n\n\n}\n\n\nvoid SPI1_DMA_Init(void)\n{\n\t\/\/enable clock access to SPI1\n\tRCC-&gt;APB2ENR|=RCC_APB2ENR_SPI1EN;\n\n\t\/\/software slave management\n\tSPI1-&gt;CR1|=SPI_CR1_SSM|SPI_CR1_SSI;\n\n\t\/*Set clock to fPCLK\/4*\/\n\tSPI1-&gt;CR1 |=(SPI_CR1_BR_0);\n\n\t\/\/ set SPI as master mode\n\tSPI1-&gt;CR1|=SPI_CR1_MSTR;\n\n\t\/*Set CPOL to 0 and CPHA to 0*\/\n\tSPI1-&gt;CR1 &amp;=~SPI_CR1_CPOL;\n\tSPI1-&gt;CR1 &amp;=~SPI_CR1_CPHA;\n\n\t\/*Set data size to 8-bit*\/\n\tSPI1-&gt;CR2&amp;=~(SPI_CR2_DS_Msk);\n\tSPI1-&gt;CR2|=(0x07&lt;&lt;SPI_CR2_DS_Pos);\n\n\t\/*Enable TXDMA*\/\n\tSPI1-&gt;CR2|=SPI_CR2_TXDMAEN;\n\n\t\/*Enable SPI global interrupt*\/\n\n\tNVIC_EnableIRQ(SPI1_IRQn);\n\n\t\/*Enable SPI peripheral*\/\n\tSPI1-&gt;CR1|=SPI_CR1_SPE;\n\n\t\/*Enable Clock Access to DMA2*\/\n\tRCC-&gt;AHB1ENR|=RCC_AHB1ENR_DMA2EN;\n\n\t\/*Disable the Stream*\/\n\t\/*Disable the Stream and make sure it is disabled*\/\n\tDMA2_Stream3-&gt;CR&amp;=~DMA_SxCR_EN;\n\n\twhile((DMA2_Stream3-&gt;CR)&amp;DMA_SxCR_EN){;}\n\n\t\/*Configure the DMA with the following parameters\n\t *\n\t * CH -&gt; channel 3.\n\t * Memory increment mode.\n\t * Enable Transfer Complete interrupt\n\t * *\/\n\n\tDMA2_Stream3-&gt;CR=(CH3&lt;&lt;DMA_SxCR_CHSEL_Pos)|DMA_SxCR_MINC|DMA_SxCR_DIR_0|DMA_SxCR_TCIE;\n\n\t\/*Enable DMA2_Stream3 interrupt in NVIC*\/\n\tNVIC_EnableIRQ(DMA2_Stream3_IRQn);\n\n\n}\n\n\n\nvoid SPI1_TX(uint8_t *data,uint32_t size)\n{\n\tuint32_t i=0;\n\twhile(i&lt;size)\n\t{\n\t\t\/*Wait until TXE is set*\/\n\t\twhile(!(SPI1-&gt;SR &amp; (SPI_SR_TXE)))\n\t\t{}\n\n\t\t\/*Write the data to the data register*\/\n\t\t*((volatile uint8_t *)&amp;SPI1-&gt;DR) = data[i];\n\t\ti++;\n\t}\n\t\/*Wait until TXE is set*\/\n\twhile(!(SPI1-&gt;SR &amp; (SPI_SR_TXE))){}\n\n\t\/*Wait for BUSY flag to reset*\/\n\twhile((SPI1-&gt;SR &amp; (SPI_SR_BSY))){}\n\n\t\/*Clear OVR flag*\/\n\t(void)SPI1-&gt;DR;\n\t(void)SPI1-&gt;SR;\n}\n\n\n\n\n\nvoid SPI1_TX_DMA(uint8_t *data,uint16_t len)\n{\n\n\n\tDMA2-&gt;LIFCR |=DMA_LIFCR_CTCIF3;\n\tDMA2_Stream3-&gt;PAR=(uint32_t)&amp;SPI1-&gt;DR;\n\tDMA2_Stream3-&gt;M0AR=(uint32_t)data;\n\tDMA2_Stream3-&gt;NDTR=len;\n\tDMA2_Stream3-&gt;CR|=DMA_SxCR_EN;\n\n}\n\n\n__WEAK void SPI_TX_Finished(void)\n{\n\t\/*Override with user code*\/\n}\n\n\nvoid DMA2_Stream3_IRQHandler(void)\n{\n\tif(DMA2-&gt;LISR&amp;(DMA_LISR_TCIF3))\n\t{\n\t\t\/*Enable SPI Tx buffer empty interrupt *\/\n\n\t\tSPI1-&gt;CR2|=SPI_CR2_TXEIE;\n\n\t\t\/*Clear pending flag*\/\n\t\tDMA2-&gt;LIFCR |=DMA_LIFCR_CTCIF3;\n\t}\n}\n\nvoid SPI1_IRQHandler(void)\n{\n\tif ((SPI1-&gt;SR &amp; SPI_SR_TXE) &amp;&amp; ((SPI1-&gt;SR &amp; SPI_SR_BSY)==0))\n\t{\n\t\t\/*Set finished to 1*\/\n\t\tSPI_TX_Finished();\n\n\t\t\/*Disable SPI Tx Buffer empty interrupt*\/\n\t\tSPI1-&gt;CR2&amp;=~SPI_CR2_TXEIE;\n\n\n\n\n\t}\n}\n<\/pre><\/div>\n\n\n\n<p>Now, we shall deal with the LCD pins.<\/p>\n\n\n\n<p>Create new source and header file with name of LCD_Pins.c and LCD_Pins.h.<\/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 LCD_PINS_H_\n#define LCD_PINS_H_\n\n#include &quot;stdint.h&quot;\n\nvoid LCD_Pins_Init(void);\n\nvoid CS_LOW(void);\n\nvoid CS_HIGH(void);\n\nvoid DC_LOW (void);\n\nvoid DC_HIGH (void);\n\nvoid LCD_RST(void);\n\n\n#endif \/* LCD_PINS_H_ *\/<\/pre><\/div>\n\n\n\n<p>Within 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;}\">#include &quot;LCD_Pins.h&quot;\n\n#include &quot;stm32f7xx.h&quot;\n#include &quot;time_base.h&quot;\n\/*Connection\n *\n * PF3 -&gt;CS\n * PF5 -&gt;DC\n * PF10 -&gt;RST\n *\n * *\/\n\n\n\nvoid LCD_Pins_Init(void)\n{\n\tRCC-&gt;AHB1ENR|=RCC_AHB1ENR_GPIOFEN;\n\n\tGPIOF-&gt;MODER|=GPIO_MODER_MODER3_0|GPIO_MODER_MODER5_0|GPIO_MODER_MODER10_0;\n\tGPIOF-&gt;MODER&amp;=~(GPIO_MODER_MODER3_1|GPIO_MODER_MODER5_1|GPIO_MODER_MODER10_1);\n\n\t\/*Set CS and RST to high*\/\n\tGPIOF-&gt;BSRR=GPIO_BSRR_BS3|GPIO_BSRR_BS10;\n}\n\n\nvoid CS_LOW(void)\n{\n\tGPIOF-&gt;BSRR=GPIO_BSRR_BR3;\n}\n\nvoid CS_HIGH(void)\n{\n\tGPIOF-&gt;BSRR=GPIO_BSRR_BS3;\n}\n\nvoid DC_LOW (void)\n{\n\tGPIOF-&gt;BSRR=GPIO_BSRR_BR5;\n}\n\nvoid DC_HIGH (void)\n{\n\tGPIOF-&gt;BSRR=GPIO_BSRR_BS5;\n}\n\nvoid LCD_RST(void)\n{\n\tGPIOF-&gt;BSRR=GPIO_BSRR_BR10;\n\tdelay(100);\n\tGPIOF-&gt;BSRR=GPIO_BSRR_BS10;\n\tdelay(10);\n\n}<\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>Next, we shall deal with TFT.<\/p>\n\n\n\n<p>Create new source and header file with name of ILI_9341.c and ILI_9341.h respectively.<\/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 ILI_9341_H_\n#define ILI_9341_H_\n\n\n#include &quot;stdint.h&quot;\n\n\n\n\n\/\/LCD dimensions defines\n#define ILI9341_WIDTH       320\n#define ILI9341_HEIGHT      240\n\n\n#define ILI9341_PIXEL_COUNT\tILI9341_WIDTH * ILI9341_HEIGHT\n\n\n\/\/ILI9341 LCD commands\n#define ILI9341_RESET\t\t\t \t\t    0x01\n#define ILI9341_SLEEP_OUT\t\t  \t\t\t0x11\n#define ILI9341_GAMMA\t\t\t    \t\t0x26\n#define ILI9341_DISPLAY_OFF\t\t\t\t\t0x28\n#define ILI9341_DISPLAY_ON\t\t\t\t\t0x29\n#define ILI9341_COLUMN_ADDR\t\t\t\t\t0x2A\n#define ILI9341_PAGE_ADDR\t\t\t  \t\t0x2B\n#define ILI9341_GRAM\t\t\t\t    \t0x2C\n#define ILI9341_TEARING_OFF\t\t\t\t\t0x34\n#define ILI9341_TEARING_ON\t\t\t\t\t0x35\n#define ILI9341_DISPLAY_INVERSION\t\t\t0xb4\n#define ILI9341_MAC\t\t\t        \t\t0x36\n#define ILI9341_PIXEL_FORMAT    \t\t\t0x3A\n#define ILI9341_WDB\t\t\t    \t  \t\t0x51\n#define ILI9341_WCD\t\t\t\t      \t\t0x53\n#define ILI9341_RGB_INTERFACE   \t\t\t0xB0\n#define ILI9341_FRC\t\t\t\t\t    \t0xB1\n#define ILI9341_BPC\t\t\t\t\t    \t0xB5\n#define ILI9341_DFC\t\t\t\t \t    \t0xB6\n#define ILI9341_Entry_Mode_Set\t\t\t\t0xB7\n#define ILI9341_POWER1\t\t\t\t\t\t0xC0\n#define ILI9341_POWER2\t\t\t\t\t\t0xC1\n#define ILI9341_VCOM1\t\t\t\t\t\t0xC5\n#define ILI9341_VCOM2\t\t\t\t\t\t0xC7\n#define ILI9341_POWERA\t\t\t\t\t\t0xCB\n#define ILI9341_POWERB\t\t\t\t\t\t0xCF\n#define ILI9341_PGAMMA\t\t\t\t\t\t0xE0\n#define ILI9341_NGAMMA\t\t\t\t\t\t0xE1\n#define ILI9341_DTCA\t\t\t\t\t\t0xE8\n#define ILI9341_DTCB\t\t\t\t\t\t0xEA\n#define ILI9341_POWER_SEQ\t\t\t\t\t0xED\n#define ILI9341_3GAMMA_EN\t\t\t\t\t0xF2\n#define ILI9341_INTERFACE\t\t\t\t\t0xF6\n#define ILI9341_PRC\t\t\t\t   \t  \t\t0xF7\n#define ILI9341_VERTICAL_SCROLL \t\t\t0x33\n\n#define ILI9341_MEMCONTROL         \t0x36\n#define ILI9341_MADCTL_MY  \t\t\t0x80\n#define ILI9341_MADCTL_MX  \t\t\t0x40\n#define ILI9341_MADCTL_MV  \t\t\t0x20\n#define ILI9341_MADCTL_ML  \t\t\t0x10\n#define ILI9341_MADCTL_RGB \t\t\t0x00\n#define ILI9341_MADCTL_BGR \t\t\t0x08\n#define ILI9341_MADCTL_MH  \t\t\t0x04\n\n\nvoid ILI9341_Init(void);\n\nvoid setAddrWindow(uint16_t X1, uint16_t Y1, uint16_t X2, uint16_t Y2);\n\nvoid ILI9341_DrawBitmap(uint16_t w, uint16_t h, uint8_t *s);\n\n\n\n\n\n#endif \/* ILI_9341_H_ *\/<\/pre><\/div>\n\n\n\n<p>Within 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;}\">#include &quot;ILI_9341.h&quot;\n#include &quot;SPI1.h&quot;\n#include &quot;LCD_Pins.h&quot;\n#include &quot;time_base.h&quot;\n\n\nstatic void LCD_Write_Cmd(uint8_t cmd)\n{\n\tCS_LOW();\n\tDC_LOW();\n\tSPI1_TX(&amp;cmd,1);\n\tCS_HIGH();\n\n}\n\nstatic void LCD_Write_Data (uint8_t data)\n{\n\tCS_LOW();\n\tDC_HIGH();\n\tSPI1_TX(&amp;data,1);\n\tCS_HIGH();\n}\n\nvoid ILI9341_Init(void)\n{\n\tLCD_RST(); \/*Reset the LCD*\/\n\n\tLCD_Write_Cmd (ILI9341_DISPLAY_OFF); \/\/ display off\n\t\/\/------------power control------------------------------\n\tLCD_Write_Cmd (ILI9341_POWER1); \/\/ power control\n\tLCD_Write_Data   (0x26); \/\/ GVDD = 4.75v\n\tLCD_Write_Cmd (ILI9341_POWER2); \/\/ power control\n\tLCD_Write_Data   (0x11); \/\/ AVDD=VCIx2, VGH=VCIx7, VGL=-VCIx3\n\t\/\/--------------VCOM-------------------------------------\n\tLCD_Write_Cmd (ILI9341_VCOM1); \/\/ vcom control\n\tLCD_Write_Data   (0x35); \/\/ Set the VCOMH voltage (0x35 = 4.025v)\n\tLCD_Write_Data   (0x3e); \/\/ Set the VCOML voltage (0x3E = -0.950v)\n\tLCD_Write_Cmd (ILI9341_VCOM2); \/\/ vcom control\n\tLCD_Write_Data   (0xbe);\n\n\t\/\/------------memory access control------------------------\n\tLCD_Write_Cmd (ILI9341_MAC); \/\/ memory access control\n\tLCD_Write_Data(0x48);\n\n\tLCD_Write_Cmd (ILI9341_PIXEL_FORMAT); \/\/ pixel format set\n\tLCD_Write_Data   (0x55); \/\/ 16bit \/pixel\n\n\tLCD_Write_Cmd(ILI9341_FRC);\n\tLCD_Write_Data(0);\n\tLCD_Write_Data(0x1F);\n\t\/\/-------------ddram ----------------------------\n\tLCD_Write_Cmd (ILI9341_COLUMN_ADDR); \/\/ column set\n\tLCD_Write_Data   (0x00); \/\/ x0_HIGH---0\n\tLCD_Write_Data   (0x00); \/\/ x0_LOW----0\n\tLCD_Write_Data   (0x00); \/\/ x1_HIGH---240\n\tLCD_Write_Data   (0x1D); \/\/ x1_LOW----240\n\tLCD_Write_Cmd (ILI9341_PAGE_ADDR); \/\/ page address set\n\tLCD_Write_Data   (0x00); \/\/ y0_HIGH---0\n\tLCD_Write_Data   (0x00); \/\/ y0_LOW----0\n\tLCD_Write_Data   (0x00); \/\/ y1_HIGH---320\n\tLCD_Write_Data   (0x27); \/\/ y1_LOW----320\n\n\tLCD_Write_Cmd (ILI9341_TEARING_OFF); \/\/ tearing effect off\n\t\/\/LCD_write_cmd(ILI9341_TEARING_ON); \/\/ tearing effect on\n\t\/\/LCD_write_cmd(ILI9341_DISPLAY_INVERSION); \/\/ display inversion\n\tLCD_Write_Cmd (ILI9341_Entry_Mode_Set); \/\/ entry mode set\n\t\/\/ Deep Standby Mode: OFF\n\t\/\/ Set the output level of gate driver G1-G320: Normal display\n\t\/\/ Low voltage detection: Disable\n\tLCD_Write_Data   (0x07);\n\t\/\/-----------------display------------------------\n\tLCD_Write_Cmd (ILI9341_DFC); \/\/ display function control\n\t\/\/Set the scan mode in non-display area\n\t\/\/Determine source\/VCOM output in a non-display area in the partial display mode\n\tLCD_Write_Data   (0x0a);\n\t\/\/Select whether the liquid crystal type is normally white type or normally black type\n\t\/\/Sets the direction of scan by the gate driver in the range determined by SCN and NL\n\t\/\/Select the shift direction of outputs from the source driver\n\t\/\/Sets the gate driver pin arrangement in combination with the GS bit to select the optimal scan mode for the module\n\t\/\/Specify the scan cycle interval of gate driver in non-display area when PTG to select interval scan\n\tLCD_Write_Data   (0x82);\n\t\/\/ Sets the number of lines to drive the LCD at an interval of 8 lines\n\tLCD_Write_Data   (0x27);\n\tLCD_Write_Data   (0x00); \/\/ clock divisor\n\n\tLCD_Write_Cmd (ILI9341_SLEEP_OUT); \/\/ sleep out\n\tdelay(100);\n\tLCD_Write_Cmd (ILI9341_DISPLAY_ON); \/\/ display on\n\tdelay(100);\n\tLCD_Write_Cmd (ILI9341_GRAM); \/\/ memory write\n\tdelay(5);\n\n}\n\n\/\/set the address of the pixel in the memory\nvoid setAddrWindow(uint16_t X1, uint16_t Y1, uint16_t X2, uint16_t Y2)\n{\n\n\tLCD_Write_Cmd(0x2A); \/\/ Column addr set\n\tLCD_Write_Data(X1&gt;&gt;8);\n\tLCD_Write_Data(X1);     \/\/ XSTART\n\tLCD_Write_Data(X2&gt;&gt;8);\n\tLCD_Write_Data(X2);     \/\/ XEND\n\n\tLCD_Write_Cmd(0x2B); \/\/ Row addr set\n\tLCD_Write_Data(Y1&gt;&gt;8);\n\tLCD_Write_Data(Y1);     \/\/ YSTART\n\tLCD_Write_Data(Y2&gt;&gt;8);\n\tLCD_Write_Data(Y2);     \/\/ YEND\n\n\tLCD_Write_Cmd(0x2C); \/\/ write to RAM\n}\n\nstatic void ConvHL(uint8_t *s, int32_t l)\n{\n\tuint8_t v;\n\twhile (l &gt; 0) {\n\t\tv = *(s+1);\n\t\t*(s+1) = *s;\n\t\t*s = v;\n\t\ts += 2;\n\t\tl -= 2;\n\t}\n}\n\n\nvoid ILI9341_DrawBitmap(uint16_t w, uint16_t h, uint8_t *s)\n{\n\tLCD_Write_Cmd(0x2c);\n\tCS_LOW();\n\tDC_HIGH();\n\tConvHL(s, (int32_t)w*h*2);\n\tSPI1_TX_DMA((uint8_t*)s, w*h*2);\n}\n\n<\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>Now. the LCD is ready to accept LvGL data.<\/p>\n\n\n\n<p>In part 2, we shall integrate LvGL and start displaying graphics.<\/p>\n\n\n\n<p>Stay tuned.<\/p>\n\n\n\n<p>Happy coding \ud83d\ude42 <\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this new guide series, we shall take a look at LvGL and develop driver to display LvGL and touch control. In this guide, we shall cover the following: What is LvGL. Required hardware. TFT connection. Environment setup. Essential drivers. 1. What is LvGL: LvGL is a free and open-source graphics library that allows you [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2,19,11,12],"tags":[],"class_list":["post-2274","post","type-post","status-publish","format-standard","hentry","category-embedded-systems","category-lcd","category-peripheral-drivers","category-stm32"],"_links":{"self":[{"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/2274"}],"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=2274"}],"version-history":[{"count":2,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/2274\/revisions"}],"predecessor-version":[{"id":2285,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/2274\/revisions\/2285"}],"wp:attachment":[{"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2274"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2274"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2274"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}