1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
#![no_std]

//! A library for direct control of a small monochrome LED display.
//!
//! This is designed to support the [micro:bit](https://microbit.org/)'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][micropython] 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.
//!
//!
//! ## Matrix
//!
//! 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.
//!
//!
//! ## Frames
//!
//! 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
//!
//! ## Display
//!
//! 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.
//!
//!
//! [micropython]: https://microbit-micropython.readthedocs.io/


mod control;
mod display;
mod timer;
mod render;

pub use control::DisplayControl;
pub use display::{RowPlan, Matrix, Frame, Display, Event,
                  initialise_timer, initialise_control,
};
pub use timer::DisplayTimer;
pub use render::{BRIGHTNESSES, MAX_BRIGHTNESS, Render};