Control your monitor settings via software on your Raspberry Pi 4

I often get the question how to control the display of your Raspberry Pi 4 through software.

When you tightly integrate your bare computer display into a nicely built picture frame you sometimes can’t access the monitor controls easily. Or you may want to have some brightness automation running which dims your screen in the evening.

Now that ddcutil has been brought to the Raspberry Pi 4 with the firmware 5.10 supporting HDMI I2C, that is possible.

Introduction to ddcutil

ddcutil is a Linux program for managing monitor settings, such as brightness, color levels, and input source. Generally speaking, any setting that can be changed by pressing buttons on the monitor can be modified by ddcutil.

ddcutil primarily uses DDC/CI (Display Data Channel Command Interface) to communicate with monitors implementing MCCS (Monitor Control Command Set) over I2C. Normally, the video driver for the monitor exposes the I2C channel as devices named /dev/i2c-n.”

I haven’t found that claim to be 100% true, but I was happy to discover that “almost” all hardware controls can now be soft-controlled. Given the number of monitor models in the market, lacking a universal standard, this is no wonder.

There are a few restrictions like that ddcutil does not support laptop displays, which are controlled using a special API, not I2C. So if you just butchered your old laptop display, ddcutil won’t work. But for most of us with a standard computer monitor, it should be fine.

In the following, I will describe how it worked using a BenQ PD3200U monitor, a 32-inches 4K resolution display that I used for my latest digital picture frame project.

Installing ddcutil on a Raspberry Pi 4

If you haven’t updated your system for a while, first run

sudo apt update && sudo apt upgrade -y

Then install ddcutil by typing

sudo apt install ddcutil

The last step is to make a change to your Pi configuration file. It assumes that you have selected “6 Advanced Options > A2 GL Driver > Choose G2 GL Fake KMS” in the sudo raspi-config settings.

Enter

sudo nano /boot/config.txt

and scroll down to the bottom section commencing with “pi4”.

Remove the “f” of “fkms” in both “pi4” and “all” like this:

[pi4]
# Enable DRM VC4 V3D driver on top of the dispmanx display stack
dtoverlay=vc4-kms-v3d
max_framebuffers=2

[all]
dtoverlay=vc4-kms-v3d gpu_mem=256

Reboot with sudo reboot.

Detecting your monitor

Once you have done all of the above, let’s test if your monitor is supported by ddcutil.

Type

ddcutil detect

If you get something like this, all is well.

Display 1
   I2C bus:             /dev/i2c-11
   EDID synopsis:
      Mfg id:           BNQ
      Model:            BenQ PD3200U
      Serial number:    FAL05444019
      Manufacture year: 2020
      EDID version:     1.3
   VCP version:         2.2

If you now enter

ddcutil capabilities

You will be able to see all the features that are being supported in detail.

In my case, with the BenQ PD3200U, this is what I get:

ddcutil capabilities
MCCS version: 2.2
Commands:
   Command: 01 (VCP Request)
   Command: 02 (VCP Response)
   Command: 03 (VCP Set)
   Command: 07 (Timing Request)
   Command: 0c (Save Settings)
   Command: e3 (Capabilities Reply)
   Command: f3 (Capabilities Request)
