{"id":2294,"date":"2024-01-21T05:31:08","date_gmt":"2024-01-21T05:31:08","guid":{"rendered":"https:\/\/blog.embeddedexpert.io\/?p=2294"},"modified":"2024-01-21T06:49:23","modified_gmt":"2024-01-21T06:49:23","slug":"getting-started-with-lvgl-part-3-touch-integration","status":"publish","type":"post","link":"https:\/\/blog.embeddedexpert.io\/?p=2294","title":{"rendered":"Getting Started with LvGL Part 3: Touch 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\/01\/logo_lvgl-2.png\" alt=\"\" class=\"wp-image-2295\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/01\/logo_lvgl-2.png 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/01\/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 the pervious guide (<a rel=\"noreferrer noopener\" href=\"https:\/\/blog.embeddedexpert.io\/?p=2283\" target=\"_blank\">here<\/a>), we have successfully integrated LCD. In part 3, we shall integrate the touch part of the LCD.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">10. Touch Connection:<\/h2>\n\n\n\n<p>The connection of Touch pins as following:<\/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-2.webp\" alt=\"\" class=\"wp-image-2296\" srcset=\"https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/01\/12f28942-feeb-445f-bcaf-e8927a6c2824.1b07a5935ffb6219e5dccd5006eb9a50.jpeg-2.webp 612w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/01\/12f28942-feeb-445f-bcaf-e8927a6c2824.1b07a5935ffb6219e5dccd5006eb9a50.jpeg-2-300x300.webp 300w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/01\/12f28942-feeb-445f-bcaf-e8927a6c2824.1b07a5935ffb6219e5dccd5006eb9a50.jpeg-2-150x150.webp 150w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/01\/12f28942-feeb-445f-bcaf-e8927a6c2824.1b07a5935ffb6219e5dccd5006eb9a50.jpeg-2-400x400.webp 400w, https:\/\/blog.embeddedexpert.io\/wp-content\/uploads\/2024\/01\/12f28942-feeb-445f-bcaf-e8927a6c2824.1b07a5935ffb6219e5dccd5006eb9a50.jpeg-2-250x250.webp 250w\" sizes=\"(max-width: 612px) 100vw, 612px\" \/><\/figure><\/div>\n\n\n\n<p><\/p>\n\n\n\n<figure class=\"wp-block-table is-style-stripes\"><table><tbody><tr><td>ILI9341<\/td><td>STM32F767Zi Nucleo-144<\/td><\/tr><tr><td>T_CLK<\/td><td>PB13<\/td><\/tr><tr><td>T_CS<\/td><td>PA3<\/td><\/tr><tr><td>T_DIN<\/td><td>PC2<\/td><\/tr><tr><td>T_OUT<\/td><td>PB15<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>PB13, PB15 and PC2 are for SPI2 peripheral of the STM32F767Zi<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">11. Initialize SPI2:<\/h2>\n\n\n\n<p><\/p>\n\n\n\n<p>Create new source and header file with name of SPI2.c and SPI2.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 SPI2_H_\n#define SPI2_H_\n\n\n#include &quot;stdint.h&quot;\n\nvoid SPI2_Pins_Init(void);\nvoid SPI2_Init(void);\nvoid SPI2_TX(uint8_t *data,uint32_t size);\nvoid SPI2_RX (uint8_t * data, uint8_t length);\n\n\n\n\n#endif \/* SPI2_H_ *\/<\/pre><\/div>\n\n\n\n<p><\/p>\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;}\">#include &quot;SPI2.h&quot;\n#include &quot;stm32f7xx.h&quot;\n\n\n\n#define SPI2_AF 0x05\n\n\nvoid SPI2_Pins_Init(void)\n{\n\tRCC-&gt;AHB1ENR|=RCC_AHB1ENR_GPIOBEN|RCC_AHB1ENR_GPIOCEN;\n\n\tGPIOB-&gt;MODER|=GPIO_MODER_MODER13_1|GPIO_MODER_MODER15_1;\n\tGPIOB-&gt;MODER&amp;=~(GPIO_MODER_MODER13_0|GPIO_MODER_MODER15_0);\n\n\tGPIOB-&gt;OSPEEDR|=GPIO_OSPEEDR_OSPEEDR15|GPIO_OSPEEDR_OSPEEDR13;\n\n\tGPIOB-&gt;AFR[1]|=(SPI2_AF&lt;&lt;GPIO_AFRH_AFRH5_Pos)|(SPI2_AF&lt;&lt;GPIO_AFRH_AFRH7_Pos);\n\n\n\n\tGPIOC-&gt;MODER|=GPIO_MODER_MODER2_1;\n\tGPIOC-&gt;MODER&amp;=~(GPIO_MODER_MODER2_0);\n\n\tGPIOC-&gt;OSPEEDR|=GPIO_OSPEEDR_OSPEEDR2;\n\n\tGPIOC-&gt;AFR[0]|=(SPI2_AF&lt;&lt;GPIO_AFRL_AFRL2_Pos);\n\n}\n\n\nvoid SPI2_Init(void)\n{\n\n\tRCC-&gt;APB1ENR|=RCC_APB1ENR_SPI2EN;\n\n\t\/\/software slave management\n\tSPI2-&gt;CR1|=SPI_CR1_SSM|SPI_CR1_SSI;\n\n\t\/*Set clock to fPCLK\/16*\/\n\tSPI2-&gt;CR1 |=(SPI_CR1_BR_0|SPI_CR1_BR_1);\n\n\t\/\/ set SPI as master mode\n\tSPI2-&gt;CR1|=SPI_CR1_MSTR;\n\n\t\/*Set CPOL to 0 and CPHA to 0*\/\n\tSPI2-&gt;CR1 &amp;=~SPI_CR1_CPOL;\n\tSPI2-&gt;CR1 &amp;=~SPI_CR1_CPHA;\n\n\t\/*Set data size to 8-bit*\/\n\tSPI2-&gt;CR2&amp;=~(SPI_CR2_DS_Msk);\n\tSPI2-&gt;CR2|=(0x07&lt;&lt;SPI_CR2_DS_Pos);\n\n\tSPI2-&gt;CR2|=SPI_CR2_FRXTH;\n\n\tSPI2-&gt;CR1|=SPI_CR1_SPE;\n\n}\n\nvoid SPI2_TX(uint8_t *data,uint32_t size)\n{\n\n\n\n\tuint32_t i=0;\n\twhile(i&lt;size)\n\t{\n\t\t\/*Wait until TXE is set*\/\n\t\twhile(!(SPI2-&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;SPI2-&gt;DR) = data[i];\n\t\ti++;\n\t}\n\t\/*Wait until TXE is set*\/\n\twhile(!(SPI2-&gt;SR &amp; (SPI_SR_TXE))){}\n\n\t\/*Wait for BUSY flag to reset*\/\n\twhile((SPI2-&gt;SR &amp; (SPI_SR_BSY))){}\n\n\t\/*Clear OVR flag*\/\n\t(void)SPI2-&gt;DR;\n\t(void)SPI2-&gt;SR;\n\n}\n\n\nvoid SPI2_RX (uint8_t * data, uint8_t length)\n{\n\n\twhile(length)\n\t{\n\t\t\/*Send dummy data*\/\n\t\t*((volatile uint8_t *)&amp;SPI2-&gt;DR) =0xFF;\n\n\t\t\/*Wait for RXNE flag to be set*\/\n\t\twhile(!(SPI2-&gt;SR &amp; (SPI_SR_RXNE))){}\n\n\t\t\/*Read data from data register*\/\n\t\t*data++ = *((volatile uint8_t *)&amp;SPI2-&gt;DR);\n\t\tlength--;\n\t}\n\n}\n<\/pre><\/div>\n\n\n\n<p>We shall read the touch in polling mode.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">12. CS Pin Initialization:<\/h2>\n\n\n\n<p>Create new source and header file with name of TouchPins.c and TouchPins.h<\/p>\n\n\n\n<p>This file will handle the CS pin initialization.<\/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 TOUCHPINS_H_\n#define TOUCHPINS_H_\n\n#include &quot;stdint.h&quot;\n\nvoid TouchPin_CS_Init(void);\nvoid TouchPin_CS_Low(void);\nvoid TouchPin_CS_High(void);\n\n\n#endif \/* TOUCHPINS_H_ *\/\n<\/pre><\/div>\n\n\n\n<p>In 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;TouchPins.h&quot;\n#include &quot;stm32f7xx.h&quot;\n\n\nvoid TouchPin_CS_Init(void)\n{\n\tRCC-&gt;AHB1ENR|=RCC_AHB1ENR_GPIOAEN;\n\n\tGPIOA-&gt;MODER|=GPIO_MODER_MODER3_0;\n\tGPIOA-&gt;MODER&amp;=~GPIO_MODER_MODER3_1;\n\n\tGPIOA-&gt;BSRR=GPIO_BSRR_BS3;\n\n\n}\n\nvoid TouchPin_CS_Low(void)\n{\n\tGPIOA-&gt;BSRR=GPIO_BSRR_BR3;\n}\n\nvoid TouchPin_CS_High(void)\n{\n\tGPIOA-&gt;BSRR=GPIO_BSRR_BS3;\n}\n<\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">13. Touchpanel initialization:<\/h2>\n\n\n\n<p>Create new source and header file with name of xpt2046.c and xpt2046.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 INC_TOUCH_H_\n#define INC_TOUCH_H_\n\n#include &quot;stdint.h&quot;\n\n\n#define TP_PRES_DOWN 0x80\n#define TP_CATH_PRES 0x40\n#define CMD_RDX 0xD0\n#define CMD_RDY 0x90\n#define XPT_XMIN 300\n#define XPT_YMIN 300\n#define XPT_XMAX 3600\n#define XPT_YMAX 3400\n#define XPT_WIDTH (XPT_XMAX - XPT_XMIN)\n#define XPT_HEIGHT (XPT_YMAX - XPT_YMIN)\n\nvoid XPT2046_Init(void);\nvoid XPT2046_Update(uint16_t *x, uint16_t *y);\nuint8_t XPT2046_IsReasonable(uint16_t x, uint16_t y);\n\n\n\n#endif \/* INC_TOUCH_H_ *\/\n<\/pre><\/div>\n\n\n\n<p>Within the source file:<\/p>\n\n\n\n<p>Taken from arduino library and modified.<\/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;xpt2046.h&quot;\n#include &quot;time_base.h&quot;\n#include &quot;TouchPins.h&quot;\n#include &quot;SPI2.h&quot;\n\n\n\n\nstatic void XPT2046_SetCS(void)\n{\n\tTouchPin_CS_High();\n}\n\nstatic void XPT2046_ResetCS(void)\n{\n\tTouchPin_CS_Low();\n}\n\n\n\/**********************************************************************************************************\/\n\n#define T_IRQ XPT2046_ReadIRQ()\n#define T_CS_ON XPT2046_SetCS()\n#define T_CS_OFF XPT2046_ResetCS()\n\n#define READ_TIMES \t5\n#define LOST_VAL \t1\n#define ERR_RANGE 50\n#define Z_THRESHOLD     400\n#define Z_THRESHOLD_INT\t75\n#define MSEC_THRESHOLD  3\n\nstatic uint8_t XPT2046_initilazed = 0;\n\n\nstatic uint16_t XPT2046_Read_AD(uint8_t CMD)\n{\n\tuint8_t num[2];\n\tuint16_t ret;\n\n\tT_CS_OFF;\n\tSPI2_TX(&amp;CMD,1);\n\tdelay(6);\n\n\tSPI2_RX(num, 2);\n\tT_CS_ON;\n\n\tret = num[0] &lt;&lt; 8 | num[1];\n\tret &gt;&gt;= 3;\n\tret &amp;= (1&lt;&lt;12)-1;\n\n\treturn ret;\n}\n\nstatic int16_t besttwoavg( int16_t x , int16_t y , int16_t z ) {\n  int16_t da, db, dc;\n  int16_t reta = 0;\n  if ( x &gt; y ) da = x - y; else da = y - x;\n  if ( x &gt; z ) db = x - z; else db = z - x;\n  if ( z &gt; y ) dc = z - y; else dc = y - z;\n\n  if ( da &lt;= db &amp;&amp; da &lt;= dc ) reta = (x + y) &gt;&gt; 1;\n  else if ( db &lt;= da &amp;&amp; db &lt;= dc ) reta = (x + z) &gt;&gt; 1;\n  else reta = (y + z) &gt;&gt; 1;   \/\/    else if ( dc &lt;= da &amp;&amp; dc &lt;= db ) reta = (x + y) &gt;&gt; 1;\n\n  return (reta);\n}\n\nvoid XPT2046_Init(void)\n{\n\tSPI2_Pins_Init();\n\tSPI2_Init();\n\tTouchPin_CS_Init();\n\n\n\tXPT2046_initilazed = 1;\n}\n\nvoid XPT2046_Update(uint16_t *x, uint16_t *y)\n{\n\tint16_t data[6];\n\tstatic uint32_t ptime = 0;\n\n\tif (XPT2046_initilazed == 0) {\n\t\treturn;\n\t}\n\n\tif (Tick_Get() - ptime &lt; MSEC_THRESHOLD) {\n\t\treturn;\n\t}\n\n\tint16_t z1 = XPT2046_Read_AD(0xb1); \/\/ z1\n\tint32_t z = z1 + 4095;\n\tint16_t z2 = XPT2046_Read_AD(0xc1); \/\/ z2\n\tz -= z2;\n\tif (z &gt;= Z_THRESHOLD) {\n\t\tXPT2046_Read_AD(0x91);  \/\/ dummy 1st X measure\n\t\tdata[0] = XPT2046_Read_AD(0x91);\n\t\tdata[1] = XPT2046_Read_AD(0xd1);\n\t\tdata[2] = XPT2046_Read_AD(0x91);\n\t\tdata[3] = XPT2046_Read_AD(0xd1);\n\t} else {\n\t\tdata[0] = data[1] = data[2] = data[3] = 0;\n\t}\n\tdata[4] = XPT2046_Read_AD(0x91);\n\tdata[5] = XPT2046_Read_AD(0xd0);\n\tptime = Tick_Get();\n\tif (z &lt; 0) z = 0;\n\tint16_t intx = besttwoavg( data[1], data[3], data[5] );\n\tint16_t inty = besttwoavg( data[0], data[2], data[4] );\n\tif (z &gt;= Z_THRESHOLD) {\n\t\t*x = intx;\n\t\t*y = inty;\n\t}\n}\n\nuint8_t XPT2046_IsReasonable(uint16_t x, uint16_t y)\n{\n\tif (x &gt;= XPT_XMIN &amp;&amp; x &lt;= XPT_XMAX &amp;&amp; y &gt;= XPT_YMIN &amp;&amp; y &lt;= XPT_YMAX) {\n\t\treturn 1;\n\t}\n\treturn 0;\n}\n<\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>Note: The these values are near enough to make the touch screen work. In your application, you will need to implement touch screen calibration or calibrate before release.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">14. Rotating the LCD:<\/h2>\n\n\n\n<p>Since this driver will only work in landscape mode, we shall rotate the LCD by 90.<\/p>\n\n\n\n<p>In ILI9341.c file, modify the memory access control (MAC) to become 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;}\">\tLCD_Write_Cmd (ILI9341_MAC); \/\/ memory access control\n\tLCD_Write_Data((1&lt;&lt;3)|(1U&lt;&lt;5)|(1&lt;&lt;2));<\/pre><\/div>\n\n\n\n<p>In LCDController.c, we shall change the dimensions 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;}\">#define MY_DISP_HOR_RES 320\n\n\n#define MY_DISP_VER_RES 240<\/pre><\/div>\n\n\n\n<p>Thats all for rotating screen.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">15. Touch Integration:<\/h2>\n\n\n\n<p>Create new source and header file with name of TouchController.c and TouchController.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 INC_TOUCHCONTROLLER_H_\n#define INC_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 *      MACROS\n **********************\/\n\n\n\n#endif \/* INC_TOUCHCONTROLLER_H_ *\/<\/pre><\/div>\n\n\n\n<p><\/p>\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;TouchController.h&quot;\n#include &quot;lvgl.h&quot;\n#include &quot;stdio.h&quot;\n#include &quot;xpt2046.h&quot;\n\n#include &quot;ILI_9341.h&quot;\n\/*********************\n *      DEFINES\n *********************\/\n\n\/**********************\n *      TYPEDEFS\n **********************\/\n\n\/**********************\n *  STATIC PROTOTYPES\n **********************\/\n\nstatic void touchpad_init(void);\nstatic void touchpad_read(lv_indev_drv_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\n\n\/**********************\n *      MACROS\n **********************\/\n\n\/**********************\n *   GLOBAL FUNCTIONS\n **********************\/\n\nvoid lv_port_indev_init(void)\n{\n    \/**\n     * Here you will find example implementation of input devices supported by LittelvGL:\n     *  - Touchpad\n     *  - Mouse (with cursor support)\n     *  - Keypad (supports GUI usage only with key)\n     *  - Encoder (supports GUI usage only with: left, right, push)\n     *  - Button (external buttons to press points on the screen)\n     *\n     *  The `..._read()` function are only examples.\n     *  You should shape them according to your hardware\n     *\/\n\n    static lv_indev_drv_t indev_drv;\n\n    \/*------------------\n     * Touchpad\n     * -----------------*\/\n\n    \/*Initialize your touchpad if you have*\/\n    touchpad_init();\n\n    \/*Register a touchpad input device*\/\n    lv_indev_drv_init(&amp;indev_drv);\n    indev_drv.type = LV_INDEV_TYPE_POINTER;\n    indev_drv.read_cb = touchpad_read;\n    indev_touchpad = lv_indev_drv_register(&amp;indev_drv);\n}\n\n\/**********************\n *   STATIC FUNCTIONS\n **********************\/\n\n\nstatic void ConvXPTtoILI(uint16_t *x, uint16_t *y)\n{\n\tuint16_t tx,ty;\n\tty = (int16_t)(((int32_t)*x - XPT_YMIN) * ILI9341_HEIGHT \/ XPT_HEIGHT);\n\tty = (ty &lt; 0) ? 0 : ty;\n\tty = (ty &gt;= ILI9341_HEIGHT) ? ILI9341_HEIGHT-1 : ty;\n\n\ttx = (int16_t)(((int32_t)*y - XPT_XMIN) * ILI9341_WIDTH \/ XPT_WIDTH);\n\ttx = (tx &lt; 0) ? 0 : tx;\n\ttx = (tx &gt;= ILI9341_WIDTH) ? ILI9341_WIDTH-1 : tx;\n\t*y = ty;\n\t*x = ILI9341_WIDTH-tx;\n}\n\nstruct {\n\tlv_coord_t x;\n\tlv_coord_t y;\n}get_xy;\n\/*------------------\n * Touchpad\n * -----------------*\/\n\n\/*Initialize your touchpad*\/\nstatic void touchpad_init(void)\n{\n    XPT2046_Init();\n}\n\n\/*Will be called by the library to read the touchpad*\/\nstatic void touchpad_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)\n{\n    static lv_coord_t last_x = 0;\n    static lv_coord_t last_y = 0;\n\n    \/*Save the pressed coordinates and the state*\/\n    if(touchpad_is_pressed()) {\n\n    \tlast_x = get_xy.x;\n    \tlast_y = get_xy.y;\n        data-&gt;state = LV_INDEV_STATE_PR;\n    }\n    else {\n        data-&gt;state = LV_INDEV_STATE_REL;\n    }\n\n    \/*Set the last pressed coordinates*\/\n    data-&gt;point.x = last_x;\n    data-&gt;point.y = last_y;\n}\n\n\n\/*Return true is the touchpad is pressed*\/\nstatic bool touchpad_is_pressed(void)\n{\n\tstatic uint16_t prevx = ILI9341_WIDTH;\n\tstatic uint16_t prevy = ILI9341_HEIGHT;\n\tuint16_t intx, inty;\n\tXPT2046_Update(&amp;intx, &amp;inty);\n\n\tif (XPT2046_IsReasonable(intx, inty))\n\t{\n\n\n\n\t\tConvXPTtoILI(&amp;intx, &amp;inty);\n\n\t\tif (intx != prevx || inty != prevy)\n\t\t{\n\t\t\tprevx = intx;\n\t\t\tprevy = inty;\n\t\t\tget_xy.x = (int32_t)intx;\n\t\t\tget_xy.y = (int32_t)inty;\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn 0;\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<\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>Thats all for the touch integration.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">16. Main code:<\/h2>\n\n\n\n<p>Include the touch controller 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;TouchController.h&quot;<\/pre><\/div>\n\n\n\n<p>Call the touch initialization after the display initialization:<\/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_port_indev_init();<\/pre><\/div>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">17. Results:<\/h2>\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 Demo on Custom LCD\" width=\"1170\" height=\"658\" src=\"https:\/\/www.youtube.com\/embed\/78LcUyoRF6g?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>Happy coding \ud83d\ude42<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In the pervious guide (here), we have successfully integrated LCD. In part 3, we shall integrate the touch part of the LCD. 10. Touch Connection: The connection of Touch pins as following: ILI9341 STM32F767Zi Nucleo-144 T_CLK PB13 T_CS PA3 T_DIN PC2 T_OUT PB15 PB13, PB15 and PC2 are for SPI2 peripheral of the STM32F767Zi 11. [&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-2294","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\/2294"}],"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=2294"}],"version-history":[{"count":2,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/2294\/revisions"}],"predecessor-version":[{"id":2298,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=\/wp\/v2\/posts\/2294\/revisions\/2298"}],"wp:attachment":[{"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2294"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2294"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.embeddedexpert.io\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2294"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}