This repository contains a configurable driver for the PCF8576 LCD driver IC. The IC is suitable for driving low segment count LCDs, e.g. displays that contains pictograms, bar graphs and numbers.
The major benefit of this driver is its high level API set that allows direct manipulation of LCD segment sets:
- Individual single digit numbers
- Multi-digit numbers with decimal point
- Pictograms and symbols via their names
- Bar graphs like battery charge level indicator or progress bar
The driver has been tested with Zephyr RTOS v 3.1.99 with the observation of future changes of v3.2.
The driver requires I2C connection between the IC and the host CPU.
In order to use the driver, the folders dts and lcd shall be included in your project. The lcd folder is a Zephyr module.
The application.overlay shall be tailored to your project's requirement and referred to in the CMakeLists.txt or its content to be included in your project's hardware definition.
The lcd.overlay contains the definition of the LCD display itself. Details about the configuration of LCD in the next chapter.
The above changes can be sumarized by the two lines in the CMakelists.txt file of the project:
list(APPEND ZEPHYR_EXTRA_MODULES ${CMAKE_CURRENT_SOURCE_DIR}/lcd)
set(DTC_OVERLAY_FILE "application.overlay lcd.overlay")
The driver's basic operation can be configured via Kconfig. This includes options to enable/disable the driver. The option can be accessed via Modules-->lcd-->LCD drivers
The definition of an LCD display is done via the file lcd.overlay. An example configuration is attached that describes the LCD layout below:
Each new segment is defined individually with the term segment that is a tuple of two integers: The first is the Backplane Output index and the second one is the Segment index. One arbitrary segment definition would look like:
seg_1a: s1 { segment = <3 1>; };
Where
- seg_1a is the unique label of the given segment, in this case the A segment of the first digit of a 7 segment number.
- s1 is an internal unique segment identifier
- segment = <3 1> assigns this segment to BP3 and S1 pins of PCF8576.
Sign symbols are LCD segments that van be turned on or off individually, These are typically small pictograms on the LCD. These are defined under the "lcd-sign" compatibility class with the sign keyword that refers to a segment definition, that we have provided for each segment in the previous chapter. An example sign definition would look like:
sign_defs: sig { compatible = "lcd-sign";
sign_OK: sig1 { sign = <&seg_t1>;};
};
Where
- sign_OK is the unique label of the sign that we can use later in the application
- sig1 is an internal unique ID of the sign
- sign = <&seg_t1> defines a single segment symbol that links to the seg_t1 segment
Bar graph symbols are a set of segments that typically indicates a proportional value. This could be for example a battery percentage indicator or a value level indicator on the display. The bar graphs are defined under the "lcd-bar" compatibility class with a set of segments each with the bar keyword. Each segment of the bar graph refers back to the segment definition on the top of the lcd overlay file.
An example battery level bar graph definition would look like:
bar_battery: barbat { compatible = "lcd-bar";
b1 { bar = <&seg_w1>;};
b2 { bar = <&seg_w5>;};
b3 { bar = <&seg_w4>;};
b4 { bar = <&seg_w3>;};
b5 { bar = <&seg_w2>;};
};
It is possible to define individual 7-segment number digits with optional decimal point, that can be referred from the application as a single digit number. Note that the current DTS supports only 7 segment numbers, so segmented alphanumeric symbols are not available at the moment.
The digits are defined under the lcd-digit compatibility class, with each number consisting of a list of 8 segment references with the digit keyword.
An example digit definition would look like:
digit1: d1 { compatible = "lcd-digit";
digit = <&seg_1a &seg_1b &seg_1c &seg_1d &seg_1e &seg_1f &seg_1g &seg_1dp>;};
It is possible to define numbers that are longer than a single digit. The application can refer to these numbers with their symbolic name and the high level API can write numbers directly. The numbers are defined under the lcd-number compatibility class with the number
An example multi-digit number would look like:
num_4digs: num1 { compatible = "lcd-number";
n1 {number = <&digit1>;};
n2 {number = <&digit2>;};
n3 {number = <&digit3>;};
n4 {number = <&digit4>;};
};
An example application is available in the file main.c that may help to identify the API an initialization.
The device struct can be acquired via the DEVICE_DT_GET api. Example:
const struct device *dev = DEVICE_DT_GET(DT_NODELABEL(lcd_drv));
where lcd_drv is the name of the device in the application overlay file under the I2C peripheral definition part.
Complex multi-segment symbols shall be declared and defined in the application in order to get the required RAM buffers allocated and init state set.
This shall be done via the pair of pcf8576_bar_declare(label) and pcf8576_bar_define(_label) macros, where label is the bar symbol name.
This shall be done via the pair of pcf8576_num_declare(label) and pcf8576_num_define(_label) macros, where label is the number symbol name.
The pcf8576_flush() API call would perform a burst write from the RAM mirror of the driver to the internal RAM of the PCF8576 device. This is needed to refresh the LCD content after it has been changed by APIs that have manipulated the segment values.
The pcf8576_num API call can convert the floating point value parameter to the format matching the 7-segment number definition and set the symbol identified by the label to this value.
The pcf8576_bar API call can set the value number of segments of a bar graph to ON, and the rest to OFF.
The pcf8576_sign API call can set the sign referred with the label to ON, if value is true and OFF if value is false.
There is a demo application included in src folder. It is tailored to a given LCD layout that is depicted above. It implements an up and a down counter display, that are accessed via their symbolic name num_large and num_small_ respectively.
The video below shows the expected operation of the LCD: