DEKI/ENGINE 文档
deki-display 0.20.2
Deki 包参考
deki-display

Deki 自己的显示库。驱动大多数爱好者开发板使用的屏幕,读取它们的触摸,并完整地发送每一帧。

仓库:github.com/dekiengine/deki-display · 最新版本:0.20.0 · 需要引擎 0.20.0 或更高版本 · 依赖:deki-spi, deki-gpio, deki-i2c, deki-input, deki-rendering

使用 DekiEditor --packages-add deki-display <project> 或通过包管理器安装。引擎自身的组件和 C++ API 见 Deki 文档。

在编辑器中显示为 **Display**。

组件

组件 类别 说明
DisplayPanelComponent 显示屏 使用 Deki 自己的显示库,通过 SPI、四线 SPI 或 8 位、16 位并行总线驱动显示面板(ST7789、ILI9341、GC9A01 等),并将其交给引擎。
TouchPanelComponent 显示屏 使用 Deki 自己的显示库读取面板的触摸控制器(I2C 上的 GT911、CST816、FT5x06;SPI 上的 XPT2046),作为指针输入。

功能开关

可以从构建中去掉的部分。带有 define 的功能通过该 define 开关,其余的随其组件一起被剥离。

功能 define 默认值
Display Panel DEKI_FEATURE_DISPLAY_PANEL 开
Touch Panel DEKI_FEATURE_DISPLAY_TOUCH 开

组件参考

DisplayPanelComponent

使用 Deki 自己的显示库,通过 SPI、四线 SPI 或 8 位、16 位并行总线驱动显示面板(ST7789、ILI9341、GC9A01 等),并将其交给引擎。

检视器中的名称:显示面板组件 · 类别:显示屏 · 类型:DekiDisplay::DisplayPanelComponent

