SSD1306 I2C OLED + 4X4 Matrix Keypad Module on RP2040/CircuiyPython 9

Exercises run on WeAct Studio Pico (rp2040) running CircuitPython 9.0.0-beta.0 with 0.96 inch 128x64 SSD1306 I2C OLED with 4X4 Matrix Keypad Module, to display on OLED using using adafruit_displayio_ssd1306, and detect 4X4 key-matrix using Keypad Module.


Libraries need:
- adafruit_displayio_ssd1306.mpy
- adafruit_display_text folder
(If you don't know how to download CircuitPython library bundle and upload to CircuitPython device, read related post RP2040/CircuitPython display on SH1107 SPI OLED)

For SSD1306 I2C OLED:

displayio.I2CDisplay moved from displayio to i2cdisplaybus and renamed I2CDisplayBus. You will not find I2CDisplay in current latest CircuitPython 9 displayio. In CircuitPython 9, it is moved to i2cdisplaybus.I2CDisplayBus.

Currently, if you use displayio.I2CDisplay in CircuitPython 9 (actually it will be switched to I2CDisplayBus), it will not raise error, but raise warning:
FutureWarning: I2CDisplay moved from displayio to i2cdisplaybus
FutureWarning: I2CDisplay renamed I2CDisplayBus


But maybe error in later version.

This exercise handle it with try...except ImportError... block, work on both CircuitPython 8 and 9.

For key-matrix:

keypad is used to detect key-matrix in this exercises.

The keypad module provides native support to scan sets of keys or buttons, connected independently to individual pins, connected to a shift register, or connected in a row-and-column matrix.

Connection:


			WeAct RP2040 Dev. Board
			+----------------+
                                         .
				    3V3  |-3V3
                                         .			
                                    GP26 |C1--------+
                                    GP22 |C2--------|-+
                                         |          | |
                                    GP21 |C3--------|-|-+
                                    GP20 |C4--------|-|-|-+
                                    GP19 |R1--------|-|-|-|-+
                                    GP18 |R2--------|-|-|-|-|-+
                                    GND	 |-GND      | | | | | |
                +----SDA| GP14      GP17 |R3--------|-|-|-|-|-|-+
                | +--SCL| GP15      GP16 |R4--------|-|-|-|-|-|-|-+
                | | 	+----------------+          | | | | | | | |
                | |                                 | | | | | | | |
                +-|-----------------------------+   | | | | | | | |
                  +---------------------------+ |   | | | | | | | |
                                              | |   | | | | | | | |
                        OLED/KeyMatrix        | |   | | | | | | | |
                        +---------------+     | |   | | | | | | | |
                        | +-------+     |     | |   | | | | | | | |
                        | |       |     |     | |   | | | | | | | |
                        | |       | GND |-GND | |   | | | | | | | |
                        | | 	  | VCC |-3V3 | |   | | | | | | | |
                        | |       | SCL |-----+ |   | | | | | | | |
                        | |       | SDA |-------+   | | | | | | | |
                        | +-------+ C1	|-----------+ | | | | | | |
                        |           C2	|-------------+ | | | | | |
                        |  X X X X  C3	|---------------+ | | | | |
                        |           C4	|-----------------+ | | | |
                        |  X X X X  R1	|-------------------+ | | |
                        |	    R2	|---------------------+ | |
                        |  X X X X  R3	|-----------------------+ |
                        |	    R4	|-------------------------+
                        |  X X X X  	|
                        |               |
                        +---------------+


Exercise Code:

rp2_16m_ssd1306_displayio.py, display on SSD1306 I2C OLED using adafruit_displayio_ssd1306.
"""
CircuitPython 9.0.0-beta.0 exercise
run on WeAct Studio Pico 16MB with rp2040
- display on SSD1306 I2C OLED
- using adafruit_displayio_ssd1306

Notice:
This execise also show how to handle new i2cdisplaybus.I2CDisplayBus() in future.

lib needed:
- adafruit_displayio_ssd1306.mpy
- adafruit_display_text folder
"""

import os
import sys
import board
import busio
import time

import displayio
#import i2cdisplaybus
import terminalio

# import adafruit_displayio_ssd1306 will raise the warning:
# FutureWarning: Display moved from displayio to busdisplay
# FutureWarning: Display renamed BusDisplay
# For now, I don't know how to handle it! May be the library will be changed later.
import adafruit_displayio_ssd1306

from adafruit_display_text import label

displayio.release_displays()

# Create the I2C interface and display object of SSD1306_I2C.
SCL = board.GP15
SDA = board.GP14
i2c = busio.I2C(SCL, SDA)

ssd1306_i2c_addr = 0x3C
display_width =128
display_height = 64
# FutureWarning: I2CDisplay moved from displayio to i2cdisplaybus
# FutureWarning: I2CDisplay renamed I2CDisplayBus
# For CircuitPython before 9
# display_bus = displayio.I2CDisplay(i2c, device_address=ssd1306_i2c_addr)
# For CircuitPython 9+
# display_bus = i2cdisplaybus.I2CDisplayBus(i2c, device_address=ssd1306_i2c_addr)

# Follow try..except.. block to import different library for CircuitPython before 9/9+
try:
    # for CircuitPython 9+
    from i2cdisplaybus import I2CDisplayBus
    display_bus = I2CDisplayBus(i2c, device_address=ssd1306_i2c_addr)
except ImportError:
    # for CircuitPython before 9
    from displayio import I2CDisplay
    display_bus = I2CDisplay(i2c, device_address=ssd1306_i2c_addr)

display = adafruit_displayio_ssd1306.SSD1306(
    display_bus, width=display_width, height=display_height)

print("=================================================")
info = sys.implementation[0] + ' ' + os.uname()[3] + '\n' + \
       'run on ' + os.uname()[4]
print(info)
print("=================================================")
print(adafruit_displayio_ssd1306.__name__,
      adafruit_displayio_ssd1306.__version__)
print(display_bus)
print("SCL: ", SCL)
print("SDA: ", SDA)

print(display)
print("display.width x height: ",
      display.width, " x ", display.height)
#================================================
# Make the display context
root_group = displayio.Group()

"""
show() is deprecated and will be removed in CircuitPython 9.0.0. Use .root_group = group instead.
https://docs.circuitpython.org/en/8.2.x/shared-bindings/displayio/index.html#displayio.Display.show
"""
#display.show(group)
display.root_group = root_group

bg_bitmap = displayio.Bitmap(display.width, display.height, 2)
bg_palette = displayio.Palette(2)
bg_palette[0] = 0x000000  # Black
bg_palette[1] = 0xFFFFFF  # White
bg_bitmap.fill(1)
background = displayio.TileGrid(bg_bitmap, pixel_shader=bg_palette, x=0, y=0)
root_group.append(background)

inner_bitmap = displayio.Bitmap(display.width-2, display.height-2, 2)
inner_bitmap.fill(0)
inner = displayio.TileGrid(inner_bitmap, pixel_shader=bg_palette, x=1, y=1)
root_group.append(inner)

# draw a label say hello
text_hello = "coxxect.blogspot.com"
label_hello = label.Label(terminalio.FONT, text=text_hello, scale=1, color=0xFFFFFF, x=5, y=10)
root_group.append(label_hello)

# label for CircuitPython info
sys_info = sys.implementation[0] + " " + os.uname()[2] + " run on " + os.uname()[4]
# labels for driver
label_sysinfo = label.Label(terminalio.FONT,
                            text=sys_info,
                            scale=1,
                            color=0xFFFFFF,
                            x=5, y=24)
root_group.append(label_sysinfo)

# labels for driver
label_drv = label.Label(terminalio.FONT,
                        text=adafruit_displayio_ssd1306.__name__
                        + " " + adafruit_displayio_ssd1306.__version__,
                        scale=1,
                        color=0xFFFFFF,
                        x=5, y=36)
root_group.append(label_drv)

# labels for driver
label_bus = label.Label(terminalio.FONT,
                        text=str(display_bus),
                        scale=1,
                        color=0xFFFFFF,
                        x=5, y=48)
root_group.append(label_bus)

# scroll()/reverse_scroll()
# ref:
# https://learn.adafruit.com/rgb-led-matrices-matrix-panels-with-circuitpython/example-simple-two-line-text-scroller

def scroll(line):
    line.x = line.x - 1
    line_width = line.bounding_box[2]
    if line.x < -line_width:
        line.x = display.width
        
def reverse_scroll(line):
    line.x = line.x + 1
    line_width = line.bounding_box[2]
    if line.x >= display.width:
        line.x = -line_width

time.sleep(1)

while True:
    reverse_scroll(label_hello)
    scroll(label_sysinfo)
    scroll(label_drv)
    display.refresh(minimum_frames_per_second=0)


rp2_16m_ssd1306_displayio_keymatrix.py, detect 4x4 key matrix using keypad.KeyMatrix (fill bitmap of buttons).
"""
CircuitPython 9.0.0-beta.0 exercise
run on WeAct Studio Pico 16MB with rp2040
- display on SSD1306 I2C OLED using adafruit_displayio_ssd1306
- detect 4x4 key matrix using keypad.KeyMatrix
  (fill bitmap of buttons)

lib needed:
- adafruit_displayio_ssd1306.mpy
- adafruit_display_shapes folder
"""

import os
import sys
import board
import busio
import time

import displayio
#import i2cdisplaybus
import terminalio

# import adafruit_displayio_ssd1306 will raise the warning:
# FutureWarning: Display moved from displayio to busdisplay
# FutureWarning: Display renamed BusDisplay
# For now, I don't know how to handle it! May be the library will be changed later.
import adafruit_displayio_ssd1306

import keypad

displayio.release_displays()

# Create the I2C interface and display object of SSD1306_I2C.
SCL = board.GP15
SDA = board.GP14
i2c = busio.I2C(SCL, SDA)

ssd1306_i2c_addr = 0x3C
display_width =128
display_height = 64
# FutureWarning: I2CDisplay moved from displayio to i2cdisplaybus
# FutureWarning: I2CDisplay renamed I2CDisplayBus
# For CircuitPython before 9
# display_bus = displayio.I2CDisplay(i2c, device_address=ssd1306_i2c_addr)
# For CircuitPython 9+
# display_bus = i2cdisplaybus.I2CDisplayBus(i2c, device_address=ssd1306_i2c_addr)

# Follow try..except.. block to import different library for CircuitPython before 9/9+
try:
    # for CircuitPython 9+
    from i2cdisplaybus import I2CDisplayBus
    display_bus = I2CDisplayBus(i2c, device_address=ssd1306_i2c_addr)
except ImportError:
    # for CircuitPython before 9
    from displayio import I2CDisplay
    display_bus = I2CDisplay(i2c, device_address=ssd1306_i2c_addr)

display = adafruit_displayio_ssd1306.SSD1306(
    display_bus, width=display_width, height=display_height)

print("=================================================")
info = sys.implementation[0] + ' ' + os.uname()[3] + '\n' + \
       'run on ' + os.uname()[4]
print(info)
print("=================================================")
print(adafruit_displayio_ssd1306.__name__,
      adafruit_displayio_ssd1306.__version__)
print(display_bus)
print("SCL: ", SCL)
print("SDA: ", SDA)

print(display)
print("display.width x height: ",
      display.width, " x ", display.height)
#================================================
# Make the display context
root_group = displayio.Group()

"""
show() is deprecated and will be removed in CircuitPython 9.0.0. Use .root_group = group instead.
https://docs.circuitpython.org/en/8.2.x/shared-bindings/displayio/index.html#displayio.Display.show
"""
#display.show(group)
display.root_group = root_group

bg_bitmap = displayio.Bitmap(display.width, display.height, 2)
bg_palette = displayio.Palette(2)
bg_palette[0] = 0x000000  # Black
bg_palette[1] = 0xFFFFFF  # White
bg_bitmap.fill(1)
background = displayio.TileGrid(bg_bitmap, pixel_shader=bg_palette, x=0, y=0)
root_group.append(background)

inner_bitmap = displayio.Bitmap(display.width-2, display.height-2, 2)
inner_bitmap.fill(0)
inner = displayio.TileGrid(inner_bitmap, pixel_shader=bg_palette, x=1, y=1)
root_group.append(inner)

num_of_row = 4
num_of_col = 4
cell_width = int(display.width/num_of_row)
cell_height= int(display.height/num_of_col)

but_width = 24
cell_x_margin = int((cell_width-but_width)/2)
but_height = 10
cell_y_margin = int((cell_height-but_height)/2)

buttons = []

but_index = 0
but_bitmap = []
for row in range(4):
    for col in range(4):
        buttons.append([row, col])
        
        b_bitmap = displayio.Bitmap(but_width, but_height, 2)
        b_bitmap.fill(1)
        b = displayio.TileGrid(b_bitmap, pixel_shader=bg_palette,
                               x=(col*cell_width)+cell_x_margin,
                               y=(row*cell_height)+cell_y_margin)
        root_group.append(b)
        but_bitmap.append(b_bitmap)

for r in range(len(but_bitmap)):
    time.sleep(0.1)
    but_bitmap[r].fill(0)

#The KeyMatrix scanner scans keys that are wired in a row-column matrix.
#ref: https://learn.adafruit.com/key-pad-matrix-scanning-in-circuitpython/keymatrix
km = keypad.KeyMatrix(column_pins=(board.GP26, board.GP22, board.GP21, board.GP20),
                      row_pins=(board.GP19, board.GP18, board.GP17, board.GP16),
                      )
while True:
    event = km.events.get()
    if event:
        print(event)
        if event.pressed:
            but_bitmap[event.key_number].fill(1)
        elif event.released:
            but_bitmap[event.key_number].fill(0)



rp2_16m_ssd1306_displayio_keymatrix_palette.py (another approach to change palette of buttons).
"""
CircuitPython 9.0.0-beta.0 exercise
run on WeAct Studio Pico 16MB with rp2040
- display on SSD1306 I2C OLED using adafruit_displayio_ssd1306
- detect 4x4 key matrix using keypad.KeyMatrix
  (another approach to change bitmap palette of buttons)

lib needed:
- adafruit_displayio_ssd1306.mpy
- adafruit_display_shapes folder
"""

import os
import sys
import board
import busio
import time

import displayio
#import i2cdisplaybus
import terminalio

# import adafruit_displayio_ssd1306 will raise the warning:
# FutureWarning: Display moved from displayio to busdisplay
# FutureWarning: Display renamed BusDisplay
# For now, I don't know how to handle it! May be the library will be changed later.
import adafruit_displayio_ssd1306

import keypad

displayio.release_displays()

# Create the I2C interface and display object of SSD1306_I2C.
SCL = board.GP15
SDA = board.GP14
i2c = busio.I2C(SCL, SDA)

ssd1306_i2c_addr = 0x3C
display_width =128
display_height = 64
# FutureWarning: I2CDisplay moved from displayio to i2cdisplaybus
# FutureWarning: I2CDisplay renamed I2CDisplayBus
# For CircuitPython before 9
# display_bus = displayio.I2CDisplay(i2c, device_address=ssd1306_i2c_addr)
# For CircuitPython 9+
# display_bus = i2cdisplaybus.I2CDisplayBus(i2c, device_address=ssd1306_i2c_addr)

# Follow try..except.. block to import different library for CircuitPython before 9/9+
try:
    # for CircuitPython 9+
    from i2cdisplaybus import I2CDisplayBus
    display_bus = I2CDisplayBus(i2c, device_address=ssd1306_i2c_addr)
except ImportError:
    # for CircuitPython before 9
    from displayio import I2CDisplay
    display_bus = I2CDisplay(i2c, device_address=ssd1306_i2c_addr)

display = adafruit_displayio_ssd1306.SSD1306(
    display_bus, width=display_width, height=display_height)

print("=================================================")
info = sys.implementation[0] + ' ' + os.uname()[3] + '\n' + \
       'run on ' + os.uname()[4]
print(info)
print("=================================================")
print(adafruit_displayio_ssd1306.__name__,
      adafruit_displayio_ssd1306.__version__)
print(display_bus)
print("SCL: ", SCL)
print("SDA: ", SDA)

print(display)
print("display.width x height: ",
      display.width, " x ", display.height)
#================================================
# Make the display context
root_group = displayio.Group()

"""
show() is deprecated and will be removed in CircuitPython 9.0.0. Use .root_group = group instead.
https://docs.circuitpython.org/en/8.2.x/shared-bindings/displayio/index.html#displayio.Display.show
"""
#display.show(group)
display.root_group = root_group

bg_bitmap = displayio.Bitmap(display.width, display.height, 2)
bg_palette = displayio.Palette(2)
bg_palette[0] = 0x000000  # Black
bg_palette[1] = 0xFFFFFF  # White
bg_bitmap.fill(1)
background = displayio.TileGrid(bg_bitmap, pixel_shader=bg_palette, x=0, y=0)
root_group.append(background)

inner_bitmap = displayio.Bitmap(display.width-2, display.height-2, 2)
inner_bitmap.fill(0)
inner = displayio.TileGrid(inner_bitmap, pixel_shader=bg_palette, x=1, y=1)
root_group.append(inner)

num_of_row = 4
num_of_col = 4
cell_width = int(display.width/num_of_row)
cell_height= int(display.height/num_of_col)

but_width = 10
cell_x_margin = int((cell_width-but_width)/2)
but_height = 10
cell_y_margin = int((cell_height-but_height)/2)


buttons = []  #actually no use in this exercise

but_index = 0
but_bitmap = []
but_palette = []
for row in range(4):
    for col in range(4):
        buttons.append([row, col])
        
        b_bitmap = displayio.Bitmap(but_width, but_height, 2)
        
        b_palette = displayio.Palette(2)
        b_palette[0] = 0xFFFFFF  # Black
        b_palette[1] = 0xFFFFFF  # Black
        b_bitmap.fill(0)
        
        for x in range(but_width):
            b_bitmap[x, 0] = 1
            b_bitmap[x, but_height-1] = 1
        for y in range(but_height):
            b_bitmap[0, y] = 1
            b_bitmap[but_width-1, y] = 1

        b = displayio.TileGrid(b_bitmap, pixel_shader=b_palette,
                               x=(col*cell_width)+cell_x_margin,
                               y=(row*cell_height)+cell_y_margin)
        root_group.append(b)
        but_bitmap.append(b_bitmap)
        but_palette.append(b_palette)
        
for r in range(len(but_bitmap)):
    time.sleep(0.1)
    but_palette[r][0] = 0x000000  # Black

#The KeyMatrix scanner scans keys that are wired in a row-column matrix.
#ref: https://learn.adafruit.com/key-pad-matrix-scanning-in-circuitpython/keymatrix
km = keypad.KeyMatrix(column_pins=(board.GP26, board.GP22, board.GP21, board.GP20),
                      row_pins=(board.GP19, board.GP18, board.GP17, board.GP16),
                      )
while True:
    event = km.events.get()
    if event:
        print(event)
        if event.pressed:
            but_palette[event.key_number][0] = 0xFFFFFF  # White
        elif event.released:
            but_palette[event.key_number][0] = 0x000000  # Black



rp2_16m_ssd1306_displayio_keymatrix_palette_bitmap.py (further create custom bitmap for keys).
"""
CircuitPython 9.0.0-beta.0 exercise
run on WeAct Studio Pico 16MB with rp2040
- display on SSD1306 I2C OLED using adafruit_displayio_ssd1306
- detect 4x4 key matrix using keypad.KeyMatrix
- further create custom bitmap for keys

lib needed:
- adafruit_displayio_ssd1306.mpy
- adafruit_display_shapes folder
"""

import os
import sys
import board
import busio
import time

import displayio
#import i2cdisplaybus
import terminalio

# import adafruit_displayio_ssd1306 will raise the warning:
# FutureWarning: Display moved from displayio to busdisplay
# FutureWarning: Display renamed BusDisplay
# For now, I don't know how to handle it! May be the library will be changed later.
import adafruit_displayio_ssd1306

import keypad

displayio.release_displays()

# Create the I2C interface and display object of SSD1306_I2C.
SCL = board.GP15
SDA = board.GP14
i2c = busio.I2C(SCL, SDA)

ssd1306_i2c_addr = 0x3C
display_width =128
display_height = 64
# FutureWarning: I2CDisplay moved from displayio to i2cdisplaybus
# FutureWarning: I2CDisplay renamed I2CDisplayBus
# For CircuitPython before 9
# display_bus = displayio.I2CDisplay(i2c, device_address=ssd1306_i2c_addr)
# For CircuitPython 9+
# display_bus = i2cdisplaybus.I2CDisplayBus(i2c, device_address=ssd1306_i2c_addr)

# Follow try..except.. block to import different library for CircuitPython before 9/9+
try:
    # for CircuitPython 9+
    from i2cdisplaybus import I2CDisplayBus
    display_bus = I2CDisplayBus(i2c, device_address=ssd1306_i2c_addr)
except ImportError:
    # for CircuitPython before 9
    from displayio import I2CDisplay
    display_bus = I2CDisplay(i2c, device_address=ssd1306_i2c_addr)

display = adafruit_displayio_ssd1306.SSD1306(
    display_bus, width=display_width, height=display_height)

print("=================================================")
info = sys.implementation[0] + ' ' + os.uname()[3] + '\n' + \
       'run on ' + os.uname()[4]
print(info)
print("=================================================")
print(adafruit_displayio_ssd1306.__name__,
      adafruit_displayio_ssd1306.__version__)
print(display_bus)
print("SCL: ", SCL)
print("SDA: ", SDA)

print(display)
print("display.width x height: ",
      display.width, " x ", display.height)
#================================================
# Make the display context
root_group = displayio.Group()

"""
show() is deprecated and will be removed in CircuitPython 9.0.0. Use .root_group = group instead.
https://docs.circuitpython.org/en/8.2.x/shared-bindings/displayio/index.html#displayio.Display.show
"""
#display.show(group)
display.root_group = root_group

bg_bitmap = displayio.Bitmap(display.width, display.height, 2)
bg_palette = displayio.Palette(2)
bg_palette[0] = 0x000000  # Black
bg_palette[1] = 0xFFFFFF  # White
bg_bitmap.fill(1)
background = displayio.TileGrid(bg_bitmap, pixel_shader=bg_palette, x=0, y=0)
root_group.append(background)

inner_bitmap = displayio.Bitmap(display.width-2, display.height-2, 2)
inner_bitmap.fill(0)
inner = displayio.TileGrid(inner_bitmap, pixel_shader=bg_palette, x=1, y=1)
root_group.append(inner)

num_of_row = 4
num_of_col = 4
cell_width = int(display.width/num_of_row)
cell_height= int(display.height/num_of_col)

but_width = 10
cell_x_margin = int((cell_width-but_width)/2)
but_height = 10
cell_y_margin = int((cell_height-but_height)/2)


BITMAP__ = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]