VCP Features:
   Feature: 02 (New control value)
   Feature: 04 (Restore factory defaults)
   Feature: 08 (Restore color defaults)
   Feature: 10 (Brightness)
   Feature: 12 (Contrast)
   Feature: 14 (Select color preset)
      Values:
         04: 5000 K
         05: 6500 K
         08: 9300 K
         0b: User 1
   Feature: 16 (Video gain: Red)
   Feature: 18 (Video gain: Green)
   Feature: 1A (Video gain: Blue)
   Feature: 60 (Input Source)
      Values:
         0f: DisplayPort-1
         10: DisplayPort-2
         11: HDMI-1
         12: HDMI-2
   Feature: 62 (Audio speaker volume)
   Feature: 72 (Gamma)
      Values: 50 64 78 8c a0 (interpretation unavailable)
   Feature: 7D (unrecognized feature)
      Values: 00 01 02 (interpretation unavailable)
   Feature: 7E (Trapezoid)
      Values: 0f 10 11 12 (interpretation unavailable)
   Feature: 7F (unrecognized feature)
   Feature: 80 (Keystone)
      Values: 00 01 02 (interpretation unavailable)
   Feature: 86 (Display Scaling)
      Values:
         01: No scaling
         02: Max image, no aspect ration distortion
         05: Max vertical image with aspect ratio distortion
         0c: Unrecognized value
         10: Unrecognized value
         11: Unrecognized value
         13: Unrecognized value
         14: Unrecognized value
         15: Unrecognized value
         16: Unrecognized value
         17: Unrecognized value
   Feature: 87 (Sharpness)
   Feature: 8D (Audio mute/Screen blank)
      Values: 01 02 (interpretation unavailable)
   Feature: 8A (Color Saturation)
   Feature: 90 (Hue)
   Feature: AA (Screen Orientation)
      Values:
         01: 0 degrees
         02: 90 degrees
   Feature: B6 (Display technology type)
   Feature: C6 (Application enable key)
   Feature: C8 (Display controller type)
   Feature: C9 (Display firmware level)
   Feature: CA (OSD/Button Control)
   Feature: CC (OSD Language)
      Values:
         01: Chinese (traditional, Hantai)
         02: English
         03: French
         04: German
         05: Italian
         06: Japanese
         07: Korean
         09: Russian
         0a: Spanish
         0b: Swedish
         0d: Chinese (simplified / Kantai)
         0e: Portuguese (Brazil)
         0f: Arabic
         12: Czech
         14: Dutch
         1a: Hungarian
         1e: Polish
         1f: Romanian 
   Feature: DA (Scan mode)
      Values:
         00: Normal operation
         02: Overscan
   Feature: DC (Display Mode)
      Values:
         00: Standard/Default mode
         0a: Demonstration
         0c: Unrecognized value
         10: Unrecognized value
         12: Unrecognized value
         13: Unrecognized value
         14: Unrecognized value
         20: Unrecognized value
   Feature: DF (VCP Version)
   Feature: E2 (manufacturer specific feature)
      Values: 00 01 (interpretation unavailable)
   Feature: E3 (manufacturer specific feature)
      Values: 00 01 (interpretation unavailable)
   Feature: E7 (manufacturer specific feature)
      Values: 00 01 (interpretation unavailable)
   Feature: E8 (manufacturer specific feature)
      Values: 00 01 (interpretation unavailable)
   Feature: E9 (manufacturer specific feature)
      Values: 00 01 02 03 (interpretation unavailable)
   Feature: EA (manufacturer specific feature)
      Values: 00 01 02 03 04 05 (interpretation unavailable)
   Feature: EE (manufacturer specific feature)
      Values: 00 01 02 (interpretation unavailable)
   Feature: EF (manufacturer specific feature)
      Values: 00 01 (interpretation unavailable)
   Feature: F0 (manufacturer specific feature)
      Values: 00 01 02 (interpretation unavailable)
   Feature: F1 (manufacturer specific feature)
      Values: 00 01 (interpretation unavailable)
   Feature: F2 (manufacturer specific feature)
      Values: 14 28 3c 50 64 (interpretation unavailable)
   Feature: F4 (manufacturer specific feature)
      Values: 00 01 ff (interpretation unavailable)
   Feature: F5 (manufacturer specific feature)
      Values: 00 01 (interpretation unavailable)
   Feature: F6 (manufacturer specific feature)
      Values: 00 01 (interpretation unavailable)
   Feature: F7 (manufacturer specific feature)
      Values: 00 01 (interpretation unavailable)
   Feature: F8 (manufacturer specific feature)
      Values: 00 0a 14 1e (interpretation unavailable)
   Feature: F9 (manufacturer specific feature)

How to read and set screen parameters

Reading the current value of a particular parameter is very simple. The basic command is:

getvcp feature-code-or-group

So to get you current brightness level, you would look up the feature number in your capabilities list, e.g.

Feature: 10 (Brightness)

and enter

ddcutil getvcp 10

This will result in

VCP code 0x10 (Brightness                    ): current value =    75, max value =   100

To reduce brightness to 50% type:

ddcutil setvcp 10 50

Another example, reduce the contrast setting to 50%:

ddcutil setvcp 12 50

My suggestion is to read all the features that you may want to read and control via ddcutil with ddcutil getvcp and see if you can change them.

Recommended settings for the digital picture frame

Quite a few people seem to be using the BenQ PD3200U as a screen for their 4K 32-inches frame judging by the user gallery and the emails I receive.

Reader Daniel sent me his favorite settings for this digital picture frame which I have adopted for my frame as well which I find useful to share:

sRGB color mode
Saturation 45%
Contrast 50%
Brightness automatically controlled between 10% and 40%.

Conclusion

Soft controlling your digital picture frame screen is a very useful feature especially when you want to manually or automatically control the brightness.

Now you can do it on a Raspberry Pi4 and the installation is a breeze!

Was this article helpful?


Thank you for your support and motivation.


Scroll to Top