属性 类型 默认值 约束 说明
controller enum "ST7789" ST7789, RM67162, ILI9341, ST7735, ST7735S, GC9A01, ST7789P3, ST7796, ILI9488, SSD1351, CO5300 面板的控制器 IC
initSequence string "" 启动此面板模块的命令,用来替换控制器的默认命令。面板的电压、VCOM 和伽马属于模块而不是控制器,因此由开发板在这里设置。每行或每个 ';' 一条命令:先写十六进制的命令字节,再写参数字节,可选地加上 'delay <ms>'。'#' 之后为注释。留空:使用控制器的默认命令
panelWidth int32 240 1 到 1024 旋转前的可见宽度(像素)
panelHeight int32 320 1 到 1024 旋转前的可见高度(像素)
rotation enum "Landscape" Portrait, Landscape, Portrait180, Landscape270, PortraitMirror, LandscapeMirror, Portrait180Mirror, Landscape270Mirror 面板的朝向
offsetX int32 0 可见面板在控制器显存中的起始位置,横向(用于原点不为 0 的面板)
offsetY int32 0 可见面板在控制器显存中的起始位置,纵向
invertColor bool false 反转面板颜色(大多数 IPS 面板需要开启)
rgbOrder bool false 面板先接收红色。关闭时设置控制器的 BGR 顺序
busType enum "SPI" SPI, QSPI, Parallel8, Parallel16 面板的接线方式:带数据/命令引脚的 SPI(大多数 LCD)、四线 SPI(RM67162 等 AMOLED 面板,需要带 IO2 和 IO3 的 SPI Bus),或 8 位、16 位并行总线(8080,由本组件自行启动)
spiHost int32 1 0 到 3;busType 允许时显示 面板所在的 SPI 主机,与启动它的 SPI Bus 组件编号一致(在 ESP32-S3 上:1 = SPI2,2 = SPI3)
spiWriteHz int32 40000000 busType 允许时显示 面板的 SPI 时钟。80 MHz 是 ESP32-S3 的最快速度,大多数 ST7789 模块都支持
parallelWriteHz int32 20000000 busType 允许时显示 并行总线上写选通的频率。大多数面板支持 20 MHz;连线短的可以更高
dcPin int32 -1 -1 到 48;busType 允许时显示 数据/命令引脚(DC,也叫 RS)
wrPin int32 -1 -1 到 48;busType 允许时显示 写选通引脚(WR)
rdPin int32 -1 -1 到 48;busType 允许时显示 读选通引脚(RD),保持高电平:只向面板写入(-1 = 在板上固定接高电平)
d0Pin int32 -1 -1 到 48;busType 允许时显示 数据线 D0
d1Pin int32 -1 -1 到 48;busType 允许时显示 数据线 D1
d2Pin int32 -1 -1 到 48;busType 允许时显示 数据线 D2
d3Pin int32 -1 -1 到 48;busType 允许时显示 数据线 D3
d4Pin int32 -1 -1 到 48;busType 允许时显示 数据线 D4
d5Pin int32 -1 -1 到 48;busType 允许时显示 数据线 D5
d6Pin int32 -1 -1 到 48;busType 允许时显示 数据线 D6
d7Pin int32 -1 -1 到 48;busType 允许时显示 数据线 D7
d8Pin int32 -1 -1 到 48;busType 允许时显示 数据线 D8
d9Pin int32 -1 -1 到 48;busType 允许时显示 数据线 D9
d10Pin int32 -1 -1 到 48;busType 允许时显示 数据线 D10
d11Pin int32 -1 -1 到 48;busType 允许时显示 数据线 D11
d12Pin int32 -1 -1 到 48;busType 允许时显示 数据线 D12
d13Pin int32 -1 -1 到 48;busType 允许时显示 数据线 D13
d14Pin int32 -1 -1 到 48;busType 允许时显示 数据线 D14
d15Pin int32 -1 -1 到 48;busType 允许时显示 数据线 D15
csPin int32 -1 -1 到 48 片选引脚(-1 = 固定接低电平)
rstPin int32 -1 -1 到 48 复位引脚(-1 = 未连接)
tePin int32 -1 -1 到 48 面板的撕裂效应(TE)输出(-1 = 未连接)。接上后画面不会撕裂:每一帧在面板开始刷新时开始发送,并按面板自身的行顺序发送;旋转的屏幕在发送时旋转,并按列条带绘制
scanlineSync bool true busType 允许时显示 没有接 TE 线时,改为读取面板的扫描线,让画面依然不会撕裂。无法回读的面板按绘制顺序发送,启动日志会说明
spiReadHz int32 10000000 scanlineSync 允许时显示 回读面板时的 SPI 时钟,比写入慢(ST7789 在 10 MHz 下读取可靠)
readsOnMosi bool false scanlineSync 允许时显示 面板在数据输入线上应答(SDA 双向,如 LilyGO T-Deck),而不是在 MISO 上
blPin int32 -1 -1 到 48 背光引脚(-1 = 无)。点亮时保持高电平:通过计数脉冲调光的背光驱动器(LilyGO T-Deck 的)正需要这样
blInvert bool false 引脚为低电平时背光点亮
memoryWidth int32 0 0 到 1024 控制器的显存宽度,可能大于可见宽度(0 = 控制器的值)
memoryHeight int32 0 0 到 1024 控制器的显存高度(0 = 控制器的值)
usePsram bool false 将帧缓冲放在 PSRAM 而不是内部 RAM 中:可腾出一屏大小的内部 RAM,但绘制会变慢
doubleBuffer bool false 两个帧缓冲区,每帧后交换
asyncPresent bool true 在绘制下一帧的同时,从芯片的另一个核心发送每一帧:一帧的耗时是绘制和发送中较长的那个,而不是两者之和。需要双核芯片和两帧的外部内存(PSRAM);没有时按绘制顺序发送,启动日志会说明

TouchPanelComponent

使用 Deki 自己的显示库读取面板的触摸控制器(I2C 上的 GT911、CST816、FT5x06;SPI 上的 XPT2046),作为指针输入。

检视器中的名称:触摸面板组件 · 类别:显示屏 · 类型:DekiDisplay::TouchPanelComponent

