Skip to content

Commit

Permalink
Add initial support of Adafruit 8x8 LED matrix
Browse files Browse the repository at this point in the history
  • Loading branch information
pdp7 committed Nov 1, 2018
1 parent 1c1584f commit 7602069
Show file tree
Hide file tree
Showing 3 changed files with 409 additions and 1 deletion.
114 changes: 114 additions & 0 deletions ports/esp32/modules/ht16k33_matrix.py
@@ -0,0 +1,114 @@
_HT16K33_BLINK_CMD = const(0x80)
_HT16K33_BLINK_DISPLAYON = const(0x01)
_HT16K33_CMD_BRIGHTNESS = const(0xE0)
_HT16K33_OSCILATOR_ON = const(0x21)


class HT16K33:
"""The base class for all HT16K33-based backpacks and wings."""

def __init__(self, i2c, address=0x70):
self.i2c = i2c
self.address = address
self._temp = bytearray(1)
self.buffer = bytearray(16)
self.fill(0)
self._write_cmd(_HT16K33_OSCILATOR_ON)
self.blink_rate(0)
self.brightness(15)

def _write_cmd(self, byte):
"""Send a command."""
self._temp[0] = byte
self.i2c.writeto(self.address, self._temp)

def blink_rate(self, rate=None):
"""Get or set the blink rate."""
if rate is None:
return self._blink_rate
rate = rate & 0x02
self._blink_rate = rate
self._write_cmd(_HT16K33_BLINK_CMD |
_HT16K33_BLINK_DISPLAYON | rate << 1)

def brightness(self, brightness):
"""Get or set the brightness (0-15)."""
if brightness is None:
return self._brightness
brightness = brightness & 0x0F
self._brightness = brightness
self._write_cmd(_HT16K33_CMD_BRIGHTNESS | brightness)

def show(self):
"""Actually send all the changes to the device."""
self.i2c.writeto_mem(self.address, 0x00, self.buffer)

def fill(self, color):
"""Fill the display with given color."""
fill = 0xff if color else 0x00
for i in range(16):
self.buffer[i] = fill

def _pixel(self, x, y, color=None):
"""Set a single pixel in the frame buffer to specified color."""
mask = 1 << x
if color is None:
return bool((self.buffer[y] | self.buffer[y + 1] << 8) & mask)
if color:
self.buffer[y * 2] |= mask & 0xff
self.buffer[y * 2 + 1] |= mask >> 8
else:
self.buffer[y * 2] &= ~(mask & 0xff)
self.buffer[y * 2 + 1] &= ~(mask >> 8)


class Matrix16x8(HT16K33):
"""The double matrix."""

def pixel(self, x, y, color=None):
"""Set a single pixel to specified color."""
if not 0 <= x <= 15:
return
if not 0 <= y <= 7:
return
if x >= 8:
x -= 8
y += 8
return super()._pixel(y, x, color)


class Matrix8x8(HT16K33):
"""The single matrix."""

def pixel(self, x, y, color=None):
"""Set a single pixel to specified color."""
if not 0 <= x <= 7:
return
if not 0 <= y <= 7:
return
x = (x - 1) % 8
return super()._pixel(x, y, color)


class Matrix8x8x2(HT16K33):
"""The bi-color matrix."""

def pixel(self, x, y, color=None):
"""Set a single pixel to specified color."""
if not 0 <= x <= 7:
return
if not 0 <= y <= 7:
return
if color is not None:
super()._pixel(y, x, (color & 0x01))
super()._pixel(y + 8, x, (color >> 1) & 0x01)
else:
return super()._pixel(y, x) | super()._pixel(y + 8, x) << 1

def fill(self, color):
"""Fill the display with given color."""
fill1 = 0xff if color & 0x01 else 0x00
fill2 = 0xff if color & 0x02 else 0x00
for i in range(8):
self.buffer[i * 2] = fill1
self.buffer[i * 2 + 1] = fill2
226 changes: 226 additions & 0 deletions ports/esp32/modules/ht16k33_seg.py
@@ -0,0 +1,226 @@
from ht16k33_matrix import HT16K33


