Display¶
Contents
Overview¶
The general process of writing a display driver is as follows:
Find a display controller IC datasheet.
A quick web search for its number usually finds a PDF datasheet.
Displays are often sold as “modules” where the display, controller IC and a printed circuit board (that breaks out I/O pins) are all sandwiched together. Vendors of such boards usually inform the IC number.
Determine which data buses it can talk to.
It is common for displays controllers to support multiple buses: 4-Wire SPI, 3-Wire SPI, I2C, Parallel 6800/8000.
eglib has support for some of those with its HAL interface.
Determine all commands & arguments it can accept.
Datasheets usually have a “commands” section. Those must be sorted out in different buckets:
Configuration: Some commands accept arguments that must be exposed by the display driver configuration. Examples of such commands are setting the number of rows / columns, color depth, voltage regulators etc. Having these commands configurable enables the driver to be easily reused for different display sizes or display module boards.
Extra functions: Some displays support specific functions such as brightness, scrolling and inversion. Those can be exposed as display specific functions.
Driver internal: Those commands do things like initialization, sleep in/out and need not to be exposed outside of the driver.
Read: eglib only supports sending data to displays, these can be ignored.
Determine the display initialization sequence.
Datasheets often have sections explaining their initialization command sequence. Unfortunately, datasheets are not always clear on this and this initialization is usually a function of how the display driver is physically connected to the display and its circuit board. It is common for vendors to share example code for interfacing with their displays (eg: for Arduino, STM32 etc). Those can be a great source for finding the initialization sequence.
Determine how to write pixels to the display memory.
Usually there are commands to set the row / column which can be followed by pixel data for that address. Some displays can auto-increment/decrement the memory address, meaning the next data write will be for a pixel adjacent to the previous. This can be leveraged to accelerate line drawing routines.
Write the driver.
Write unit tests.
Send a pull request.
Scaffold the Code¶
Add src/eglib/display/${IC_NUMBER}.h
:
#include "../display.h"
typedef struct {
// Add entries here for all configuration that must be sent as commands
} ic_number_config_t;
extern const display_t ic_number;
void ic_number_DoSomethingSpecific(eglib_t *eglib);
Then add src/eglib/display/${IC_NUMBER}.c
. This must define the display_t
ic_number
variable declared at the header. This variable type is actually display_struct
, which must be filled with:
HAL communication configuration for each supported bus.
Pointers to functions that implement the various bits of the driver.
display_struct
is well documented: you should be able to follow it though to a working driver.
Make sure to add both new source files to Makefile.am
, so that they’re picked up by the build system.
- Important
Create defines for all display commands used: sending a “maigic” value
0x33
is meaningless, butIC_NUMBER_SLEEP_IN
is not.- Tip
Peek at other drivers implementations at src/eglib/display/ for reference.
Add An Example¶
Add a working example at examples/, including a Makefile
for it.
Add a build target for the example at examples/local.mk
and make the check
target depend on it.
- Important
test your example with real hardware to make sure it works.
Add Documentation¶
Peek at other existing drivers at src/eglib/display/ to see how the documentation inside the C code should be.
Add a documentation page sphinx/reference/display/drivers/${IC_NUMBER}.rst
, following the example of other display drivers. Also add this to sphinx/reference/display/index.rst and to sphinx/local.mk
(so the build system picks it up).
Add Unit Tests¶
Add one or more tests to master/tests/display.
Send A Pull Request¶
Send a pull request of your good work, so others can benefit from it.