How to create a scrolling text on a 2.4 inch 240x320 TFT display?
How to Create a Scrolling Text on a 2.4 inch 240x320 TFT Display
To create scrolling text on a 2.4 inch 240x320 tft display, you need to combine hardware interfacing with a software routine that shifts pixel data horizontally or vertically across the screen. The display itself is typically driven by an SPI or MCU interface, with common controllers like the ILI9341 or ST7789. For a 240x320 resolution, you’re working with 76,800 pixels in total, and each pixel requires 16-bit color data (RGB565) for full color depth, meaning you’re moving about 153,600 bytes per frame if you refresh the entire screen. But scrolling text doesn’t need a full refresh—you only update the region where the text moves, which saves processing time and reduces flicker. The key is to use a framebuffer in the microcontroller’s RAM, typically 320x240 pixels * 2 bytes = 153,600 bytes, which fits in a chip like the ESP32 (520KB SRAM) or an STM32F4 (192KB+ SRAM). If your MCU has less RAM, like an Arduino Uno (2KB), you’ll need to scroll in small chunks, updating only a few rows at a time, or use an external SPI RAM chip.
Start by initializing the display with the correct command set for your controller. For the ILI9341, you send commands like 0x11 (sleep out), 0x3A (pixel format set to 16-bit), and 0x29 (display on). The SPI clock speed should be at least 10 MHz to achieve smooth scrolling—higher speeds like 40 MHz reduce update time below 10 ms per row. For text scrolling, you’ll need a font library, such as Adafruit GFX or u8g2, which stores glyphs as bitmaps. A typical 16x16 pixel font character uses 32 bytes (16 rows * 16 bits/row). To scroll horizontally, you shift the text column by column: for each frame, you read the current column of pixels from the framebuffer, move it left by one pixel, and write the new column from the next character. This requires a loop that iterates over the display width (240 pixels), reading and writing 240 * 2 bytes = 480 bytes per row. If you scroll 16 rows of text, that’s 16 * 480 = 7,680 bytes per frame. At 30 FPS, you’re moving 230 KB/s, which is well within SPI bandwidth.
For vertical scrolling, you shift rows instead of columns. The ILI9341 has a hardware scrolling feature via command 0x33 (vertical scrolling start address) and 0x37 (vertical scrolling end address), but that only scrolls the entire display buffer, not individual text. For partial scrolling, you need to manually copy pixel rows in the framebuffer. A common technique is to use a circular buffer: store the text in a bitmap larger than the screen, and adjust the start offset each frame. For example, if your text is 1000 pixels wide (about 62 characters at 16px each), you store it in a 1000x16 bitmap (16,000 bytes). Each frame, you copy a 240-pixel-wide window starting at offset X, where X increments by 1 each frame. This copy operation reads 240 * 16 * 2 = 7,680 bytes per frame, and you can do this at 60 FPS with a 40 MHz SPI bus. The bottleneck is the framebuffer copy, which takes about 1.5 ms on a 168 MHz STM32F4 using DMA. If you use DMA for SPI transfers, the CPU is free to compute the next frame during the transfer, achieving near-zero overhead.
Data-wise, the display’s pixel clock is typically 6.5 MHz for 60 FPS, but SPI is much slower. A 40 MHz SPI clock gives a theoretical throughput of 5 MB/s, but overhead from command bytes and chip select adds about 20%. So you get about 4 MB/s, which is enough for 240x320 (153,600 bytes) at 26 FPS. For scrolling text, you only update a small region, so you can hit 60 FPS easily. The ILI9341’s write cycle time is 66 ns per pixel, meaning 240 pixels take 15.84 µs per row. For 16 rows, that’s 253 µs per frame, plus SPI overhead. So your scrolling text can update at over 1000 FPS theoretically, but you’ll be limited by the MCU’s memory bandwidth and the font rendering speed.
To avoid tearing, use double buffering: write to a back buffer while the display shows the front buffer. This requires 2x the framebuffer RAM (307,200 bytes), which is feasible on an ESP32 (520KB) or a Raspberry Pi Pico (264KB). On a Pico, you can use the PIO (Programmable I/O) to drive the SPI at 62.5 MHz, achieving 7.8 MB/s. For a 240x320 display, that’s 19.7 FPS for full screen, but for scrolling text, you can do 100+ FPS. The font rendering itself adds overhead: a 16x16 character from a bitmap font takes 32 bytes, and you need to blit it into the framebuffer. Blitting a 16x16 character uses 16 rows * 16 pixels * 2 bytes = 512 bytes per character. If you scroll 10 characters, that’s 5,120 bytes per frame, which takes about 0.64 ms at 8 MB/s. So the total frame time is under 1 ms, leaving plenty of headroom for other tasks.
For a real-world implementation, consider the 2.4 inch 240x320 tft display from DisplayModule, which uses the ILI9341 controller and supports both SPI (4-wire) and MCU 8-bit parallel modes. The SPI mode uses pins: CS, DC, SCK, MOSI, MISO (optional), and RESET. The parallel mode uses 8 data pins plus control pins, which is faster but uses more GPIO. For scrolling text, SPI is fine because you’re not updating the whole screen. The display’s datasheet specifies a minimum SPI clock of 10 MHz, but I’ve run it at 40 MHz with no issues on a 3.3V logic level. The power consumption is about 50 mA at full brightness, which is low enough for battery-powered projects. The display’s response time is 10 ms (typical), so fast scrolling won’t ghost.
Here’s a quick reference table for scrolling text performance on common MCUs:
| MCU | RAM (KB) | SPI Speed (MHz) | Full Frame FPS | Scrolling Text FPS (16 rows) |
|---|---|---|---|---|
| Arduino Uno | 2 | 8 | 0.5 | 8 |
| ESP32 | 520 | 40 | 26 | 400 |
| STM32F407 | 192 | 42 | 28 | 420 |
| Raspberry Pi Pico | 264 | 62.5 | 19.7 | 300 |
The table shows that even a low-end Arduino can scroll text at 8 FPS, which is usable for slow marquee effects. The ESP32 and STM32 give smooth 60 FPS scrolling with ease. The key bottleneck is the font rendering library: Adafruit GFX uses software rendering, which is slow for proportional fonts. For faster rendering, use a bitmap font stored in flash, like the 8x8 or 16x16 fixed-width fonts. A 16x16 font for all ASCII characters (95 chars) takes 95 * 32 = 3,040 bytes, which fits in any MCU’s flash. For scrolling, you pre-render the entire text string into a bitmap buffer, then shift the viewport. This avoids per-character rendering every frame.
Another optimization is to use the display’s windowed write mode. The ILI9341 supports setting a rectangular window via command 0x2A (column address) and 0x2B (row address), then you can write pixels only within that window. For scrolling text, you set the window to the text area (e.g., rows 0-15, columns 0-239) and write only those pixels. This reduces SPI traffic by 90% compared to full-screen updates. The window coordinates are set with 16-bit values, so you can specify any sub-rectangle. The display’s memory is organized as a 240x320 grid, but the controller can wrap around if you exceed the boundaries, which is useful for seamless scrolling.
For a practical example, let’s say you want to scroll the text “Hello World” horizontally across the top of the screen. The text is 11 characters at 16px each = 176 pixels wide. You store it in a 176x16 bitmap (5,632 bytes). Each frame, you copy 240 pixels from this bitmap starting at offset X, where X increments from 0 to 176-240 = -64 (negative offset means the text starts off-screen). When X reaches 240, you reset to 0. The copy uses a nested loop: for each row (0 to 15), for each column (0 to 239), read the pixel from the bitmap at (X + col, row) and write it to the display’s framebuffer. This is a simple memcpy if you use a linear framebuffer. The total data per frame is 240 * 16 * 2 = 7,680 bytes, which takes about 1.5 ms at 40 MHz SPI. With DMA, you can start the transfer and then compute the next frame’s offset, achieving zero latency.
If you’re using a 2.4 inch 240x320 tft display, the physical dimensions are 42.72mm x 60.26mm, with a pixel pitch of 0.178mm. The viewing angle is 120 degrees typical, and the brightness is 250 cd/m². The display’s driver IC is the ILI9341, which has a 240x320x16-bit frame buffer internally. You can also use the MCU 8-bit parallel interface for faster updates, but that requires 8 data pins plus 4 control pins, totaling 12 GPIOs. The SPI interface uses only 4 pins (CS, DC, SCK, MOSI) plus RESET, which is ideal for projects with limited GPIO. The display’s operating voltage is 2.8V to 3.3V, but the logic pins are 5V tolerant if you use a level shifter. The backlight is driven by a separate LED pin with a maximum current of 20 mA, controlled via PWM for brightness adjustment.
For scrolling text, you also need to handle the font’s background. If you want a transparent background, you need to store an alpha mask or use a monochrome font. A 16x16 monochrome font uses 32 bytes per character (1 bit per pixel), and you can overlay it on a background color by checking each bit. This adds a few microseconds per character but saves memory. For a 240x320 display, a full-screen monochrome bitmap uses 240 * 320 / 8 = 9,600 bytes, which is easy to store. But for color text, you need 16-bit per pixel, which is 153,600 bytes for full screen. For scrolling text, you only need to store the text bitmap, which is much smaller. For example, a 100-character string at 16x16 pixels uses 100 * 16 * 16 * 2 = 51,200 bytes, which fits in an ESP32’s heap.
The scrolling algorithm itself can be optimized by using hardware scrolling if your display supports it. The ILI9341 has a vertical scrolling mode that shifts the entire display buffer by a specified number of rows. But this only works for vertical scrolling, not horizontal. For horizontal scrolling, you need to do it in software. Some newer displays like the ST7789 have a horizontal scrolling mode, but the ILI9341 does not. So for the 2.4 inch display, you’ll stick with software scrolling. The key is to minimize the number of SPI writes by using the windowed write mode and DMA. On an ESP32, you can use the SPI peripheral in half-duplex mode to send data at 80 MHz, but the display’s maximum is 40 MHz, so you’re limited by the display, not the MCU.
One common issue is flicker when scrolling. This happens if the display update is not synchronized with the display’s refresh rate. The ILI9341’s refresh rate is typically 60 Hz, but it can vary from 50 to 70 Hz depending on the oscillator. To avoid flicker, use a timer to trigger updates at a fixed interval, like 16.67 ms for 60 FPS. Also, use double buffering to avoid tearing. If you’re using a single buffer, the display might read the buffer while you’re writing to it, causing a partial update. With double buffering, you write to the back buffer and then swap the display pointer to the front buffer. The ILI9341 supports this via command 0x36 (memory access control), which can flip the display orientation but not swap buffers. So you need to implement double buffering in the MCU’s RAM. For a 240x320 display, two buffers take 307,200 bytes, which is fine on an ESP32 or STM32F4.
For a more advanced approach, use a real-time operating system (RTOS) like FreeRTOS on the ESP32. Create a task for scrolling that runs at 60 FPS, and another task for handling user input. The scrolling task uses a queue to receive new text strings, and it pre-renders the text into a bitmap buffer. The task then updates the display via SPI using DMA, and the CPU is free to do other work. The DMA transfer is non-blocking, so you can use the CPU to compute the next frame. On an ESP32, the SPI DMA can transfer up to 64 KB per transaction, so you can send the entire 7,680 bytes in one go. The DMA completion interrupt triggers the next frame, creating a smooth loop.
Finally, test the scrolling speed with a stopwatch or an oscilloscope. Measure the time between frame updates by toggling a GPIO pin. At 60 FPS, the pin should toggle every 16.67 ms. If it’s slower, optimize the font rendering or increase the SPI clock. The display’s datasheet says the maximum SPI clock is 10 MHz for the ILI9341, but I’ve seen it work at 40 MHz on many units. If you get artifacts, reduce the clock speed. Also, check the power supply: a 3.3V regulator with 100 mA capacity is sufficient, but the backlight can draw up to 20 mA, and the display plus MCU can draw 150 mA total. Use a 100 µF capacitor near the display’s power pins to smooth out spikes. With these steps, you’ll have a robust scrolling text implementation that runs smoothly on any 2.4 inch 240x320 TFT display.
Spec it on your stack. Talk to an engineer.
Bring your BOM, latency budget, or platform constraints. We will scope a sensor fusion path against your timeline.