CHARS = (
0b00000000, 0b00000000, #
0b01000000, 0b00000110, # !
0b00000010, 0b00100000, # "
0b00010010, 0b11001110, # #
0b00010010, 0b11101101, # $
0b00001100, 0b00100100, # %
0b00100011, 0b01011101, # &
0b00000100, 0b00000000, # '
0b00100100, 0b00000000, # (
0b00001001, 0b00000000, # )
0b00111111, 0b11000000, # *
0b00010010, 0b11000000, # +
0b00001000, 0b00000000, # ,
0b00000000, 0b11000000, # -
0b00000000, 0b00000000, # .
0b00001100, 0b00000000, # /
0b00001100, 0b00111111, # 0
0b00000000, 0b00000110, # 1
0b00000000, 0b11011011, # 2
0b00000000, 0b10001111, # 3
0b00000000, 0b11100110, # 4
0b00100000, 0b01101001, # 5
0b00000000, 0b11111101, # 6
0b00000000, 0b00000111, # 7
0b00000000, 0b11111111, # 8
0b00000000, 0b11101111, # 9
0b00010010, 0b00000000, # :
0b00001010, 0b00000000, # ;
0b00100100, 0b01000000, # <
0b00000000, 0b11001000, # =
0b00001001, 0b10000000, # >
0b01100000, 0b10100011, # ?
0b00000010, 0b10111011, # @
0b00000000, 0b11110111, # A
0b00010010, 0b10001111, # B
0b00000000, 0b00111001, # C
0b00010010, 0b00001111, # D
0b00000000, 0b11111001, # E
0b00000000, 0b01110001, # F
0b00000000, 0b10111101, # G
0b00000000, 0b11110110, # H
0b00010010, 0b00000000, # I
0b00000000, 0b00011110, # J
0b00100100, 0b01110000, # K
0b00000000, 0b00111000, # L
0b00000101, 0b00110110, # M
0b00100001, 0b00110110, # N
0b00000000, 0b00111111, # O
0b00000000, 0b11110011, # P
0b00100000, 0b00111111, # Q
0b00100000, 0b11110011, # R
0b00000000, 0b11101101, # S
0b00010010, 0b00000001, # T
0b00000000, 0b00111110, # U
0b00001100, 0b00110000, # V
0b00101000, 0b00110110, # W
0b00101101, 0b00000000, # X
0b00010101, 0b00000000, # Y
0b00001100, 0b00001001, # Z
0b00000000, 0b00111001, # [
0b00100001, 0b00000000, # \
0b00000000, 0b00001111, # ]
0b00001100, 0b00000011, # ^
0b00000000, 0b00001000, # _
0b00000001, 0b00000000, # `
0b00010000, 0b01011000, # a
0b00100000, 0b01111000, # b
0b00000000, 0b11011000, # c
0b00001000, 0b10001110, # d
0b00001000, 0b01011000, # e
0b00000000, 0b01110001, # f
0b00000100, 0b10001110, # g
0b00010000, 0b01110000, # h
0b00010000, 0b00000000, # i
0b00000000, 0b00001110, # j
0b00110110, 0b00000000, # k
0b00000000, 0b00110000, # l
0b00010000, 0b11010100, # m
0b00010000, 0b01010000, # n
0b00000000, 0b11011100, # o
0b00000001, 0b01110000, # p
0b00000100, 0b10000110, # q
0b00000000, 0b01010000, # r
0b00100000, 0b10001000, # s
0b00000000, 0b01111000, # t
0b00000000, 0b00011100, # u
0b00100000, 0b00000100, # v
0b00101000, 0b00010100, # w
0b00101000, 0b11000000, # x
0b00100000, 0b00001100, # y
0b00001000, 0b01001000, # z
0b00001001, 0b01001001, # {
0b00010010, 0b00000000, # |
0b00100100, 0b10001001, # }
0b00000101, 0b00100000, # ~
0b00111111, 0b11111111,
)
NUMBERS = (
0x3F, # 0
0x06, # 1
0x5B, # 2
0x4F, # 3
0x66, # 4
0x6D, # 5
0x7D, # 6
0x07, # 7
0x7F, # 8
0x6F, # 9
0x77, # a
0x7C, # b
0x39, # C
0x5E, # d
0x79, # E
0x71, # F
0x40, # -
)


class Seg14x4(HT16K33):
"""The alpha-numeric 14-segment display."""

def scroll(self, count=1):
"""Scroll the display by specified number of places."""
if count >= 0:
offset = 0
else:
offset = 2
for i in range(6):
self.buffer[i + offset] = self.buffer[i + 2 * count]

def put(self, char, index=0):
"""Put a character at the specified place."""
if not 0 <= index <= 3:
return
if not 32 <= ord(char) <= 127:
return
if char == '.':
self.buffer[index * 2 + 1] |= 0b01000000
return
c = ord(char) * 2 - 64
self.buffer[index * 2] = CHARS[1 + c]
self.buffer[index * 2 + 1] = CHARS[c]

def push(self, char):
"""Scroll the display and add a character at the end."""
if char != '.' or self.buffer[7] & 0b01000000:
self.scroll()
self.put(' ', 3)
self.put(char, 3)

def text(self, text):
"""Display the specified text."""
for c in text:
self.push(c)

def number(self, number):
"""Display the specified decimal number."""
s = "{:f}".format(number)
if len(s) > 4:
if s.find('.') > 4:
raise ValueError("Overflow")
self.fill(False)
places = 4
if '.' in s:
places += 1
self.text(s[:places])

def hex(self, number):
"""Display the specified hexadecimal number."""
s = "{:x}".format(number)
if len(s) > 4:
raise ValueError("Overflow")
self.fill(False)
self.text(s)


class Seg7x4(Seg14x4):
"""The numeric 7-segment display."""

P = [0, 2, 6, 8] # The positions of characters.

def scroll(self, count=1):
"""Scroll the display by specified number of places."""
if count >= 0:
offset = 0
else:
offset = 1
for i in range(3):
self.buffer[self.P[i + offset]] = self.buffer[self.P[i + count]]

def push(self, char):
"""Scroll the display and add a character at the end."""
if char in ':;':
self.put(char)
else:
super().push(char)

def put(self, char, index=0):
"""Put a character at the specified place."""
if not 0 <= index <= 3:
return
char = char.lower()
if char == '.':
self.buffer[self.P[index]] |= 0b10000000
return
elif char in 'abcdef':
c = ord(char) - 97 + 10
elif char == '-':
c = 16
elif char in '0123456789':
c = ord(char) - 48
elif char == ' ':
c = 0x00
elif char == ':':
self.buffer[4] = 0x02
return
elif char == ';':
self.buffer[4] = 0x00
return
else:
return
self.buffer[self.P[index]] = NUMBERS[c]

0 comments on commit 7602069

Please sign in to comment.