planet-community / planet-devices

Repository for Planet Computers devices. Use this for feature requests, bugs, and *constructive* feedback.
Creative Commons Zero v1.0 Universal
19 stars 1 forks source link

Can't avoid PWM screen flickering #52

Open ZimbiX opened 1 year ago

ZimbiX commented 1 year ago

Problem

The AMOLED screen on the Astro Slide uses PWM to control brightness. If you don't know about PWM, here's an excellent slow-mo demo and a technical explanation.

I am one of those people highly sensitive to flicker. As I'd feared since Planet Computers announced their screen selection of an AMOLED screen (Indigogo update 9), I do see the Astro's screen constantly flickering during saccades (moving my eyes across the screen); and this makes the device extremely irritating to use. For this reason, I have avoided OLED/AMOLED screens like the plague. IPS LCD screens do not typically have this issue.

Additionally, the screen appears to have a PenTile-like subpixel matrix. This makes the image appear spotty, kind of like a colour photo printed in a newspaper. I guess my eyes must be better / more sensitive than most people's. Unfortunately, I don't have a good enough camera to capture a closeup photo of the screen to show exactly what it looks like, but this is a good PenTile closeup (notice how the straight edges of the text look frayed). It is particularly noticeable in the tiny boot warning text that appears since unlocking the bootloader. Update: I found some closeups of the Astro screen recently posted on OESF - it's not PenTile exactly, but some other non-RGB-stripe subpixel layout I can't find the name of.

Solution investigation

Frustratingly now owning a device with a PWM screen, I've been trying to figure out if there is a way to make it usable. I'll just have to get used to tolerating the ugly subpixel matrix, but hopefully there's something that can be done about the PWM.

It sounds like many other phones with AMOLED screens turn off PWM (or effectively do that) when the screen is set to high brightness. This is not the case on the Astro - the flickering is noticeable to me at all brightness levels.

I suspect that the Astro's maximum brightness is an artificial limit, and that there is a way to increase it to the point of avoiding any off time in the PWM duty cycle. Or a way to disable PWM entirely.

I've fiddled around in a root shell a bit, trying to find a file that controls brightness or PWM, and haven't had much luck as yet.

Astro:/ # find . 2>/dev/null | grep backlight | sort                                                                                     
./proc/mtkcooler/mtk-cl-backlight01
./proc/mtkcooler/mtk-cl-backlight02
./proc/mtkcooler/mtk-cl-backlight03
./sys/class/backlight
./sys/class/leds/lcd-backlight
./sys/devices/platform/disp_leds/leds/lcd-backlight
./sys/devices/platform/disp_leds/leds/lcd-backlight/brightness
./sys/devices/platform/disp_leds/leds/lcd-backlight/device
./sys/devices/platform/disp_leds/leds/lcd-backlight/max_brightness
./sys/devices/platform/disp_leds/leds/lcd-backlight/power
./sys/devices/platform/disp_leds/leds/lcd-backlight/power/autosuspend_delay_ms
./sys/devices/platform/disp_leds/leds/lcd-backlight/power/control
./sys/devices/platform/disp_leds/leds/lcd-backlight/power/runtime_active_time
./sys/devices/platform/disp_leds/leds/lcd-backlight/power/runtime_status
./sys/devices/platform/disp_leds/leds/lcd-backlight/power/runtime_suspended_time
./sys/devices/platform/disp_leds/leds/lcd-backlight/subsystem
./sys/devices/platform/disp_leds/leds/lcd-backlight/trigger
./sys/devices/platform/disp_leds/leds/lcd-backlight/uevent
./sys/firmware/devicetree/base/disp_leds/backlight
./sys/firmware/devicetree/base/disp_leds/backlight/default-state
./sys/firmware/devicetree/base/disp_leds/backlight/label
./sys/firmware/devicetree/base/disp_leds/backlight/led-bits
./sys/firmware/devicetree/base/disp_leds/backlight/max-brightness
./sys/firmware/devicetree/base/disp_leds/backlight/name
./sys/firmware/devicetree/base/pwmleds/backlight
./sys/firmware/devicetree/base/pwmleds/backlight/label
./sys/firmware/devicetree/base/pwmleds/backlight/max-brightness
./sys/firmware/devicetree/base/pwmleds/backlight/name
./sys/firmware/devicetree/base/pwmleds/backlight/pwm-names
./sys/firmware/devicetree/base/pwmleds/backlight/pwms

