{"id":163176,"date":"2024-12-12T13:51:25","date_gmt":"2024-12-12T13:51:25","guid":{"rendered":"https:\/\/randomnerdtutorials.com\/?p=163176"},"modified":"2024-12-12T14:11:23","modified_gmt":"2024-12-12T14:11:23","slug":"micropython-cheap-yellow-display-board-cyd-esp32-2432s028r","status":"publish","type":"post","link":"https:\/\/randomnerdtutorials.com\/micropython-cheap-yellow-display-board-cyd-esp32-2432s028r\/","title":{"rendered":"MicroPython: ESP32 Cheap Yellow Display Board \u2013 CYD (ESP32-2432S028R)"},"content":{"rendered":"\n<p>In this guide, you&#8217;ll learn how to get started with the ESP32 Cheap Yellow Display (and other compatible displays) using MicroPython. We&#8217;ll quickly introduce the board, and cover how to upload the right libraries, how to display static text and images, and control the on-board RGB LED and LDR (light-dependent resistor).<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" fetchpriority=\"high\" decoding=\"async\" width=\"1200\" height=\"675\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/10\/cheap-yellow-display-micropython.jpg?resize=1200%2C675&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"MicroPython: ESP32 Cheap Yellow Display Board \u2013 CYD (ESP32-2432S028R)\" class=\"wp-image-163382\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/10\/cheap-yellow-display-micropython.jpg?w=1920&amp;quality=100&amp;strip=all&amp;ssl=1 1920w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/10\/cheap-yellow-display-micropython.jpg?resize=300%2C169&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/10\/cheap-yellow-display-micropython.jpg?resize=1024%2C576&amp;quality=100&amp;strip=all&amp;ssl=1 1024w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/10\/cheap-yellow-display-micropython.jpg?resize=768%2C432&amp;quality=100&amp;strip=all&amp;ssl=1 768w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/10\/cheap-yellow-display-micropython.jpg?resize=1536%2C864&amp;quality=100&amp;strip=all&amp;ssl=1 1536w\" sizes=\"(max-width: 1200px) 100vw, 1200px\" \/><\/figure><\/div>\n\n\n<p class=\"rntbox rntclgray\">If you have a standalone TFT Touchscreen Display 2.8 inch with ILI9341 driver, <a href=\"https:\/\/randomnerdtutorials.com\/lvgl-esp32-tft-touchscreen-display-ili9341-arduino\/\">you can read our LVGL guide for the ESP32<\/a>.<\/p>\n\n\n\n<p><strong>Table of Contents:<\/strong><\/p>\n\n\n\n<p>In this guide, we&#8217;ll cover the following topics:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"#esp32-cyd-intro\" title=\"\">Introducing the ESP32 Cheap Yellow Display<\/a><\/li>\n\n\n\n<li><a href=\"#ILI9341-Library\" title=\"\">MicroPython ILI9341 Library<\/a><\/li>\n\n\n\n<li><a href=\"#display-static-text\" title=\"\">Draw Static Text<\/a><\/li>\n\n\n\n<li><a href=\"#custom-font\" title=\"\">Load Custom Font and Display Text<\/a><\/li>\n\n\n\n<li><a href=\"#touchscreen\" title=\"\">Testing the Touchscreen<\/a><\/li>\n\n\n\n<li><a href=\"#load-image\" title=\"\">Loading Image on the Display<\/a><\/li>\n\n\n\n<li><a href=\"#draw-shapes\" title=\"\">Draw Shapes on the Display<\/a><\/li>\n\n\n\n<li><a href=\"#rgb-led\" title=\"\">Control the On-board RGB LED<\/a><\/li>\n\n\n\n<li><a href=\"#ldr\" title=\"\">Read the On-board LDR<\/a><\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Prerequisites<\/h2>\n\n\n\n<p>To follow this tutorial you need MicroPython firmware installed in your ESP32 CYD board. You also need an IDE to write and upload the code to your board. We suggest using Thonny IDE:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/getting-started-thonny-micropython-python-ide-esp32-esp8266\/\">Flashing MicroPython Firmware and Getting Started with Thonny IDE<\/a><\/li>\n<\/ul>\n\n\n\n<p class=\"rntbox rntclblue\">Learn more about MicroPython:\u00a0<a href=\"https:\/\/randomnerdtutorials.com\/micropython-programming-with-esp32-and-esp8266\/\">MicroPython Programming with ESP32 and ESP8266<\/a><\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"esp32-cyd-intro\">Introducing the ESP32 Cheap Yellow Display &#8211; CYD (ESP32-2432S028R)<\/h2>\n\n\n\n<p>The <a href=\"https:\/\/makeradvisor.com\/tools\/cyd-cheap-yellow-display-esp32-2432s028r\/\" target=\"_blank\" rel=\"noopener\" title=\"\">ESP32-2432S028R<\/a> development board has become known in the maker community as the &#8220;<em>Cheap Yellow Display<\/em>&#8221; or CYD for short. This development board, whose main chip is an ESP32-WROOM-32 module, comes with a 2.8-inch TFT touchscreen LCD, a microSD card interface, an RGB LED, and all the required circuitry to program and apply power to the board.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full is-resized\"><a href=\"https:\/\/makeradvisor.com\/tools\/cyd-cheap-yellow-display-esp32-2432s028r\/\" target=\"_blank\" rel=\"noreferrer noopener\"><img data-recalc-dims=\"1\" decoding=\"async\" width=\"750\" height=\"421\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/03\/ESP32-Cheap-Yellow-Display-CYD-Board-ESP32-2432S028R-front.jpg?resize=750%2C421&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 Cheap Yellow Display CYD Board ESP32-2432S028R front\" class=\"wp-image-149592\" style=\"width:750px;height:auto\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/03\/ESP32-Cheap-Yellow-Display-CYD-Board-ESP32-2432S028R-front.jpg?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/03\/ESP32-Cheap-Yellow-Display-CYD-Board-ESP32-2432S028R-front.jpg?resize=300%2C168&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 750px) 100vw, 750px\" \/><\/a><\/figure><\/div>\n\n\n<p>This is a very versatile board to build GUIs for your IoT projects and is much more convenient and practical than using a separate ESP32 board with a TFT screen.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" decoding=\"async\" width=\"1200\" height=\"609\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/03\/ESP32-Cheap-Yellow-Display-CYD-Board-ESP32-2432S028R-back-labeled.jpg?resize=1200%2C609&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 Cheap Yellow Display CYD Board ESP32-2432S028R back labeled\" class=\"wp-image-149597\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/03\/ESP32-Cheap-Yellow-Display-CYD-Board-ESP32-2432S028R-back-labeled.jpg?w=1280&amp;quality=100&amp;strip=all&amp;ssl=1 1280w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/03\/ESP32-Cheap-Yellow-Display-CYD-Board-ESP32-2432S028R-back-labeled.jpg?resize=300%2C152&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/03\/ESP32-Cheap-Yellow-Display-CYD-Board-ESP32-2432S028R-back-labeled.jpg?resize=1024%2C520&amp;quality=100&amp;strip=all&amp;ssl=1 1024w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/03\/ESP32-Cheap-Yellow-Display-CYD-Board-ESP32-2432S028R-back-labeled.jpg?resize=768%2C390&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 1200px) 100vw, 1200px\" \/><\/figure><\/div>\n\n\n<p class=\"rntbox rntclgreen\"><strong>Related content:<\/strong> <a href=\"https:\/\/randomnerdtutorials.com\/cheap-yellow-display-esp32-2432s028r\/\">Getting Started with ESP32 Cheap Yellow Display Board \u2013 CYD (ESP32-2432S028R) using Arduino IDE<\/a><\/p>\n\n\n\n<p>Here&#8217;s a list of more detailed specifications of this development board:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Dual-core MCU, integrated WI-FI and Bluetooth functions<\/li>\n\n\n\n<li>Frequency can reach 240MHz<\/li>\n\n\n\n<li>520KB SRAM, 448KB ROM, Flash size is 4MB<\/li>\n\n\n\n<li>Module size 50.0\u00d786.0mm<\/li>\n\n\n\n<li>Operating Voltage: 5V<\/li>\n\n\n\n<li>Power consumption: approximately 115mA<\/li>\n\n\n\n<li>Product weight: approximately 50g<\/li>\n\n\n\n<li>The module includes:\n<ul class=\"wp-block-list\">\n<li>2.8-inch color TFT display screen with ILI9341 driver chip<\/li>\n\n\n\n<li>Display resolution: 240x320px with resistive touchscreen<\/li>\n\n\n\n<li>Backlight control circuit<\/li>\n\n\n\n<li>TF card interface for external storage<\/li>\n\n\n\n<li>Serial interface<\/li>\n\n\n\n<li>Temperature and humidity sensor interface (DHT11 interface) and reserved IO port interface<\/li>\n\n\n\n<li>It can be programmed with: Arduino IDE, MicroPython, ESP-IDF<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<p class=\"rntbox rntclgray\">In the Extended GPIO connectors, there are at least 4 GPIOs available: GPIO 35, GPIO 22, GPIO 21, and GPIO 27. It also has the TX\/RX pins available (see previous image).<\/p>\n\n\n\n<p class=\"rntbox rntclblue\">More information about the CYD board GPIOs: <a href=\"https:\/\/randomnerdtutorials.com\/esp32-cheap-yellow-display-cyd-pinout-esp32-2432s028r\/\">ESP32 Cheap Yellow Display (CYD) Pinout (ESP32-2432S028R)<\/a>.<\/p>\n\n\n\n<p><strong>Where to buy?<\/strong><\/p>\n\n\n\n<p>You can click the link below to check where to buy the ESP32 Cheap Yellow display and its price in different stores.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/cyd-cheap-yellow-display-esp32-2432s028r\/\" target=\"_blank\" rel=\"noopener\" title=\"\">ESP32-2432S028R \u2013 2.8 inch 240\u00d7320 Smart Display TFT with Touchscreen &#8211; Maker Advisor<\/a><\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"ILI9341-Library\">MicroPython ILI9341 Library<\/h2>\n\n\n\n<p>There are different libraries that make it easy to communicate with the CYD board. For MicroPython firmware, we\u2019ll use the <strong>MicroPython ILI9341 Display<\/strong> and <strong>XPT2046 Touch Screen<\/strong> Drivers <a href=\"https:\/\/github.com\/rdagger\/micropython-ili9341\" target=\"_blank\" rel=\"noopener\" title=\"\">developed by rdagger GitHub user<\/a>. You must follow the next steps to install the three required modules.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Download and Upload the <em>ili9341.py<\/em><\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li><a href=\"https:\/\/raw.githubusercontent.com\/RuiSantosdotme\/micropython-ili9341\/refs\/heads\/master\/ili9341.py\" target=\"_blank\" rel=\"noopener\" title=\"\"><strong>Click here to download the <em>ili9341.py<\/em> code<\/strong><\/a>;<\/li>\n\n\n\n<li>Copy the code to a file on Thonny IDE;<\/li>\n\n\n\n<li>Go to <strong>File<\/strong> &gt; <strong>Save as\u2026<\/strong> and select <em>MicroPython Device<\/em>;<\/li>\n\n\n\n<li>Save the file with the name <strong><em>ili9341.py<\/em><\/strong> (don\u2019t change the name).<\/li>\n<\/ol>\n\n\n<pre style=\"max-height: 40em; margin-bottom: 20px;\"><code class=\"language-python\">&quot;&quot;&quot;ILI9341 LCD\/Touch module.&quot;&quot;&quot;\nfrom time import sleep\nfrom math import cos, sin, pi, radians\nfrom sys import implementation\nfrom framebuf import FrameBuffer, RGB565  # type: ignore\nfrom micropython import const  # type: ignore\n\n\ndef color565(r, g, b):\n    &quot;&quot;&quot;Return RGB565 color value.\n\n    Args:\n        r (int): Red value.\n        g (int): Green value.\n        b (int): Blue value.\n    &quot;&quot;&quot;\n    return (r &amp; 0xf8) &lt;&lt; 8 | (g &amp; 0xfc) &lt;&lt; 3 | b &gt;&gt; 3\n\n\nclass Display(object):\n    &quot;&quot;&quot;Serial interface for 16-bit color (5-6-5 RGB) IL9341 display.\n\n    Note:  All coordinates are zero based.\n    &quot;&quot;&quot;\n\n    # Command constants from ILI9341 datasheet\n    NOP = const(0x00)  # No-op\n    SWRESET = const(0x01)  # Software reset\n    RDDID = const(0x04)  # Read display ID info\n    RDDST = const(0x09)  # Read display status\n    SLPIN = const(0x10)  # Enter sleep mode\n    SLPOUT = const(0x11)  # Exit sleep mode\n    PTLON = const(0x12)  # Partial mode on\n    NORON = const(0x13)  # Normal display mode on\n    RDMODE = const(0x0A)  # Read display power mode\n    RDMADCTL = const(0x0B)  # Read display MADCTL\n    RDPIXFMT = const(0x0C)  # Read display pixel format\n    RDIMGFMT = const(0x0D)  # Read display image format\n    RDSELFDIAG = const(0x0F)  # Read display self-diagnostic\n    INVOFF = const(0x20)  # Display inversion off\n    INVON = const(0x21)  # Display inversion on\n    GAMMASET = const(0x26)  # Gamma set\n    DISPLAY_OFF = const(0x28)  # Display off\n    DISPLAY_ON = const(0x29)  # Display on\n    SET_COLUMN = const(0x2A)  # Column address set\n    SET_PAGE = const(0x2B)  # Page address set\n    WRITE_RAM = const(0x2C)  # Memory write\n    READ_RAM = const(0x2E)  # Memory read\n    PTLAR = const(0x30)  # Partial area\n    VSCRDEF = const(0x33)  # Vertical scrolling definition\n    MADCTL = const(0x36)  # Memory access control\n    VSCRSADD = const(0x37)  # Vertical scrolling start address\n    PIXFMT = const(0x3A)  # COLMOD: Pixel format set\n    WRITE_DISPLAY_BRIGHTNESS = const(0x51)  # Brightness hardware dependent!\n    READ_DISPLAY_BRIGHTNESS = const(0x52)\n    WRITE_CTRL_DISPLAY = const(0x53)\n    READ_CTRL_DISPLAY = const(0x54)\n    WRITE_CABC = const(0x55)  # Write Content Adaptive Brightness Control\n    READ_CABC = const(0x56)  # Read Content Adaptive Brightness Control\n    WRITE_CABC_MINIMUM = const(0x5E)  # Write CABC Minimum Brightness\n    READ_CABC_MINIMUM = const(0x5F)  # Read CABC Minimum Brightness\n    FRMCTR1 = const(0xB1)  # Frame rate control (In normal mode\/full colors)\n    FRMCTR2 = const(0xB2)  # Frame rate control (In idle mode\/8 colors)\n    FRMCTR3 = const(0xB3)  # Frame rate control (In partial mode\/full colors)\n    INVCTR = const(0xB4)  # Display inversion control\n    DFUNCTR = const(0xB6)  # Display function control\n    PWCTR1 = const(0xC0)  # Power control 1\n    PWCTR2 = const(0xC1)  # Power control 2\n    PWCTRA = const(0xCB)  # Power control A\n    PWCTRB = const(0xCF)  # Power control B\n    VMCTR1 = const(0xC5)  # VCOM control 1\n    VMCTR2 = const(0xC7)  # VCOM control 2\n    RDID1 = const(0xDA)  # Read ID 1\n    RDID2 = const(0xDB)  # Read ID 2\n    RDID3 = const(0xDC)  # Read ID 3\n    RDID4 = const(0xDD)  # Read ID 4\n    GMCTRP1 = const(0xE0)  # Positive gamma correction\n    GMCTRN1 = const(0xE1)  # Negative gamma correction\n    DTCA = const(0xE8)  # Driver timing control A\n    DTCB = const(0xEA)  # Driver timing control B\n    POSC = const(0xED)  # Power on sequence control\n    ENABLE3G = const(0xF2)  # Enable 3 gamma control\n    PUMPRC = const(0xF7)  # Pump ratio control\n\n    MIRROR_ROTATE = {  # MADCTL configurations for rotation and mirroring\n        (False, 0): 0x80,  # 1000 0000\n        (False, 90): 0xE0,  # 1110 0000\n        (False, 180): 0x40,  # 0100 0000\n        (False, 270): 0x20,  # 0010 0000\n        (True, 0): 0xC0,   # 1100 0000\n        (True, 90): 0x60,  # 0110 0000\n        (True, 180): 0x00,  # 0000 0000\n        (True, 270): 0xA0  # 1010 0000\n    }\n\n    def __init__(self, spi, cs, dc, rst, width=240, height=320, rotation=0,\n                 mirror=False, bgr=True, gamma=True):\n        &quot;&quot;&quot;Initialize OLED.\n\n        Args:\n            spi (Class Spi):  SPI interface for OLED\n            cs (Class Pin):  Chip select pin\n            dc (Class Pin):  Data\/Command pin\n            rst (Class Pin):  Reset pin\n            width (Optional int): Screen width (default 240)\n            height (Optional int): Screen height (default 320)\n            rotation (Optional int): Rotation must be 0 default, 90. 180 or 270\n            mirror (Optional bool): Mirror display (default False)\n            bgr (Optional bool): Swaps red and blue colors (default True)\n            gamma (Optional bool): Custom gamma correction (default True)\n        &quot;&quot;&quot;\n        self.spi = spi\n        self.cs = cs\n        self.dc = dc\n        self.rst = rst\n        self.width = width\n        self.height = height\n        if (mirror, rotation) not in self.MIRROR_ROTATE:\n            raise ValueError('Rotation must be 0, 90, 180 or 270.')\n        else:\n            self.rotation = self.MIRROR_ROTATE[mirror, rotation]\n            if bgr:  # Set BGR bit\n                self.rotation |= 0b00001000\n\n        # Initialize GPIO pins and set implementation specific methods\n        if implementation.name == 'circuitpython':\n            self.cs.switch_to_output(value=True)\n            self.dc.switch_to_output(value=False)\n            self.rst.switch_to_output(value=True)\n            self.reset = self.reset_cpy\n            self.write_cmd = self.write_cmd_cpy\n            self.write_data = self.write_data_cpy\n        else:\n            self.cs.init(self.cs.OUT, value=1)\n            self.dc.init(self.dc.OUT, value=0)\n            self.rst.init(self.rst.OUT, value=1)\n            self.reset = self.reset_mpy\n            self.write_cmd = self.write_cmd_mpy\n            self.write_data = self.write_data_mpy\n        self.reset()\n        # Send initialization commands\n        self.write_cmd(self.SWRESET)  # Software reset\n        sleep(.1)\n        self.write_cmd(self.PWCTRB, 0x00, 0xC1, 0x30)  # Pwr ctrl B\n        self.write_cmd(self.POSC, 0x64, 0x03, 0x12, 0x81)  # Pwr on seq. ctrl\n        self.write_cmd(self.DTCA, 0x85, 0x00, 0x78)  # Driver timing ctrl A\n        self.write_cmd(self.PWCTRA, 0x39, 0x2C, 0x00, 0x34, 0x02)  # Pwr ctrl A\n        self.write_cmd(self.PUMPRC, 0x20)  # Pump ratio control\n        self.write_cmd(self.DTCB, 0x00, 0x00)  # Driver timing ctrl B\n        self.write_cmd(self.PWCTR1, 0x23)  # Pwr ctrl 1\n        self.write_cmd(self.PWCTR2, 0x10)  # Pwr ctrl 2\n        self.write_cmd(self.VMCTR1, 0x3E, 0x28)  # VCOM ctrl 1\n        self.write_cmd(self.VMCTR2, 0x86)  # VCOM ctrl 2\n        self.write_cmd(self.MADCTL, self.rotation)  # Memory access ctrl\n        self.write_cmd(self.VSCRSADD, 0x00)  # Vertical scrolling start address\n        self.write_cmd(self.PIXFMT, 0x55)  # COLMOD: Pixel format\n        self.write_cmd(self.FRMCTR1, 0x00, 0x18)  # Frame rate ctrl\n        self.write_cmd(self.DFUNCTR, 0x08, 0x82, 0x27)\n        self.write_cmd(self.ENABLE3G, 0x00)  # Enable 3 gamma ctrl\n        self.write_cmd(self.GAMMASET, 0x01)  # Gamma curve selected\n        if gamma:  # Use custom gamma correction values\n            self.write_cmd(self.GMCTRP1, 0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08,\n                           0x4E, 0xF1, 0x37, 0x07, 0x10, 0x03, 0x0E, 0x09,\n                           0x00)\n            self.write_cmd(self.GMCTRN1, 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07,\n                           0x31, 0xC1, 0x48, 0x08, 0x0F, 0x0C, 0x31, 0x36,\n                           0x0F)\n        self.write_cmd(self.SLPOUT)  # Exit sleep\n        sleep(.1)\n        self.write_cmd(self.DISPLAY_ON)  # Display on\n        sleep(.1)\n        self.clear()\n\n    def block(self, x0, y0, x1, y1, data):\n        &quot;&quot;&quot;Write a block of data to display.\n\n        Args:\n            x0 (int):  Starting X position.\n            y0 (int):  Starting Y position.\n            x1 (int):  Ending X position.\n            y1 (int):  Ending Y position.\n            data (bytes): Data buffer to write.\n        &quot;&quot;&quot;\n        self.write_cmd(self.SET_COLUMN,\n                       x0 &gt;&gt; 8, x0 &amp; 0xff, x1 &gt;&gt; 8, x1 &amp; 0xff)\n        self.write_cmd(self.SET_PAGE,\n                       y0 &gt;&gt; 8, y0 &amp; 0xff, y1 &gt;&gt; 8, y1 &amp; 0xff)\n        self.write_cmd(self.WRITE_RAM)\n        self.write_data(data)\n\n    def cleanup(self):\n        &quot;&quot;&quot;Clean up resources.&quot;&quot;&quot;\n        self.clear()\n        self.display_off()\n        self.spi.deinit()\n        print('display off')\n\n    def clear(self, color=0, hlines=8):\n        &quot;&quot;&quot;Clear display.\n\n        Args:\n            color (Optional int): RGB565 color value (Default: 0 = Black).\n            hlines (Optional int): # of horizontal lines per chunk (Default: 8)\n        Note:\n            hlines was introduced to deal with memory allocation on some\n            boards.  Smaller values allocate less memory but take longer\n            to execute.  hlines must be a factor of the display height.\n            For example, for a 240 pixel height, valid values for hline\n            would be 1, 2, 3, 4, 5, 6, 8, 10, 12, 15, 16, 20, 24, 30, 40, etc.\n            Higher values may result in memory allocation errors.\n        &quot;&quot;&quot;\n        w = self.width\n        h = self.height\n        assert hlines &gt; 0 and h % hlines == 0, (\n            &quot;hlines must be a non-zero factor of height.&quot;)\n        # Clear display\n        if color:\n            line = color.to_bytes(2, 'big') * (w * hlines)\n        else:\n            line = bytearray(w * 2 * hlines)\n        for y in range(0, h, hlines):\n            self.block(0, y, w - 1, y + hlines - 1, line)\n\n    def display_off(self):\n        &quot;&quot;&quot;Turn display off.&quot;&quot;&quot;\n        self.write_cmd(self.DISPLAY_OFF)\n\n    def display_on(self):\n        &quot;&quot;&quot;Turn display on.&quot;&quot;&quot;\n        self.write_cmd(self.DISPLAY_ON)\n\n    def draw_circle(self, x0, y0, r, color):\n        &quot;&quot;&quot;Draw a circle.\n\n        Args:\n            x0 (int): X coordinate of center point.\n            y0 (int): Y coordinate of center point.\n            r (int): Radius.\n            color (int): RGB565 color value.\n        &quot;&quot;&quot;\n        f = 1 - r\n        dx = 1\n        dy = -r - r\n        x = 0\n        y = r\n        self.draw_pixel(x0, y0 + r, color)\n        self.draw_pixel(x0, y0 - r, color)\n        self.draw_pixel(x0 + r, y0, color)\n        self.draw_pixel(x0 - r, y0, color)\n        while x &lt; y:\n            if f &gt;= 0:\n                y -= 1\n                dy += 2\n                f += dy\n            x += 1\n            dx += 2\n            f += dx\n            self.draw_pixel(x0 + x, y0 + y, color)\n            self.draw_pixel(x0 - x, y0 + y, color)\n            self.draw_pixel(x0 + x, y0 - y, color)\n            self.draw_pixel(x0 - x, y0 - y, color)\n            self.draw_pixel(x0 + y, y0 + x, color)\n            self.draw_pixel(x0 - y, y0 + x, color)\n            self.draw_pixel(x0 + y, y0 - x, color)\n            self.draw_pixel(x0 - y, y0 - x, color)\n\n    def draw_ellipse(self, x0, y0, a, b, color):\n        &quot;&quot;&quot;Draw an ellipse.\n\n        Args:\n            x0, y0 (int): Coordinates of center point.\n            a (int): Semi axis horizontal.\n            b (int): Semi axis vertical.\n            color (int): RGB565 color value.\n        Note:\n            The center point is the center of the x0,y0 pixel.\n            Since pixels are not divisible, the axes are integer rounded\n            up to complete on a full pixel.  Therefore the major and\n            minor axes are increased by 1.\n        &quot;&quot;&quot;\n        a2 = a * a\n        b2 = b * b\n        twoa2 = a2 + a2\n        twob2 = b2 + b2\n        x = 0\n        y = b\n        px = 0\n        py = twoa2 * y\n        # Plot initial points\n        self.draw_pixel(x0 + x, y0 + y, color)\n        self.draw_pixel(x0 - x, y0 + y, color)\n        self.draw_pixel(x0 + x, y0 - y, color)\n        self.draw_pixel(x0 - x, y0 - y, color)\n        # Region 1\n        p = round(b2 - (a2 * b) + (0.25 * a2))\n        while px &lt; py:\n            x += 1\n            px += twob2\n            if p &lt; 0:\n                p += b2 + px\n            else:\n                y -= 1\n                py -= twoa2\n                p += b2 + px - py\n            self.draw_pixel(x0 + x, y0 + y, color)\n            self.draw_pixel(x0 - x, y0 + y, color)\n            self.draw_pixel(x0 + x, y0 - y, color)\n            self.draw_pixel(x0 - x, y0 - y, color)\n        # Region 2\n        p = round(b2 * (x + 0.5) * (x + 0.5) +\n                  a2 * (y - 1) * (y - 1) - a2 * b2)\n        while y &gt; 0:\n            y -= 1\n            py -= twoa2\n            if p &gt; 0:\n                p += a2 - py\n            else:\n                x += 1\n                px += twob2\n                p += a2 - py + px\n            self.draw_pixel(x0 + x, y0 + y, color)\n            self.draw_pixel(x0 - x, y0 + y, color)\n            self.draw_pixel(x0 + x, y0 - y, color)\n            self.draw_pixel(x0 - x, y0 - y, color)\n\n    def draw_hline(self, x, y, w, color):\n        &quot;&quot;&quot;Draw a horizontal line.\n\n        Args:\n            x (int): Starting X position.\n            y (int): Starting Y position.\n            w (int): Width of line.\n            color (int): RGB565 color value.\n        &quot;&quot;&quot;\n        if self.is_off_grid(x, y, x + w - 1, y):\n            return\n        line = color.to_bytes(2, 'big') * w\n        self.block(x, y, x + w - 1, y, line)\n\n    def draw_image(self, path, x=0, y=0, w=320, h=240):\n        &quot;&quot;&quot;Draw image from flash.\n\n        Args:\n            path (string): Image file path.\n            x (int): X coordinate of image left.  Default is 0.\n            y (int): Y coordinate of image top.  Default is 0.\n            w (int): Width of image.  Default is 320.\n            h (int): Height of image.  Default is 240.\n        &quot;&quot;&quot;\n        x2 = x + w - 1\n        y2 = y + h - 1\n        if self.is_off_grid(x, y, x2, y2):\n            return\n        with open(path, &quot;rb&quot;) as f:\n            chunk_height = 1024 \/\/ w\n            chunk_count, remainder = divmod(h, chunk_height)\n            chunk_size = chunk_height * w * 2\n            chunk_y = y\n            if chunk_count:\n                for c in range(0, chunk_count):\n                    buf = f.read(chunk_size)\n                    self.block(x, chunk_y,\n                               x2, chunk_y + chunk_height - 1,\n                               buf)\n                    chunk_y += chunk_height\n            if remainder:\n                buf = f.read(remainder * w * 2)\n                self.block(x, chunk_y,\n                           x2, chunk_y + remainder - 1,\n                           buf)\n\n    def draw_letter(self, x, y, letter, font, color, background=0,\n                    landscape=False, rotate_180=False):\n        &quot;&quot;&quot;Draw a letter.\n\n        Args:\n            x (int): Starting X position.\n            y (int): Starting Y position.\n            letter (string): Letter to draw.\n            font (XglcdFont object): Font.\n            color (int): RGB565 color value.\n            background (int): RGB565 background color (default: black)\n            landscape (bool): Orientation (default: False = portrait)\n            rotate_180 (bool): Rotate text by 180 degrees\n        &quot;&quot;&quot;\n        buf, w, h = font.get_letter(letter, color, background, landscape)\n        if rotate_180:\n            # Manually rotate the buffer by 180 degrees\n            # ensure bytes pairs for each pixel retain color565\n            new_buf = bytearray(len(buf))\n            num_pixels = len(buf) \/\/ 2\n            for i in range(num_pixels):\n                # The index for the new buffer's byte pair\n                new_idx = (num_pixels - 1 - i) * 2\n                # The index for the original buffer's byte pair\n                old_idx = i * 2\n                # Swap the pixels\n                new_buf[new_idx], new_buf[new_idx + 1] = buf[old_idx], buf[old_idx + 1]\n            buf = new_buf\n\n        # Check for errors (Font could be missing specified letter)\n        if w == 0:\n            return w, h\n\n        if landscape:\n            y -= w\n            if self.is_off_grid(x, y, x + h - 1, y + w - 1):\n                return 0, 0\n            self.block(x, y,\n                       x + h - 1, y + w - 1,\n                       buf)\n        else:\n            if self.is_off_grid(x, y, x + w - 1, y + h - 1):\n                return 0, 0\n            self.block(x, y,\n                       x + w - 1, y + h - 1,\n                       buf)\n        return w, h\n\n    def draw_line(self, x1, y1, x2, y2, color):\n        &quot;&quot;&quot;Draw a line using Bresenham's algorithm.\n\n        Args:\n            x1, y1 (int): Starting coordinates of the line\n            x2, y2 (int): Ending coordinates of the line\n            color (int): RGB565 color value.\n        &quot;&quot;&quot;\n        # Check for horizontal line\n        if y1 == y2:\n            if x1 &gt; x2:\n                x1, x2 = x2, x1\n            self.draw_hline(x1, y1, x2 - x1 + 1, color)\n            return\n        # Check for vertical line\n        if x1 == x2:\n            if y1 &gt; y2:\n                y1, y2 = y2, y1\n            self.draw_vline(x1, y1, y2 - y1 + 1, color)\n            return\n        # Confirm coordinates in boundary\n        if self.is_off_grid(min(x1, x2), min(y1, y2),\n                            max(x1, x2), max(y1, y2)):\n            return\n        # Changes in x, y\n        dx = x2 - x1\n        dy = y2 - y1\n        # Determine how steep the line is\n        is_steep = abs(dy) &gt; abs(dx)\n        # Rotate line\n        if is_steep:\n            x1, y1 = y1, x1\n            x2, y2 = y2, x2\n        # Swap start and end points if necessary\n        if x1 &gt; x2:\n            x1, x2 = x2, x1\n            y1, y2 = y2, y1\n        # Recalculate differentials\n        dx = x2 - x1\n        dy = y2 - y1\n        # Calculate error\n        error = dx &gt;&gt; 1\n        ystep = 1 if y1 &lt; y2 else -1\n        y = y1\n        for x in range(x1, x2 + 1):\n            # Had to reverse HW ????\n            if not is_steep:\n                self.draw_pixel(x, y, color)\n            else:\n                self.draw_pixel(y, x, color)\n            error -= abs(dy)\n            if error &lt; 0:\n                y += ystep\n                error += dx\n\n    def draw_lines(self, coords, color):\n        &quot;&quot;&quot;Draw multiple lines.\n\n        Args:\n            coords ([[int, int],...]): Line coordinate X, Y pairs\n            color (int): RGB565 color value.\n        &quot;&quot;&quot;\n        # Starting point\n        x1, y1 = coords[0]\n        # Iterate through coordinates\n        for i in range(1, len(coords)):\n            x2, y2 = coords[i]\n            self.draw_line(x1, y1, x2, y2, color)\n            x1, y1 = x2, y2\n\n    def draw_pixel(self, x, y, color):\n        &quot;&quot;&quot;Draw a single pixel.\n\n        Args:\n            x (int): X position.\n            y (int): Y position.\n            color (int): RGB565 color value.\n        &quot;&quot;&quot;\n        if self.is_off_grid(x, y, x, y):\n            return\n        self.block(x, y, x, y, color.to_bytes(2, 'big'))\n\n    def draw_polygon(self, sides, x0, y0, r, color, rotate=0):\n        &quot;&quot;&quot;Draw an n-sided regular polygon.\n\n        Args:\n            sides (int): Number of polygon sides.\n            x0, y0 (int): Coordinates of center point.\n            r (int): Radius.\n            color (int): RGB565 color value.\n            rotate (Optional float): Rotation in degrees relative to origin.\n        Note:\n            The center point is the center of the x0,y0 pixel.\n            Since pixels are not divisible, the radius is integer rounded\n            up to complete on a full pixel.  Therefore diameter = 2 x r + 1.\n        &quot;&quot;&quot;\n        coords = []\n        theta = radians(rotate)\n        n = sides + 1\n        for s in range(n):\n            t = 2.0 * pi * s \/ sides + theta\n            coords.append([int(r * cos(t) + x0), int(r * sin(t) + y0)])\n\n        # Cast to python float first to fix rounding errors\n        self.draw_lines(coords, color=color)\n\n    def draw_rectangle(self, x, y, w, h, color):\n        &quot;&quot;&quot;Draw a rectangle.\n\n        Args:\n            x (int): Starting X position.\n            y (int): Starting Y position.\n            w (int): Width of rectangle.\n            h (int): Height of rectangle.\n            color (int): RGB565 color value.\n        &quot;&quot;&quot;\n        x2 = x + w - 1\n        y2 = y + h - 1\n        self.draw_hline(x, y, w, color)\n        self.draw_hline(x, y2, w, color)\n        self.draw_vline(x, y, h, color)\n        self.draw_vline(x2, y, h, color)\n\n    def draw_sprite(self, buf, x, y, w, h):\n        &quot;&quot;&quot;Draw a sprite (optimized for horizontal drawing).\n\n        Args:\n            buf (bytearray): Buffer to draw.\n            x (int): Starting X position.\n            y (int): Starting Y position.\n            w (int): Width of drawing.\n            h (int): Height of drawing.\n        &quot;&quot;&quot;\n        x2 = x + w - 1\n        y2 = y + h - 1\n        if self.is_off_grid(x, y, x2, y2):\n            return\n        self.block(x, y, x2, y2, buf)\n\n    def draw_text(self, x, y, text, font, color,  background=0,\n                  landscape=False, rotate_180=False, spacing=1):\n        &quot;&quot;&quot;Draw text.\n\n        Args:\n            x (int): Starting X position\n            y (int): Starting Y position\n            text (string): Text to draw\n            font (XglcdFont object): Font\n            color (int): RGB565 color value\n            background (int): RGB565 background color (default: black)\n            landscape (bool): Orientation (default: False = portrait)\n            rotate_180 (bool): Rotate text by 180 degrees\n            spacing (int): Pixels between letters (default: 1)\n        &quot;&quot;&quot;\n        iterable_text = reversed(text) if rotate_180 else text\n        for letter in iterable_text:\n            # Get letter array and letter dimensions\n            w, h = self.draw_letter(x, y, letter, font, color, background,\n                                    landscape, rotate_180)\n            # Stop on error\n            if w == 0 or h == 0:\n                print('Invalid width {0} or height {1}'.format(w, h))\n                return\n\n            if landscape:\n                # Fill in spacing\n                if spacing:\n                    self.fill_hrect(x, y - w - spacing, h, spacing, background)\n                # Position y for next letter\n                y -= (w + spacing)\n            else:\n                # Fill in spacing\n                if spacing:\n                    self.fill_hrect(x + w, y, spacing, h, background)\n                # Position x for next letter\n                x += (w + spacing)\n\n                # # Fill in spacing\n                # if spacing:\n                #     self.fill_vrect(x + w, y, spacing, h, background)\n                # # Position x for next letter\n                # x += w + spacing\n\n    def draw_text8x8(self, x, y, text, color,  background=0,\n                     rotate=0):\n        &quot;&quot;&quot;Draw text using built-in MicroPython 8x8 bit font.\n\n        Args:\n            x (int): Starting X position.\n            y (int): Starting Y position.\n            text (string): Text to draw.\n            color (int): RGB565 color value.\n            background (int): RGB565 background color (default: black).\n            rotate(int): 0, 90, 180, 270\n        &quot;&quot;&quot;\n        w = len(text) * 8\n        h = 8\n        # Confirm coordinates in boundary\n        if self.is_off_grid(x, y, x + 7, y + 7):\n            return\n        buf = bytearray(w * 16)\n        fbuf = FrameBuffer(buf, w, h, RGB565)\n        if background != 0:\n            # Swap background color bytes to correct for framebuf endianness\n            b_color = ((background &amp; 0xFF) &lt;&lt; 8) | ((background &amp; 0xFF00) &gt;&gt; 8)\n            fbuf.fill(b_color)\n        # Swap text color bytes to correct for framebuf endianness\n        t_color = ((color &amp; 0xFF) &lt;&lt; 8) | ((color &amp; 0xFF00) &gt;&gt; 8)\n        fbuf.text(text, 0, 0, t_color)\n        if rotate == 0:\n            self.block(x, y, x + w - 1, y + (h - 1), buf)\n        elif rotate == 90:\n            buf2 = bytearray(w * 16)\n            fbuf2 = FrameBuffer(buf2, h, w, RGB565)\n            for y1 in range(h):\n                for x1 in range(w):\n                    fbuf2.pixel(y1, x1,\n                                fbuf.pixel(x1, (h - 1) - y1))\n            self.block(x, y, x + (h - 1), y + w - 1, buf2)\n        elif rotate == 180:\n            buf2 = bytearray(w * 16)\n            fbuf2 = FrameBuffer(buf2, w, h, RGB565)\n            for y1 in range(h):\n                for x1 in range(w):\n                    fbuf2.pixel(x1, y1,\n                                fbuf.pixel((w - 1) - x1, (h - 1) - y1))\n            self.block(x, y, x + w - 1, y + (h - 1), buf2)\n        elif rotate == 270:\n            buf2 = bytearray(w * 16)\n            fbuf2 = FrameBuffer(buf2, h, w, RGB565)\n            for y1 in range(h):\n                for x1 in range(w):\n                    fbuf2.pixel(y1, x1,\n                                fbuf.pixel((w - 1) - x1, y1))\n            self.block(x, y, x + (h - 1), y + w - 1, buf2)\n\n    def draw_vline(self, x, y, h, color):\n        &quot;&quot;&quot;Draw a vertical line.\n\n        Args:\n            x (int): Starting X position.\n            y (int): Starting Y position.\n            h (int): Height of line.\n            color (int): RGB565 color value.\n        &quot;&quot;&quot;\n        # Confirm coordinates in boundary\n        if self.is_off_grid(x, y, x, y + h - 1):\n            return\n        line = color.to_bytes(2, 'big') * h\n        self.block(x, y, x, y + h - 1, line)\n\n    def fill_circle(self, x0, y0, r, color):\n        &quot;&quot;&quot;Draw a filled circle.\n\n        Args:\n            x0 (int): X coordinate of center point.\n            y0 (int): Y coordinate of center point.\n            r (int): Radius.\n            color (int): RGB565 color value.\n        &quot;&quot;&quot;\n        f = 1 - r\n        dx = 1\n        dy = -r - r\n        x = 0\n        y = r\n        self.draw_vline(x0, y0 - r, 2 * r + 1, color)\n        while x &lt; y:\n            if f &gt;= 0:\n                y -= 1\n                dy += 2\n                f += dy\n            x += 1\n            dx += 2\n            f += dx\n            self.draw_vline(x0 + x, y0 - y, 2 * y + 1, color)\n            self.draw_vline(x0 - x, y0 - y, 2 * y + 1, color)\n            self.draw_vline(x0 - y, y0 - x, 2 * x + 1, color)\n            self.draw_vline(x0 + y, y0 - x, 2 * x + 1, color)\n\n    def fill_ellipse(self, x0, y0, a, b, color):\n        &quot;&quot;&quot;Draw a filled ellipse.\n\n        Args:\n            x0, y0 (int): Coordinates of center point.\n            a (int): Semi axis horizontal.\n            b (int): Semi axis vertical.\n            color (int): RGB565 color value.\n        Note:\n            The center point is the center of the x0,y0 pixel.\n            Since pixels are not divisible, the axes are integer rounded\n            up to complete on a full pixel.  Therefore the major and\n            minor axes are increased by 1.\n        &quot;&quot;&quot;\n        a2 = a * a\n        b2 = b * b\n        twoa2 = a2 + a2\n        twob2 = b2 + b2\n        x = 0\n        y = b\n        px = 0\n        py = twoa2 * y\n        # Plot initial points\n        self.draw_line(x0, y0 - y, x0, y0 + y, color)\n        # Region 1\n        p = round(b2 - (a2 * b) + (0.25 * a2))\n        while px &lt; py:\n            x += 1\n            px += twob2\n            if p &lt; 0:\n                p += b2 + px\n            else:\n                y -= 1\n                py -= twoa2\n                p += b2 + px - py\n            self.draw_line(x0 + x, y0 - y, x0 + x, y0 + y, color)\n            self.draw_line(x0 - x, y0 - y, x0 - x, y0 + y, color)\n        # Region 2\n        p = round(b2 * (x + 0.5) * (x + 0.5) +\n                  a2 * (y - 1) * (y - 1) - a2 * b2)\n        while y &gt; 0:\n            y -= 1\n            py -= twoa2\n            if p &gt; 0:\n                p += a2 - py\n            else:\n                x += 1\n                px += twob2\n                p += a2 - py + px\n            self.draw_line(x0 + x, y0 - y, x0 + x, y0 + y, color)\n            self.draw_line(x0 - x, y0 - y, x0 - x, y0 + y, color)\n\n    def fill_hrect(self, x, y, w, h, color):\n        &quot;&quot;&quot;Draw a filled rectangle (optimized for horizontal drawing).\n\n        Args:\n            x (int): Starting X position.\n            y (int): Starting Y position.\n            w (int): Width of rectangle.\n            h (int): Height of rectangle.\n            color (int): RGB565 color value.\n        &quot;&quot;&quot;\n        if self.is_off_grid(x, y, x + w - 1, y + h - 1):\n            return\n        chunk_height = 1024 \/\/ w\n        chunk_count, remainder = divmod(h, chunk_height)\n        chunk_size = chunk_height * w\n        chunk_y = y\n        if chunk_count:\n            buf = color.to_bytes(2, 'big') * chunk_size\n            for c in range(0, chunk_count):\n                self.block(x, chunk_y,\n                           x + w - 1, chunk_y + chunk_height - 1,\n                           buf)\n                chunk_y += chunk_height\n\n        if remainder:\n            buf = color.to_bytes(2, 'big') * remainder * w\n            self.block(x, chunk_y,\n                       x + w - 1, chunk_y + remainder - 1,\n                       buf)\n\n    def fill_rectangle(self, x, y, w, h, color):\n        &quot;&quot;&quot;Draw a filled rectangle.\n\n        Args:\n            x (int): Starting X position.\n            y (int): Starting Y position.\n            w (int): Width of rectangle.\n            h (int): Height of rectangle.\n            color (int): RGB565 color value.\n        &quot;&quot;&quot;\n        if self.is_off_grid(x, y, x + w - 1, y + h - 1):\n            return\n        if w &gt; h:\n            self.fill_hrect(x, y, w, h, color)\n        else:\n            self.fill_vrect(x, y, w, h, color)\n\n    def fill_polygon(self, sides, x0, y0, r, color, rotate=0):\n        &quot;&quot;&quot;Draw a filled n-sided regular polygon.\n\n        Args:\n            sides (int): Number of polygon sides.\n            x0, y0 (int): Coordinates of center point.\n            r (int): Radius.\n            color (int): RGB565 color value.\n            rotate (Optional float): Rotation in degrees relative to origin.\n        Note:\n            The center point is the center of the x0,y0 pixel.\n            Since pixels are not divisible, the radius is integer rounded\n            up to complete on a full pixel.  Therefore diameter = 2 x r + 1.\n        &quot;&quot;&quot;\n        # Determine side coordinates\n        coords = []\n        theta = radians(rotate)\n        n = sides + 1\n        for s in range(n):\n            t = 2.0 * pi * s \/ sides + theta\n            coords.append([int(r * cos(t) + x0), int(r * sin(t) + y0)])\n        # Starting point\n        x1, y1 = coords[0]\n        # Minimum Maximum X dict\n        xdict = {y1: [x1, x1]}\n        # Iterate through coordinates\n        for row in coords[1:]:\n            x2, y2 = row\n            xprev, yprev = x2, y2\n            # Calculate perimeter\n            # Check for horizontal side\n            if y1 == y2:\n                if x1 &gt; x2:\n                    x1, x2 = x2, x1\n                if y1 in xdict:\n                    xdict[y1] = [min(x1, xdict[y1][0]), max(x2, xdict[y1][1])]\n                else:\n                    xdict[y1] = [x1, x2]\n                x1, y1 = xprev, yprev\n                continue\n            # Non horizontal side\n            # Changes in x, y\n            dx = x2 - x1\n            dy = y2 - y1\n            # Determine how steep the line is\n            is_steep = abs(dy) &gt; abs(dx)\n            # Rotate line\n            if is_steep:\n                x1, y1 = y1, x1\n                x2, y2 = y2, x2\n            # Swap start and end points if necessary\n            if x1 &gt; x2:\n                x1, x2 = x2, x1\n                y1, y2 = y2, y1\n            # Recalculate differentials\n            dx = x2 - x1\n            dy = y2 - y1\n            # Calculate error\n            error = dx &gt;&gt; 1\n            ystep = 1 if y1 &lt; y2 else -1\n            y = y1\n            # Calcualte minimum and maximum x values\n            for x in range(x1, x2 + 1):\n                if is_steep:\n                    if x in xdict:\n                        xdict[x] = [min(y, xdict[x][0]), max(y, xdict[x][1])]\n                    else:\n                        xdict[x] = [y, y]\n                else:\n                    if y in xdict:\n                        xdict[y] = [min(x, xdict[y][0]), max(x, xdict[y][1])]\n                    else:\n                        xdict[y] = [x, x]\n                error -= abs(dy)\n                if error &lt; 0:\n                    y += ystep\n                    error += dx\n            x1, y1 = xprev, yprev\n        # Fill polygon\n        for y, x in xdict.items():\n            self.draw_hline(x[0], y, x[1] - x[0] + 2, color)\n\n    def fill_vrect(self, x, y, w, h, color):\n        &quot;&quot;&quot;Draw a filled rectangle (optimized for vertical drawing).\n\n        Args:\n            x (int): Starting X position.\n            y (int): Starting Y position.\n            w (int): Width of rectangle.\n            h (int): Height of rectangle.\n            color (int): RGB565 color value.\n        &quot;&quot;&quot;\n        if self.is_off_grid(x, y, x + w - 1, y + h - 1):\n            return\n        chunk_width = 1024 \/\/ h\n        chunk_count, remainder = divmod(w, chunk_width)\n        chunk_size = chunk_width * h\n        chunk_x = x\n        if chunk_count:\n            buf = color.to_bytes(2, 'big') * chunk_size\n            for c in range(0, chunk_count):\n                self.block(chunk_x, y,\n                           chunk_x + chunk_width - 1, y + h - 1,\n                           buf)\n                chunk_x += chunk_width\n\n        if remainder:\n            buf = color.to_bytes(2, 'big') * remainder * h\n            self.block(chunk_x, y,\n                       chunk_x + remainder - 1, y + h - 1,\n                       buf)\n\n    def invert(self, enable=True):\n        &quot;&quot;&quot;Enables or disables inversion of display colors.\n\n        Args:\n            enable (Optional bool): True=enable, False=disable\n        &quot;&quot;&quot;\n        if enable:\n            self.write_cmd(self.INVON)\n        else:\n            self.write_cmd(self.INVOFF)\n\n    def is_off_grid(self, xmin, ymin, xmax, ymax):\n        &quot;&quot;&quot;Check if coordinates extend past display boundaries.\n\n        Args:\n            xmin (int): Minimum horizontal pixel.\n            ymin (int): Minimum vertical pixel.\n            xmax (int): Maximum horizontal pixel.\n            ymax (int): Maximum vertical pixel.\n        Returns:\n            boolean: False = Coordinates OK, True = Error.\n        &quot;&quot;&quot;\n        if xmin &lt; 0:\n            print('x-coordinate: {0} below minimum of 0.'.format(xmin))\n            return True\n        if ymin &lt; 0:\n            print('y-coordinate: {0} below minimum of 0.'.format(ymin))\n            return True\n        if xmax &gt;= self.width:\n            print('x-coordinate: {0} above maximum of {1}.'.format(\n                xmax, self.width - 1))\n            return True\n        if ymax &gt;= self.height:\n            print('y-coordinate: {0} above maximum of {1}.'.format(\n                ymax, self.height - 1))\n            return True\n        return False\n\n    def load_sprite(self, path, w, h):\n        &quot;&quot;&quot;Load sprite image.\n\n        Args:\n            path (string): Image file path.\n            w (int): Width of image.\n            h (int): Height of image.\n        Notes:\n            w x h cannot exceed 2048 on boards w\/o PSRAM\n        &quot;&quot;&quot;\n        buf_size = w * h * 2\n        with open(path, &quot;rb&quot;) as f:\n            return f.read(buf_size)\n\n    def reset_cpy(self):\n        &quot;&quot;&quot;Perform reset: Low=initialization, High=normal operation.\n\n        Notes: CircuitPython implemntation\n        &quot;&quot;&quot;\n        self.rst.value = False\n        sleep(.05)\n        self.rst.value = True\n        sleep(.05)\n\n    def reset_mpy(self):\n        &quot;&quot;&quot;Perform reset: Low=initialization, High=normal operation.\n\n        Notes: MicroPython implemntation\n        &quot;&quot;&quot;\n        self.rst(0)\n        sleep(.05)\n        self.rst(1)\n        sleep(.05)\n\n    def scroll(self, y):\n        &quot;&quot;&quot;Scroll display vertically.\n\n        Args:\n            y (int): Number of pixels to scroll display.\n        &quot;&quot;&quot;\n        self.write_cmd(self.VSCRSADD, y &gt;&gt; 8, y &amp; 0xFF)\n\n    def set_scroll(self, top, bottom):\n        &quot;&quot;&quot;Set the height of the top and bottom scroll margins.\n\n        Args:\n            top (int): Height of top scroll margin\n            bottom (int): Height of bottom scroll margin\n        &quot;&quot;&quot;\n        if top + bottom &lt;= self.height:\n            middle = self.height - (top + bottom)\n            self.write_cmd(self.VSCRDEF,\n                           top &gt;&gt; 8,\n                           top &amp; 0xFF,\n                           middle &gt;&gt; 8,\n                           middle &amp; 0xFF,\n                           bottom &gt;&gt; 8,\n                           bottom &amp; 0xFF)\n\n    def sleep(self, enable=True):\n        &quot;&quot;&quot;Enters or exits sleep mode.\n\n        Args:\n            enable (bool): True (default)=Enter sleep mode, False=Exit sleep\n        &quot;&quot;&quot;\n        if enable:\n            self.write_cmd(self.SLPIN)\n        else:\n            self.write_cmd(self.SLPOUT)\n\n    def write_cmd_mpy(self, command, *args):\n        &quot;&quot;&quot;Write command to OLED (MicroPython).\n\n        Args:\n            command (byte): ILI9341 command code.\n            *args (optional bytes): Data to transmit.\n        &quot;&quot;&quot;\n        self.dc(0)\n        self.cs(0)\n        self.spi.write(bytearray([command]))\n        self.cs(1)\n        # Handle any passed data\n        if len(args) &gt; 0:\n            self.write_data(bytearray(args))\n\n    def write_cmd_cpy(self, command, *args):\n        &quot;&quot;&quot;Write command to OLED (CircuitPython).\n\n        Args:\n            command (byte): ILI9341 command code.\n            *args (optional bytes): Data to transmit.\n        &quot;&quot;&quot;\n        self.dc.value = False\n        self.cs.value = False\n        # Confirm SPI locked before writing\n        while not self.spi.try_lock():\n            pass\n        self.spi.write(bytearray([command]))\n        self.spi.unlock()\n        self.cs.value = True\n        # Handle any passed data\n        if len(args) &gt; 0:\n            self.write_data(bytearray(args))\n\n    def write_data_mpy(self, data):\n        &quot;&quot;&quot;Write data to OLED (MicroPython).\n\n        Args:\n            data (bytes): Data to transmit.\n        &quot;&quot;&quot;\n        self.dc(1)\n        self.cs(0)\n        self.spi.write(data)\n        self.cs(1)\n\n    def write_data_cpy(self, data):\n        &quot;&quot;&quot;Write data to OLED (CircuitPython).\n\n        Args:\n            data (bytes): Data to transmit.\n        &quot;&quot;&quot;\n        self.dc.value = True\n        self.cs.value = False\n        # Confirm SPI locked before writing\n        while not self.spi.try_lock():\n            pass\n        self.spi.write(data)\n        self.spi.unlock()\n        self.cs.value = True\n<\/code><\/pre>\n\t<p style=\"text-align:center\"><a class=\"rntwhite\" href=\"https:\/\/github.com\/RuiSantosdotme\/micropython-ili9341\/raw\/master\/ili9341.py\" target=\"_blank\">View raw code<\/a><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Download and Upload the <em>xpt2046.py<\/em><\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li><a href=\"https:\/\/raw.githubusercontent.com\/RuiSantosdotme\/micropython-ili9341\/refs\/heads\/master\/xpt2046.py\" target=\"_blank\" rel=\"noopener\" title=\"\"><strong>Click here to download the <em>xpt2046.py<\/em> code<\/strong><\/a>;<\/li>\n\n\n\n<li>Copy the code to a file on Thonny IDE;<\/li>\n\n\n\n<li>Go to <strong>File<\/strong> &gt; <strong>Save as\u2026<\/strong> and select <em>MicroPython Device<\/em>;<\/li>\n\n\n\n<li>Save the file with the name <strong><em>xpt2046.py<\/em><\/strong> (don\u2019t change the name).<\/li>\n<\/ol>\n\n\n<pre style=\"max-height: 40em; margin-bottom: 20px;\"><code class=\"language-python\">&quot;&quot;&quot;XPT2046 Touch module.&quot;&quot;&quot;\nfrom time import sleep\n\n\nclass Touch(object):\n    &quot;&quot;&quot;Serial interface for XPT2046 Touch Screen Controller.&quot;&quot;&quot;\n\n    # Command constants from ILI9341 datasheet\n    GET_X = const(0b11010000)  # X position\n    GET_Y = const(0b10010000)  # Y position\n    GET_Z1 = const(0b10110000)  # Z1 position\n    GET_Z2 = const(0b11000000)  # Z2 position\n    GET_TEMP0 = const(0b10000000)  # Temperature 0\n    GET_TEMP1 = const(0b11110000)  # Temperature 1\n    GET_BATTERY = const(0b10100000)  # Battery monitor\n    GET_AUX = const(0b11100000)  # Auxiliary input to ADC\n\n    def __init__(self, spi, cs, int_pin=None, int_handler=None,\n                 width=240, height=320,\n                 x_min=100, x_max=1962, y_min=100, y_max=1900):\n        &quot;&quot;&quot;Initialize touch screen controller.\n\n        Args:\n            spi (Class Spi):  SPI interface for OLED\n            cs (Class Pin):  Chip select pin\n            int_pin (Class Pin):  Touch controller interrupt pin\n            int_handler (function): Handler for screen interrupt\n            width (int): Width of LCD screen\n            height (int): Height of LCD screen\n            x_min (int): Minimum x coordinate\n            x_max (int): Maximum x coordinate\n            y_min (int): Minimum Y coordinate\n            y_max (int): Maximum Y coordinate\n        &quot;&quot;&quot;\n        self.spi = spi\n        self.cs = cs\n        self.cs.init(self.cs.OUT, value=1)\n        self.rx_buf = bytearray(3)  # Receive buffer\n        self.tx_buf = bytearray(3)  # Transmit buffer\n        self.width = width\n        self.height = height\n        # Set calibration\n        self.x_min = x_min\n        self.x_max = x_max\n        self.y_min = y_min\n        self.y_max = y_max\n        self.x_multiplier = width \/ (x_max - x_min)\n        self.x_add = x_min * -self.x_multiplier\n        self.y_multiplier = height \/ (y_max - y_min)\n        self.y_add = y_min * -self.y_multiplier\n\n        if int_pin is not None:\n            self.int_pin = int_pin\n            self.int_pin.init(int_pin.IN)\n            self.int_handler = int_handler\n            self.int_locked = False\n            int_pin.irq(trigger=int_pin.IRQ_FALLING | int_pin.IRQ_RISING,\n                        handler=self.int_press)\n\n    def get_touch(self):\n        &quot;&quot;&quot;Take multiple samples to get accurate touch reading.&quot;&quot;&quot;\n        timeout = 2  # set timeout to 2 seconds\n        confidence = 5\n        buff = [[0, 0] for x in range(confidence)]\n        buf_length = confidence  # Require a confidence of 5 good samples\n        buffptr = 0  # Track current buffer position\n        nsamples = 0  # Count samples\n        while timeout &gt; 0:\n            if nsamples == buf_length:\n                meanx = sum([c[0] for c in buff]) \/\/ buf_length\n                meany = sum([c[1] for c in buff]) \/\/ buf_length\n                dev = sum([(c[0] - meanx)**2 +\n                          (c[1] - meany)**2 for c in buff]) \/ buf_length\n                if dev &lt;= 50:  # Deviation should be under margin of 50\n                    return self.normalize(meanx, meany)\n            # get a new value\n            sample = self.raw_touch()  # get a touch\n            if sample is None:\n                nsamples = 0    # Invalidate buff\n            else:\n                buff[buffptr] = sample  # put in buff\n                buffptr = (buffptr + 1) % buf_length  # Incr, until rollover\n                nsamples = min(nsamples + 1, buf_length)  # Incr. until max\n\n            sleep(.05)\n            timeout -= .05\n        return None\n\n    def int_press(self, pin):\n        &quot;&quot;&quot;Send X,Y values to passed interrupt handler.&quot;&quot;&quot;\n        if not pin.value() and not self.int_locked:\n            self.int_locked = True  # Lock Interrupt\n            buff = self.raw_touch()\n\n            if buff is not None:\n                x, y = self.normalize(*buff)\n                self.int_handler(x, y)\n            sleep(.1)  # Debounce falling edge\n        elif pin.value() and self.int_locked:\n            sleep(.1)  # Debounce rising edge\n            self.int_locked = False  # Unlock interrupt\n\n    def normalize(self, x, y):\n        &quot;&quot;&quot;Normalize mean X,Y values to match LCD screen.&quot;&quot;&quot;\n        x = int(self.x_multiplier * x + self.x_add)\n        y = int(self.y_multiplier * y + self.y_add)\n        return x, y\n\n    def raw_touch(self):\n        &quot;&quot;&quot;Read raw X,Y touch values.\n\n        Returns:\n            tuple(int, int): X, Y\n        &quot;&quot;&quot;\n        x = self.send_command(self.GET_X)\n        y = self.send_command(self.GET_Y)\n        if self.x_min &lt;= x &lt;= self.x_max and self.y_min &lt;= y &lt;= self.y_max:\n            return (x, y)\n        else:\n            return None\n\n    def send_command(self, command):\n        &quot;&quot;&quot;Write command to XT2046 (MicroPython).\n\n        Args:\n            command (byte): XT2046 command code.\n        Returns:\n            int: 12 bit response\n        &quot;&quot;&quot;\n        self.tx_buf[0] = command\n        self.cs(0)\n        self.spi.write_readinto(self.tx_buf, self.rx_buf)\n        self.cs(1)\n\n        return (self.rx_buf[1] &lt;&lt; 4) | (self.rx_buf[2] &gt;&gt; 4)\n<\/code><\/pre>\n\t<p style=\"text-align:center\"><a class=\"rntwhite\" href=\"https:\/\/github.com\/RuiSantosdotme\/micropython-ili9341\/raw\/master\/xpt2046.py\" target=\"_blank\">View raw code<\/a><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Download and Upload the <em>xglcd_font.py<\/em><\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li><a href=\"https:\/\/raw.githubusercontent.com\/RuiSantosdotme\/micropython-ili9341\/refs\/heads\/master\/xglcd_font.py\" target=\"_blank\" rel=\"noopener\" title=\"\"><strong>Click here to download the <em>xglcd_font.py<\/em> code<\/strong><\/a>;<\/li>\n\n\n\n<li>Copy the code to a file on Thonny IDE;<\/li>\n\n\n\n<li>Go to <strong>File<\/strong> &gt; <strong>Save as\u2026<\/strong> and select <em>MicroPython Device<\/em>;<\/li>\n\n\n\n<li>Save the file with the name <strong><em>xglcd_font.py<\/em><\/strong> (don\u2019t change the name).<\/li>\n<\/ol>\n\n\n<pre style=\"max-height: 40em; margin-bottom: 20px;\"><code class=\"language-python\">&quot;&quot;&quot;XGLCD Font Utility.&quot;&quot;&quot;\nfrom math import ceil, floor\n\n\nclass XglcdFont(object):\n    &quot;&quot;&quot;Font data in X-GLCD format.\n\n    Attributes:\n        letters: A bytearray of letters (columns consist of bytes)\n        width: Maximum pixel width of font\n        height: Pixel height of font\n        start_letter: ASCII number of first letter\n        height_bytes: How many bytes comprises letter height\n\n    Note:\n        Font files can be generated with the free version of MikroElektronika\n        GLCD Font Creator:  www.mikroe.com\/glcd-font-creator\n        The font file must be in X-GLCD 'C' format.\n        To save text files from this font creator program in Win7 or higher\n        you must use XP compatibility mode or you can just use the clipboard.\n    &quot;&quot;&quot;\n\n    # Dict to tranlate bitwise values to byte position\n    BIT_POS = {1: 0, 2: 2, 4: 4, 8: 6, 16: 8, 32: 10, 64: 12, 128: 14, 256: 16}\n\n    def __init__(self, path, width, height, start_letter=32, letter_count=96):\n        &quot;&quot;&quot;Constructor for X-GLCD Font object.\n\n        Args:\n            path (string): Full path of font file\n            width (int): Maximum width in pixels of each letter\n            height (int): Height in pixels of each letter\n            start_letter (int): First ACII letter.  Default is 32.\n            letter_count (int): Total number of letters.  Default is 96.\n        &quot;&quot;&quot;\n        self.width = width\n        self.height = max(height, 8)\n        self.start_letter = start_letter\n        self.letter_count = letter_count\n        self.bytes_per_letter = (floor(\n            (self.height - 1) \/ 8) + 1) * self.width + 1\n        self.__load_xglcd_font(path)\n\n    def __load_xglcd_font(self, path):\n        &quot;&quot;&quot;Load X-GLCD font data from text file.\n\n        Args:\n            path (string): Full path of font file.\n        &quot;&quot;&quot;\n        bytes_per_letter = self.bytes_per_letter\n        # Buffer to hold letter byte values\n        self.letters = bytearray(bytes_per_letter * self.letter_count)\n        mv = memoryview(self.letters)\n        offset = 0\n        with open(path, 'r') as f:\n            for line in f:\n                # Skip lines that do not start with hex values\n                line = line.strip()\n                if len(line) == 0 or line[0:2] != '0x':\n                    continue\n                # Remove comments\n                comment = line.find('\/\/')\n                if comment != -1:\n                    line = line[0:comment].strip()\n                # Remove trailing commas\n                if line.endswith(','):\n                    line = line[0:len(line) - 1]\n                # Convert hex strings to bytearray and insert in to letters\n                mv[offset: offset + bytes_per_letter] = bytearray(\n                    int(b, 16) for b in line.split(','))\n                offset += bytes_per_letter\n\n    def lit_bits(self, n):\n        &quot;&quot;&quot;Return positions of 1 bits only.&quot;&quot;&quot;\n        while n:\n            b = n &amp; (~n+1)\n            yield self.BIT_POS[b]\n            n ^= b\n\n    def get_letter(self, letter, color, background=0, landscape=False):\n        &quot;&quot;&quot;Convert letter byte data to pixels.\n\n        Args:\n            letter (string): Letter to return (must exist within font).\n            color (int): RGB565 color value.\n            background (int): RGB565 background color (default: black).\n            landscape (bool): Orientation (default: False = portrait)\n        Returns:\n            (bytearray): Pixel data.\n            (int, int): Letter width and height.\n        &quot;&quot;&quot;\n        # Get index of letter\n        letter_ord = ord(letter) - self.start_letter\n        # Confirm font contains letter\n        if letter_ord &gt;= self.letter_count:\n            print('Font does not contain character: ' + letter)\n            return b'', 0, 0\n        bytes_per_letter = self.bytes_per_letter\n        offset = letter_ord * bytes_per_letter\n        mv = memoryview(self.letters[offset:offset + bytes_per_letter])\n\n        # Get width of letter (specified by first byte)\n        letter_width = mv[0]\n        letter_height = self.height\n        # Get size in bytes of specified letter\n        letter_size = letter_height * letter_width\n        # Create buffer (double size to accommodate 16 bit colors)\n        if background:\n            buf = bytearray(background.to_bytes(2, 'big') * letter_size)\n        else:\n            buf = bytearray(letter_size * 2)\n\n        msb, lsb = color.to_bytes(2, 'big')\n\n        if landscape:\n            # Populate buffer in order for landscape\n            pos = (letter_size * 2) - (letter_height * 2)\n            lh = letter_height\n            # Loop through letter byte data and convert to pixel data\n            for b in mv[1:]:\n                # Process only colored bits\n                for bit in self.lit_bits(b):\n                    buf[bit + pos] = msb\n                    buf[bit + pos + 1] = lsb\n                if lh &gt; 8:\n                    # Increment position by double byte\n                    pos += 16\n                    lh -= 8\n                else:\n                    # Descrease position to start of previous column\n                    pos -= (letter_height * 4) - (lh * 2)\n                    lh = letter_height\n        else:\n            # Populate buffer in order for portrait\n            col = 0  # Set column to first column\n            bytes_per_letter = ceil(letter_height \/ 8)\n            letter_byte = 0\n            # Loop through letter byte data and convert to pixel data\n            for b in mv[1:]:\n                # Process only colored bits\n                segment_size = letter_byte * letter_width * 16\n                for bit in self.lit_bits(b):\n                    pos = (bit * letter_width) + (col * 2) + segment_size\n                    buf[pos] = msb\n                    pos = (bit * letter_width) + (col * 2) + 1 + segment_size\n                    buf[pos] = lsb\n                letter_byte += 1\n                if letter_byte + 1 &gt; bytes_per_letter:\n                    col += 1\n                    letter_byte = 0\n\n        return buf, letter_width, letter_height\n\n    def measure_text(self, text, spacing=1):\n        &quot;&quot;&quot;Measure length of text string in pixels.\n\n        Args:\n            text (string): Text string to measure\n            spacing (optional int): Pixel spacing between letters.  Default: 1.\n        Returns:\n            int: length of text\n        &quot;&quot;&quot;\n        length = 0\n        for letter in text:\n            # Get index of letter\n            letter_ord = ord(letter) - self.start_letter\n            offset = letter_ord * self.bytes_per_letter\n            # Add length of letter and spacing\n            length += self.letters[offset] + spacing\n        return length\n<\/code><\/pre>\n\t<p style=\"text-align:center\"><a class=\"rntwhite\" href=\"https:\/\/github.com\/RuiSantosdotme\/micropython-ili9341\/raw\/master\/xglcd_font.py\" target=\"_blank\">View raw code<\/a><\/p>\n\n\n\n<p>With the modules loaded to the CYD board, now you can use the library functionalities in your code to control the display. <\/p>\n\n\n\n<p>Before proceeding, you must have the following files loaded to your board. You can check that on the left sidebar of Thonny IDE, by going to <strong>View <\/strong>&gt; <strong>Files<\/strong>.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"145\" height=\"104\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/10\/MicroPython-Cheap-Yellow-Display-Board-Load-ILI9341-Libraries.png?resize=145%2C104&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"MicroPython Cheap Yellow Display CYD Board Load ILI9341 Libraries\" class=\"wp-image-163320\"\/><\/figure><\/div>\n\n\n<h2 class=\"wp-block-heading\" id=\"display-static-text\">Draw Static Text &#8211; Code<\/h2>\n\n\n\n<p>Displaying static text on the LCD is very simple. All you have to do is to load all required modules, initialize the display, select where you want the characters to be displayed on the screen, and the message content that will be displayed.<\/p>\n\n\n\n<p>This example displays the \u201cESP32 says hello!\u201d message in the (0, 0) coordinates, at the center of the display and text with rotation.<\/p>\n\n\n<pre style=\"max-height: 40em; margin-bottom: 20px;\"><code class=\"language-python\"># Rui Santos &amp; Sara Santos - Random Nerd Tutorials\r\n# Complete project details at https:\/\/RandomNerdTutorials.com\/micropython-cheap-yellow-display-board-cyd-esp32-2432s028r\/\r\n \r\nfrom machine import Pin, SPI, ADC, idle\r\nimport os\r\nfrom time import sleep\r\n\r\n# Save this file as ili9341.py https:\/\/github.com\/rdagger\/micropython-ili9341\/blob\/master\/ili9341.py\r\nfrom ili9341 import Display, color565\r\n# Save this file as xglcd_font.py https:\/\/github.com\/rdagger\/micropython-ili9341\/blob\/master\/xglcd_font.py\r\nfrom xglcd_font import XglcdFont\r\n\r\n# Function to set up SPI for TFT display\r\ndisplay_spi = SPI(1, baudrate=60000000, sck=Pin(14), mosi=Pin(13))\r\n# Set up display\r\ndisplay = Display(display_spi, dc=Pin(2), cs=Pin(15), rst=Pin(15),\r\n                  width=320, height=240, rotation=90)\r\n\r\ndef draw_text():\r\n    # Set colors\r\n    white_color = color565(255, 255, 255)  # white color\r\n    black_color = color565(0, 0, 0)        # black color\r\n\r\n    # Turn on display backlight\r\n    backlight = Pin(21, Pin.OUT)\r\n    backlight.on()\r\n\r\n    # Clear display\r\n    display.clear(black_color)\r\n\r\n    # Draw the text on (0, 0) coordinates (x, y, text, font color, font background color, rotation)\r\n    display.draw_text8x8(0, 0, 'ESP32 says hello!', white_color, black_color, 0)\r\n    \r\n    # Draw the text on the center of the display\r\n    font_size = 8\r\n    text_msg = 'Centered text'\r\n    x_center = int((display.width-len(text_msg)*font_size)\/2)\r\n    y_center = int(((display.height)\/2)-(font_size\/2))\r\n    display.draw_text8x8(x_center, y_center, text_msg, white_color, black_color, 0)\r\n    \r\n    # Draw the text on the right with rotation\r\n    display.draw_text8x8(display.width-font_size, 0, 'Text with rotation', white_color, black_color, 90)\r\n\r\ntry:\r\n    draw_text()\r\nexcept Exception as e:\r\n    print('Error occured: ', e)\r\nexcept KeyboardInterrupt:\r\n    print('Program Interrupted by the user')        \r\n    display.cleanup()<\/code><\/pre>\n\t<p style=\"text-align:center\"><a class=\"rntwhite\" href=\"https:\/\/github.com\/RuiSantosdotme\/ESP32-TFT-Touchscreen\/raw\/main\/examples\/ESP32_CYD_MicroPython_Getting_Started\/draw_text8x8.py\" target=\"_blank\">View raw code<\/a><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">How the Code Works<\/h3>\n\n\n\n<p>Let\u2019s take a quick look at how the code works to see how to display text on the screen.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Importing libraries<\/h4>\n\n\n\n<p>First, you need to import the required libraries<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code>from machine import Pin, SPI, ADC, idle\nimport os\nfrom time import sleep\n\n# Save this file as ili9341.py https:\/\/github.com\/rdagger\/micropython-ili9341\/blob\/master\/ili9341.py\nfrom ili9341 import Display, color565\n# Save this file as xglcd_font.py https:\/\/github.com\/rdagger\/micropython-ili9341\/blob\/master\/xglcd_font.py\nfrom xglcd_font import XglcdFont<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Initialize the SPI Bus and the Display<\/h4>\n\n\n\n<p>Then, you initialize an SPI bus to communicate with the display\u2014double-check that your display also uses GPIO 14 as SCK and GPIO 13 as MOSI.<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code># Function to set up SPI for TFT display\ndisplay_spi = SPI(1, baudrate=60000000, sck=Pin(14), mosi=Pin(13))<\/code><\/pre>\n\n\n\n<p>Create a <span class=\"rnthl rntliteral\">Display<\/span> object called <span class=\"rnthl rntliteral\">display<\/span> and we pass as arguments, the SPI bus we just created, the DC, CS, and RST pins, as well as the display size and rotation. Change the following parameters if your display has a different Pinout or different dimensions.<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code># Set up display\ndisplay = Display(display_spi, dc=Pin(2), cs=Pin(15), rst=Pin(15),\n                  width=320, height=240, rotation=90)<\/code><\/pre>\n\n\n\n<p class=\"rntbox rntclgreen\">If your board is similar to the one used in this tutorial, you can check the pinout here: <a href=\"https:\/\/randomnerdtutorials.com\/esp32-cheap-yellow-display-cyd-pinout-esp32-2432s028r\/\" title=\"\">ESP32 Cheap Yellow Display (CYD) Pinout (ESP32-2432S028R)<\/a>.<\/p>\n\n\n\n<p>After initializing and setting up the display, we create a function to draw some sample text.<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code>def draw_text():<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Creating Colors<\/h4>\n\n\n\n<p>We start by creating variables to refer to white and black colors:<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code>white_color = color565(255, 255, 255)  # white color\nblack_color = color565(0, 0, 0)        # black color<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Turn on the Backlight and Set the Background Color<\/h4>\n\n\n\n<p>Then, we initialize the pin that controls the backlight and set it to ON to light up the backlight.<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code># Turn on display backlight\nbacklight = Pin(21, Pin.OUT)\nbacklight.on()<\/code><\/pre>\n\n\n\n<p>Clear the display by setting the background color to black.<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code># Clear display\ndisplay.clear(black_color)<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Displaying Text<\/h4>\n\n\n\n<p>Finally, to draw text, you just need to call the <span class=\"rnthl rntliteral\">draw_8x8()<\/span> function. This function accepts as arguments: the x and y coordinates, the message you want to display, the font color, the background color, and the rotation.<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code># Draw the text on (0, 0) coordinates (x, y, text, font color, font background color, rotation)\ndisplay.draw_text8x8(0, 0, 'ESP32 says hello!', white_color, black_color, 0)<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Display Centered Text<\/h4>\n\n\n\n<p>The following lines calculate the center of the display to print centered text.<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code># Draw the text on the center of the display\nfont_size = 8\ntext_msg = 'Centered text'\nx_center = int((display.width-len(text_msg)*font_size)\/2)\ny_center = int(((display.height)\/2)-(font_size\/2))\ndisplay.draw_text8x8(x_center, y_center, text_msg, white_color, black_color, 0)<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Display Text with Rotation<\/h4>\n\n\n\n<p>This displays text with rotation. The rotation is the last argument of the <span class=\"rnthl rntliteral\">draw_text8x8()<\/span> function.<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code># Draw the text on the right with rotation\ndisplay.draw_text8x8(display.width-font_size, 0, 'Text with rotation', white_color, black_color, 90)<\/code><\/pre>\n\n\n\n<p>Finally, we call the <span class=\"rnthl rntliteral\">draw_text()<\/span> function we created previously to display the three text messages in different places on the screen.<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code>try:\n    draw_text()<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Testing the Example<\/h3>\n\n\n\n<p>Run the following code on your display. You should get something similar as shown in the following picture.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"750\" height=\"422\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/10\/ESP32-Cheap-Yellow-Display-CYD-Board-Display-Centered-Static-Text-MicroPython.jpg?resize=750%2C422&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 Cheap Yellow Display CYD Board Display Centered Static Text MicroPython\" class=\"wp-image-163384\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/10\/ESP32-Cheap-Yellow-Display-CYD-Board-Display-Centered-Static-Text-MicroPython.jpg?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/10\/ESP32-Cheap-Yellow-Display-CYD-Board-Display-Centered-Static-Text-MicroPython.jpg?resize=300%2C169&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 750px) 100vw, 750px\" \/><\/figure><\/div>\n\n\n<div class=\"wp-block-group rntbox rntclblue is-vertical is-layout-flex wp-container-core-group-is-layout-8cf370e7 wp-block-group-is-layout-flex\">\n<p><strong>Note:<\/strong> if you want the code to <span style=\"text-decoration: underline;\">run automatically<\/span> when the ESP32 boots (for example, without being connected to your computer), you need to save the file to the board with the name\u00a0<strong><em>main.py<\/em><\/strong>.<\/p>\n\n\n\n<p>When you name a file&nbsp;<strong><em>main.py<\/em><\/strong>, the ESP32 will run that file automatically on boot. If you call it a different name, it will still be saved on the board filesystem, but it will not run automatically on boot.<\/p>\n<\/div>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"custom-font\">Load Custom Font and Display Text &#8211; Code<\/h2>\n\n\n\n<p>The library allows you to choose different fonts to display your text (even though the options are limited). You can see all available font options here: <a href=\"https:\/\/github.com\/rdagger\/micropython-ili9341\/tree\/master\/fonts\" target=\"_blank\" rel=\"noopener\" title=\"\">Library Fonts Folder<\/a>.<\/p>\n\n\n\n<p>With a connection opened with your board on Thonny IDE, go to <strong>View <\/strong>&gt; <strong>Files<\/strong>. A new tab on the left side will open with the files saved on the ESP32. Click on the icon next to the MicroPython device and click <strong>New Directory&#8230;<\/strong><\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"509\" height=\"216\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/10\/MicroPython-Load-ILI9341-Libraries-new-font-directory.png?resize=509%2C216&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"MicroPython Load ILI9341 Libraries new font directory\" class=\"wp-image-163321\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/10\/MicroPython-Load-ILI9341-Libraries-new-font-directory.png?w=509&amp;quality=100&amp;strip=all&amp;ssl=1 509w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/10\/MicroPython-Load-ILI9341-Libraries-new-font-directory.png?resize=300%2C127&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 509px) 100vw, 509px\" \/><\/figure><\/div>\n\n\n<p>The new directory should be called <strong>fonts<\/strong>.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"257\" height=\"170\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/10\/New-MicroPython-directory-named-fonts.png?resize=257%2C170&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"New MicroPython directory named fonts\" class=\"wp-image-163322\"\/><\/figure><\/div>\n\n\n<p>As an example, we&#8217;ll load the <em>Unispace12x24<\/em> font. You can load <a href=\"https:\/\/github.com\/rdagger\/micropython-ili9341\/tree\/master\/fonts\" target=\"_blank\" rel=\"noopener\" title=\"\">any available font on the library repository<\/a>. Follow the next steps:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><a href=\"https:\/\/raw.githubusercontent.com\/RuiSantosdotme\/micropython-ili9341\/refs\/heads\/master\/fonts\/Unispace12x24.c\" target=\"_blank\" rel=\"noopener\" title=\"\"><strong>Click here to download the <em>Unispace12x24.c<\/em> code<\/strong><\/a>;<\/li>\n\n\n\n<li>Copy the content to a file on Thonny IDE;<\/li>\n\n\n\n<li>Go to <strong>File<\/strong> &gt; <strong>Save as\u2026<\/strong> and select MicroPython Device;<\/li>\n\n\n\n<li>Save the file with the name <strong><em>Unispace12x24.c<\/em><\/strong> (don\u2019t change the name) <span style=\"text-decoration: underline;\">inside the <strong>fonts <\/strong>folder<\/span>.<\/li>\n<\/ol>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"170\" height=\"127\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/10\/New-Font-Created-Inside-Fonts-Folder-MicroPython.png?resize=170%2C127&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"New Font Created Inside Fonts Folder MicroPython\" class=\"wp-image-163325\"\/><\/figure><\/div>\n\n\n<p>Here&#8217;s the code that draws text using a custom font. This is in all similar to the previous examples, but uses a custom font.<\/p>\n\n\n<pre style=\"max-height: 40em; margin-bottom: 20px;\"><code class=\"language-python\"># Rui Santos &amp; Sara Santos - Random Nerd Tutorials\r\n# Complete project details at https:\/\/RandomNerdTutorials.com\/micropython-cheap-yellow-display-board-cyd-esp32-2432s028r\/\r\n \r\nfrom machine import Pin, SPI, ADC, idle\r\nimport os\r\nfrom time import sleep\r\n\r\n# Save this file as ili9341.py https:\/\/github.com\/rdagger\/micropython-ili9341\/blob\/master\/ili9341.py\r\nfrom ili9341 import Display, color565\r\n# Save this file as xglcd_font.py https:\/\/github.com\/rdagger\/micropython-ili9341\/blob\/master\/xglcd_font.py\r\nfrom xglcd_font import XglcdFont\r\n\r\n# Function to set up SPI for TFT display\r\ndisplay_spi = SPI(1, baudrate=60000000, sck=Pin(14), mosi=Pin(13))\r\n# Set up display\r\ndisplay = Display(display_spi, dc=Pin(2), cs=Pin(15), rst=Pin(15),\r\n                  width=320, height=240, rotation=90)\r\n\r\ndef draw_text():\r\n    # Set colors\r\n    white_color = color565(255, 255, 255)  # white color\r\n    black_color = color565(0, 0, 0)        # black color\r\n\r\n    # Turn on display backlight\r\n    backlight = Pin(21, Pin.OUT)\r\n    backlight.on()\r\n\r\n    # Clear display\r\n    display.clear(white_color)\r\n\r\n    # Loading Unispace font\r\n    print('Loading Unispace font...')\r\n    unispace_font = XglcdFont('fonts\/Unispace12x24.c', 12, 24)\r\n    \r\n    # Draw the text on (0, 0) coordinates (x, y, text, font,  font color, font background color,\r\n    #                                      landscape=False, rotate_180=False, spacing=1)\r\n    display.draw_text(0, 0, 'ESP32 says hello!', unispace_font, black_color, white_color)\r\n\r\n    # Draw the text on the center of the display\r\n    font_size_w = unispace_font.width\r\n    font_size_h = unispace_font.height\r\n    text_msg = 'Centered text'\r\n    x_center = int((display.width-len(text_msg)*font_size_w)\/2)\r\n    y_center = int(((display.height)\/2)-(font_size_h\/2))\r\n    display.draw_text(x_center, y_center, text_msg, unispace_font, black_color, white_color)\r\n    \r\n    # Draw the text with rotation\r\n    display.draw_text(display.width-font_size_h, display.height-font_size_w, 'Text with rotation',\r\n                      unispace_font, black_color, white_color, landscape=True)\r\n\r\ntry:\r\n    draw_text()\r\nexcept Exception as e:\r\n    print('Error occured: ', e)\r\nexcept KeyboardInterrupt:\r\n    print('Program Interrupted by the user')        \r\n    display.cleanup()<\/code><\/pre>\n\t<p style=\"text-align:center\"><a class=\"rntwhite\" href=\"https:\/\/github.com\/RuiSantosdotme\/ESP32-TFT-Touchscreen\/raw\/main\/examples\/ESP32_CYD_MicroPython_Getting_Started\/draw_text_custom_font.py\" target=\"_blank\">View raw code<\/a><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">How Does the Code Work?<\/h3>\n\n\n\n<p>First,  you need to load the desired font as follows:<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code># Loading Unispace font\nprint('Loading Unispace font...')\nunispace_font = XglcdFont('fonts\/Unispace12x24.c', 12, 24)<\/code><\/pre>\n\n\n\n<p>The font is saved on the <span class=\"rnthl rntliteral\">unispace_font<\/span> variable.<\/p>\n\n\n\n<p>Then, use the <span class=\"rnthl rntliteral\">draw_text()<\/span> function that accepts the font as the fourth argument.<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code># Draw the text on (0, 0) coordinates (x, y, text, font, font color, font background color,\n#                                      landscape=False, rotate_180=False, spacing=1)\ndisplay.draw_text(0, 0, 'ESP32 says hello!', unispace_font, black_color, white_color)<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Testing the Example<\/h3>\n\n\n\n<p>Run the code on your board, or upload it as <strong>main.py<\/strong>. Your display will look like the following picture.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"750\" height=\"422\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/10\/ESP32-Cheap-Yellow-Display-CYD-Board-Load-Custom-Font-MicroPython.jpg?resize=750%2C422&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 Cheap Yellow Display CYD Board Load Custom Font MicroPython\" class=\"wp-image-163385\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/10\/ESP32-Cheap-Yellow-Display-CYD-Board-Load-Custom-Font-MicroPython.jpg?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/10\/ESP32-Cheap-Yellow-Display-CYD-Board-Load-Custom-Font-MicroPython.jpg?resize=300%2C169&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 750px) 100vw, 750px\" \/><\/figure><\/div>\n\n\n<h2 class=\"wp-block-heading\" id=\"touchscreen\">Testing the Touchscreen &#8211; Code<\/h2>\n\n\n\n<p>The following code tests the touchscreen. It detects touch and prints the coordinates where touch was detected.<\/p>\n\n\n<pre style=\"max-height: 40em; margin-bottom: 20px;\"><code class=\"language-python\"># Rui Santos &amp; Sara Santos - Random Nerd Tutorials\r\n# Complete project details at https:\/\/RandomNerdTutorials.com\/micropython-cheap-yellow-display-board-cyd-esp32-2432s028r\/\r\n \r\nfrom machine import Pin, SPI, ADC, idle\r\nimport os\r\nfrom time import sleep\r\n\r\n# Save this file as ili9341.py https:\/\/github.com\/rdagger\/micropython-ili9341\/blob\/master\/ili9341.py\r\nfrom ili9341 import Display, color565\r\n# Save this file as xpt2046.py https:\/\/github.com\/rdagger\/micropython-ili9341\/blob\/master\/xpt2046.py\r\nfrom xpt2046 import Touch\r\n# Save this file as xglcd_font.py https:\/\/github.com\/rdagger\/micropython-ili9341\/blob\/master\/xglcd_font.py\r\nfrom xglcd_font import XglcdFont\r\n\r\n# Function to set up SPI for TFT display\r\ndisplay_spi = SPI(1, baudrate=60000000, sck=Pin(14), mosi=Pin(13))\r\n# Set up display\r\ndisplay = Display(display_spi, dc=Pin(2), cs=Pin(15), \r\n                  rst=Pin(15), width=320, height=240, rotation=90)\r\n\r\nprint('Display height: ' + str(display.height))\r\nprint('Display width: ' + str(display.width))\r\n\r\n# Set colors (foreground) and background color\r\nwhite_color = color565(255, 255, 255)  # white\r\nblack_color = color565(0, 0, 0)  # Black\r\n\r\n# Turn on display backlight\r\nbacklight = Pin(21, Pin.OUT)\r\nbacklight.on()\r\n\r\n# Clear display\r\ndisplay.clear(black_color)\r\n\r\n# Initial message\r\n# Draw the text on the center of the display\r\nfont_size = 8\r\ntext_msg = 'Touch screen to test'\r\nx_center = int((display.width-len(text_msg)*font_size)\/2)\r\ny_center = int(((display.height)\/2)-(font_size\/2))\r\n\r\ndisplay.draw_text8x8(x_center, y_center,text_msg, white_color, black_color, 0)\r\n\r\n# SPI for touchscreen\r\ntouchscreen_spi = SPI(2, baudrate=1000000, sck=Pin(25), mosi=Pin(32), miso=Pin(39))\r\n\r\ndef touchscreen_press(x, y):\r\n    display.clear(black_color)\r\n    text_touch_coordinates = &quot;Touch: X = &quot; + str(x) + &quot; | Y = &quot; + str(y)\r\n    x_center = int((display.width-len(text_touch_coordinates)*font_size)\/2)\r\n    display.draw_text8x8(x_center, y_center, text_touch_coordinates, white_color, black_color, 0)\r\n    print(&quot;Touch: X = &quot; + str(x) + &quot; | Y = &quot; + str(y))\r\n\r\ntouchscreen = Touch(touchscreen_spi, cs=Pin(33), int_pin=Pin(36), int_handler=touchscreen_press)\r\n\r\ntry:\r\n    # Run the event loop indefinitely\r\n    while True:\r\n        # Loop to wait for touchscreen press\r\n        touchscreen.get_touch()   \r\nexcept Exception as e:\r\n    print('Error occured: ', e)\r\nexcept KeyboardInterrupt:\r\n    print('Program Interrupted by the user')        \r\nfinally:\r\n    display.cleanup()<\/code><\/pre>\n\t<p style=\"text-align:center\"><a class=\"rntwhite\" href=\"https:\/\/github.com\/RuiSantosdotme\/ESP32-TFT-Touchscreen\/raw\/main\/examples\/ESP32_CYD_MicroPython_Getting_Started\/touchscreen_test.py\" target=\"_blank\">View raw code<\/a><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">How Does the Code Work?<\/h3>\n\n\n\n<p>First, you need to include the required libraries, including the <span class=\"rnthl rntliteral\">xpt2046<\/span> from the <span class=\"rnthl rntliteral\">Touch<\/span> module.<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code>from machine import Pin, SPI, ADC, idle\nimport os\nfrom time import sleep\n\n# Save this file as ili9341.py https:\/\/github.com\/rdagger\/micropython-ili9341\/blob\/master\/ili9341.py\nfrom ili9341 import Display, color565\n# Save this file as xpt2046.py https:\/\/github.com\/rdagger\/micropython-ili9341\/blob\/master\/xpt2046.py\nfrom xpt2046 import Touch\n# Save this file as xglcd_font.py https:\/\/github.com\/rdagger\/micropython-ili9341\/blob\/master\/xglcd_font.py\nfrom xglcd_font import XglcdFont<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">SPI Bus for the Touchscreen<\/h4>\n\n\n\n<p>We create an SPI bus for the touchscreen. Pass as arguments the GPIOs used by the touchscreen as shown below (SCK, MOSI, and MISO).<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code>touchscreen_spi = SPI(2, baudrate=1000000, sck=Pin(25), mosi=Pin(32), miso=Pin(39))<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Detecting Touch<\/h4>\n\n\n\n<p>To detect touch on the touschscreen, you need to create a <span class=\"rnthl rntliteral\">Touch<\/span> object and pass as arguments the touchscreen SPI bus, the CS and INT (interrupt pin) and the touchscreen handler function. This handler function will run when touch is detected. The library will automatically pass the <span class=\"rnthl rntliteral\">x<\/span> and <span class=\"rnthl rntliteral\">y<\/span> coordinates to that function. In our case, it will call the <span class=\"rnthl rntliteral\">touchscreen_press<\/span> function that must be defined earlier.<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code>touchscreen = Touch(touchscreen_spi, cs=Pin(33), int_pin=Pin(36), int_handler=touchscreen_press)<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">touchscreen_press()<\/h4>\n\n\n\n<p>This function will run when touch is detected on the screen. In this case, we print the touch coordinates on the screen. You can do any other task.<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code>def touchscreen_press(x, y):\n    display.clear(black_color)\n    text_touch_coordinates = \"Touch: X = \" + str(x) + \" | Y = \" + str(y)\n    x_center = int((display.width-len(text_touch_coordinates)*font_size)\/2)\n    display.draw_text8x8(x_center, y_center, text_touch_coordinates, white_color, black_color, 0)\n    print(\"Touch: X = \" + str(x) + \" | Y = \" + str(y))<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Keep Detecting Touch<\/h4>\n\n\n\n<p>To keep detecting touch, you need to create a while loop that includes the <span class=\"rnthl rntliteral\">touchscreen.get_touch()<\/span> instruction as follows.<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code>try:\n    # Run the event loop indefinitely\n    while True:\n        # Loop to wait for touchscreen press\n        touchscreen.get_touch() <\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Testing the Example<\/h4>\n\n\n\n<p>Run the code on your board, or upload it as <strong>main.py<\/strong>. Your display will look like the following picture.<\/p>\n\n\n\n<p>It will display a message at first.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"750\" height=\"422\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/10\/ESP32-Cheap-Yellow-Display-CYD-Board-Display-Touchscreen-Test-MicroPython.jpg?resize=750%2C422&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 Cheap Yellow Display CYD Board Display Touchscreen Test MicroPython\" class=\"wp-image-163387\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/10\/ESP32-Cheap-Yellow-Display-CYD-Board-Display-Touchscreen-Test-MicroPython.jpg?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/10\/ESP32-Cheap-Yellow-Display-CYD-Board-Display-Touchscreen-Test-MicroPython.jpg?resize=300%2C169&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 750px) 100vw, 750px\" \/><\/figure><\/div>\n\n\n<p>Then, touch on the screen. It will display the touched coordinates.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"750\" height=\"423\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/10\/ESP32-Cheap-Yellow-Display-CYD-Board-Display-Touchscreen-Testing-Coordinates-MicroPython.jpg?resize=750%2C423&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 Cheap Yellow Display CYD Board Display Touchscreen Testing Coordinates MicroPython\" class=\"wp-image-163390\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/10\/ESP32-Cheap-Yellow-Display-CYD-Board-Display-Touchscreen-Testing-Coordinates-MicroPython.jpg?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/10\/ESP32-Cheap-Yellow-Display-CYD-Board-Display-Touchscreen-Testing-Coordinates-MicroPython.jpg?resize=300%2C169&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 750px) 100vw, 750px\" \/><\/figure><\/div>\n\n\n<p>If you have the board connected to your computer, it will also display the coordinates on the shell.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"744\" height=\"320\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/10\/touchscreen_test_ESP32_Micropython.png?resize=744%2C320&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 Cheap Yellow Display Board with MicroPython - Testing the touchscreen\" class=\"wp-image-163395\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/10\/touchscreen_test_ESP32_Micropython.png?w=744&amp;quality=100&amp;strip=all&amp;ssl=1 744w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/10\/touchscreen_test_ESP32_Micropython.png?resize=300%2C129&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 744px) 100vw, 744px\" \/><\/figure><\/div>\n\n\n<h2 class=\"wp-block-heading\" id=\"load-image\">Loading Image on the Display &#8211; Code<\/h2>\n\n\n\n<p>In this section, we&#8217;ll show you how to display an image on the screen. The images or icons to be displayed on the screen must be converted to <em><strong>.raw<\/strong><\/em> type. We already have a .raw file prepared to test the example.<\/p>\n\n\n\n<p>However, if you want to display a custom image, you need to use the<em> <\/em><a href=\"https:\/\/github.com\/rdagger\/micropython-ili9341\/blob\/master\/utils\/img2rgb565.py\" target=\"_blank\" rel=\"noopener\" title=\"\"><em>img2rgb565.py<\/em> tool located in the Library <em>utils <\/em>folder<\/a> to change image files like JPEG and PNG into the required raw RGB565 format.<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><a href=\"https:\/\/github.com\/RuiSantosdotme\/micropython-ili9341\/raw\/refs\/heads\/master\/images\/MicroPython128x128.raw\" target=\"_blank\" rel=\"noopener\" title=\"\"><strong>Click here to download the <em>MicroPython128x128.raw<\/em> file<\/strong><\/a>. Thonny IDE can&#8217;t open this kind of files. To upload it to your board, you need to follow the next instructions.<\/li>\n\n\n\n<li>In Thonny IDE, establish a connection with your board.<\/li>\n\n\n\n<li>Go to <strong>View <\/strong>&gt; <strong>Files<\/strong>. A left sidebar will show up with the files on your computer and the files on the MicroPython device (ESP32).<\/li>\n\n\n\n<li>Browse your computer until your find the <strong><em>MicroPython128x128.raw<\/em><\/strong> file (don\u2019t change the name);<\/li>\n\n\n\n<li>Right-click on the file and select the &#8220;Upload to \/&#8221; option and upload it to your board.<\/li>\n<\/ol>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"387\" height=\"331\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/10\/MicroPython-Load-Image-Raw-File-to-ESP32-board.png?resize=387%2C331&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"MicroPython Load Image Raw File to ESP32 board\" class=\"wp-image-163327\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/10\/MicroPython-Load-Image-Raw-File-to-ESP32-board.png?w=387&amp;quality=100&amp;strip=all&amp;ssl=1 387w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/10\/MicroPython-Load-Image-Raw-File-to-ESP32-board.png?resize=300%2C257&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 387px) 100vw, 387px\" \/><\/figure><\/div>\n\n\n<p>After a few seconds, the raw image file will show up on the list of files of your Micropython device.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"357\" height=\"173\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/10\/MicroPython-Loaded-Uploaded-Raw-File-to-ESP32.png?resize=357%2C173&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"MicroPython Loaded Uploaded Raw File to ESP32\" class=\"wp-image-163328\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/10\/MicroPython-Loaded-Uploaded-Raw-File-to-ESP32.png?w=357&amp;quality=100&amp;strip=all&amp;ssl=1 357w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/10\/MicroPython-Loaded-Uploaded-Raw-File-to-ESP32.png?resize=300%2C145&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 357px) 100vw, 357px\" \/><\/figure><\/div>\n\n<pre style=\"max-height: 40em; margin-bottom: 20px;\"><code class=\"language-python\"># Rui Santos &amp; Sara Santos - Random Nerd Tutorials\r\n# Complete project details at https:\/\/RandomNerdTutorials.com\/micropython-cheap-yellow-display-board-cyd-esp32-2432s028r\/\r\n \r\nfrom machine import Pin, SPI, ADC, idle\r\nimport os\r\nfrom time import sleep\r\n\r\n# Save this file as ili9341.py https:\/\/github.com\/rdagger\/micropython-ili9341\/blob\/master\/ili9341.py\r\nfrom ili9341 import Display, color565\r\n# Save this file as xglcd_font.py https:\/\/github.com\/rdagger\/micropython-ili9341\/blob\/master\/xglcd_font.py\r\nfrom xglcd_font import XglcdFont\r\n\r\n# Function to set up SPI for TFT display\r\ndisplay_spi = SPI(1, baudrate=60000000, sck=Pin(14), mosi=Pin(13))\r\n# Set up display\r\ndisplay = Display(display_spi, dc=Pin(2), cs=Pin(15), \r\n                  rst=Pin(15), width=320, height=240, rotation=90)\r\n\r\nprint('Display height: ' + str(display.height))\r\nprint('Display width: ' + str(display.width))\r\n\r\n# Set colors (foreground) and background color\r\nwhite_color = color565(255, 255, 255)  # white\r\nblack_color = color565(0, 0, 0)  # Black\r\n\r\n# Turn on display backlight\r\nbacklight = Pin(21, Pin.OUT)\r\nbacklight.on()\r\n\r\n# Clear display\r\ndisplay.clear(black_color)\r\n\r\ndef load_image():\r\n    display.draw_image('MicroPython128x128.raw', 0, 0, 128, 128)\r\n\r\ntry:\r\n    load_image()  \r\nexcept Exception as e:\r\n    print('Error occured: ', e)\r\nexcept KeyboardInterrupt:\r\n    print('Program Interrupted by the user')<\/code><\/pre>\n\t<p style=\"text-align:center\"><a class=\"rntwhite\" href=\"https:\/\/github.com\/RuiSantosdotme\/ESP32-TFT-Touchscreen\/raw\/main\/examples\/ESP32_CYD_MicroPython_Getting_Started\/load_image.py\" target=\"_blank\">View raw code<\/a><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">How does the Code Work?<\/h3>\n\n\n\n<p>To display an image on the display, you just need to call the following function.<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code>def load_image():\n    display.draw_image('MicroPython128x128.raw', 0, 0, 128, 128)<\/code><\/pre>\n\n\n\n<p>You just need to call the <span class=\"rnthl rntliteral\">draw_image()<\/span> function on the <span class=\"rnthl rntliteral\">display<\/span> object. Pass as arguments the x and y coordinates where you want to display the image, and the image width and height.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Testing the Example<\/h3>\n\n\n\n<p>After uploading or running the code on the board, you&#8217;ll have an image displayed on the screen.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"750\" height=\"423\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/10\/ESP32-Cheap-Yellow-Display-CYD-Board-Load-Raw-Image-File-MicroPython.jpg?resize=750%2C423&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 Cheap Yellow Display CYD Board Load Raw Image File MicroPython\" class=\"wp-image-163389\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/10\/ESP32-Cheap-Yellow-Display-CYD-Board-Load-Raw-Image-File-MicroPython.jpg?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/10\/ESP32-Cheap-Yellow-Display-CYD-Board-Load-Raw-Image-File-MicroPython.jpg?resize=300%2C169&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 750px) 100vw, 750px\" \/><\/figure><\/div>\n\n\n<h2 class=\"wp-block-heading\" id=\"draw-shapes\">Draw Shapes on the Display &#8211; Code<\/h2>\n\n\n\n<p>The following example shows how to draw different shapes on the display.<\/p>\n\n\n<pre style=\"max-height: 40em; margin-bottom: 20px;\"><code class=\"language-python\"># Rui Santos &amp; Sara Santos - Random Nerd Tutorials\r\n# Complete project details at https:\/\/RandomNerdTutorials.com\/micropython-cheap-yellow-display-board-cyd-esp32-2432s028r\/\r\n \r\nfrom machine import Pin, SPI, ADC, idle\r\nimport os\r\nfrom time import sleep\r\n\r\n# Save this file as ili9341.py https:\/\/github.com\/rdagger\/micropython-ili9341\/blob\/master\/ili9341.py\r\nfrom ili9341 import Display, color565\r\n# Save this file as xglcd_font.py https:\/\/github.com\/rdagger\/micropython-ili9341\/blob\/master\/xglcd_font.py\r\nfrom xglcd_font import XglcdFont\r\n\r\n# Function to set up SPI for TFT display\r\ndisplay_spi = SPI(1, baudrate=60000000, sck=Pin(14), mosi=Pin(13))\r\n# Set up display\r\ndisplay = Display(display_spi, dc=Pin(2), cs=Pin(15), rst=Pin(15), \r\n                  width=320, height=240, rotation=90)\r\n\r\nprint('Display height: ' + str(display.height))\r\nprint('Display width: ' + str(display.width))\r\n\r\n# Set colors (foreground) and background color\r\nwhite_color = color565(255, 255, 255)  # white\r\nblack_color = color565(0, 0, 0)  # Black\r\n\r\n# Turn on display backlight\r\nbacklight = Pin(21, Pin.OUT)\r\nbacklight.on()\r\n\r\n# Clear display\r\ndisplay.clear(black_color)\r\n\r\ndef draw_shapes():\r\n    display.draw_hline(10, 40, 70, color565(255, 0, 255))\r\n    sleep(1)\r\n\r\n    display.draw_vline(10, 0, 40, color565(0, 255, 255))\r\n    sleep(1)\r\n\r\n    display.fill_hrect(23, 50, 30, 75, color565(255, 255, 255))\r\n    sleep(1)\r\n\r\n    display.draw_hline(0, 0, 100, color565(255, 0, 0))\r\n    sleep(1)\r\n\r\n    display.draw_line(50, 0, 64, 40, color565(255, 255, 0))\r\n    sleep(2)\r\n\r\n    display.clear()\r\n\r\n    coords = [[0, 63], [78, 80], [122, 92], [50, 50], [78, 15], [0, 63]]\r\n    display.draw_lines(coords, color565(0, 255, 255))\r\n    sleep(1)\r\n\r\n    display.clear()\r\n    display.fill_polygon(7, 120, 120, 100, color565(0, 255, 0))\r\n    sleep(1)\r\n\r\n    display.fill_rectangle(0, 0, 15, 227, color565(255, 0, 0))\r\n    sleep(1)\r\n\r\n    display.clear()\r\n\r\n    display.fill_rectangle(0, 0, 163, 163, color565(128, 128, 255))\r\n    sleep(1)\r\n\r\n    display.draw_rectangle(0, 64, 163, 163, color565(255, 0, 255))\r\n    sleep(1)\r\n\r\n    display.fill_rectangle(64, 0, 163, 163, color565(128, 0, 255))\r\n    sleep(1)\r\n\r\n    display.draw_polygon(3, 120, 110, 30, color565(0, 64, 255), rotate=15)\r\n    sleep(3)\r\n\r\n    display.clear()\r\n\r\n    display.fill_circle(132, 132, 70, color565(0, 255, 0))\r\n    sleep(1)\r\n\r\n    display.draw_circle(132, 96, 70, color565(0, 0, 255))\r\n    sleep(1)\r\n\r\n    display.fill_ellipse(96, 96, 30, 16, color565(255, 0, 0))\r\n    sleep(1)\r\n\r\n    display.draw_ellipse(96, 85, 16, 30, color565(255, 255, 0))\r\n\r\n    sleep(5)\r\n    display.cleanup()\r\n\r\ntry:\r\n    draw_shapes()  \r\nexcept Exception as e:\r\n    print('Error occured: ', e)\r\nexcept KeyboardInterrupt:\r\n    print('Program Interrupted by the user')        \r\nfinally:\r\n    display.cleanup()<\/code><\/pre>\n\t<p style=\"text-align:center\"><a class=\"rntwhite\" href=\"https:\/\/github.com\/RuiSantosdotme\/ESP32-TFT-Touchscreen\/raw\/main\/examples\/ESP32_CYD_MicroPython_Getting_Started\/draw_shapes.py\" target=\"_blank\">View raw code<\/a><\/p>\n\n\n\n<p>After initializing the display, we apply different methods on the <span class=\"rnthl rntliteral\">display<\/span> object to display different shapes. The names of the methods are self-explanatory.<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code>def draw_shapes():\n    display.draw_hline(10, 40, 70, color565(255, 0, 255))\n    sleep(1)\n\n    display.draw_vline(10, 0, 40, color565(0, 255, 255))\n    sleep(1)\n\n    display.fill_hrect(23, 50, 30, 75, color565(255, 255, 255))\n    sleep(1)\n\n    display.draw_hline(0, 0, 100, color565(255, 0, 0))\n    sleep(1)\n\n    display.draw_line(50, 0, 64, 40, color565(255, 255, 0))\n    sleep(2)\n\n    display.clear()\n\n    coords = &#091;&#091;0, 63], &#091;78, 80], &#091;122, 92], &#091;50, 50], &#091;78, 15], &#091;0, 63]]\n    display.draw_lines(coords, color565(0, 255, 255))\n    sleep(1)\n\n    display.clear()\n    display.fill_polygon(7, 120, 120, 100, color565(0, 255, 0))\n    sleep(1)\n\n    display.fill_rectangle(0, 0, 15, 227, color565(255, 0, 0))\n    sleep(1)\n\n    (...)<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Testing the Example<\/h3>\n\n\n\n<p>This example will display multiple shapes on the screen and with different colors.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"750\" height=\"422\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/10\/ESP32-Cheap-Yellow-Display-CYD-Board-Display-Draw-Circle-Shapes-MicroPython.jpg?resize=750%2C422&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 Cheap Yellow Display CYD Board Display Draw Circle Shapes MicroPython\" class=\"wp-image-163388\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/10\/ESP32-Cheap-Yellow-Display-CYD-Board-Display-Draw-Circle-Shapes-MicroPython.jpg?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/10\/ESP32-Cheap-Yellow-Display-CYD-Board-Display-Draw-Circle-Shapes-MicroPython.jpg?resize=300%2C169&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 750px) 100vw, 750px\" \/><\/figure><\/div>\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"750\" height=\"422\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/10\/ESP32-Cheap-Yellow-Display-CYD-Board-Display-Shapes-Draw-MicroPython.jpg?resize=750%2C422&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 Cheap Yellow Display CYD Board Display Shapes Draw MicroPython\" class=\"wp-image-163386\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/10\/ESP32-Cheap-Yellow-Display-CYD-Board-Display-Shapes-Draw-MicroPython.jpg?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/10\/ESP32-Cheap-Yellow-Display-CYD-Board-Display-Shapes-Draw-MicroPython.jpg?resize=300%2C169&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 750px) 100vw, 750px\" \/><\/figure><\/div>\n\n\n<h2 class=\"wp-block-heading\" id=\"rgb-led\">Control the On-board RGB LED &#8211; Code<\/h2>\n\n\n\n<p>The ESP32 CYD board comes with an RGB LED that might be useful for debugging. In this section, you&#8217;ll learn how to control that RBG LED.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"750\" height=\"421\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/06\/Cheap-Yellow-Display-ESP32-RGB-LED-pinout.jpg?resize=750%2C421&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 Cheap Yellow Display RGB LED\" class=\"wp-image-159206\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/06\/Cheap-Yellow-Display-ESP32-RGB-LED-pinout.jpg?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/06\/Cheap-Yellow-Display-ESP32-RGB-LED-pinout.jpg?resize=300%2C168&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 750px) 100vw, 750px\" \/><\/figure><\/div>\n\n\n<p>Here&#8217;s the RGB LED pinout:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><tbody><tr><td><strong>RGB LED<\/strong><\/td><td><strong>GPIO<\/strong><\/td><\/tr><tr><td><strong>Red LED<\/strong><\/td><td>GPIO 4<\/td><\/tr><tr><td><strong>Green LED<\/strong><\/td><td>GPIO 16<\/td><\/tr><tr><td><strong>Blue LED<\/strong><\/td><td>GPIO 17<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>The pinout and location of the LED might be different depending on your board model.<\/p>\n\n\n\n<p><strong>Important:<\/strong> the RGB LEDs work with inverted logic because they are active low. This means that if you set them to HIGH = OFF and LOW = ON.<\/p>\n\n\n\n<p>The following examples turns the RGB LED in different colors: red, green and blue.<\/p>\n\n\n<pre style=\"max-height: 40em; margin-bottom: 20px;\"><code class=\"language-python\"># Rui Santos &amp; Sara Santos - Random Nerd Tutorials\r\n# Complete project details at https:\/\/RandomNerdTutorials.com\/micropython-cheap-yellow-display-board-cyd-esp32-2432s028r\/\r\n \r\nfrom machine import Pin\r\nimport os\r\nfrom time import sleep\r\n\r\n# RGB LED at the back\r\nred_led = Pin(4, Pin.OUT)\r\ngreen_led = Pin(16, Pin.OUT)\r\nblue_led = Pin(17, Pin.OUT)\r\n\r\n# Turn on all LEDs (they are active low, so they work with inverted logic)\r\n# Example: red_led.on() command turns the red LED off\r\nred_led.on()\r\ngreen_led.on()\r\nblue_led.on()\r\nsleep(3)\r\n\r\nred_led.off()\r\nsleep(3)\r\n\r\nred_led.on()\r\ngreen_led.off()\r\nsleep(3)\r\n\r\ngreen_led.on()\r\nblue_led.off()\r\nsleep(3)\r\n\r\nblue_led.on()<\/code><\/pre>\n\t<p style=\"text-align:center\"><a class=\"rntwhite\" href=\"https:\/\/github.com\/RuiSantosdotme\/ESP32-TFT-Touchscreen\/raw\/main\/examples\/ESP32_CYD_MicroPython_Getting_Started\/rgb_led.py\" target=\"_blank\">View raw code<\/a><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">How Does the Code Work?<\/h3>\n\n\n\n<p>First, we create variables to refer to the LEDs.<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code>red_led = Pin(4, Pin.OUT)\ngreen_led = Pin(16, Pin.OUT)\nblue_led = Pin(17, Pin.OUT)<\/code><\/pre>\n\n\n\n<p>Then, we turn all the LEDs off (these LEDs work with inverted logic).<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code>red_led.on()\ngreen_led.on()\nblue_led.on()<\/code><\/pre>\n\n\n\n<p>Then, use the the <span class=\"rnthl rntliteral\">off()<\/span> command to turn a certain LED on and the <span class=\"rnthl rntliteral\">on()<\/span> command to turn a specific LED off.<\/p>\n\n\n\n<pre class=\"wp-block-code language-python\"><code>red_led.off()\nsleep(3)\n\nred_led.on()\ngreen_led.off()\nsleep(3)\n\ngreen_led.on()\nblue_led.off()\nsleep(3)\n\nblue_led.on()<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"ldr\">Read the On-board LDR &#8211; Code<\/h2>\n\n\n\n<p>The CYD board comes with an LDR at the front, right next to the display. The LDR is connected to GPIO 34.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"750\" height=\"423\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/06\/ESP32-Cheap-Yellow-Display-LDR.jpg?resize=750%2C423&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 Cheap Yellow Display LDR (Light Dependent ResistorESP32-Cheap-Yellow-)\" class=\"wp-image-159209\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/06\/ESP32-Cheap-Yellow-Display-LDR.jpg?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/06\/ESP32-Cheap-Yellow-Display-LDR.jpg?resize=300%2C169&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 750px) 100vw, 750px\" \/><\/figure><\/div>\n\n\n<p>To read the value from the LDR, you just need to read the analog signal on GPIO 34. <\/p>\n\n\n<pre style=\"max-height: 40em; margin-bottom: 20px;\"><code class=\"language-python\"># Rui Santos &amp; Sara Santos - Random Nerd Tutorials\r\n# Complete project details at https:\/\/RandomNerdTutorials.com\/micropython-cheap-yellow-display-board-cyd-esp32-2432s028r\/\r\n \r\nfrom machine import Pin, ADC\r\nimport os\r\nfrom time import sleep\r\n\r\ntry:\r\n    # Run the event loop indefinitely\r\n    while True:\r\n        # Read light sensor\r\n        lightsensor = ADC(34, atten=ADC.ATTN_0DB)\r\n        print('LDR value: ' + str(lightsensor.read_uv()))\r\n        sleep(1)\r\nexcept Exception as e:\r\n    print('Error occured: ', e)\r\nexcept KeyboardInterrupt:\r\n    print('Program Interrupted by the user')<\/code><\/pre>\n\t<p style=\"text-align:center\"><a class=\"rntwhite\" href=\"https:\/\/github.com\/RuiSantosdotme\/ESP32-TFT-Touchscreen\/raw\/main\/examples\/ESP32_CYD_MicroPython_Getting_Started\/adc_read_ldr.py\" target=\"_blank\">View raw code<\/a><\/p>\n\n\n\n<p class=\"rntbox rntclgreen\">Recommended reading: <a href=\"https:\/\/randomnerdtutorials.com\/esp32-esp8266-analog-readings-micropython\/\">ESP32\/ESP8266 Analog Readings with MicroPython<\/a>.<\/p>\n\n\n\n<p><strong>Note:<\/strong>&nbsp;on many CYD boards, the LDR will not work as expected without modifying the internal circuit. So, if you\u2019re getting the same value regardless of the luminosity, it will be the case that the LDR on your board doesn&#8217;t work properly.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Wrapping Up<\/h2>\n\n\n\n<p>This tutorial was a quick getting started guide for the ESP32 CYD (Cheap Yellow Display) board with MicroPython. We&#8217;ve covered displaying text, images and shapes and how to control the RGB LED and read values from the LDR.<\/p>\n\n\n\n<p>This tutorial should also be compatible with other TFT displays by setting the right pinout and dimensions in the code.<\/p>\n\n\n\n<p>If you prefer to use Arduino IDE instead, check this <a href=\"https:\/\/randomnerdtutorials.com\/cheap-yellow-display-esp32-2432s028r\/\" title=\"\">guide for the CYD board with Arduino IDE<\/a>.<\/p>\n\n\n\n<p>If you would like to learn more about Micropython with the ESP32 board, check out our resources:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/projects-esp32-esp8266-micropython\/\" title=\"\">All our MicroPython projects and guides<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/micropython-programming-with-esp32-and-esp8266\/\" title=\"\">MicroPython Programming with ESP32 and ESP8266 eBook<\/a><\/li>\n<\/ul>\n\n\n\n<p>Thanks for reading.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this guide, you&#8217;ll learn how to get started with the ESP32 Cheap Yellow Display (and other compatible displays) using MicroPython. We&#8217;ll quickly introduce the board, and cover how to &#8230; <\/p>\n<p class=\"read-more-container\"><a title=\"MicroPython: ESP32 Cheap Yellow Display Board \u2013 CYD (ESP32-2432S028R)\" class=\"read-more button\" href=\"https:\/\/randomnerdtutorials.com\/micropython-cheap-yellow-display-board-cyd-esp32-2432s028r\/#more-163176\" aria-label=\"Read more about MicroPython: ESP32 Cheap Yellow Display Board \u2013 CYD (ESP32-2432S028R)\">CONTINUE READING \u00bb<\/a><\/p>\n","protected":false},"author":1,"featured_media":163382,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[310,309,264],"tags":[],"class_list":["post-163176","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-micropython","category-0-esp32-micropython","category-project"],"aioseo_notices":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/10\/cheap-yellow-display-micropython.jpg?fit=1920%2C1080&quality=100&strip=all&ssl=1","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/163176","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/comments?post=163176"}],"version-history":[{"count":31,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/163176\/revisions"}],"predecessor-version":[{"id":164608,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/163176\/revisions\/164608"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/media\/163382"}],"wp:attachment":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/media?parent=163176"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/categories?post=163176"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/tags?post=163176"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}