BITMAP_0 = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 1, 1, 0, 0, 0, 0],
            [0, 0, 0, 1, 0, 0, 1, 0, 0, 0],
            [0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 0, 1, 0, 0, 1, 0, 0, 0],
            [0, 0, 0, 0, 1, 1, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]

BITMAP_1 = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 1, 1, 0, 0, 0, 0],
            [0, 0, 0, 1, 0, 1, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 1, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 1, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 1, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 1, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 1, 0, 0, 0, 0],
            [0, 0, 0, 1, 1, 1, 1, 1, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]

BITMAP_2 = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 1, 1, 1, 0, 0, 0],
            [0, 0, 0, 1, 0, 0, 0, 1, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 0, 0, 0, 0, 1, 0, 0, 0],
            [0, 0, 0, 0, 0, 1, 0, 0, 0, 0],
            [0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
            [0, 0, 0, 1, 0, 0, 0, 0, 0, 0],
            [0, 0, 1, 1, 1, 1, 1, 1, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]

BITMAP_3 = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 1, 1, 1, 1, 1, 1, 0, 0],
            [0, 0, 0, 0, 0, 0, 1, 0, 0, 0],
            [0, 0, 0, 0, 0, 1, 0, 1, 0, 0],
            [0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 1, 1, 1, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 0, 1, 1, 1, 1, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]

