User Tools

Site Tools

한국어

comfilepi:controlling_the_lcd_backlight:index

Controlling the LCD Backlight

The ComfilePi's LCD backlight is connected to one of the panel PC's internal GPIO pins. The backlight can be turned on or off via the command line or via a programming language.

Command Line Interface

CPi-A/B/F/S

To turn off the backlight:

# using Bullseye
raspi-gpio set 34 op
raspi-gpio set 34 dl
 
# using Buster or prior OSes
gpio mode 34 output
gpio write 34 0

To turn on the backlight:

# using Bullseye
raspi-gpio set 34 op
raspi-gpio set 34 dh

# using Buster or prior OSes
gpio mode 34 output
gpio write 34 1

CPi-C

To turn off the backlight:

# using Bullseye
raspi-gpio set 44 op
raspi-gpio set 44 dl
 
# using Buster or prior OSes
gpio mode 44 output
gpio write 44 0

To turn on the backlight:

# using Bullseye
raspi-gpio set 44 op
raspi-gpio set 44 dh

# using Buster or prior OSes
gpio mode 44 output
gpio write 44 1

Sample C Program

The backlight can be controlled in the C programming language using the pigpio library.

#include <pigpiod_if2.h>
 
#define PIN 34  // CPi-A/B/F/S
// #define PIN 44  // CPi-C
 
void backlight_on()
{
    auto instance = pigpio_start(NULL, NULL);
 
    set_mode(instance, PIN, PI_OUTPUT);
    gpio_write(instance, PIN, 1);
 
    pigpio_stop(instance);
}
 
void backlight_off()
{
    auto instance = pigpio_start(NULL, NULL);
 
    set_mode(instance, PIN, PI_OUTPUT);
    gpio_write(instance, PIN, 0);
 
    pigpio_stop(instance);
}

Synchronizing the Backlight with the X11 Screensaver

This program will turn the backlight ON or OFF according to the ON/OFF state of the display as reported by DPMS (run xset q from a terminal to see the DPMS report).

#include <cstdlib>
#include <cstdio>
#include <X11/Xlib.h>
#include <X11/extensions/dpms.h>
#include <chrono>
#include <thread>
#include <sys/syslog.h>
#include <pigpiod_if2.h>
 
using namespace std;
using namespace std::chrono;
 
#define PIN 34  // CPi-A/B/F/S
// #define PIN 44 // CPi-C
 
void log_info(const char *const message)
{
    printf("%s\n", message);
    syslog(LOG_INFO, "%s", message);
}
 
void log_err(const char *const message)
{
    printf("%s\n", message);
    syslog(LOG_ERR, "%s", message);
}
 
void backlight_on()
{
    auto instance = pigpio_start(NULL, NULL);
    if (instance != 0)
    {
        log_err("pigpio_start did not return success");
        return;
    }
 
    auto result = set_mode(instance, PIN, PI_OUTPUT);
    if (instance != 0)
    {
        log_err("set_mode did not return success");
        return;
    }
 
    result = gpio_write(instance, PIN, 1);
    if (instance != 0)
    {
        log_err("gpio_write did not return success");
        return;
    }
 
    pigpio_stop(instance);
}
 
void backlight_off()
{
    auto instance = pigpio_start(NULL, NULL);
    if (instance != 0)
    {
        log_err("pigpio_start did not return success");
        return;
    }
 
    auto result = set_mode(instance, PIN, PI_OUTPUT);
    if (instance != 0)
    {
        log_err("set_mode did not return success");
        return;
    }
 
    result = gpio_write(instance, PIN, 0);
    if (instance != 0)
    {
        log_err("gpio_write did not return success");
        return;
    }
 
    pigpio_stop(instance);
}
 
void set_backlight(CARD16 state)
{
    switch (state)
    {
        case DPMSModeOn:
            log_info("Turning backlight on");
            backlight_on();
            break;
        case DPMSModeOff:
            log_info("Turning backlight off");
            backlight_off();
            break;
        default:
            log_info("Invalid state");
            break;
    }
}
 
