Pico Inky Pack with Circuit Python

Hi, all! I’m new to the forum and have been tinkering with using the Pico Inky Pack with Circuit Python since I want to use it in conjunction with my RGB Keypad. Here are my current findings:

  • It uses the uc8151d library to interface with the screen. Ensure that the correct pins are being set for proper communication:
  • The following are the default pins used for connecting a Pico to the Inky Pack:
    • Pin 16 / GP12 - SWA (A button)
    • Pin 17 / GP13 - SWB (B Button)
    • Pin 19 / GP14 - SWC (C Button)
    • Pin 21 / GP16 - MISO
    • Pin 22 / GP17 - INKY_CS
    • Pin 24 / GP18 - SCLK
    • Pin 25 / GP19 - MOSI
    • Pin 26 / GP20 - INKY_D/C
    • Pin 27 / GP21 - INKY_RES
    • Pin 30 / RUN - RESET
    • Pin 31 / GP26 - INKY_BUSY
    • Pin 36 / +3V3 - 3V3 (Power)
  • Used the corresponding example.py for the module found in the circuitpython-bundle for a template on how to write to the screen.
  • Here is the code I used to make it work:
# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
# SPDX-License-Identifier: MIT

"""Simple test script for 2.9" 296x128 grayscale display.

Supported products:
  * Adafruit 2.9" Grayscale
    * https://www.adafruit.com/product/4777

import time
import busio
import board
import displayio
import terminalio
from adafruit_display_text import label
import adafruit_uc8151d


# This pinout works on the Raspberry Pi Pico and Pico W and may need to be altered if these pins are being used by other packs or bases.
spi = busio.SPI(board.GP18, MOSI=board.GP19, MISO=board.GP16)  # Uses SCK and MOSI
epd_cs = board.GP17
epd_dc = board.GP20
epd_reset = board.GP21
epd_busy = None

# Make a bus to communicate with the screen.
display_bus = displayio.FourWire(
    spi, command=epd_dc, chip_select=epd_cs, reset=epd_reset, baudrate=400000

# Setting parameters for the display.
display = adafruit_uc8151d.UC8151D(

# Make a group to write to.
g = displayio.Group()

text = "Hello World"
text_area = label.Label(terminalio.FONT,text=text)
text_area.x = 10
text_area.y = 10
while True:

Note: Rotating the screen to values other than 0 and 180 results in a garbled image with this driver. Might be a bug in my code or the driver.

Nice Share!

I’m, not familiar with that driver, it might be as simple as swapping the width height values when you try to rotate 90deg

or, as a longshot, if either the display or the text libraries has (flip_x or flip_y) and swap_xy (or similar settings) you might force a 90deg rotation with doing a flip and a swap. the rotation direction would be dependent on whether you flip the x or the y axis

Hi, thanks for the suggestion. Your first fix appears to have worked for the display and it is no longer displaying a garbled image. A bit weird that you have to change the resolution with the rotation since there is code in the driver to flip the values when the rotation is not 0 or 180 degrees.

class UC8151D(displayio.EPaperDisplay):
r"""UC8151D driver

:param bus: The data bus the display is on
:param \**kwargs:
    See below

:Keyword Arguments:
    * *width* (``int``) --
      Display width
    * *height* (``int``) --
      Display height
    * *rotation* (``int``) --
      Display rotation

def __init__(self, bus: displayio.FourWire, **kwargs) -> None:
    color_bits_inverted = kwargs.pop("color_bits_inverted", False)
    write_color_ram_command = 0x10
    write_black_ram_command = 0x13
    if kwargs.get("grayscale", False):
        start_sequence = bytearray(_GRAYSCALE_START_SEQUENCE)
    elif kwargs.get("highlight_color", False):
        write_color_ram_command = 0x13
        write_black_ram_command = 0x10
        color_bits_inverted = kwargs.pop("color_bits_inverted", True)
        start_sequence = bytearray(_COLOR_START_SEQUENCE)
        start_sequence = bytearray(_START_SEQUENCE)
    width = kwargs["width"]
    height = kwargs["height"]
    if "rotation" in kwargs and kwargs["rotation"] % 180 != 0:
        width, height = height, width


There are also arguments in the adafruit_display_text library for flipping in the x and y axes, so that could be used if the first fix didn’t work.

Glad it worked, and yeah definitely weird, might wanna report it (and the workaround). they may have doubled up their expectations somewhere else or have a bad assumption in their rotation logic.

small note on the flip/swap method. both the order and choice of flip matters… flip_X before swap_XY == swap_XY before flip_Y, which is helpful if you only have one flip version, but potentially confusing if you’re testing for effect and accidentally change the order and the flip at the same time. The one benefit is that it doesn’t actually matter what the internal logic thinks the axes are for it to work, it’ll only determine the direction of ‘rotation’ (which is why I didn’t say which is clockwise, depends on the internals)