BITMAP_4 = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 1, 1, 0, 0],
            [0, 0, 0, 0, 0, 1, 0, 1, 0, 0],
            [0, 0, 0, 0, 1, 0, 0, 1, 0, 0],
            [0, 0, 0, 1, 0, 0, 0, 1, 0, 0],
            [0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 1, 1, 1, 1, 1, 1, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 1, 0, 0]]

BITMAP_5 = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 1, 1, 1, 1, 1, 1, 0, 0],
            [0, 0, 1, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 1, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 1, 1, 1, 1, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 0, 1, 1, 1, 1, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]

BITMAP_6 = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 1, 0, 0, 0, 0],
            [0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
            [0, 0, 0, 1, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 1, 1, 1, 1, 0, 0, 0],
            [0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 0, 1, 1, 1, 1, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]

BITMAP_7 = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 1, 1, 1, 1, 1, 1, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 0, 0, 0, 0, 1, 0, 0, 0],
            [0, 0, 0, 0, 0, 1, 0, 0, 0, 0],
            [0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]

BITMAP_8 = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 1, 1, 1, 1, 0, 0, 0],
            [0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 0, 1, 1, 1, 1, 0, 0, 0],
            [0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 0, 1, 1, 1, 1, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]

BITMAP_9 = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 1, 1, 1, 1, 0, 0, 0],
            [0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 0, 1, 1, 1, 1, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 1, 0, 0, 0],
            [0, 0, 0, 0, 0, 1, 0, 0, 0, 0],
            [0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
            [0, 0, 0, 1, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]

BITMAP_A = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 1, 1, 0, 0, 0, 0],
            [0, 0, 0, 1, 0, 0, 1, 0, 0, 0],
            [0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 1, 1, 1, 1, 1, 1, 0, 0],
            [0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]