Astro:/ # find . 2>/dev/null | grep pwm | sort
./dev/stpwmt
./proc/irq/260/mt-pwm
./sys/bus/platform/devices/10048000.pwm
./sys/bus/platform/devices/1100e000.disp_pwm0
./sys/bus/platform/devices/irtx_pwm
./sys/bus/platform/devices/pwmleds
./sys/bus/platform/drivers/mediatek-disp-pwm
./sys/bus/platform/drivers/mediatek-disp-pwm/1100e000.disp_pwm0
./sys/bus/platform/drivers/mediatek-disp-pwm/bind
./sys/bus/platform/drivers/mediatek-disp-pwm/uevent
./sys/bus/platform/drivers/mediatek-disp-pwm/unbind
./sys/bus/platform/drivers/mt-pwm
./sys/bus/platform/drivers/mt-pwm/10048000.pwm
./sys/bus/platform/drivers/mt-pwm/bind
./sys/bus/platform/drivers/mt-pwm/uevent
./sys/bus/platform/drivers/mt-pwm/unbind
./sys/class/pwm
./sys/class/pwm/pwmchip0
./sys/class/stpwmt
./sys/class/stpwmt/stpwmt
./sys/devices/platform/10048000.pwm
./sys/devices/platform/10048000.pwm/driver
./sys/devices/platform/10048000.pwm/driver_override
./sys/devices/platform/10048000.pwm/modalias
./sys/devices/platform/10048000.pwm/of_node
./sys/devices/platform/10048000.pwm/power
./sys/devices/platform/10048000.pwm/power/autosuspend_delay_ms
./sys/devices/platform/10048000.pwm/power/control
./sys/devices/platform/10048000.pwm/power/runtime_active_time
./sys/devices/platform/10048000.pwm/power/runtime_status
./sys/devices/platform/10048000.pwm/power/runtime_suspended_time
./sys/devices/platform/10048000.pwm/pwm_debug
./sys/devices/platform/10048000.pwm/subsystem
./sys/devices/platform/10048000.pwm/uevent
./sys/devices/platform/1100e000.disp_pwm0
./sys/devices/platform/1100e000.disp_pwm0/driver
./sys/devices/platform/1100e000.disp_pwm0/driver_override
./sys/devices/platform/1100e000.disp_pwm0/modalias
./sys/devices/platform/1100e000.disp_pwm0/of_node
./sys/devices/platform/1100e000.disp_pwm0/power
./sys/devices/platform/1100e000.disp_pwm0/power/autosuspend_delay_ms
./sys/devices/platform/1100e000.disp_pwm0/power/control
./sys/devices/platform/1100e000.disp_pwm0/power/runtime_active_time
./sys/devices/platform/1100e000.disp_pwm0/power/runtime_status
./sys/devices/platform/1100e000.disp_pwm0/power/runtime_suspended_time
./sys/devices/platform/1100e000.disp_pwm0/pwm
./sys/devices/platform/1100e000.disp_pwm0/pwm/pwmchip0
./sys/devices/platform/1100e000.disp_pwm0/pwm/pwmchip0/device
./sys/devices/platform/1100e000.disp_pwm0/pwm/pwmchip0/export
./sys/devices/platform/1100e000.disp_pwm0/pwm/pwmchip0/npwm
./sys/devices/platform/1100e000.disp_pwm0/pwm/pwmchip0/power
./sys/devices/platform/1100e000.disp_pwm0/pwm/pwmchip0/power/autosuspend_delay_ms
./sys/devices/platform/1100e000.disp_pwm0/pwm/pwmchip0/power/control
./sys/devices/platform/1100e000.disp_pwm0/pwm/pwmchip0/power/runtime_active_time
./sys/devices/platform/1100e000.disp_pwm0/pwm/pwmchip0/power/runtime_status
./sys/devices/platform/1100e000.disp_pwm0/pwm/pwmchip0/power/runtime_suspended_time
./sys/devices/platform/1100e000.disp_pwm0/pwm/pwmchip0/subsystem
./sys/devices/platform/1100e000.disp_pwm0/pwm/pwmchip0/uevent
./sys/devices/platform/1100e000.disp_pwm0/pwm/pwmchip0/unexport
./sys/devices/platform/1100e000.disp_pwm0/subsystem
./sys/devices/platform/1100e000.disp_pwm0/uevent
./sys/devices/platform/irtx_pwm
./sys/devices/platform/irtx_pwm/driver_override
./sys/devices/platform/irtx_pwm/modalias
./sys/devices/platform/irtx_pwm/of_node
./sys/devices/platform/irtx_pwm/power
./sys/devices/platform/irtx_pwm/power/autosuspend_delay_ms
./sys/devices/platform/irtx_pwm/power/control
./sys/devices/platform/irtx_pwm/power/runtime_active_time
./sys/devices/platform/irtx_pwm/power/runtime_status
./sys/devices/platform/irtx_pwm/power/runtime_suspended_time
./sys/devices/platform/irtx_pwm/subsystem
./sys/devices/platform/irtx_pwm/uevent
./sys/devices/platform/pwmleds
./sys/devices/platform/pwmleds/driver_override
./sys/devices/platform/pwmleds/modalias
./sys/devices/platform/pwmleds/of_node
./sys/devices/platform/pwmleds/power
./sys/devices/platform/pwmleds/power/autosuspend_delay_ms
./sys/devices/platform/pwmleds/power/control
./sys/devices/platform/pwmleds/power/runtime_active_time
./sys/devices/platform/pwmleds/power/runtime_status
./sys/devices/platform/pwmleds/power/runtime_suspended_time
./sys/devices/platform/pwmleds/subsystem
./sys/devices/platform/pwmleds/uevent
./sys/devices/virtual/stpwmt
./sys/devices/virtual/stpwmt/stpwmt
./sys/devices/virtual/stpwmt/stpwmt/dev
./sys/devices/virtual/stpwmt/stpwmt/power
./sys/devices/virtual/stpwmt/stpwmt/power/autosuspend_delay_ms
./sys/devices/virtual/stpwmt/stpwmt/power/control
./sys/devices/virtual/stpwmt/stpwmt/power/runtime_active_time
./sys/devices/virtual/stpwmt/stpwmt/power/runtime_status
./sys/devices/virtual/stpwmt/stpwmt/power/runtime_suspended_time
./sys/devices/virtual/stpwmt/stpwmt/subsystem
./sys/devices/virtual/stpwmt/stpwmt/uevent
./sys/firmware/devicetree/base/__symbols__/aeon_keyboardlight_gpio_pwm
./sys/firmware/devicetree/base/__symbols__/disp_pwm
./sys/firmware/devicetree/base/__symbols__/irtx_pwm
./sys/firmware/devicetree/base/disp_pwm0@1100e000
./sys/firmware/devicetree/base/disp_pwm0@1100e000/#pwm-cells
./sys/firmware/devicetree/base/disp_pwm0@1100e000/clock-names
./sys/firmware/devicetree/base/disp_pwm0@1100e000/clocks
./sys/firmware/devicetree/base/disp_pwm0@1100e000/compatible
./sys/firmware/devicetree/base/disp_pwm0@1100e000/interrupts
./sys/firmware/devicetree/base/disp_pwm0@1100e000/name
./sys/firmware/devicetree/base/disp_pwm0@1100e000/phandle
./sys/firmware/devicetree/base/disp_pwm0@1100e000/reg
./sys/firmware/devicetree/base/irtx_pwm
./sys/firmware/devicetree/base/irtx_pwm/compatible
./sys/firmware/devicetree/base/irtx_pwm/name
./sys/firmware/devicetree/base/irtx_pwm/phandle
./sys/firmware/devicetree/base/irtx_pwm/pinctrl-0
./sys/firmware/devicetree/base/irtx_pwm/pinctrl-1
./sys/firmware/devicetree/base/irtx_pwm/pinctrl-names
./sys/firmware/devicetree/base/irtx_pwm/pwm_ch
./sys/firmware/devicetree/base/irtx_pwm/pwm_data_invert
./sys/firmware/devicetree/base/irtx_pwm/status
./sys/firmware/devicetree/base/odm/led@0/pwm_config
./sys/firmware/devicetree/base/odm/led@1/pwm_config
./sys/firmware/devicetree/base/odm/led@2/pwm_config
./sys/firmware/devicetree/base/odm/led@3/pwm_config
./sys/firmware/devicetree/base/odm/led@4/pwm_config
./sys/firmware/devicetree/base/odm/led@5/pwm_config
./sys/firmware/devicetree/base/odm/led@6/pwm_config
./sys/firmware/devicetree/base/pwm@10048000
./sys/firmware/devicetree/base/pwm@10048000/clock-names
./sys/firmware/devicetree/base/pwm@10048000/clocks
./sys/firmware/devicetree/base/pwm@10048000/compatible
./sys/firmware/devicetree/base/pwm@10048000/interrupts
./sys/firmware/devicetree/base/pwm@10048000/name
./sys/firmware/devicetree/base/pwm@10048000/reg
./sys/firmware/devicetree/base/pwmleds
./sys/firmware/devicetree/base/pwmleds/backlight
./sys/firmware/devicetree/base/pwmleds/backlight/label
./sys/firmware/devicetree/base/pwmleds/backlight/max-brightness
./sys/firmware/devicetree/base/pwmleds/backlight/name
./sys/firmware/devicetree/base/pwmleds/backlight/pwm-names
./sys/firmware/devicetree/base/pwmleds/backlight/pwms
./sys/firmware/devicetree/base/pwmleds/compatible
./sys/firmware/devicetree/base/pwmleds/name
./sys/module/pwm_mtk_disp
./sys/module/pwm_mtk_disp/parameters
./sys/module/pwm_mtk_disp/parameters/disp_pwm_case
./sys/module/pwm_mtk_disp/uevent

