How to change the color on a 1.14 inch 240x135 LCD?
How to Change the Color on a 1.14 inch 240x135 LCD
To change the color on a 1.14 inch 240x135 ips display, you need to send specific pixel data via a microcontroller (like an ESP32 or STM32) using the SPI interface, because these displays use a 16-bit RGB565 color format where each pixel is represented by two bytes. The most common driver chip for these small LCDs is the ST7789V, which supports a 240x135 resolution with a 1.14-inch diagonal. The color change is achieved by writing to the display’s RAM (GRAM) using commands like 0x2C (RAMWR) for pixel data, and you can set a solid color by filling the entire 240x135 pixel array with a uniform RGB565 value. For example, to set the screen to pure red, you send 0xF800 (binary: 11111 000000 00000) for each pixel, while green uses 0x07E0 (00000 111111 00000), and blue uses 0x001F (00000 000000 11111). The total number of pixels is 32,400 (240 × 135), so you need to send 64,800 bytes of data for a full-screen color fill. This process is handled by libraries like Adafruit_ST7789 or TFT_eSPI for Arduino, which abstract the low-level SPI commands. However, for precise control, you can directly manipulate the SPI registers to reduce latency, especially when doing animations. The SPI clock speed typically ranges from 20 MHz to 40 MHz, but for the 1.14 inch 240x135 ips display, a stable 26 MHz is recommended to avoid signal integrity issues on longer wires. The color depth is 65,536 colors (2^16), which is sufficient for most GUI applications, but if you need more accurate color reproduction, you can calibrate the gamma curve using the 0xE0 and 0xE1 commands (positive and negative gamma control). Many users overlook that the default gamma settings on ST7789V are often too contrasty, leading to washed-out colors; adjusting the 14 gamma registers (e.g., for positive gamma: 0xD0, 0x04, 0x0D, 0x11, 0x13, 0x2B, 0x3F, 0x54, 0x4C, 0x18, 0x0D, 0x0B, 0x1F, 0x23) can significantly improve color accuracy.
The physical layer uses a 4-wire SPI (SCLK, MOSI, CS, DC) plus a reset pin, and the display module typically operates at 3.3V logic, though some versions have a 5V-tolerant input. The pixel format is controlled by the 0x3A command (COLMOD), where you set the interface pixel format to 0x05 for 16-bit color (RGB565). If you accidentally set it to 0x03 (12-bit), the colors will appear posterized because each pixel only uses 4 bits per channel. For real-time color changes, you can use the 0x2A and 0x2B commands to set the column and page address windows, which allows you to update only a portion of the screen—this is critical for reducing SPI traffic when changing colors in a small area. For example, to change the color of a 100x50 pixel rectangle, you only send 10,000 bytes instead of 64,800. The typical write cycle time per byte is about 0.5 microseconds at 20 MHz, so a full-screen fill takes roughly 32 milliseconds, which is fast enough for 30 FPS animations. However, if you’re using a slower microcontroller like an Arduino Uno (16 MHz), the SPI throughput is limited by the CPU, and you might see frame drops. In that case, you can use DMA (Direct Memory Access) on ESP32 to offload the data transfer, achieving up to 40 Mbps SPI speed.
From a software perspective, the most common mistake is not initializing the display correctly. The ST7789V requires a specific sequence of commands after power-up: 0x01 (Software Reset), wait 120 ms, then 0x11 (Sleep Out), wait 120 ms, then 0x29 (Display On). Without this, the display stays in sleep mode and won’t respond to color commands. The color encoding itself is little-endian, meaning the first byte sent is the high byte (bits 15-8) and the second byte is the low byte (bits 7-0). For example, orange (0xFD20) is sent as 0xFD followed by 0x20. If you swap the bytes, the color will be wrong—e.g., 0x20FD gives a dark purple instead of orange. Many libraries like Adafruit_GFX handle this internally, but if you’re writing raw SPI commands, you must ensure the byte order matches the display’s expectation. The ST7789V datasheet specifies that the pixel data is stored in a 240x135 RAM matrix, but the row and column order can be flipped using the 0x36 command (MADCTL), which controls the memory access direction. For instance, setting MADCTL to 0x60 rotates the display 180 degrees, which also affects how color data is mapped. If you’re changing colors in a rotated orientation, you need to recalculate the pixel coordinates accordingly.
For advanced color control, you can use the 0xCA command (Display Control) to adjust the brightness of the backlight, which indirectly affects perceived color saturation. The backlight is usually driven by a separate PWM pin (e.g., on the ESP32, you can use LEDC with a 1 kHz frequency and 8-bit resolution). The typical backlight current is 20-30 mA at 3.3V, and the display’s contrast ratio is around 1000:1, but the actual color gamut is about 70% of the NTSC standard due to the IPS panel’s limitations. If you’re working with high-precision color matching (e.g., for medical or industrial displays), you might need to use a lookup table to correct the non-linear response of the LCD. The gamma curve of the ST7789V is set to 2.2 by default, but the actual response can vary by ±0.1 due to manufacturing tolerances. You can measure the color accuracy using a colorimeter and adjust the gamma registers accordingly. The 14 gamma registers for positive gamma (0xE0) are: D0, 04, 0D, 11, 13, 2B, 3F, 54, 4C, 18, 0D, 0B, 1F, 23. For negative gamma (0xE1), the values are: D0, 04, 0C, 11, 13, 2C, 3F, 44, 51, 2F, 1F, 1F, 20, 23. Changing these values can shift the color temperature from 6500K to 9300K, which is useful for different ambient lighting conditions.
Another practical aspect is the power consumption during color changes. The ST7789V draws about 4-6 mA when displaying a static image, but during a full-screen color update, the current spikes to 10-12 mA due to the charging and discharging of the pixel capacitors. If you’re battery-powered, you should minimize the number of full-screen updates. Instead, use partial updates with the window address commands. For example, to change the color of a status bar at the top of the screen, you only update rows 0-20, which reduces the data transfer by 85%. The SPI interface also supports a 3-wire mode (without DC pin) if you use 9-bit data frames, but this is less common and requires careful timing. Most ready-made modules for the 1.14 inch 240x135 ips display use a 4-wire SPI with a separate DC pin, which is easier to drive with standard Arduino libraries. The display’s refresh rate is 60 Hz, but the actual frame rate depends on how fast you can send data. With a 26 MHz SPI clock, the theoretical maximum frame rate for full-screen updates is about 30 FPS, but in practice, you’ll get around 20-25 FPS due to overhead from command setup and GPIO toggling.
Color calibration is often overlooked by hobbyists, but it’s crucial for applications like digital art or UI design. The ST7789V’s default color temperature is around 7500K, which gives a cool blue tint. To get a neutral 6500K, you can adjust the gamma registers to reduce the blue channel gain. For instance, decreasing the 14th gamma register (0x23 to 0x20) for positive gamma will lower the blue response. You can also use the 0xC0 command (Power Control 1) to adjust the GVDD voltage, which affects the overall brightness and contrast. The default GVDD is 4.6V, but you can set it to 4.4V to reduce power consumption or 4.8V for higher contrast. However, increasing GVDD above 4.8V can cause color shift and reduced lifespan. The display’s viewing angle is 80 degrees in all directions (IPS technology), so color consistency is good even at extreme angles, but the brightness drops by about 10% at 45 degrees. For critical color work, you should always view the display head-on.
For developers using the ESP32, the TFT_eSPI library by Bodmer is the most optimized for the ST7789V, with support for DMA, double buffering, and hardware acceleration. The library allows you to change colors using the fillScreen(uint16_t color) function, which internally uses the window address method to update the entire screen. The color parameter is a 16-bit value, and you can use predefined constants like TFT_RED (0xF800) or TFT_GREEN (0x07E0). If you need to create custom colors, you can use the color565(uint8_t r, uint8_t g, uint8_t b) function, which converts 8-bit RGB values to 16-bit RGB565. For example, a 50% gray (R=128, G=128, B=128) becomes 0x8410. The library also supports anti-aliased fonts and sprites, which can be used to create color-changing UI elements. The SPI bus speed can be set to 40 MHz on ESP32, but you must ensure the wiring is short (less than 10 cm) to avoid signal degradation. If you’re using a breadboard, the capacitance of the wires can cause the SPI clock to distort, leading to color artifacts. In that case, reduce the SPI speed to 20 MHz or use shielded cables.
Another technique for changing colors is to use the display’s 0x20 command (INVOFF) and 0x21 command (INVON) for color inversion. This flips all pixel values, turning black to white and vice versa, but it also affects the hue. For example, red (0xF800) becomes cyan (0x07FF) because the inversion is bitwise. This is useful for low-power modes where you want to toggle between a dark and light theme without sending new pixel data. The inversion command takes only 1 byte and executes in microseconds, making it ideal for quick color changes. However, the inverted colors are not true complementary colors because the RGB565 format has uneven bit allocations (5 bits for red, 6 for green, 5 for blue). The inversion of pure red (0xF800) is 0x07FF (binary: 00000 111111 11111), which is a bright cyan. If you need true complementary colors, you must calculate them manually: for a given color, the complement is (0xFFFF - color) but with the caveat that the green channel has 6 bits, so the formula is (0xFFFF - color) & 0xFFFF. For example, the complement of 0xF800 is 0x07FF, which matches the inversion.
From a hardware perspective, the 1.14 inch 240x135 ips display typically uses a 6-pin interface (VCC, GND, SCL, SDA, RES, DC, but some modules have 7 pins including a backlight control). The VCC can be 3.3V or 5V depending on the module, but the logic pins are always 3.3V. If you’re using a 5V microcontroller like an Arduino Uno, you need a level shifter for the SPI lines, otherwise the 5V signals can damage the display’s driver IC. The display’s power consumption is 40-50 mW at full brightness, which is efficient for a 1.14-inch panel. The pixel pitch is 0.108 mm, giving a PPI (pixels per inch) of 235, which is sharp enough for reading text at a normal viewing distance. The color gamut covers about 70% of the sRGB color space, so saturated colors like neon green or deep purple may appear slightly muted. For applications requiring wider color gamut, you might need to use a different display technology like OLED, but the IPS LCD offers better sunlight readability and lower cost.
When debugging color issues, the first step is to verify the SPI communication using a logic analyzer. The ST7789V expects the CS pin to be low during the entire command or data transfer, and the DC pin must be set to 0 for commands and 1 for data. A common mistake is to toggle the CS pin between bytes, which causes the display to interpret the data as multiple separate commands. The correct sequence is: set CS low, send command byte (DC=0), then send data bytes (DC=1), then set CS high. The data bytes for a color fill must be sent continuously without any gaps. If you use the Arduino SPI.transfer() function, it automatically handles the byte-by-byte transfer, but if you’re using a bit-banged SPI, you need to ensure the clock polarity (CPOL=0) and phase (CPHA=0) are correct. The ST7789V uses mode 0, meaning the data is sampled on the rising edge of the clock. If you accidentally use mode 3, the data will be shifted by half a clock cycle, causing corrupted colors.
For dynamic color changes in animations, you can use the 0x2C command with a continuous stream of pixel data. The display’s write cycle is 16 bits per pixel, but you can send multiple pixels in a single SPI transaction to reduce overhead. For example, to change the color of a 64x64 pixel area, you can precompute the color data in a buffer and send it in one burst. The ESP32’s SPI driver supports transactions up to 4096 bytes, so you can send up to 2048 pixels per transaction. For larger areas, you need to split the data into multiple transactions. The library LovyanGFX is optimized for this, using a frame buffer in PSRAM (if available) to achieve 60 FPS full-screen animations. The color accuracy during fast updates can suffer from ghosting, which is a characteristic of IPS panels with a response time of 20-30 ms. To mitigate this, you can use the 0x36 command to set the display to BGR order instead of RGB if your color data is in BGR format. This is a common mistake when using libraries that assume RGB order—the colors will appear swapped (red becomes blue).
In terms of reliability, the ST7789V has a built-in 0x0C command (Read ID) that returns the driver ID (0x85 or 0x86), which you can use to verify the display is responding correctly. If the ID is wrong, the SPI wiring or initialization sequence is incorrect. The display also has a 0x4D command (Read Frame Rate) that returns the current refresh rate, which is useful for debugging performance issues. The default frame rate is 60 Hz, but it can drop to 30 Hz if the SPI clock is too slow. The color change operation itself is non-destructive—you can overwrite any pixel without affecting the rest of the display. However, if you use the 0x2A and 0x2B commands to set a window, the display will only update that window, and any subsequent color data will be written to that window until you reset the window to the full screen. This is a common source of bugs: if you forget to reset the window after a partial update, the next color fill will only affect the previous window area.
For practical implementation, here’s a typical initialization sequence for the ST7789V on a 1.14-inch display: after power-up, send 0x01 (Software Reset), wait 120 ms, then 0x11 (Sleep Out), wait 120 ms, then 0x3A with 0x05 (16-bit color), then 0x36 with 0x00 (default orientation), then 0x21 (Inversion On) if you want the default color scheme, then 0x13 (Normal Display Mode On), then 0x29 (Display On). After this, you can send 0x2C followed by the pixel data. The total initialization time is about 250 ms, which is acceptable for most applications. If you need faster startup, you can skip the software reset and go directly to sleep out, but this might cause display