BITMAP_B = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 1, 1, 1, 1, 0, 0, 0, 0],
            [0, 0, 1, 0, 0, 0, 1, 0, 0, 0],
            [0, 0, 1, 0, 0, 0, 1, 0, 0, 0],
            [0, 0, 1, 0, 0, 1, 0, 0, 0, 0],
            [0, 0, 1, 1, 1, 1, 1, 0, 0, 0],
            [0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 1, 1, 1, 1, 1, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]

BITMAP_C = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 1, 1, 1, 0, 0, 0],
            [0, 0, 0, 1, 0, 0, 0, 1, 0, 0],
            [0, 0, 1, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 1, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 1, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 1, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 1, 0, 0, 0, 1, 0, 0],
            [0, 0, 0, 0, 1, 1, 1, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]

BITMAP_D = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 1, 1, 1, 1, 0, 0, 0, 0],
            [0, 0, 1, 0, 0, 0, 1, 0, 0, 0],
            [0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 1, 0, 0, 0, 1, 0, 0, 0],
            [0, 0, 1, 1, 1, 1, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]

BITMAP_STAR = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
               [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
               [0, 0, 1, 0, 0, 1, 0, 0, 1, 0],
               [0, 0, 0, 1, 0, 1, 0, 1, 0, 0],
               [0, 0, 0, 0, 1, 1, 1, 0, 0, 0],
               [0, 0, 1, 1, 1, 1, 1, 1, 1, 0],
               [0, 0, 0, 0, 1, 1, 1, 0, 0, 0],
               [0, 0, 0, 1, 0, 1, 0, 1, 0, 0],
               [0, 0, 1, 0, 0, 1, 0, 0, 1, 0],
               [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]

BITMAP_SHARP = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 1, 0, 0, 1, 0, 0],
                [0, 0, 0, 0, 1, 0, 0, 1, 0, 0],
                [0, 0, 1, 1, 1, 1, 1, 1, 1, 0],
                [0, 0, 0, 0, 1, 0, 0, 1, 0, 0],
                [0, 0, 0, 0, 1, 0, 0, 1, 0, 0],
                [0, 0, 1, 1, 1, 1, 1, 1, 1, 0],
                [0, 0, 0, 0, 1, 0, 0, 1, 0, 0],
                [0, 0, 0, 0, 1, 0, 0, 1, 0, 0],
                [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]