I can change the brightness with:

Astro:/ # echo 255 > /sys/devices/platform/disp_leds/leds/lcd-backlight/brightness

but it's capped to 255 (same as maxing out the brightness slider), and the adjacent max_brightness file cannot be changed.

I've found mention of some PWM control files for another screen; but I'm guessing this is specific to that chipset / display driver, as the Astro does not have the same/similar paths.

There are mentions of PWM backlight in the Astro kernel source code, e.g. here (the kernel is also forked here). I'm an experienced software developer, but haven't done any kernel compiling/development before, and only did a small amount of C back at uni.

At the moment, I'm trying to figure out how to compile the kernel - thankfully, I found some scripts for that, but had to make some modifications to get it to work. We should really add documentation somewhere for the process of compiling the kernel.

Any pointers greatly appreciated. Although perhaps this is not the best place to discuss the finer points of kernel compilation, I'd prefer to do so somewhere indexable by Google, and Discord is not. Maybe on OESF would be better..

Device: Astro Slide Android build number: Astro-11.0-Planet-05182022-V01 Custom build number: alps-mp-r0.mp1-V8.132_haocheng.r0mp1.k61v1.64.bsp_P20

shymega commented 1 year ago

OESF isn't much better IMO, it gets spammed easily, and the GH Discussions tab here is better. Personally, I prefer Discord or Matrix/IRC/Telegram, but use the Discussions tab on this repo for now. Can you make the PR for the scripts please, and perhaps you could make a PR for the wiki on compiling the Astro kernel?