属性 类型 默认值 约束 说明
controller enum "GT911" GT911, CST816, FT5x06, XPT2046 触摸控制器 IC
i2cPort int32 0 0 到 3;controller 允许时显示 它所在的 I2C 端口(必须在此组件之前由 I2C Bus 组件启动该端口)
i2cAddress int32 0 0 到 127;controller 允许时显示 其 I2C 地址;0 表示使用控制器的常用地址(GT911:0x5D,无应答时改用 0x14;CST816:0x15;FT5x06:0x38)
spiHost int32 1 0 到 3;controller 允许时显示 其所在的 SPI 主机,与启动它的 SPI Bus 组件编号一致(通常与显示屏相同)
csPin int32 -1 -1 到 48;controller 允许时显示 其片选引脚
spiHz int32 1000000 controller 允许时显示 触摸控制器的 SPI 时钟。XPT2046 在 1 MHz 下读取效果好,最高支持 2.5 MHz
intPin int32 -1 -1 到 48 中断引脚:有触摸报告等待读取时,或按下期间(XPT2046 的 PENIRQ),控制器将其拉低(-1 = 未连接,每帧读取)
rstPin int32 -1 -1 到 48;controller 允许时显示 复位引脚(-1 = 未连接)
xMin int32 0 触摸控制器报告的原始 X 最小值,沿显示屏旋转前的面板宽度方向(电容式:0;XPT2046 从约 300 开始,需要校准)
xMax int32 239 触摸控制器报告的原始 X 最大值,沿显示屏旋转前的面板宽度方向(240x320 面板横向显示时:239)
yMin int32 0 触摸控制器报告的原始 Y 最小值,沿显示屏旋转前的面板高度方向
yMax int32 319 触摸控制器报告的原始 Y 最大值,沿显示屏旋转前的面板高度方向(240x320 面板横向显示时:319)
offsetRotation enum "None" None, CW_90, CW_180, CW_270, Mirror, Mirror_CW_90, Mirror_CW_180, Mirror_CW_270 触摸控制器相对面板的旋转方向,会叠加到显示屏旋转上。控制器按面板自身方向报告坐标时选择“无”

更新日志

更新日志为英文。

0.20.0

Changed

  • minEngine 0.20.0: built against engine 0.20.0. A build of this package from before does not load and is rebuilt.

