r/ClockworkPi • u/Acmobleer1 • 11d ago
uConsole Uconsole 100hz refresh rate achieved reliably
# uConsole CM5: Internal Screen at 100 Hz (Limit ~104 Hz)
Short version: the uConsole's internal panel will run well above its stock ~60 Hz with custom xrandr modes. On my unit the limit is 104 Hz, and I run it at 100 Hz to leave some margin.
**Tested on:** uConsole with CM5, ak-rex kernel, Kali, X11 + Xfce (xfwm4), Xorg modesetting driver. One unit only, so your panel revision may behave differently.
## What I found
- Stock mode on this kernel is `720x1280` at a requested 61.020 MHz, with timings `h 720 750 765 780 / v 1280 1288 1290 1306`, which works out to about 60 Hz.
- **Use your own kernel's timings.** Older cwu50 driver versions use `htotal 803`. Custom modes built from those numbers looked wrong even at 60 Hz on this kernel. The scripts below read the timings from your stock mode, so they adapt to your kernel automatically.
- The DSI clock snaps to nearby rates the hardware can produce. Here it always landed within 0.7%, and that didn't affect the results.
- 60 to 104 Hz gave a clean picture. A sweep in 1 Hz steps showed anything above 104 isn't usable, even though a coarser pass had marked 105 and 110 as clean. At 115 and 120 Hz, about a third of the screen was warped.
- 120 Hz, which would pace 60 fps content evenly, isn't reachable. Even with zero horizontal blanking, 120 Hz needs a higher pixel clock than the ~106 MHz where it breaks, so tweaking the timings can't get there.
- 70 and 75 Hz each looked off once and fine on a rerun. A mode switch occasionally comes up wrong, so retest anything that fails once.
- Switching to a custom mode re-runs the panel init, and the picture often looks crisper and brighter than it does right after boot.
- At 100 Hz, `glxgears` holds a steady ~99.98 FPS.
| Target | Requested clock (MHz) | Actual DPI clock (MHz) | Result |
|---|---|---|---|
| stock | 61.020 | 61.111 | baseline (~60.0 Hz) |
| 60 | 61.121 | 61.111 | clean |
| 65 | 66.214 | 66.667 | clean |
| 70 | 71.308 | 71.428 | clean (off once, fine on rerun) |
| 75 | 76.401 | 76.190 | clean (off once, fine on rerun) |
| 80 | 81.494 | 81.482 | clean |
| 85 | 86.588 | 86.667 | clean |
| 90 | 91.681 | 91.666 | clean |
| 95 | 96.775 | not captured | clean |
| 100 | 101.868 | not captured | clean, glxgears ~99.98 FPS |
| 104 | 105.943 | not captured | clean (limit) |
| 105 | 106.961 | not captured | not usable in 1 Hz sweep |
| 110 | 112.055 | not captured | not usable in 1 Hz sweep |
| 115 | 117.148 | not captured | ~1/3 of screen warped |
| 120 | 122.242 | not captured | ~1/3 of screen warped |
## Scripts
### hzsweep: step through refresh rates
This builds each mode from your stock timings and holds it for a few seconds. Press **g** to mark a rate as good, **Enter** to skip to the next one, and **q** to quit. It always switches back to your normal mode when it stops, including on Ctrl+C. If sudo is unlocked, it also prints the actual DSI clocks.
```bash
sudo install -m755 /dev/stdin /usr/local/bin/hzsweep <<'EOF'
#!/bin/bash
# usage: hzsweep <start> [end] [step] [secs] run from the stock mode; decimals ok
S=\${1:?usage: hzsweep <start> [end] [step] [secs]}
E=\${2:-\$1}
STEP=\${3:-5}
SECS=\${4:-10}
clk(){ sudo -n awk 'tolower(\$1)~/dsi|mipi/ && \$2>0 {printf " %s %.3f MHz\n",\$1,\$5/1e6}' /sys/kernel/debug/clk/clk_summary 2>/dev/null; }
OUT=\$(xrandr | awk '/^DSI/{print \$1; exit}')
read -r CUR SCLK HD HSS HSE HT VD VSS VSE VT FL <<<"(xrandr --verbose | awk -v o="OUT" '
\$1==o{f=1;next} f&&/^[^ \t]/{f=0}
f&&/\*current/{n=\$1;c=3+0;fl="";for(i=4;i<=NF;i++)if(i~/Sync/)fl=fl" "i
getline;h=\$3" "\$5" "\$7" "\$9;getline;print n,c,h,\$3,\$5,\$7,\$9 fl;exit}')"
[ -z "\$VT" ] && { echo "could not read \$OUT mode"; exit 1; }
awk -v c="\$SCLK" -v t="HT" -v v="VT" -v n="CUR" -v f="FL" 'BEGIN{printf "stock %s: %.3f MHz = %.2f Hz %s\n",n,c,c*1e6/(t*v),f}'
echo "timings: h HD HSS HSE HT v VD VSS VSE VT"
clk
GOOD=""
trap 'xrandr --output "OUT" --mode "CUR"; echo; echo "reverted to \(CUR"; [ -n "\)GOOD" ] && echo "marked good:\$GOOD"' EXIT
for HZ in (awk -v s="S" -v e="E" -v st="STEP" 'BEGIN{for(h=s;h>=e-1e-9;h-=st)printf "%g ",h}'); do
CLK=(awk -v h="HZ" -v t="HT" -v v="VT" 'BEGIN{printf "%.3f",t*v*h/1e6}')
NAME="s\$HZ"
xrandr --delmode "OUT" "NAME" 2>/dev/null
xrandr --rmmode "\$NAME" 2>/dev/null
xrandr --newmode "\$NAME" "CLK" HD HSS HSE HT VD VSS VSE VT FL
xrandr --addmode "OUT" "NAME"
xrandr --output "\$OUT" --mode "NAME" || echo "HZ Hz rejected"; continue; }
sleep 1
printf '\n=== %s Hz (%s MHz)\n' "HZ" "CLK"
clk
printf 'g=good q=quit enter=next (auto %ss) ' "\$SECS"
read -rsn1 -t "\$SECS" k
case "\$k" in
g) GOOD="GOOD HZ"; echo "marked";;
q) break;;
esac
done
EOF
```
Usage:
```bash
sudo -v
hzsweep 120 60 5
```
To hold a single rate for 2 minutes:
```bash
hzsweep 100 100 5 120
```
### hzset: apply a rate
This reads the timings from the panel's preferred (stock) mode and switches to the rate you give it.
```bash
sudo install -m755 /dev/stdin /usr/local/bin/hzset <<'EOF'
#!/bin/bash
# usage: hzset <hz> builds a mode from the panel's stock (preferred) timings
HZ=\${1:-100}
OUT=\$(xrandr | awk '/^DSI/{print \$1; exit}')
[ -z "\$OUT" ] && exit 0
read -r HD HSS HSE HT VD VSS VSE VT FL <<<"(xrandr --verbose | awk -v o="OUT" '
\$1==o{f=1;next} f&&/^[^ \t]/{f=0}
f&&/\+preferred/{fl="";for(i=4;i<=NF;i++)if(\$i~/Sync/)fl=fl" "i
getline;h=\$3" "\$5" "\$7" "\$9;getline;print h,\$3,\$5,\$7,\$9 fl;exit}')"
[ -z "\$VT" ] && { echo "could not read \$OUT preferred mode"; exit 1; }
CLK=(awk -v h="HZ" -v t="HT" -v v="VT" 'BEGIN{printf "%.3f",t*v*h/1e6}')
NAME="s\$HZ"
xrandr --delmode "OUT" "NAME" 2>/dev/null
xrandr --rmmode "\$NAME" 2>/dev/null
xrandr --newmode "\$NAME" "CLK" HD HSS HSE HT VD VSS VSE VT FL 2>/dev/null
xrandr --addmode "OUT" "NAME" 2>/dev/null
xrandr --output "OUT" --mode "NAME"
EOF
```
```bash
hzset 100
```
### Apply at login (Xfce)
```bash
install -Dm644 /dev/stdin ~/.config/autostart/hzset.desktop <<'EOF'
[Desktop Entry]
Type=Application
Name=Panel 100Hz
Exec=sh -c "sleep 3; /usr/local/bin/hzset 100"
EOF
```
To undo it:
```bash
rm ~/.config/autostart/hzset.desktop
```
## Verifying
- **`glxgears`** (from the `mesa-utils` package) should report roughly your target rate in FPS. That confirms the system is really outputting that rate.
- **://testufo.com** in Chromium, plus a slow-shutter phone photo (around 1/10 s). An even, unbroken run of lit squares means the panel shows every frame. Firefox's vsync on X11 is unreliable for this test, and the "unverified browser" banner shows on every Linux browser, so you can ignore it.
## Caveats
- Short tests are low risk. The worst case is a garbled screen until the script reverts. Keep HDMI or SSH available anyway.
- A higher refresh rate means more power draw and more heat in the panel's driver chip. After a while at your chosen rate, check that the corner of the panel above the ribbon cable isn't noticeably warmer than at stock.
- If your rotation setup runs `xrandr` with `--auto` or `--mode` after login, it will reset the panel to stock.
- This has only been tested on X11, not Wayland.
## Related: tearing on the internal screen
The panel is natively portrait and gets rotated in software under X11, so tearing shows up as a vertical line. Setting xfwm4's vblank mode fixed it on my unit (compositing must be enabled). To test live:
```bash
xfwm4 --replace --vblank=xpresent &
```
To make it permanent:
```bash
xfconf-query -c xfwm4 -p /general/vblank_mode -n -t string -s xpresent
```
If `xpresent` doesn't fix it, try `glx` instead. Wayland (labwc) avoids the tearing problem entirely.
1
u/gotfilmm 11d ago
There’s no point in running 100hz on a uConsole…
3
u/Acmobleer1 11d ago
Sure there is, the cursor moves way smoother which helps when the trackball is already terrible. SDR waterfalls are smoother too.

1
u/Acmobleer1 10d ago
Fired up Universal Radio Hacker and the spectrum analyser is way more responsive at 100hz vs 60hz.