ZimbiX commented 1 year ago

OESF isn't much better IMO, it gets spammed easily,

Interesting, I haven't noticed any spam. But I guess I wasn't subscribed to new threads by default.

Personally, I prefer Discord or Matrix/IRC/Telegram, but use the Discussions tab on this repo for now.

Hmm, the Discussions tab is an idea.. but I guess then we'd be splitting discussion into yet another place :sweat_smile: Maybe let's just Discord. Is the #dev channel on the Astro Slide server most appropriate?

Can you make the PR for the scripts please

Sure, I was planning on submitting one once I was sure I got it working (I haven't tried flashing the result yet). Feel free to cherry-pick though. I was also reworking it a bit to make reruns faster using Docker mounts, but that's probably a separate PR.

and perhaps you could make a PR for the wiki on compiling the Astro kernel?

Haha, a wiki page would be great, but I really don't feel qualified to do a writeup about that! I'm poking around in the dark here 😝 Given you wrote the scripts, and I take it are familiar with the process, could that be something you could throw together a draft of please?

steward-fu commented 1 year ago

I am happy someone has the sensitive eye as mine. The frame rate of screen on Astro Slide 5G seems very slow, just like a shit screen. I have compiled kernel source and then flashed into Astro Slide 5G. Even though adjust PWM setting value from dtbs but no luck after tested. https://steward-fu.github.io/website/phone.htm#astro

I know it is not easy to obtain the datasheet of OLED, so, what I can do is just trial-and-error for testing.

ZimbiX commented 1 year ago

@steward-fu Cheers. I like that you have a place to publish notes like that.

Let us know exactly what you tried/try so we can avoid duplicating effort =)

