Skip to main content

<alp/display.h> — Display Subsystem

Raw display control. For widget-level UIs use <alp/gui.h> (LVGL).

:::danger Breaking change — alp_display_config_t gained a required allow_modeset field alp_display_config_t now carries bool allow_modeset, defaulting to false. The Yocto/Linux backend refuses to open with ALP_ERR_INVAL unless the caller explicitly sets it true.

This is deliberate: opening the display on Linux means taking DRM master, which can silently steal a live framebuffer or console out from under the system. Existing code that opens a display on the Yocto/Linux backend without setting allow_modeset = true will now fail at alp_display_open(). :::

#include <alp/display.h>

Quick example

alp_display_t *disp = alp_display_open(&(alp_display_config_t){
.display_id = 0, // Studio-resolved display instance
.allow_modeset = true, // required on the Yocto/Linux backend — takes DRM master
});

// Read geometry + pixel format before drawing.
alp_display_caps_t caps = { 0 };
alp_display_get_caps(disp, &caps);

alp_display_clear(disp);

// Push a rectangular framebuffer region. `pixels` byte size is
// implied by w * h * bytes-per-pixel-for-caps.format.
alp_display_blit(disp, /* x */ 0, /* y */ 0,
/* w */ caps.width, /* h */ caps.height, pixels);

alp_display_close(disp);

The raw surface is pixel-oriented: there is no text-drawing primitive. To render strings or widgets, drive <alp/gui.h> (LVGL) instead.

Supported panels

Driver chips supported out of the box:

  • SSD1306 — monochrome 128×64 OLED (E1M EVK)
  • SSD1331 — small colour OLED (E1M EVK)
  • SSD1683 / UC8175 — e-paper (v0.3+)
  • ST7789 / ILI9341 — small TFT (v0.3+)

All are opt-in via board.yaml's chips: array.

FieldTypeDefaultNotes
display_iduint32_tStudio-resolved display instance.
allow_modesetboolfalseRequired on the Yocto/Linux backend. alp_display_open() returns NULL + ALP_ERR_INVAL unless it is true.

Opening a display on Linux takes DRM master and programs a CRTC. Doing that without the application's explicit consent can silently steal a live framebuffer or console out from under the running system — so the SDK will not do it implicitly. The flag is the caller stating, in code, that this process owns the screen.

On backends that do not take DRM master (the Zephyr display backend, the stub) the field is inert — but portable code should set it anyway, because the same source built for Yocto will otherwise fail at open().

Backend status

As of v0.9 a real Zephyr display backend exists (issue #23, ADR-0017 Tier 1). It wraps the upstream Zephyr display_* driver class, so any panel that already has an upstream Zephyr display driver resolves through the SDK surface via the new alp-display0..3 devicetree aliases.

  • Gate: CONFIG_ALP_SDK_DISPLAY_ZEPHYR_DRV (default y when CONFIG_DISPLAY is on), registered at priority 50.
  • Fallback: the priority-0 NOT_IMPLEMENTED stub remains, so the surface stays linkable on builds without a display. Boards with no display node degrade cleanly — ops return ALP_ERR_NOT_READY / ALP_ERR_NOT_IMPLEMENTED rather than faulting.
  • Bounds: alp_display_blit rects are bounds-checked against the panel geometry; a rect outside the display returns ALP_ERR_OUT_OF_RANGE.
  • Coverage (Zephyr backend): verified on native_sim. No silicon run yet — the V2N DSI / parallel-RGB framebuffer path and the Alif LCD-IF path are still tracked under issue #23.

The LVGL re-export path (<alp/gui.h>) still owns the zephyr,display chosen node.

Yocto / Linux (V2N) — real DRM/KMS dumb buffers

The V2N Linux/Yocto backend is now a real DRM/KMS dumb-buffer implementation; it previously returned ALP_ERR_NOSUPPORT for everything. The open path is:

  1. GETRESOURCES — enumerate connectors, encoders and CRTCs;
  2. CREATE_DUMB + ADDFB2 with DRM_FORMAT_ARGB8888 — allocate the scanout buffer;
  3. MAP_DUMB + mmap — map it into the process;
  4. SETCRTC — program the mode.

Step 4 is why allow_modeset exists: this sequence takes DRM master.

:::warning Unproven on silicon This path has not been run on V2N silicon yet — treat it as unproven. It is code-complete, not bench-verified. :::

Default-initialiser macro

alp_display_config_t cfg = ALP_DISPLAY_CONFIG_DEFAULT(0);
cfg.allow_modeset = true; // required on the Yocto/Linux backend
alp_display_t *d = alp_display_open(&cfg);

ALP_DISPLAY_CONFIG_DEFAULT(id) sets display_id from id and allow_modeset to false:

ALP_DISPLAY_CONFIG_DEFAULT(id) /* { .display_id = (id), .allow_modeset = false } */

The macro's shape changed when allow_modeset was added — the safe default is the one that does not take DRM master, so a caller who wants the screen must say so explicitly.

See the shared macro contract for the C++ compound-literal caveat that applies to every ALP_*_CONFIG_DEFAULT.

See also

Questions about this page? Discuss in Community Forum