BITMAP_MASK = [BITMAP_1, BITMAP_2, BITMAP_3, BITMAP_A,
               BITMAP_4, BITMAP_5, BITMAP_6, BITMAP_B,
               BITMAP_7, BITMAP_8, BITMAP_9, BITMAP_C,
               BITMAP_STAR, BITMAP_0, BITMAP_SHARP, BITMAP_D]

def load_bitmap(bitmap_i):
    bmap = displayio.Bitmap(10, 10, 2)
    for y in range(10):
        for x in range(10):
            bmap[x, y] = bitmap_i[y][x]
    return bmap

buttons = []

but_index = 0
but_bitmap = []
but_palette = []
for row in range(4):
    for col in range(4):
        buttons.append([row, col])
        
        b_palette = displayio.Palette(2)
        b_palette[0] = 0x000000  # Black
        b_palette[1] = 0xFFFFFF  # White
        b_bitmap = load_bitmap(BITMAP_MASK[but_index])
        
        b = displayio.TileGrid(b_bitmap, pixel_shader=b_palette,
                               x=(col*cell_width)+cell_x_margin,
                               y=(row*cell_height)+cell_y_margin)
        root_group.append(b)
        but_bitmap.append(b_bitmap)
        but_palette.append(b_palette)
        but_index = but_index+1