Do you have experience using other AMOLED screens?

steward-fu commented 1 year ago

Hello, I only tried the PWM setting as you mentioned before, which changed from 39385 to 100000: https://github.com/PCLineageOS-Ports/android_kernel_planet_mt6873/blob/main/arch/arm64/boot/dts/mediatek/mt6873.dts#L250

I have some experiences related to OLED but it is long time ago: https://steward-fu.github.io/website/handheld/a320/oled_s6e63d6.htm

In modern OLED, it seems combaine with backlight LED, not nature brightness. I don't have any datasheet related to OLED panel. So, I am trying to modify something under: drivers/misc/mediatek/leds/leds-mtk-pwm.c

If you have any suggestion, it is welcome to provide it to me. I can compile kernel and then testing :)

ZimbiX commented 1 year ago

I still haven't gotten around to trying out a compiled kernel, unfortunately.

However, I recently purchased a device for testing flicker - an Opple Light Master Pro, which I found via this review video, for AUD $57.49. I've just done a bunch of testing with it, and established that the Astro has a constant PWM frequency of 120 Hz with constant 100% modulation.


Here are the readings from a purely white screen at different brightness levels - set using the command above. The Chinese characters translate as 'time'.

Brightness 255

Brightness 128

Brightness 5


At some brightness levels (e.g. 5 above), the app misinterprets the readings as the wrong frequency, which is a bit odd. From the graphs, the spikes are clearly always every ~8 ms; 1000/120 = 8.333; so 120 Hz is the correct frequency.

It's strange that at 100% brightness (255), the duty cycle is so low still. It seems that the screen would be able to go significantly brighter if a 100% duty cycle were to be permitted.

The coloured chart is interesting. As it shows, the constant ~100% modulation depth (turning the light completely off between pulses) is a hugely significant factor in the risk of flicker sensitivity. To illustate this point: I had LED lightbulbs installed about a year ago. At the time, I was glad to find them flicker-free, but I actually recently discovered that they do actually have a bit of flicker, it's just that it's hard to notice. The readings show why - here's the readings from one bulb:

The AC frequency in Australia is 50Hz, and this would be being doubled to 100Hz in the process of full-wave rectification, converting AC to DC. Although the frequency is much lower than the Astro, the modulation depth of the bulb is relatively small, which significantly reduces the flicker sensitivity risk.


Here's readings of a few other things for comparison:

My LCD computer screen - Dell U2715H

Cosmo Communicator

Cosmo Communicator's CoDi

This one was difficult to measure, so might not be accurate. To make the screen produce enough light to register a reading, I had to use the camera function pointed at the lit ceiling, while covering the Opple and CoDi to prevent interference from the ambient light.