Log 1 mentioned "render directly to the framebuffer" as one of six ground rules and moved on. It deserves its own post, because this is the decision that almost every other design choice in Scottina traces back to.

Why not just run Xorg like everybody else?
The obvious path for a touchscreen kiosk is a desktop stack: Xorg or Wayland,
SDL or Qt, a browser or a toolkit on top. I tried variations on that and kept
running into the same wall — anything that can lose the DRM device
eventually does, and on a 3.5" panel wired over SPI, "eventually" shows up as
a frozen or blank screen at the worst possible bench moment. The only
approach that's proven reliable on this hardware is the boring one: own
/dev/fb0 directly.
Scottina composes every frame with PIL + numpy and writes it straight to the
ili9486drmfb framebuffer. Touch comes from the ADS7846 controller's evdev
node, polled, not grabbed. No SDL, no Xorg, nothing else that can fight
Scottina for the display.
The ILI9486 has its own opinions
Owning the framebuffer doesn't mean the panel behaves. A few things it took real bench time to work around:
- No controllable backlight.
/sys/class/backlightis empty on this panel, so "dimming" after idle is a software screensaver that darkens the rendered image rather than a hardware fade. If a PWM backlight ever gets wired in, Scottina will auto-detect the sysfs node and use it — the code's already there, just unused. - Rotation lives in the overlay, calibration doesn't. The panel comes up
through one line in
config.txt—dtoverlay=piscreen,drm,rotate=90— and that's the only display setting that needs a reboot. Touch axis mapping (swap X/Y, invert X, invert Y) is a runtime config value instead, so re-calibrating after a mount change is a Settings-screen toggle or aconfig.jsonedit over SSH, never a re-flash. - The console has to be told where to live. The panel only scans out
over SPI once its DRM pipe is enabled, and that's driven by whatever the
console is mapped onto — not guaranteed to be
fb0by default. The systemd unit forces it withcon2fbmapbefore Scottina starts, blanks the cursor, and gives the modeset a moment to settle first.
Making an SPI panel feel fast
SPI is not a fast bus, so full-frame redraws at interactive rates were never
going to happen. Every screen that ticks reports the boxes that actually
changed; framebuffer.py merges those into row bands (bands within 8 rows of
each other get fused — a seek costs more than a few extra rows) and writes
only those, since the DRM fbdev layer derives its SPI damage from the byte
range touched anyway. That's a 2–15× saving over a full blit, and it's what
lets live screens like CAN Bus tick at ~20 Hz while everything idle sits at
~1 Hz without cooking the bus.
Next log: hotplug — how a screen's tile appears the instant its dongle is plugged in, and disappears the instant it isn't.
Scottsky
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.