[][src]Crate tiny_led_matrix

A library for direct control of a small monochrome LED display.

This is designed to support the micro:bit's 5×5 display, but nothing in this crate is specific to the micro:bit.

The library assumes the display is internally organised as a two-dimensional matrix of rows and columns, with the individual LEDs addressed directly (typically with one GPIO pin for each row and one for each column).

It isn't designed for the kind of display where you “clock in” the data for an LED row using a smaller number of output pins.

Display model

The LED display must be organised as a two-dimensional array of matrix rows and matrix columns. These describe how the LEDs are wired up, and need not match their visible arrangement.

At any time, LEDs from at most one matrix row of the display are lit; the display driver repeatedly lights LEDs from each row in turn to create the illusion of a stable image.

At present this crate supports at most 16 matrix columns. There's no strict limit on the number of rows, but in practice it must be small so that the LEDs are lit for a reasonable proportion of the time.

Greyscale model

LED brightness levels are described using a scale from 0 (off) to 9 (brightest) inclusive.

These are converted to time slices using the same relative durations as the micro:bit MicroPython port uses.

The time slice for each level above 1 is approximately 1.9× the slice for the previous level.

If there are three matrix rows in the display, an LED with brightness 9 is lit for one third of the time.

Configuring the library for a device.

To use this library, you will have to supply implementations of a number of traits, describing your device and its display.


You must supply an implementation of the Matrix trait to describe the matrix dimensions, and how the matrix corresponds to the visible arrangement of LEDs.

Images and Render

The Render trait defines the interface that an image-like type needs to provide in order to be displayed.

The image reports the brightness to use for a given LED, given coordinates according to the visible arrangement.

This crate doesn't supply any implementations of Render; you should define at least one image type of a suitable size and implement Render for it.


Types implementing Render are used to update a Frame (which is in turn passed to a Display).

A Frame instance is a 'compiled' representation of a greyscale image of the size required by the display, in a form that's more directly usable by the display code.

This is exposed in the public API so that you can construct the Frame representation in code running at a low priority. Then only Display::set_frame() has to be called in code that can't be interrupted by the display timer.

You must supply an implementation of the Frame trait.

Timer control

The Display expects to control a single timer which will generate interrupts at appropriate times. Display::handle_event() is intended to be called from these interrupts.

You must supply an implementation of the DisplayTimer trait providing the interface that the Display needs to control the timer.

The DisplayTimer implementation determines the refresh rate for the display.

The Display requests an interrupt for the point in time when the next row is due to be lit. When rendering greyscale images, it requests additional interrupts within each row's time period. It only requests interrupts for the greyscale levels which are required for what's currently being displayed.

LED control

The Display expects to be able to light an arbitrary subset of the LEDs in a given matrix row.

You must supply an implementation of the DisplayControl trait to provide the interface that it needs.

Using the library


A Display instance controls the LEDs and programs a timer. There will normally be a single Display instance in a program using this library.

Display is generic over a type implementing Frame, which in turn determines the Matrix in use.

Putting it together

Once you have provided implementations of all the necessary traits, you can use this library as follows:

When your program starts, call initialise_control() (passing it the device implementing DisplayControl) and initialise_timer() (passing it the device implementing DisplayTimer), and create a Display using your Frame type.

In an interrupt handler for the timer you used for initialise_timer(), call Display::handle_event(), passing it the same two devices.

To display an image: create a Frame instance, use Frame::set() to put the image in it, then call Display::set_frame().

You can call set_frame() at any time, so long as you're not interrupting, or interruptable by, handle_event().

Once you've called set_frame(), you are free to reuse the Frame instance.



Manages a small LED display.


A 'compiled' representation of the part of an image displayed on a single matrix row.



The reason for a display-timer interrupt.



The number of brightness levels for greyscale images (ie, 10).


The maximum brightness level for greyscale images (ie, 9; the minimum is 0).



The interface that Display needs to work with an LED matrix.


The interface that Display needs to work with a timer.


A 'Compiled' representation of an image to be displayed.


Description of a device's LED layout.


A trait providing the information that Display needs to render an image.



Initialises the display hardware you plan to use with a Display.


Starts the timer you plan to use with a Display.