How to set up a 1.3 inch display with CircuitPython?

By admin

To set up a 1.3 inch display with CircuitPython, you need to connect a 1.3 inch 240x240 ips display to a microcontroller board like the Raspberry Pi Pico or Adafruit Feather RP2040, install the necessary CircuitPython libraries, and write a script to initialize the display and render graphics. This specific display uses the ST7789 driver chip over SPI, which is widely supported in CircuitPython. The display has a resolution of 240x240 pixels, a 16-bit color depth (65,536 colors), and a typical refresh rate of 60 Hz when driven at 24 MHz SPI clock. The SPI interface requires four pins: SCK (clock), MOSI (data), DC (data/command), and CS (chip select). You also need a RST (reset) pin and a backlight pin (often tied to 3.3V or controlled via PWM).

First, identify the pinout of your display module. Most 1.3 inch 240x240 ips display modules break out 8 pins: GND, VCC (3.3V), SCL (SCK), SDA (MOSI), RES (reset), DC (data/command), CS (chip select), and BLK (backlight). Some modules may have a different order, so always check the datasheet or the silkscreen labels. For a Raspberry Pi Pico, a common wiring is: GND to GND, VCC to 3.3V, SCL to GP2, SDA to GP3, RES to GP4, DC to GP5, CS to GP6, and BLK to 3.3V (or GP7 if you want PWM control). The SPI clock frequency should not exceed 24 MHz for stable operation, though many displays work fine at 40 MHz if your wiring is short and clean.

Next, install CircuitPython on your board. Download the latest stable CircuitPython firmware for your specific board from the official CircuitPython website. For the Raspberry Pi Pico, use the .uf2 file. Hold the BOOTSEL button while connecting the Pico to USB, then copy the .uf2 file to the RPI-RP2 drive. After a reboot, the board will appear as a CIRCUITPY drive. You need to install the Adafruit CircuitPython Bundle, which includes the displayio, adafruit_st7789, and adafruit_display_text libraries. Download the latest bundle (e.g., adafruit-circuitpython-bundle-9.x-mpy-2025xxxx.zip) and extract the lib folder. Copy the following folders to the lib folder on your CIRCUITPY drive: adafruit_st7789.mpy, adafruit_display_text, and the entire displayio folder (if not already present). The displayio library is built into CircuitPython versions 6.0 and later, so you only need the ST7789 driver and display text support.

Now, write the main.py file on the CIRCUITPY drive. Start by importing the required modules: import board, busio, displayio, adafruit_st7789. Then, release any previously used display resources with displayio.release_displays(). Create an SPI bus object: spi = busio.SPI(clock=board.GP2, MOSI=board.GP3). Define the chip select, data/command, and reset pins: cs = board.GP6, dc = board.GP5, reset = board.GP4. Initialize the display with display_bus = displayio.FourWire(spi, command=dc, chip_select=cs, reset=reset). Then create the display object: display = adafruit_st7789.ST7789(display_bus, width=240, height=240, rowstart=0, colstart=0). The rowstart and colstart parameters are critical because some ST7789 displays have a memory offset. For a 1.3 inch 240x240 ips display, these are typically 0, but if you see a shifted image, try rowstart=80 or colstart=80 depending on the orientation. The display orientation can be set using the rotation parameter in the ST7789 constructor, which accepts 0, 90, 180, or 270 degrees.

To display something, create a displayio.Group() and add a displayio.Bitmap and displayio.TileGrid. For example, to show a red screen: bitmap = displayio.Bitmap(240, 240, 1), palette = displayio.Palette(1), palette[0] = 0xFF0000, tile_grid = displayio.TileGrid(bitmap, pixel_shader=palette), group.append(tile_grid), display.show(group). This will fill the entire display with red. If you want to display text, use the adafruit_display_text library. Import from adafruit_display_text import label and from adafruit_bitmap_font import bitmap_font. Load a font file (e.g., font = bitmap_font.load_font("/lib/fonts/LeagueSpartan-Bold-16.bdf")). Create a text label: text_area = label.Label(font, text="Hello World", color=0xFFFFFF, x=10, y=30). Add it to the group: group.append(text_area). Note that you must copy the font files from the bundle’s fonts folder to the lib/fonts folder on your CIRCUITPY drive.

Power consumption is a practical concern. The 1.3 inch 240x240 ips display draws about 20-30 mA with the backlight on at full brightness, and around 1-2 mA when the backlight is off (the display itself consumes about 5-10 mA for pixel refresh). If you’re running on battery, you can control the backlight with a PWM pin to dim it or turn it off entirely. For example, set up a PWM output on pin GP7: import pwmio; backlight = pwmio.PWMOut(board.GP7, frequency=1000, duty_cycle=0). A duty_cycle of 65535 is full brightness, 0 is off. You can also use a simple digital output to toggle the backlight on/off, but PWM gives finer control.

Performance metrics: The SPI bus speed directly affects frame rate. At 24 MHz, you can update the entire 240x240 frame in about 4.5 ms (assuming 16-bit color, 240*240*2 bytes = 115,200 bytes, at 24 MHz that’s 115,200 / 3,000,000 bytes per second ≈ 38 ms, but with overhead it’s closer to 50 ms for a full frame write). Partial updates, like drawing a small rectangle, are much faster. For animations, you can use the display.auto_refresh property to control when the display updates. Set display.auto_refresh = False, then call display.refresh() after making changes to the group. This reduces flicker and improves speed.

