HT16K33 8x8 Dot-Matrix Display

The Keyestudio I2C 8x8 Dot-Matrix display [1]. is a clear, bright display for representing data, such as analogue values, temperatures, or for playing games.

HT16K338x8.jpg 

It's based on an HT16K33 I2C driver chip [2]. This code will also work with the simplar display from Adafruit [3].

You can choose one of four I2C addresses for each display, allowing you to drive up to four displays simultaneously. The default I2C address is #x70 or 112.

Initialising the display

The variable adr is used to specify the I2C address of the display; by default this is 112:

(defvar adr 112)

The routine set initialises the display and sets the brightness, from 0 (off) to 15 (maximum):

(defun set (bri)
  (with-i2c (s adr)
    (write-byte #x21 s)
    (restart-i2c s)
    (write-byte #x81 s)
    (restart-i2c s)
    (write-byte (+ #xe0 bri) s)))

The routine clr clears the display by setting each column to zero:

(defun clr ()
  (with-i2c (s adr)
    (dotimes (x 16)
      (write-byte #x00 s))))

Displaying a bitmap

The following routine put displays an 8x8 bitmap on the display:

(defun put (&rest byt)
  (with-i2c (s adr)
    (write-byte 0 s)
    (dotimes (n 8)
      (let ((col (nth n byt)))
        (write-byte (logior (ash col -1) (ash col 7)) s)
        (write-byte 0 s)))))

The parameter is a list of eight bytes representing the columns you want to display.

For example, the following call displays a smiley (rotated through 90°). Using binary numbers for the columns makes it easy to design the bitmap:

(put #b00111100
     #b01000010
     #b10100101
     #b10000001
     #b10100101
     #b10011001
     #b01000010
     #b00111100)

The expression:

(logior (ash col -1) (ash col 7))

is designed to compensate for the fact that for some reason the rows are numbered 7, 0, 1, 2, 3, 4, 5, 6 from bottom to top.

Plotting a point

The plt routine treats the display as an 8x8 graphics display, and allows you to toggle one LED on or off by specifying its coordinates:

(defun plt (x y)
  (let (b)
    (with-i2c (s adr)
      (write-byte (* x 2) s)
      (restart-i2c s 1)
      (setq b (read-byte s))
      (restart-i2c s)
      (write-byte (* x 2) s)
      (write-byte
       (logxor b (ash 1 (logand (+ y 7) 7))) s))))

For example, to toggle the LED in the bottom left-hand corner (with the connector at the bottom), give the command:

(plt 0 0)

Again, the expression:

(logand (+ y 7) 7)

compensates for the odd row numbering.

For a simple demo that randomly toggles LEDs on the display to give a changing series of patterns see LED 8x8 dot-matrix display.


  1. ^ Useful Keyestudio I2C 8x8 LED Matrix on AliExpress.
  2. ^ HT16K33 Datasheet on Adafruit.
  3. ^ Mini 8x8 LED Matrix w/I2C Backpack on Adafruit.