time.sleep(1)
for r in range(len(but_bitmap)):
    time.sleep(0.1)
    but_palette[r][1] = 0x000000  # Black

#The KeyMatrix scanner scans keys that are wired in a row-column matrix.
#ref: https://learn.adafruit.com/key-pad-matrix-scanning-in-circuitpython/keymatrix
km = keypad.KeyMatrix(column_pins=(board.GP26, board.GP22, board.GP21, board.GP20),
                      row_pins=(board.GP19, board.GP18, board.GP17, board.GP16),
                      )
while True:
    event = km.events.get()
    if event:
        print(event)
        if event.pressed:
            but_palette[event.key_number][1] = 0xFFFFFF
        elif event.released:
            but_palette[event.key_number][1] = 0x000000



rp2_16m_ssd1306_displayio_keymatrix_palette_bitmap2.py (more flexible version).
"""
CircuitPython 9.0.0-beta.0 exercise
run on WeAct Studio Pico 16MB with rp2040
- display on SSD1306 I2C OLED using adafruit_displayio_ssd1306
- detect 4x4 key matrix using keypad.KeyMatrix
- Further create custom bitmap for keys
  to make it more flexible in button design.
  The bitmap process once only in setup.
  When key events raised, change palette only.
  
  Also implement buttons[] to re-assign the key return value.

lib needed:
- adafruit_displayio_ssd1306.mpy
- adafruit_display_shapes folder
"""

import os
import sys
import board
import busio
import time

import displayio
#import i2cdisplaybus
import terminalio

# import adafruit_displayio_ssd1306 will raise the warning:
# FutureWarning: Display moved from displayio to busdisplay
# FutureWarning: Display renamed BusDisplay
# For now, I don't know how to handle it! May be the library will be changed later.
import adafruit_displayio_ssd1306

import keypad

displayio.release_displays()

# Create the I2C interface and display object of SSD1306_I2C.
SCL = board.GP15
SDA = board.GP14
i2c = busio.I2C(SCL, SDA)

ssd1306_i2c_addr = 0x3C
display_width =128
display_height = 64
# FutureWarning: I2CDisplay moved from displayio to i2cdisplaybus
# FutureWarning: I2CDisplay renamed I2CDisplayBus
# For CircuitPython before 9
# display_bus = displayio.I2CDisplay(i2c, device_address=ssd1306_i2c_addr)
# For CircuitPython 9+
# display_bus = i2cdisplaybus.I2CDisplayBus(i2c, device_address=ssd1306_i2c_addr)

# Follow try..except.. block to import different library for CircuitPython before 9/9+
try:
    # for CircuitPython 9+
    from i2cdisplaybus import I2CDisplayBus
    display_bus = I2CDisplayBus(i2c, device_address=ssd1306_i2c_addr)
except ImportError:
    # for CircuitPython before 9
    from displayio import I2CDisplay
    display_bus = I2CDisplay(i2c, device_address=ssd1306_i2c_addr)

display = adafruit_displayio_ssd1306.SSD1306(
    display_bus, width=display_width, height=display_height)