Common issues and troubleshooting: If the display shows nothing, check the wiring for loose connections, especially the CS and DC pins. Use a multimeter to verify voltage at the VCC pin (should be 3.3V). If the display shows a white screen or garbled content, the rowstart/colstart values might be wrong. For a 1.3 inch 240x240 ips display, the ST7789 driver often uses a 240x240 pixel memory layout, but some modules have a 320x240 memory and offset the window. Experiment with rowstart=0, colstart=0, then try rowstart=80, colstart=0, or rowstart=0, colstart=80. If the colors are inverted, swap the color order by setting color_order="BGR" in the ST7789 constructor (default is RGB). Another common issue is the SPI bus being used by other devices; ensure no other SPI peripherals are active on the same bus. The backlight pin must be pulled high (3.3V) or connected to a PWM output; if left floating, the display will be dark.

Advanced usage: You can use the displayio.OnDiskBitmap to load images from a BMP file on the CIRCUITPY drive. The BMP must be 240x240 pixels and 16-bit color (RGB565 format). Convert your image using a tool like GIMP or ImageMagick. For example, bitmap = displayio.OnDiskBitmap("/images/logo.bmp"); tile_grid = displayio.TileGrid(bitmap, pixel_shader=bitmap.pixel_shader); group.append(tile_grid). This allows you to display complex graphics without consuming RAM. The OnDiskBitmap reads directly from the storage, so it’s limited by the SPI flash speed on the microcontroller (typically 1-2 MB/s for the Pico’s flash). For smooth animations, pre-load frames into a buffer or use a smaller bitmap.

Touch input is not built into this display, but you can add a separate resistive touch panel or a capacitive touch sensor over I2C. The 1.3 inch 240x240 ips display is purely a display module, so any interaction requires external sensors. For a simple UI, use push buttons connected to GPIO pins. For example, read a button on GP10: import digitalio; button = digitalio.DigitalInOut(board.GP10); button.direction = digitalio.Direction.INPUT; button.pull = digitalio.Pull.UP. Then check if not button.value: to detect a press. Combine this with the display to create a menu system or a game.

Library alternatives: While Adafruit’s ST7789 library is the most common, you can also use the st7789 library from other sources, but the Adafruit version is well-tested and integrates with displayio. The displayio approach is hardware-accelerated on some boards (like the RP2040) because it uses the PIO (Programmable I/O) for SPI, reducing CPU load. On the Raspberry Pi Pico, the displayio implementation uses the PIO to drive the SPI bus, achieving up to 62.5 MHz in some cases, but the ST7789 chip itself is limited to about 24 MHz for reliable operation. Benchmarks show that the Pico can push about 30 frames per second for full-screen updates with the displayio library, which is sufficient for most UI tasks.

For a complete setup, you’ll also need a 3.3V power supply that can deliver at least 100 mA (the Pico draws about 30 mA, the display 30 mA, plus any peripherals). A USB power bank or a 3.7V LiPo battery with a 3.3V regulator works. The display’s backlight can be a significant power drain; if you’re using a battery, consider dimming the backlight to 50% duty cycle, which reduces power consumption by about half while maintaining readability. The display’s viewing angles are excellent (IPS technology means 178 degrees), so you can read it from almost any angle without color shift.

If you need to order a reliable module, check the specifications of the 1.3 inch 240x240 ips display from a reputable supplier. Look for a module that includes the ST7789V driver, a 4-wire SPI interface, and a built-in backlight driver. Some modules also include a capacitive touch panel, but the standard version is just the display. Verify the pinout before wiring, as some modules swap the DC and RES pins or use a different order for CS and DC. The datasheet should list the exact command set and timing parameters, but for most CircuitPython projects, the default initialization sequence in the Adafruit library works fine.

One more detail: The display’s refresh rate is limited by the SPI bus and the microcontroller’s processing speed. For real-time data visualization (like a waveform or a gauge), you can update only a portion of the screen using the displayio.Group’s hidden attribute or by modifying the bitmap’s pixel values directly. For example, to draw a moving line, create a bitmap for the line area and update its pixels in a loop. The displayio.Bitmap supports direct pixel access via bitmap[x, y] = color_index, where color_index is an index into the palette. This is much faster than redrawing the entire screen. A typical update for a 100-pixel line takes about 1 ms, allowing for 1000 updates per second if you’re only changing that line.

Finally, test your setup with a simple example: a counter that increments every second, displayed in the center of the screen. Use a time.sleep(1) loop and update the text label. This confirms that the display, SPI, and libraries are working correctly. If you encounter any errors, check the serial console (via USB) for Python tracebacks. Common errors include missing libraries (e.g., ModuleNotFoundError: No module named 'adafruit_st7789'), incorrect pin assignments (e.g., ValueError: Invalid pins), or memory issues (e.g., MemoryError when loading large bitmaps). The RP2040 has 264 KB of RAM, so a 240x240 16-bit bitmap takes 115,200 bytes (115 KB), leaving about 150 KB for other data. If you’re using multiple bitmaps, consider using OnDiskBitmap to save RAM.