int main(int argc, char *argv[])
{
    openlog("backlight_service", LOG_NDELAY, LOG_USER);
 
    log_info("Starting");
 
    Display *dpy;
    dpy = XOpenDisplay(NULL);
    if (dpy == NULL)
    {
        log_err("Unable to open display");
        exit(EXIT_FAILURE);
    }
 
    BOOL onoff;
    CARD16 last_state;
    CARD16 state;
 
    // Initialize last_state
    if (!DPMSInfo(dpy, &state, &onoff))
    {
        log_err("DPMSInfo returned FALSE");
    }
    set_backlight(state);
    last_state = state;
 
    while(true)
    {
        if (!DPMSInfo(dpy, &state, &onoff))
        {
            log_err("DPMSInfo returned FALSE");
            this_thread::sleep_for(seconds(2));
            continue;
        }
 
        // If DPMS is not enabled, then display a message
        if (!onoff)
        {
            log_err("DPMSInfo is not enabled");
            this_thread::sleep_for(seconds(2));
            continue;
        }
 
        if (last_state != state)
        {
            set_backlight(state);
 
            last_state = state;
        }
        this_thread::sleep_for(milliseconds(200));
    }
 
    XCloseDisplay(dpy);
 
    log_info("Exiting");
 
    return 0;
}

Compile

Add the necessary development packages …

sudo apt install libx11-dev libxext-dev

… then compile.

g++ backlight_service.cpp -lX11 -lXext -lpigpiod_if2 -o backlight_service

Bash Script Implementation

The same can be a achieved using the following Bash script:

#!/bin/bash
 
PWM_PIN=31
PIN=34
 
# Set pins as output
raspi-gpio set $PWM_PIN op
raspi-gpio set $PIN op
 
# Start with both pins HIGH.  If either of the
# pins go LOW, the backlight will turn off.
raspi-gpio set $PWM_PIN dh
raspi-gpio set $PIN dh
 
# Get the current state
CURRENT_STATUS=$(xset q | grep "Monitor is" | awk '{print $3}')
LAST_STATUS=$CURRENT_STATUS
 
logger -p info -t "backlight_service" -s "Monitor is $CURRENT_STATUS"
 
# Loop indefinitely updating backlight in sync with monitor status
while true; do
 
  # Check the current monitor status
  CURRENT_STATUS=$(xset q | grep "Monitor is" | awk '{print $3}')
 
  # Only turn the backlight on/off if the Monitor state has changed
  if [ "$CURRENT_STATUS" != "$LAST_STATUS" ]; then
    logger -p info -t "backlight_service" -s "Monitor is $CURRENT_STATUS"
 
    # Control backlight pin according to the monitor status
    if [ "$CURRENT_STATUS" = "On" ]; then
      logger -p info -t "backlight_service" -s "Turning Backlight On"
      raspi-gpio set $PIN dh
    else
      logger -p info -t "backlight_service" -s "Turning Backlight Off"
      raspi-gpio set $PIN dl
    fi
    LAST_STATUS=$CURRENT_STATUS
  fi
 
  # Sleep before checking again
  sleep 0.2s
done

Automatically Start the Service

Add the line @{/path/to/}backlight_service to the /etc/xdg/lxsession/LXDE-pi/autostart file or to the file .config/lxsession/LXDE-pi/autostart in the user's home directory to automatically start the backlight_service executable when the desktop starts. See Configure an X Program to Auto-Start for more information.

To set the timeout to 60 seconds run xset dpms 0 0 60 from a terminal.

Add the line @xset dpms 0 0 {timeout_in_seconds} to the autostart file to set the timeout each time the desktop loads.

Run journalctl -t backlight_service -r to view the log entries.

Screensaver Functionality In Non-X Programs

To put the backlight on a timer that turns OFF after a specified timeout, and turns back ON when the screen is touched, the following program can be used.

#include <cstdio>
#include <cstdint>
#include <fstream>
#include <unistd.h>
#include <errno.h>
#include <getopt.h>
#include <sys/file.h>
#include <linux/input.h>
#include <chrono>
#include <thread>
 
#include <pigpiod_if2.h>
 
using namespace std;
using namespace std::chrono;
 
static int instance = -1;
 