print("=================================================")
info = sys.implementation[0] + ' ' + os.uname()[3] + '\n' + \
       'run on ' + os.uname()[4]
print(info)
print("=================================================")
print(adafruit_displayio_ssd1306.__name__,
      adafruit_displayio_ssd1306.__version__)
print(display_bus)
print("SCL: ", SCL)
print("SDA: ", SDA)

print(display)
print("display.width x height: ",
      display.width, " x ", display.height)
#================================================
# Make the display context
root_group = displayio.Group()

"""
show() is deprecated and will be removed in CircuitPython 9.0.0. Use .root_group = group instead.
https://docs.circuitpython.org/en/8.2.x/shared-bindings/displayio/index.html#displayio.Display.show
"""
#display.show(group)
display.root_group = root_group

bg_bitmap = displayio.Bitmap(display.width, display.height, 2)
bg_palette = displayio.Palette(2)
bg_palette[0] = 0x000000  # Black
bg_palette[1] = 0xFFFFFF  # White
bg_bitmap.fill(1)
background = displayio.TileGrid(bg_bitmap, pixel_shader=bg_palette, x=0, y=0)
root_group.append(background)

inner_bitmap = displayio.Bitmap(display.width-2, display.height-2, 2)
inner_bitmap.fill(0)
inner = displayio.TileGrid(inner_bitmap, pixel_shader=bg_palette, x=1, y=1)
root_group.append(inner)

num_of_row = 4
num_of_col = 4
cell_width = int(display.width/num_of_row)
cell_height= int(display.height/num_of_col)

but_width = 10
cell_x_margin = int((cell_width-but_width)/2)
but_height = 10
cell_y_margin = int((cell_height-but_height)/2)


BITMAP__ = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]

BITMAP_0 = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 1, 1, 0, 0, 0, 0],
            [0, 0, 0, 1, 0, 0, 1, 0, 0, 0],
            [0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 0, 1, 0, 0, 1, 0, 0, 0],
            [0, 0, 0, 0, 1, 1, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]

BITMAP_1 = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 1, 1, 0, 0, 0, 0],
            [0, 0, 0, 1, 0, 1, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 1, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 1, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 1, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 1, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 1, 0, 0, 0, 0],
            [0, 0, 0, 1, 1, 1, 1, 1, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]

BITMAP_2 = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 1, 1, 1, 0, 0, 0],
            [0, 0, 0, 1, 0, 0, 0, 1, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 0, 0, 0, 0, 1, 0, 0, 0],
            [0, 0, 0, 0, 0, 1, 0, 0, 0, 0],
            [0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
            [0, 0, 0, 1, 0, 0, 0, 0, 0, 0],
            [0, 0, 1, 1, 1, 1, 1, 1, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]

BITMAP_3 = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 1, 1, 1, 1, 1, 1, 0, 0],
            [0, 0, 0, 0, 0, 0, 1, 0, 0, 0],
            [0, 0, 0, 0, 0, 1, 0, 1, 0, 0],
            [0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 1, 1, 1, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 0, 1, 1, 1, 1, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]

BITMAP_4 = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 1, 1, 0, 0],
            [0, 0, 0, 0, 0, 1, 0, 1, 0, 0],
            [0, 0, 0, 0, 1, 0, 0, 1, 0, 0],
            [0, 0, 0, 1, 0, 0, 0, 1, 0, 0],
            [0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 1, 1, 1, 1, 1, 1, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 1, 0, 0]]

BITMAP_5 = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 1, 1, 1, 1, 1, 1, 0, 0],
            [0, 0, 1, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 1, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 1, 1, 1, 1, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 0, 1, 1, 1, 1, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]

BITMAP_6 = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 1, 0, 0, 0, 0],
            [0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
            [0, 0, 0, 1, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 1, 1, 1, 1, 0, 0, 0],
            [0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 0, 1, 1, 1, 1, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]

BITMAP_7 = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 1, 1, 1, 1, 1, 1, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 0, 0, 0, 0, 1, 0, 0, 0],
            [0, 0, 0, 0, 0, 1, 0, 0, 0, 0],
            [0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]

BITMAP_8 = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 1, 1, 1, 1, 0, 0, 0],
            [0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 0, 1, 1, 1, 1, 0, 0, 0],
            [0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 0, 1, 1, 1, 1, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]

BITMAP_9 = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 1, 1, 1, 1, 0, 0, 0],
            [0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 0, 1, 1, 1, 1, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 1, 0, 0, 0],
            [0, 0, 0, 0, 0, 1, 0, 0, 0, 0],
            [0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
            [0, 0, 0, 1, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]

BITMAP_A = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 1, 1, 0, 0, 0, 0],
            [0, 0, 0, 1, 0, 0, 1, 0, 0, 0],
            [0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 1, 1, 1, 1, 1, 1, 0, 0],
            [0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]

BITMAP_B = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 1, 1, 1, 1, 0, 0, 0, 0],
            [0, 0, 1, 0, 0, 0, 1, 0, 0, 0],
            [0, 0, 1, 0, 0, 0, 1, 0, 0, 0],
            [0, 0, 1, 0, 0, 1, 0, 0, 0, 0],
            [0, 0, 1, 1, 1, 1, 1, 0, 0, 0],
            [0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 1, 1, 1, 1, 1, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]

BITMAP_C = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 1, 1, 1, 0, 0, 0],
            [0, 0, 0, 1, 0, 0, 0, 1, 0, 0],
            [0, 0, 1, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 1, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 1, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 1, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 0, 1, 0, 0, 0, 1, 0, 0],
            [0, 0, 0, 0, 1, 1, 1, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]