Added

  • The package: DisplayPanelComponent, which starts a panel on a deki-spi bus from the boot scene and gives the engine PanelDisplay, a Deki::IDisplay presenting whole frames and changed rectangles with the UI overlay blended over them; PanelController, a MIPI DCS controller driven by a table per controller (ST7789 first, its start-up and MADCTL ported from LovyanGFX); SpiPanelIO, 4-wire SPI with pixels queued for DMA; and initSequence, a board's own start-up for its panel module, as text.
  • Async present (asyncPresent): each frame is sent from the other core while the next is drawn. A whole frame is copied, swapped into the wire's byte order as it is copied, to one of two copies in external DMA memory, and sent from there by DMA in parts as long as the bus takes, with no bands in internal RAM; a strip is copied to one of two copies in internal DMA memory and swapped in place a chunk at a time. The worker holds the bus across back-to-back frames and strips, with each one's window commands queued behind the one before, so the wire does not wait between them; a copy goes back to the drawing core as soon as its last part is sent. The platform runs the worker through PanelDisplay::SetWorkerBackend (deki-esp32-integration: a FreeRTOS task pinned to the other core). On a LilyGO T-Deck Plus at 80 MHz with the frame rate uncapped: 63.2 fps in whole frames with 83.6 KB of internal RAM free, 61.0 in strips of 40 rows (LovyanGFX: 62.6 with 73.8 KB, and 60.2).
  • Touch: TouchPanelComponent starts a GT911 (GT911Touch, ported from LovyanGFX's driver) on a deki-i2c bus, shared with whatever else is on it, and gives deki-input PanelTouchInput: a press, moves and a release at screen pixels, turned with the display by TouchMapper (LovyanGFX's default calibration and rotation, so a board's touch bounds carry over). Without an INT pin, a point that stops changing is released and not pressed again until it moves.
  • QSPI panels: DisplayPanelComponent's busType QSPI drives an AMOLED through QspiPanelIO (each register write framed 0x02, pixels 0x32 on four lines, as LovyanGFX frames them). The RM67162 is the first: its start-up, MADCTL and offsets ported from LovyanGFX, rows widened to even, and brightness by command where an LCD has a backlight.
  • The CST816S/T touch controller (TouchController::CST816). It sleeps, and does not answer on I2C, until touched: it is set up when it first answers, and a read it does not answer is no touch.
  • Async present works with render buffers (usePsram, doubleBuffer) too: the worker sends a copy, so the engine never draws into what is being sent.
  • Tear-free presenting: DisplayPanelComponent's tePin, the panel's tearing-effect output. A panel refreshes its own rows one after another, and a frame written while the refresh passes shows half of each frame. With TE on (0x35), each frame starts as the panel starts a refresh, and goes in the panel's own row order, which a write outruns the refresh in. A screen shown turned is turned as it is sent: the controller stays at its own orientation, and the renderer is asked for strips of columns in the order the panel refreshes them (deki-rendering's IScanOrderedDisplay). With async present the worker does the turning, a band at a time while the band before it is on the wire. Whole frames and strips both. A TE line that never pulses is said once in the log, and frames go on without waiting. On a LilyGO T-Display S3 AMOLED (its panel refreshes at 59.6 Hz): 59.5 fps in strips with no tearing, and 28.6 in whole frames, which take 25 ms to draw in PSRAM.
  • More controllers, each a table ported from LovyanGFX 1.2.29: ILI9341, ST7735 (the B version), ST7735S (the R version), GC9A01, ST7789P3, ST7796, ILI9488 and SSD1351 on SPI or a parallel bus, and the CO5300 AMOLED on QSPI. A controller names its own commands (ControllerCommands): the SSD1351's window is a byte a coordinate, its column and row commands trade places when turned, and its remap takes MADCTL's place. The GC9A01 opens its rows before a turned window's columns, as LovyanGFX does. Checked against LovyanGFX's bytes in tests; none has run on a board yet.
  • 18 bits a pixel: the ILI9488 takes no RGB565 over SPI, so its pixels go out as RGB666 through Rgb666PanelIO, which widens each piece into its own DMA buffers while the piece before is sent, and COLMOD is 0x66.
  • Parallel panels: busType Parallel8 and Parallel16, an 8080 bus of 8 or 16 data lines with DC, WR and RD pins and its write clock (parallelWriteHz). The platform drives the bus (ParallelBus, a factory it registers; ParallelPanelIO speaks to it), and the component starts it itself. On 16 lines a pixel goes as memory holds it, so a little-endian frame needs no byte swap.
  • Touch: the FT5x06 family (FT5206, FT6206, FT6336 and others) on I2C, and the XPT2046 resistive controller on SPI, both ported from LovyanGFX. The XPT2046's raw readings need calibrating in the touch bounds. A controller whose count or pressure says when the finger has gone (ITouchController::MayRepeatLastTouch false) is not released for holding still.
  • Tear-free: a frame that missed its refresh's start is started for the longest write any frame has taken (PanelDisplay::LongestWriteUs), not the shorter of the last two. The frame that opens a new scene is late (the scene loads in it) and changes the whole screen, while the frames before it changed a little: started for theirs, it began too late, the refresh caught it, and the screen tore across.
  • Tear-free with no TE line: scanlineSync reads the panel's scanline (Get_Scanline, 0x45) back through the panel IO (IPanelIO::Read) at its own clock (spiReadHz), on MISO or, with readsOnMosi, on the panel's data line. ScanlineClock finds two refresh starts, where the count drops from the last row to the blanking (it holds there; the low byte rolling over at row 256 does not), and keeps the clock right with each start it catches. On a LilyGO T-Deck Plus: 60.2 Hz found, every demo scene at 60 fps with frames in step with the refresh.
  • A frame that takes about a refresh to go out, or up to two, is started just behind the refresh rather than at once (PanelDisplay::WritesBehind): it never catches the refresh's rows up, and the next refresh shows it whole. Before, such a frame was taken to tear wherever it started.
  • A turned frame is read a screen row at a time while it is turned, a run of neighbouring pixels from each, instead of one pixel per screen row: a whole frame in PSRAM, turned on the way out, went from 47.8 fps to 60 on the T-Deck Plus.
  • asyncPresent and scanlineSync are on by default: a board gets frames sent from the other core, and tear-free frames without a TE line, where it can. Where it cannot (one core, no PSRAM for the copies, a panel that cannot be read back) frames are sent as they are drawn, and the boot log says so as information, not an error. Scenes that set them keep what they set.

更早的版本:CHANGELOG.md


由包的反射数据生成(引擎 0.20.2)。属性名就是场景文件中使用的键。重命名后会保留别名(兼容性)。