#define PIN 34  // CPi-A & CPi-B
// #define PIN 44  // CPi-C
 
void backlight_on()
{
    auto instance = pigpio_start(NULL, NULL);
 
    set_mode(instance, PIN, PI_OUTPUT);
    gpio_write(instance, PIN, 1);
 
    pigpio_stop(instance);
}
 
void backlight_off()
{
    auto instance = pigpio_start(NULL, NULL);
 
    set_mode(instance, PIN, PI_OUTPUT);
    gpio_write(instance, PIN, 0);
 
    pigpio_stop(instance);
}
 
bool backlight_isOn()
{
    auto instance = pigpio_start(NULL, NULL);
 
    set_mode(instance, PIN, PI_INPUT);
    auto isOn = gpio_read(instance, PIN) == 1;
 
    pigpio_stop(instance);
 
    return isOn;
}
 
int main(int argc, char* argv[])
{
    int secs = 60;
 
    if (argc >= 2)
    {
        secs = stoi(argv[1]);
    }
 
    // Touch events happen on event0
    auto input_fd = open("/dev/input/event0", O_RDONLY | O_NONBLOCK);
 
    struct input_event ev;
    auto lastTouch = high_resolution_clock::now();
    while (true)
    {
        // get the input event
        auto n = read(input_fd, &ev, sizeof(ev));
 
        // If an input event
        if (n != (ssize_t)-1)
        {
            if (ev.type == EV_KEY && ev.value >= 0 && ev.value <= 2)
            {
                if (ev.value == 1)  // If a touch
                {
                    backlight_on();
                    lastTouch = high_resolution_clock::now();
                }
            }
        }
 
        auto now = chrono::high_resolution_clock::now();
        auto sec = duration_cast<seconds>(now - lastTouch).count();
        if (sec > secs)
        {
            backlight_off();
        }
 
        this_thread::sleep_for(milliseconds(10));
    }
 
    return 0;
}

Compile

g++ main.cpp -lpigpiod_if2 -lpthread -o backlight

Run

To cause the backlight to turn OFF after 60 seconds.

backlight 60

Register as a Background Service

[Unit]
Description=backlight service
After=pigpio.service

[Service]
ExecStart={path/to/}backlight 60
Restart=always

[Install]
WantedBy=multi-user.target

Dimming the Backlight

Backlight dimming can be controlled using the PWM on GPIO31 on the CPi-A & CPi-B or GPIO26 on the CPi-C. Use the pigpio library to adjust the brightness of the backlight.

#include <pigpiod_if2.h>
#include <iostream>
#include <string>
 
using namespace std;
 
#define PIN 31  // CPi-A/B/F/S
// #define PIN 26  // CPi-C
 
int main(int argc, char *argv[])
{
   int value = stoi(argv[1]);
 
   auto instance = pigpio_start(NULL, NULL);
 
   set_mode(instance, PIN, PI_OUTPUT);
 
   set_PWM_frequency(instance, PIN, 200);
 
   set_PWM_dutycycle(instance, PIN, value);
 
   pigpio_stop(instance);
}

Compile and run:

g++ backlight.cpp -lpigpiod_if2 -lpthread -o backlight

./backlight 0    # minimum brightness
./backlight 128  # medium brightness
./backlight 255  # maximum brightness

Hardware Revisions

v2.0+

CPi_A070WR (S/N : A01001-17-7-11 ~ A01001-17-11-91)

CPi_A102WR (S/N : A01003-17-7-1 ~ A01003-17-10-26)

The initial ComfilePi that was produced did not populate R33 on the main board's PCB. On those models, switching the LCD backlight on or off will not work unless R33 is populated. Hardware revision v2.0 populates R33 with a 22 Ohm resistor, so switching the backlight on or off will work out of the box.

To test which hardware revision you have, simply run the commands illustrated above and see if they work.

v2.1+ (Refer to hardware version printed on sticker)

Hardware revision v2.1 connects the backlight to GPIO 31 which supports PWM. See Dimming the Backlight.

ComfilePi - Industrial Raspberry Pi Panel PC

comfilepi/controlling_the_lcd_backlight/index.txt · Last modified: 2023/12/06 10:00 by COMFILE Technology