BITMAP_D = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
            [0, 0, 1, 1, 1, 1, 0, 0, 0, 0],
            [0, 0, 1, 0, 0, 0, 1, 0, 0, 0],
            [0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 1, 0, 0, 0, 0, 1, 0, 0],
            [0, 0, 1, 0, 0, 0, 1, 0, 0, 0],
            [0, 0, 1, 1, 1, 1, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]

BITMAP_STAR = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
               [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
               [0, 0, 1, 0, 0, 1, 0, 0, 1, 0],
               [0, 0, 0, 1, 0, 1, 0, 1, 0, 0],
               [0, 0, 0, 0, 1, 1, 1, 0, 0, 0],
               [0, 0, 1, 1, 1, 1, 1, 1, 1, 0],
               [0, 0, 0, 0, 1, 1, 1, 0, 0, 0],
               [0, 0, 0, 1, 0, 1, 0, 1, 0, 0],
               [0, 0, 1, 0, 0, 1, 0, 0, 1, 0],
               [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]

BITMAP_SHARP = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 1, 0, 0, 1, 0, 0],
                [0, 0, 0, 0, 1, 0, 0, 1, 0, 0],
                [0, 0, 1, 1, 1, 1, 1, 1, 1, 0],
                [0, 0, 0, 0, 1, 0, 0, 1, 0, 0],
                [0, 0, 0, 0, 1, 0, 0, 1, 0, 0],
                [0, 0, 1, 1, 1, 1, 1, 1, 1, 0],
                [0, 0, 0, 0, 1, 0, 0, 1, 0, 0],
                [0, 0, 0, 0, 1, 0, 0, 1, 0, 0],
                [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]

BITMAP_FRAME = [[1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
                [1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
                [1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
                [1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
                [1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
                [1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
                [1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
                [1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
                [1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
                [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]]

BITMAP_ROUND = [[0, 0, 1, 1, 1, 1, 1, 1, 0, 0],
                [0, 1, 0, 0, 0, 0, 0, 0, 1, 0],
                [1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
                [1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
                [1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
                [1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
                [1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
                [1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
                [0, 1, 0, 0, 0, 0, 0, 0, 1, 0],
                [0, 0, 1, 1, 1, 1, 1, 1, 0, 0]]

BITMAP_MASK = [[BITMAP_1, BITMAP_FRAME],
               [BITMAP_2, BITMAP_FRAME],
               [BITMAP_3, BITMAP_FRAME],
               [BITMAP_A, None],
               [BITMAP_4, BITMAP_FRAME],
               [BITMAP_5, BITMAP_FRAME],
               [BITMAP_6, BITMAP_FRAME],
               [BITMAP_B, None],
               [BITMAP_7, BITMAP_FRAME],
               [BITMAP_8, BITMAP_FRAME],
               [BITMAP_9, BITMAP_FRAME],
               [BITMAP_C, None],
               [BITMAP_STAR, BITMAP_ROUND],
               [BITMAP_0, BITMAP_FRAME],
               [BITMAP_SHARP, BITMAP_ROUND],
               [BITMAP_D, None]]

# event.key_number return the hardware keys sequency
# with buttons[], you can re-assign the expected value returned for each key
buttons = ['1', '2', '3', 'A', '4', '5', '6', 'B', '7', '8', '9', 'C', '*', '0', '#', 'D']

def load_bitmap(bitmap_i):
    bmap = displayio.Bitmap(10, 10, 2)
    for y in range(10):
        for x in range(10):
            if bitmap_i[1] is None:
                bmap[x, y] = bitmap_i[0][y][x]
            else:
                bmap[x, y] = bitmap_i[0][y][x] or bitmap_i[1][y][x]
    return bmap

but_index = 0
but_bitmap = []
but_palette = []
for row in range(4):
    for col in range(4):
        buttons.append([row, col])
        
        b_palette = displayio.Palette(2)
        b_palette[0] = 0x000000  # Black
        b_palette[1] = 0xFFFFFF  # White
        b_bitmap = load_bitmap(BITMAP_MASK[but_index])
        
        b = displayio.TileGrid(b_bitmap, pixel_shader=b_palette,
                               x=(col*cell_width)+cell_x_margin,
                               y=(row*cell_height)+cell_y_margin)
        root_group.append(b)
        but_bitmap.append(b_bitmap)
        but_palette.append(b_palette)
        but_index = but_index+1

time.sleep(1)
for r in range(len(but_bitmap)):
    time.sleep(0.1)
    but_palette[r][1] = 0x000000  # Black

#The KeyMatrix scanner scans keys that are wired in a row-column matrix.
#ref: https://learn.adafruit.com/key-pad-matrix-scanning-in-circuitpython/keymatrix
km = keypad.KeyMatrix(column_pins=(board.GP26, board.GP22, board.GP21, board.GP20),
                      row_pins=(board.GP19, board.GP18, board.GP17, board.GP16),
                      )
while True:
    event = km.events.get()
    if event:
        print(event, ":", buttons[event.key_number])
        if event.pressed:
            but_palette[event.key_number][1] = 0xFFFFFF
        elif event.released:
            but_palette[event.key_number][1] = 0x000000



Comments

Popular posts from this blog

MicroPython/ESP32-C3 + 1.8" 128x160 TFT ST7735 SPI, using boochow/MicroPython-ST7735 library.

CameraWebServe: ESP32-S3 (arduino-esp32) + OV5640 camera module