@typecad/framework-zephyr 1.0.0-alpha.10 → 1.0.0-alpha.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chips/esp32.js +12 -0
- package/dist/chips/types.d.ts +30 -0
- package/dist/chips/xiao-ble.js +6 -0
- package/dist/display/gfx.d.ts +12 -3
- package/dist/display/gfx.js +130 -17
- package/dist/display/profiles.d.ts +25 -0
- package/dist/display/profiles.js +30 -0
- package/dist/display/touch-adapter.d.ts +3 -4
- package/dist/display/touch-adapter.js +119 -16
- package/dist/display/ui-adapter.js +308 -139
- package/dist/doctor.d.ts +3 -3
- package/dist/doctor.js +56 -29
- package/dist/dt-config/kconfig.d.ts +8 -1
- package/dist/dt-config/kconfig.js +40 -5
- package/dist/dt-config/overlay.d.ts +18 -1
- package/dist/dt-config/overlay.js +124 -26
- package/dist/framework.manifest.d.ts +29 -28
- package/dist/framework.manifest.js +46 -17
- package/dist/index.d.ts +1 -0
- package/dist/index.js +5 -0
- package/dist/licenses.d.ts +59 -0
- package/dist/licenses.js +347 -0
- package/dist/lowering/ble.js +3 -1
- package/dist/lowering/dac.d.ts +15 -0
- package/dist/lowering/dac.js +69 -0
- package/dist/lowering/fs.d.ts +16 -0
- package/dist/lowering/fs.js +121 -0
- package/dist/lowering/hwtimer.d.ts +15 -0
- package/dist/lowering/hwtimer.js +84 -0
- package/dist/lowering/index.d.ts +4 -1
- package/dist/lowering/index.js +12 -3
- package/dist/strategy.d.ts +4 -0
- package/dist/strategy.js +275 -35
- package/dist/toolchain/compat.js +10 -1
- package/dist/toolchain/env-check.d.ts +93 -0
- package/dist/toolchain/env-check.js +190 -0
- package/dist/toolchain/index.js +39 -9
- package/dist/toolchain/scaffold.js +7 -2
- package/dist/toolchain/west-discover.d.ts +11 -3
- package/dist/toolchain/west-discover.js +84 -7
- package/dist/toolchain/west-spawn.js +15 -0
- package/package.json +4 -4
- package/src/chips/esp32.ts +12 -0
- package/src/chips/types.ts +29 -0
- package/src/chips/xiao-ble.ts +6 -0
- package/src/display/gfx.ts +135 -19
- package/src/display/profiles.ts +53 -0
- package/src/display/touch-adapter.ts +119 -15
- package/src/display/ui-adapter.ts +311 -139
- package/src/doctor.ts +77 -56
- package/src/dt-config/kconfig.ts +45 -6
- package/src/dt-config/overlay.ts +159 -29
- package/src/framework.manifest.ts +47 -17
- package/src/index.ts +6 -0
- package/src/licenses.ts +425 -0
- package/src/lowering/ble.ts +3 -1
- package/src/lowering/dac.ts +82 -0
- package/src/lowering/fs.ts +127 -0
- package/src/lowering/hwtimer.ts +101 -0
- package/src/lowering/index.ts +9 -2
- package/src/strategy.ts +271 -35
- package/src/toolchain/compat.ts +154 -145
- package/src/toolchain/env-check.ts +285 -0
- package/src/toolchain/index.ts +40 -9
- package/src/toolchain/scaffold.ts +7 -2
- package/src/toolchain/west-discover.ts +92 -9
- package/src/toolchain/west-spawn.ts +15 -0
|
@@ -2,14 +2,23 @@
|
|
|
2
2
|
// Zephyr UI display adapter for the Cuttlefish UI rendering pipeline.
|
|
3
3
|
//
|
|
4
4
|
// Bridges the in-tree CuttlefishGFX/CuttlefishCanvas16 class (emitted by the
|
|
5
|
-
// runtime header's cuttlefish-gfx slice) to
|
|
5
|
+
// runtime header's cuttlefish-gfx slice) to an SPI TFT panel. The panel is
|
|
6
6
|
// driven DIRECTLY over the SPI controller with GPIO chip-select, DC and reset
|
|
7
7
|
// pins — NOT through Zephyr's mipi-dbi-spi bridge: that bridge issues separate
|
|
8
8
|
// SPI transactions for the command byte and its parameters (CS deasserts
|
|
9
|
-
// between them), which scrambles this panel's command decoder and
|
|
10
|
-
// white. Verified on hardware: the direct protocol (CS
|
|
11
|
-
// command+data burst, DC toggled mid-burst — the Adafruit
|
|
12
|
-
// initializes the panel and renders pixels correctly.
|
|
9
|
+
// between them), which scrambles this panel family's command decoder and
|
|
10
|
+
// leaves it white. Verified on hardware (ST7796S): the direct protocol (CS
|
|
11
|
+
// held low across the command+data burst, DC toggled mid-burst — the Adafruit
|
|
12
|
+
// ST77xx protocol) initializes the panel and renders pixels correctly.
|
|
13
|
+
//
|
|
14
|
+
// Per-controller support lives in two places, keyed off the display profile's
|
|
15
|
+
// `controller` field (see profiles.ts):
|
|
16
|
+
// - the init command table (byte-for-byte Adafruit sequences)
|
|
17
|
+
// - the pixel wire format: ST7796S is driven in 18-bit (666) mode (its
|
|
18
|
+
// 16-bit channel routing is crossed on the verified clone panel), ILI9341
|
|
19
|
+
// in native 16-bit (565) big-endian. The ST7796S path below is frozen
|
|
20
|
+
// exactly as hardware-verified; the ILI9341 path mirrors it with the
|
|
21
|
+
// Adafruit ILI9341 init + 565 packing and is not yet hardware-tuned.
|
|
13
22
|
//
|
|
14
23
|
// This is the Zephyr analog of the Adafruit adapters in framework-arduino,
|
|
15
24
|
// using the in-tree native GFX class (no #define CuttlefishCanvas16) driven
|
|
@@ -22,13 +31,25 @@
|
|
|
22
31
|
// per-frame allocated); fillRect writes row-by-row. Pixel bursts use 16-bit
|
|
23
32
|
// SPI words (MSB-first on the wire = RGB565 big-endian, no byte swap).
|
|
24
33
|
// ---------------------------------------------------------------------------
|
|
25
|
-
import { ZEPHYR_DISPLAY_PROFILES } from "./profiles.js";
|
|
34
|
+
import { ZEPHYR_DISPLAY_PROFILES, panelControllerFor } from "./profiles.js";
|
|
26
35
|
export function zephyrUiDisplayAdapter(profile, readback = {}) {
|
|
27
36
|
const w = profile.width;
|
|
28
37
|
const h = profile.height;
|
|
29
38
|
const maxDim = Math.max(w, h);
|
|
30
39
|
const dtLabel = profile.dtLabel;
|
|
31
40
|
const backlightAlias = profile.backlight;
|
|
41
|
+
const bus = profile.busLabel ?? 'spi2';
|
|
42
|
+
const bridge = profile.bridgeLabel ?? 'mipi_dbi';
|
|
43
|
+
const controller = panelControllerFor(profile);
|
|
44
|
+
const isIli9341 = controller === 'ili9341';
|
|
45
|
+
// Bytes per pixel on the wire: 3 (18-bit 666) for ST7796S, 2 (16-bit 565)
|
|
46
|
+
// for ILI9341. The row/block scratch buffers and pack loops key off this.
|
|
47
|
+
const bpp = isIli9341 ? 2 : 3;
|
|
48
|
+
const rowBuf = `__tc_display_row${bpp}`;
|
|
49
|
+
const blockBuf = `__tc_display_block${bpp}`;
|
|
50
|
+
const packFn = isIli9341 ? '__tc_pnl_pack565' : '__tc_pnl_pack666';
|
|
51
|
+
const pixelsFn = isIli9341 ? '__tc_pnl_pixels565' : '__tc_pnl_pixels666';
|
|
52
|
+
const wireTag = isIli9341 ? '16-bit 565' : '18-bit';
|
|
32
53
|
// Never infer readback from a board's default pinmux. SDO/MISO may be left
|
|
33
54
|
// floating or shared with another device, and ST7796S modules are known to
|
|
34
55
|
// react badly to GSCAN reads. Both an explicit opt-in and an explicit MISO
|
|
@@ -44,6 +65,40 @@ export function zephyrUiDisplayAdapter(profile, readback = {}) {
|
|
|
44
65
|
`#include <zephyr/drivers/spi.h>`,
|
|
45
66
|
`#include <zephyr/drivers/gpio.h>`,
|
|
46
67
|
].join("\n");
|
|
68
|
+
// Per-controller scratch-buffer declarations. The ST7796S text is frozen as
|
|
69
|
+
// hardware-verified; the ILI9341 variant documents its 565 wire format.
|
|
70
|
+
const bufferDecls = isIli9341
|
|
71
|
+
? [
|
|
72
|
+
`// One-row scratch buffer in 16-bit (565) wire format: maxDim px x 2 bytes.`,
|
|
73
|
+
`// Reused across fillRect/draw calls — never per-frame (AGENTS.md: no`,
|
|
74
|
+
`// per-frame heap allocation). The ILI9341 is driven in its native`,
|
|
75
|
+
`// 16-bit COLMOD (0x55): RGB565 pixels go out big-endian (MSB-first SPI),`,
|
|
76
|
+
`// the Adafruit ILI9341 convention, with no repacking needed.`,
|
|
77
|
+
`static uint8_t ${rowBuf}[${maxDim} * 2];`,
|
|
78
|
+
`// Multi-row block buffer for solid fills (8 rows of maxDim px in 565).`,
|
|
79
|
+
`// fillRect fills this once with the color, then sends the whole rect in a`,
|
|
80
|
+
`// few large spi_write chunks instead of one spi_write per row — a full`,
|
|
81
|
+
`// 480x320 clear went from ~320 syscalls (~110ms) to ~40 (~15ms). Reused,`,
|
|
82
|
+
`// not per-frame (AGENTS.md).`,
|
|
83
|
+
`#define __TC_FILL_ROWS 8`,
|
|
84
|
+
`static uint8_t ${blockBuf}[${maxDim} * 2 * __TC_FILL_ROWS];`,
|
|
85
|
+
]
|
|
86
|
+
: [
|
|
87
|
+
`// One-row scratch buffer in 18-bit (666) wire format: maxDim px x 3 bytes.`,
|
|
88
|
+
`// Reused across fillRect/draw calls — never per-frame (AGENTS.md: no`,
|
|
89
|
+
`// per-frame heap allocation). The panel is driven in 18-bit mode (COLMOD`,
|
|
90
|
+
`// 0x66): its 16-bit (565) channel routing is crossed (G/B swap, verified`,
|
|
91
|
+
`// with calibration bands), while 18-bit mode routes every channel`,
|
|
92
|
+
`// correctly with plain (R,G,B) byte order.`,
|
|
93
|
+
`static uint8_t ${rowBuf}[${maxDim} * 3];`,
|
|
94
|
+
`// Multi-row block buffer for solid fills (8 rows of maxDim px in 18-bit).`,
|
|
95
|
+
`// fillRect fills this once with the color, then sends the whole rect in a`,
|
|
96
|
+
`// few large spi_write chunks instead of one spi_write per row — a full`,
|
|
97
|
+
`// 480x320 clear went from ~320 syscalls (~110ms) to ~40 (~15ms). Reused,`,
|
|
98
|
+
`// not per-frame (AGENTS.md).`,
|
|
99
|
+
`#define __TC_FILL_ROWS 8`,
|
|
100
|
+
`static uint8_t ${blockBuf}[${maxDim} * 3 * __TC_FILL_ROWS];`,
|
|
101
|
+
];
|
|
47
102
|
const declaration = [
|
|
48
103
|
`// CUTTLEFISH_DISPLAY_BEGIN`,
|
|
49
104
|
// The display0 DT node carries frequency/dimensions for DT_PROP reads, but
|
|
@@ -52,20 +107,7 @@ export function zephyrUiDisplayAdapter(profile, readback = {}) {
|
|
|
52
107
|
// allocates a tearing-effect GPIO interrupt that conflicts with the SPI/I2C
|
|
53
108
|
// interrupts — the VECDESC_FL_SHARED assertion crash on the 3rd frame).
|
|
54
109
|
`#define __tc_display_dev 1`,
|
|
55
|
-
|
|
56
|
-
`// Reused across fillRect/draw calls — never per-frame (AGENTS.md: no`,
|
|
57
|
-
`// per-frame heap allocation). The panel is driven in 18-bit mode (COLMOD`,
|
|
58
|
-
`// 0x66): its 16-bit (565) channel routing is crossed (G/B swap, verified`,
|
|
59
|
-
`// with calibration bands), while 18-bit mode routes every channel`,
|
|
60
|
-
`// correctly with plain (R,G,B) byte order.`,
|
|
61
|
-
`static uint8_t __tc_display_row3[${maxDim} * 3];`,
|
|
62
|
-
`// Multi-row block buffer for solid fills (8 rows of maxDim px in 18-bit).`,
|
|
63
|
-
`// fillRect fills this once with the color, then sends the whole rect in a`,
|
|
64
|
-
`// few large spi_write chunks instead of one spi_write per row — a full`,
|
|
65
|
-
`// 480x320 clear went from ~320 syscalls (~110ms) to ~40 (~15ms). Reused,`,
|
|
66
|
-
`// not per-frame (AGENTS.md).`,
|
|
67
|
-
`#define __TC_FILL_ROWS 8`,
|
|
68
|
-
`static uint8_t __tc_display_block3[${maxDim} * 3 * __TC_FILL_ROWS];`,
|
|
110
|
+
...bufferDecls,
|
|
69
111
|
`// startWrite/endWrite batching depth. When > 0 the panel CS is held asserted`,
|
|
70
112
|
`// (low) across multiple primitives — DC still toggles mid-burst, but CS does`,
|
|
71
113
|
`// not, matching the Adafruit ST77xx protocol and avoiding one full CS-toggle`,
|
|
@@ -95,6 +137,230 @@ export function zephyrUiDisplayAdapter(profile, readback = {}) {
|
|
|
95
137
|
const blInit = backlightAlias
|
|
96
138
|
? `#if DT_HAS_ALIAS(${backlightAlias})\n const struct gpio_dt_spec __bl = GPIO_DT_SPEC_GET(DT_ALIAS(${backlightAlias}), gpios);\n if (device_is_ready(__bl.port)) { gpio_pin_configure_dt(&__bl, GPIO_OUTPUT_ACTIVE); }\n#endif`
|
|
97
139
|
: '';
|
|
140
|
+
// Per-controller pixel pack/stream helpers. Both share the row-chunked
|
|
141
|
+
// transport; only the per-pixel wire encoding differs.
|
|
142
|
+
const pixelHelpers = isIli9341
|
|
143
|
+
? `
|
|
144
|
+
// Pack count rgb565 pixels into the row2 scratch buffer as big-endian 16-bit
|
|
145
|
+
// wire bytes (c>>8, c&0xFF) — the ILI9341's native 565 format under COLMOD
|
|
146
|
+
// 0x55. The caller then streams the buffer with the 8-bit config (one row at
|
|
147
|
+
// a time; the buffer holds maxDim pixels).
|
|
148
|
+
static void ${packFn}(const uint16_t* px, uint32_t count) {
|
|
149
|
+
for (uint32_t i = 0; i < count; i++) {
|
|
150
|
+
uint16_t c = px[i];
|
|
151
|
+
${rowBuf}[i * 2] = static_cast<uint8_t>(c >> 8);
|
|
152
|
+
${rowBuf}[i * 2 + 1] = static_cast<uint8_t>(c);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Stream count rgb565 pixels to the panel (chunked through the row2 scratch).
|
|
157
|
+
// Caller holds the RAMWR burst.
|
|
158
|
+
static void ${pixelsFn}(const uint16_t* px, uint32_t count) {
|
|
159
|
+
while (count > 0) {
|
|
160
|
+
uint32_t __chunk = (count > ${maxDim}) ? ${maxDim} : count;
|
|
161
|
+
${packFn}(px, __chunk);
|
|
162
|
+
struct spi_buf __bd = { ${rowBuf}, static_cast<size_t>(__chunk) * 2U };
|
|
163
|
+
struct spi_buf_set __sd = { &__bd, 1 };
|
|
164
|
+
(void)spi_write(DEVICE_DT_GET(DT_NODELABEL(${bus})), &__tc_pnl_cfg8, &__sd);
|
|
165
|
+
px += __chunk;
|
|
166
|
+
count -= __chunk;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
`
|
|
170
|
+
: `
|
|
171
|
+
// Pack count rgb565 pixels into the row3 scratch buffer as 18-bit (666) wire
|
|
172
|
+
// format: (r<<3, g<<2, b<<3) — R,G,B byte order, verified correct on this
|
|
173
|
+
// panel in 18-bit mode. The caller then streams the buffer with the 8-bit
|
|
174
|
+
// config (one row at a time; the buffer holds maxDim pixels).
|
|
175
|
+
static void ${packFn}(const uint16_t* px, uint32_t count) {
|
|
176
|
+
for (uint32_t i = 0; i < count; i++) {
|
|
177
|
+
uint16_t c = px[i];
|
|
178
|
+
${rowBuf}[i * 3] = static_cast<uint8_t>((c >> 8) & 0xF8u);
|
|
179
|
+
${rowBuf}[i * 3 + 1] = static_cast<uint8_t>((c >> 3) & 0xFCu);
|
|
180
|
+
${rowBuf}[i * 3 + 2] = static_cast<uint8_t>((c << 3) & 0xF8u);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Stream count rgb565 pixels to the panel (converted to 18-bit, chunked
|
|
185
|
+
// through the row3 scratch). Caller holds the RAMWR burst.
|
|
186
|
+
static void ${pixelsFn}(const uint16_t* px, uint32_t count) {
|
|
187
|
+
while (count > 0) {
|
|
188
|
+
uint32_t __chunk = (count > ${maxDim}) ? ${maxDim} : count;
|
|
189
|
+
${packFn}(px, __chunk);
|
|
190
|
+
struct spi_buf __bd = { ${rowBuf}, static_cast<size_t>(__chunk) * 3U };
|
|
191
|
+
struct spi_buf_set __sd = { &__bd, 1 };
|
|
192
|
+
(void)spi_write(DEVICE_DT_GET(DT_NODELABEL(${bus})), &__tc_pnl_cfg8, &__sd);
|
|
193
|
+
px += __chunk;
|
|
194
|
+
count -= __chunk;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
`;
|
|
198
|
+
// Per-controller solid-fill. Both tile one built row into the block buffer
|
|
199
|
+
// and stream it in multi-row chunks; only the color encoding differs.
|
|
200
|
+
const fillRectFn = isIli9341
|
|
201
|
+
? `
|
|
202
|
+
static void __tc_op_fillRect(void* /*ctx*/, int16_t x, int16_t y, int16_t rw, int16_t rh, uint16_t c) {
|
|
203
|
+
if (rw <= 0 || rh <= 0) return;
|
|
204
|
+
uint8_t __b0 = static_cast<uint8_t>(c >> 8);
|
|
205
|
+
uint8_t __b1 = static_cast<uint8_t>(c);
|
|
206
|
+
// Build one row, then tile it into the block buffer.
|
|
207
|
+
for (int16_t i = 0; i < rw; i++) {
|
|
208
|
+
${rowBuf}[i * 2] = __b0;
|
|
209
|
+
${rowBuf}[i * 2 + 1] = __b1;
|
|
210
|
+
}
|
|
211
|
+
size_t rowBytes = static_cast<size_t>(rw) * 2U;
|
|
212
|
+
for (int16_t r = 0; r < __TC_FILL_ROWS; r++) {
|
|
213
|
+
memcpy(&${blockBuf}[static_cast<size_t>(r) * rowBytes], ${rowBuf}, rowBytes);
|
|
214
|
+
}
|
|
215
|
+
__tc_pnl_set_window(x, y, rw, rh);
|
|
216
|
+
__tc_pnl_ramwr_begin();
|
|
217
|
+
int16_t remaining = rh;
|
|
218
|
+
while (remaining > 0) {
|
|
219
|
+
int16_t chunk = (remaining > __TC_FILL_ROWS) ? __TC_FILL_ROWS : remaining;
|
|
220
|
+
struct spi_buf __bd = { ${blockBuf}, static_cast<size_t>(chunk) * rowBytes };
|
|
221
|
+
struct spi_buf_set __sd = { &__bd, 1 };
|
|
222
|
+
(void)spi_write(DEVICE_DT_GET(DT_NODELABEL(${bus})), &__tc_pnl_cfg8, &__sd);
|
|
223
|
+
remaining -= chunk;
|
|
224
|
+
}
|
|
225
|
+
__tc_pnl_ramwr_end();
|
|
226
|
+
}
|
|
227
|
+
`
|
|
228
|
+
: `
|
|
229
|
+
// Fill a rect row-by-row using the one-row 18-bit scratch buffer. This is the
|
|
230
|
+
// hot path for background clears and large fills; building the color into the
|
|
231
|
+
// reused buffer and writing each row keeps memory bounded.
|
|
232
|
+
// Fill a rect with a solid color. The 18-bit row is tiled into the block buffer
|
|
233
|
+
// (__TC_FILL_ROWS rows), then the whole rect is sent in multi-row spi_write
|
|
234
|
+
// chunks. A full 480x320 clear is ~40 writes instead of ~320, dropping it from
|
|
235
|
+
// ~110ms to ~15ms — the ESP32 SPI driver's per-transaction overhead (not SPI
|
|
236
|
+
// bandwidth) is the binding cost, so fewer/larger writes win. Scatter-gather
|
|
237
|
+
// descriptor lists tested slower (the driver walks each descriptor), so this
|
|
238
|
+
// uses one contiguous buffer per write.
|
|
239
|
+
static void __tc_op_fillRect(void* /*ctx*/, int16_t x, int16_t y, int16_t rw, int16_t rh, uint16_t c) {
|
|
240
|
+
if (rw <= 0 || rh <= 0) return;
|
|
241
|
+
uint8_t __b0 = static_cast<uint8_t>((c >> 8) & 0xF8u);
|
|
242
|
+
uint8_t __b1 = static_cast<uint8_t>((c >> 3) & 0xFCu);
|
|
243
|
+
uint8_t __b2 = static_cast<uint8_t>((c << 3) & 0xF8u);
|
|
244
|
+
// Build one 18-bit row, then tile it into the block buffer.
|
|
245
|
+
for (int16_t i = 0; i < rw; i++) {
|
|
246
|
+
${rowBuf}[i * 3] = __b0;
|
|
247
|
+
${rowBuf}[i * 3 + 1] = __b1;
|
|
248
|
+
${rowBuf}[i * 3 + 2] = __b2;
|
|
249
|
+
}
|
|
250
|
+
size_t rowBytes = static_cast<size_t>(rw) * 3U;
|
|
251
|
+
for (int16_t r = 0; r < __TC_FILL_ROWS; r++) {
|
|
252
|
+
memcpy(&${blockBuf}[static_cast<size_t>(r) * rowBytes], ${rowBuf}, rowBytes);
|
|
253
|
+
}
|
|
254
|
+
__tc_pnl_set_window(x, y, rw, rh);
|
|
255
|
+
__tc_pnl_ramwr_begin();
|
|
256
|
+
int16_t remaining = rh;
|
|
257
|
+
while (remaining > 0) {
|
|
258
|
+
int16_t chunk = (remaining > __TC_FILL_ROWS) ? __TC_FILL_ROWS : remaining;
|
|
259
|
+
struct spi_buf __bd = { ${blockBuf}, static_cast<size_t>(chunk) * rowBytes };
|
|
260
|
+
struct spi_buf_set __sd = { &__bd, 1 };
|
|
261
|
+
(void)spi_write(DEVICE_DT_GET(DT_NODELABEL(${bus})), &__tc_pnl_cfg8, &__sd);
|
|
262
|
+
remaining -= chunk;
|
|
263
|
+
}
|
|
264
|
+
__tc_pnl_ramwr_end();
|
|
265
|
+
}
|
|
266
|
+
`;
|
|
267
|
+
// Per-controller init table. Both are byte-for-byte Adafruit sequences
|
|
268
|
+
// emitted as (cmd, len, data, delay) records walked in display_init.
|
|
269
|
+
const initBlock = isIli9341
|
|
270
|
+
? `
|
|
271
|
+
// ── Panel init ──────────────────────────────────────────────────────────
|
|
272
|
+
// Adafruit ILI9341 init sequence (initILI9341), byte for byte: SWRESET,
|
|
273
|
+
// manufacturer/power/gamma registers, MADCTL 0x28 (MV landscape + BGR, the
|
|
274
|
+
// same convention as the ST7796S path), COLMOD 0x55 (16-bit RGB565 — the
|
|
275
|
+
// native wire format of the pack565 transport), SLPOUT (150ms), DISPON
|
|
276
|
+
// (150ms), INVON. INVON is included because the common ILI9341 SPI modules
|
|
277
|
+
// (2.2"/2.4" TFTs) ship with an inverted panel; the in-tree binding's
|
|
278
|
+
// display-inversion property mirrors this for the stock driver.
|
|
279
|
+
struct __tc_pnl_init_cmd { uint8_t cmd; uint8_t len; const uint8_t* data; uint16_t delay_ms; };
|
|
280
|
+
static const uint8_t __tc_pnl_i1[] = {0x03, 0x80, 0x02};
|
|
281
|
+
static const uint8_t __tc_pnl_i2[] = {0x00, 0xC1, 0x30};
|
|
282
|
+
static const uint8_t __tc_pnl_i3[] = {0x64, 0x03, 0x12, 0x81};
|
|
283
|
+
static const uint8_t __tc_pnl_i4[] = {0x85, 0x00, 0x78};
|
|
284
|
+
static const uint8_t __tc_pnl_i5[] = {0x39, 0x2C, 0x00, 0x34, 0x02};
|
|
285
|
+
static const uint8_t __tc_pnl_i6[] = {0x20};
|
|
286
|
+
static const uint8_t __tc_pnl_i7[] = {0x00, 0x00};
|
|
287
|
+
static const uint8_t __tc_pnl_i8[] = {0x23};
|
|
288
|
+
static const uint8_t __tc_pnl_i9[] = {0x10};
|
|
289
|
+
static const uint8_t __tc_pnl_i10[] = {0x3E, 0x28};
|
|
290
|
+
static const uint8_t __tc_pnl_i11[] = {0x86};
|
|
291
|
+
static const uint8_t __tc_pnl_i12[] = {0x28};
|
|
292
|
+
static const uint8_t __tc_pnl_i13[] = {0x55};
|
|
293
|
+
static const uint8_t __tc_pnl_i14[] = {0x00, 0x18};
|
|
294
|
+
static const uint8_t __tc_pnl_i15[] = {0x08, 0x82, 0x27};
|
|
295
|
+
static const uint8_t __tc_pnl_i16[] = {0x00};
|
|
296
|
+
static const uint8_t __tc_pnl_i17[] = {0x01};
|
|
297
|
+
static const uint8_t __tc_pnl_i18[] = {0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, 0x4E, 0xF1, 0x37, 0x07, 0x10, 0x03, 0x0E, 0x09, 0x00};
|
|
298
|
+
static const uint8_t __tc_pnl_i19[] = {0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, 0x31, 0xC1, 0x48, 0x08, 0x0F, 0x0C, 0x31, 0x36, 0x0F};
|
|
299
|
+
static const struct __tc_pnl_init_cmd __tc_pnl_init_seq[] = {
|
|
300
|
+
{0x01, 0, NULL, 150}, // SWRESET
|
|
301
|
+
{0xEF, 3, __tc_pnl_i1, 0},
|
|
302
|
+
{0xCF, 3, __tc_pnl_i2, 0},
|
|
303
|
+
{0xED, 4, __tc_pnl_i3, 0},
|
|
304
|
+
{0xE8, 3, __tc_pnl_i4, 0},
|
|
305
|
+
{0xCB, 5, __tc_pnl_i5, 0},
|
|
306
|
+
{0xF7, 1, __tc_pnl_i6, 0},
|
|
307
|
+
{0xEA, 2, __tc_pnl_i7, 0},
|
|
308
|
+
{0xC0, 1, __tc_pnl_i8, 0}, // PWCTRL1
|
|
309
|
+
{0xC1, 1, __tc_pnl_i9, 0}, // PWCTRL2
|
|
310
|
+
{0xC5, 2, __tc_pnl_i10, 0}, // VMCTRL1
|
|
311
|
+
{0xC7, 1, __tc_pnl_i11, 0}, // VMCTRL2
|
|
312
|
+
{0x36, 1, __tc_pnl_i12, 0}, // MADCTL 0x28: MV (landscape) + BGR=1
|
|
313
|
+
{0x3A, 1, __tc_pnl_i13, 0}, // COLMOD 0x55 (16-bit RGB565)
|
|
314
|
+
{0xB1, 2, __tc_pnl_i14, 0}, // FRMCTR1
|
|
315
|
+
{0xB6, 3, __tc_pnl_i15, 0}, // DISCTRL
|
|
316
|
+
{0xF2, 1, __tc_pnl_i16, 0}, // ENABLE3G off
|
|
317
|
+
{0x26, 1, __tc_pnl_i17, 0}, // GAMSET gamma curve 1
|
|
318
|
+
{0xE0, 15, __tc_pnl_i18, 0}, // PGAMCTRL
|
|
319
|
+
{0xE1, 15, __tc_pnl_i19, 0}, // NGAMCTRL
|
|
320
|
+
{0x11, 0, NULL, 150}, // SLPOUT (sleep out — 120ms typical)
|
|
321
|
+
{0x29, 0, NULL, 150}, // DISPON
|
|
322
|
+
{0x21, 0, NULL, 0}, // INVON (common ILI9341 modules ship inverted)
|
|
323
|
+
};
|
|
324
|
+
`
|
|
325
|
+
: `
|
|
326
|
+
// ── Panel init ──────────────────────────────────────────────────────────
|
|
327
|
+
// Adafruit ST7796S init sequence (demo-st lib fork), byte for byte: hw reset
|
|
328
|
+
// pulse, SWRESET, manufacturer unlock, VCOM/MADCTL/COLMOD/porch registers,
|
|
329
|
+
// lock, SLPOUT (150ms), DISPON (150ms), INVOFF. MADCTL 0x28 = MV (rotation 1
|
|
330
|
+
// landscape) + BGR=1. BGR=1 makes the controller route data R/B to the
|
|
331
|
+
// B/R subpixels (verified: red data shows blue with BGR=1), which combined
|
|
332
|
+
// with a lossless R/B data swap renders the UI correctly; BGR=0 leaves a
|
|
333
|
+
// half-lossy G/B quirk on this clone controller.
|
|
334
|
+
struct __tc_pnl_init_cmd { uint8_t cmd; uint8_t len; const uint8_t* data; uint16_t delay_ms; };
|
|
335
|
+
static const uint8_t __tc_pnl_i1[] = {0xC3};
|
|
336
|
+
static const uint8_t __tc_pnl_i2[] = {0x96};
|
|
337
|
+
static const uint8_t __tc_pnl_i3[] = {0x1C};
|
|
338
|
+
static const uint8_t __tc_pnl_i4[] = {0x28};
|
|
339
|
+
static const uint8_t __tc_pnl_i5[] = {0x66};
|
|
340
|
+
static const uint8_t __tc_pnl_i6[] = {0x80};
|
|
341
|
+
static const uint8_t __tc_pnl_i7[] = {0x00};
|
|
342
|
+
static const uint8_t __tc_pnl_i8[] = {0x80, 0x02, 0x3B};
|
|
343
|
+
static const uint8_t __tc_pnl_i9[] = {0xC6};
|
|
344
|
+
static const uint8_t __tc_pnl_i10[] = {0x69};
|
|
345
|
+
static const uint8_t __tc_pnl_i11[] = {0x3C};
|
|
346
|
+
static const struct __tc_pnl_init_cmd __tc_pnl_init_seq[] = {
|
|
347
|
+
{0x01, 0, NULL, 150}, // SWRESET
|
|
348
|
+
{0xF0, 1, __tc_pnl_i1, 0}, // unlock manufacturer
|
|
349
|
+
{0xF0, 1, __tc_pnl_i2, 0},
|
|
350
|
+
{0xC5, 1, __tc_pnl_i3, 0}, // VCOM control
|
|
351
|
+
{0x36, 1, __tc_pnl_i4, 0}, // MADCTL 0x28: MV (rotation 1) + BGR=1
|
|
352
|
+
{0x3A, 1, __tc_pnl_i5, 0}, // COLMOD 0x66 (18-bit, 262K) — clean channel routing
|
|
353
|
+
{0xB0, 1, __tc_pnl_i6, 0}, // interface control
|
|
354
|
+
{0xB4, 1, __tc_pnl_i7, 0}, // inversion control
|
|
355
|
+
{0xB6, 3, __tc_pnl_i8, 0}, // display function control
|
|
356
|
+
{0xB7, 1, __tc_pnl_i9, 0}, // entry mode
|
|
357
|
+
{0xF0, 1, __tc_pnl_i10, 0}, // lock manufacturer
|
|
358
|
+
{0xF0, 1, __tc_pnl_i11, 0},
|
|
359
|
+
{0x11, 0, NULL, 150}, // SLPOUT (sleep out — 120ms typical)
|
|
360
|
+
{0x29, 0, NULL, 150}, // DISPON
|
|
361
|
+
{0x20, 0, NULL, 0}, // INVOFF (non-inverted at power-on)
|
|
362
|
+
};
|
|
363
|
+
`;
|
|
98
364
|
const functions = `
|
|
99
365
|
// ── Direct panel transport ──────────────────────────────────────────────
|
|
100
366
|
// GPIOs: CS/DC/RST driven manually; CS stays LOW for the whole command+data
|
|
@@ -102,11 +368,11 @@ export function zephyrUiDisplayAdapter(profile, readback = {}) {
|
|
|
102
368
|
// Adafruit ST77xx protocol this panel requires. The SPI config carries no CS
|
|
103
369
|
// (cs_is_gpio = false -> the ESP32 driver's hardware CSEL pin is left idle;
|
|
104
370
|
// it is not connected to the panel).
|
|
105
|
-
static const struct gpio_dt_spec __tc_pnl_cs = GPIO_DT_SPEC_GET(DT_NODELABEL(
|
|
106
|
-
static const struct gpio_dt_spec __tc_pnl_dc = GPIO_DT_SPEC_GET(DT_NODELABEL(
|
|
107
|
-
static const struct gpio_dt_spec __tc_pnl_rst = GPIO_DT_SPEC_GET(DT_NODELABEL(
|
|
371
|
+
static const struct gpio_dt_spec __tc_pnl_cs = GPIO_DT_SPEC_GET(DT_NODELABEL(${bus}), cs_gpios);
|
|
372
|
+
static const struct gpio_dt_spec __tc_pnl_dc = GPIO_DT_SPEC_GET(DT_NODELABEL(${bridge}), dc_gpios);
|
|
373
|
+
static const struct gpio_dt_spec __tc_pnl_rst = GPIO_DT_SPEC_GET(DT_NODELABEL(${bridge}), reset_gpios);
|
|
108
374
|
|
|
109
|
-
// 8-bit frames for commands/parameters and 18-bit (3 bytes/pixel) pixel data.
|
|
375
|
+
// 8-bit frames for commands/parameters and ${isIli9341 ? '16-bit (2 bytes/pixel)' : '18-bit (3 bytes/pixel)'} pixel data.
|
|
110
376
|
static struct spi_config __tc_pnl_cfg8 = {
|
|
111
377
|
.frequency = DT_PROP(DT_NODELABEL(${dtLabel}), mipi_max_frequency),
|
|
112
378
|
.operation = SPI_OP_MODE_MASTER | SPI_WORD_SET(8),
|
|
@@ -129,12 +395,12 @@ static void __tc_pnl_cmd(uint8_t cmd, const uint8_t* data, uint16_t len) {
|
|
|
129
395
|
struct spi_buf_set __sc = { &__bc, 1 };
|
|
130
396
|
__tc_pnl_cs_assert();
|
|
131
397
|
gpio_pin_set_dt(&__tc_pnl_dc, 0);
|
|
132
|
-
(void)spi_write(DEVICE_DT_GET(DT_NODELABEL(
|
|
398
|
+
(void)spi_write(DEVICE_DT_GET(DT_NODELABEL(${bus})), &__tc_pnl_cfg8, &__sc);
|
|
133
399
|
if (len > 0) {
|
|
134
400
|
struct spi_buf __bd = { const_cast<uint8_t*>(data), len };
|
|
135
401
|
struct spi_buf_set __sd = { &__bd, 1 };
|
|
136
402
|
gpio_pin_set_dt(&__tc_pnl_dc, 1);
|
|
137
|
-
(void)spi_write(DEVICE_DT_GET(DT_NODELABEL(
|
|
403
|
+
(void)spi_write(DEVICE_DT_GET(DT_NODELABEL(${bus})), &__tc_pnl_cfg8, &__sd);
|
|
138
404
|
}
|
|
139
405
|
__tc_pnl_cs_release();
|
|
140
406
|
}
|
|
@@ -146,7 +412,7 @@ static void __tc_pnl_ramwr_begin(void) {
|
|
|
146
412
|
struct spi_buf_set __sc = { &__bc, 1 };
|
|
147
413
|
__tc_pnl_cs_assert();
|
|
148
414
|
gpio_pin_set_dt(&__tc_pnl_dc, 0);
|
|
149
|
-
(void)spi_write(DEVICE_DT_GET(DT_NODELABEL(
|
|
415
|
+
(void)spi_write(DEVICE_DT_GET(DT_NODELABEL(${bus})), &__tc_pnl_cfg8, &__sc);
|
|
150
416
|
gpio_pin_set_dt(&__tc_pnl_dc, 1);
|
|
151
417
|
}
|
|
152
418
|
|
|
@@ -169,11 +435,11 @@ static uint16_t __tc_pnl_read_scanline(void) {
|
|
|
169
435
|
struct spi_buf_set __sr = { &__br, 1 };
|
|
170
436
|
__tc_pnl_cs_assert();
|
|
171
437
|
gpio_pin_set_dt(&__tc_pnl_dc, 0);
|
|
172
|
-
int __cmd_err = spi_write(DEVICE_DT_GET(DT_NODELABEL(
|
|
438
|
+
int __cmd_err = spi_write(DEVICE_DT_GET(DT_NODELABEL(${bus})), &__tc_pnl_cfg8, &__sc);
|
|
173
439
|
int __read_err = 0;
|
|
174
440
|
if (__cmd_err == 0) {
|
|
175
441
|
gpio_pin_set_dt(&__tc_pnl_dc, 1);
|
|
176
|
-
__read_err = spi_transceive(DEVICE_DT_GET(DT_NODELABEL(
|
|
442
|
+
__read_err = spi_transceive(DEVICE_DT_GET(DT_NODELABEL(${bus})), &__tc_pnl_cfg8, &__st, &__sr);
|
|
177
443
|
}
|
|
178
444
|
__tc_pnl_cs_release();
|
|
179
445
|
if (__cmd_err != 0 || __read_err != 0) return 0xFFFFu;
|
|
@@ -197,34 +463,7 @@ static void __tc_pnl_wait_for_safe_rect(int16_t y, int16_t rh) {
|
|
|
197
463
|
k_msleep(0);
|
|
198
464
|
}
|
|
199
465
|
}
|
|
200
|
-
|
|
201
|
-
// Pack count rgb565 pixels into the row3 scratch buffer as 18-bit (666) wire
|
|
202
|
-
// format: (r<<3, g<<2, b<<3) — R,G,B byte order, verified correct on this
|
|
203
|
-
// panel in 18-bit mode. The caller then streams the buffer with the 8-bit
|
|
204
|
-
// config (one row at a time; the buffer holds maxDim pixels).
|
|
205
|
-
static void __tc_pnl_pack666(const uint16_t* px, uint32_t count) {
|
|
206
|
-
for (uint32_t i = 0; i < count; i++) {
|
|
207
|
-
uint16_t c = px[i];
|
|
208
|
-
__tc_display_row3[i * 3] = static_cast<uint8_t>((c >> 8) & 0xF8u);
|
|
209
|
-
__tc_display_row3[i * 3 + 1] = static_cast<uint8_t>((c >> 3) & 0xFCu);
|
|
210
|
-
__tc_display_row3[i * 3 + 2] = static_cast<uint8_t>((c << 3) & 0xF8u);
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
// Stream count rgb565 pixels to the panel (converted to 18-bit, chunked
|
|
215
|
-
// through the row3 scratch). Caller holds the RAMWR burst.
|
|
216
|
-
static void __tc_pnl_pixels666(const uint16_t* px, uint32_t count) {
|
|
217
|
-
while (count > 0) {
|
|
218
|
-
uint32_t __chunk = (count > ${maxDim}) ? ${maxDim} : count;
|
|
219
|
-
__tc_pnl_pack666(px, __chunk);
|
|
220
|
-
struct spi_buf __bd = { __tc_display_row3, static_cast<size_t>(__chunk) * 3U };
|
|
221
|
-
struct spi_buf_set __sd = { &__bd, 1 };
|
|
222
|
-
(void)spi_write(DEVICE_DT_GET(DT_NODELABEL(spi2)), &__tc_pnl_cfg8, &__sd);
|
|
223
|
-
px += __chunk;
|
|
224
|
-
count -= __chunk;
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
|
|
466
|
+
${pixelHelpers}
|
|
228
467
|
// Set the address window. Coordinates are in the effective (rotated) UI
|
|
229
468
|
// space; the panel's MADCTL (rotation 1: MV) maps them onto the native
|
|
230
469
|
// 320x480 raster, so CASET/RASET take the UI x/y ranges directly.
|
|
@@ -271,12 +510,12 @@ static void __tc_op_setAddrWindow(void* /*ctx*/, int16_t x, int16_t y, int16_t w
|
|
|
271
510
|
// Push the stashed rect's worth of rgb565 pixels. Called right after
|
|
272
511
|
// setAddrWindow with exactly (aw_w * aw_h) pixels. The caller's buffer is
|
|
273
512
|
// never mutated (scroll canvases persist across frames), so pixels are
|
|
274
|
-
// converted in chunks through the
|
|
513
|
+
// converted in chunks through the row${bpp} scratch buffer.
|
|
275
514
|
static void __tc_op_writePixels(void* /*ctx*/, const uint16_t* px, uint32_t n) {
|
|
276
515
|
if (n == 0U) return;
|
|
277
516
|
__tc_pnl_set_window(__tc_aw_x, __tc_aw_y, __tc_aw_w, __tc_aw_h);
|
|
278
517
|
__tc_pnl_ramwr_begin();
|
|
279
|
-
|
|
518
|
+
${pixelsFn}(px, n);
|
|
280
519
|
__tc_pnl_ramwr_end();
|
|
281
520
|
}
|
|
282
521
|
|
|
@@ -285,48 +524,10 @@ static void __tc_op_writePixel(void* /*ctx*/, int16_t x, int16_t y, uint16_t c)
|
|
|
285
524
|
uint16_t __c = c;
|
|
286
525
|
__tc_pnl_set_window(x, y, 1, 1);
|
|
287
526
|
__tc_pnl_ramwr_begin();
|
|
288
|
-
|
|
527
|
+
${pixelsFn}(&__c, 1);
|
|
289
528
|
__tc_pnl_ramwr_end();
|
|
290
529
|
}
|
|
291
|
-
|
|
292
|
-
// Fill a rect row-by-row using the one-row 18-bit scratch buffer. This is the
|
|
293
|
-
// hot path for background clears and large fills; building the color into the
|
|
294
|
-
// reused buffer and writing each row keeps memory bounded.
|
|
295
|
-
// Fill a rect with a solid color. The 18-bit row is tiled into the block buffer
|
|
296
|
-
// (__TC_FILL_ROWS rows), then the whole rect is sent in multi-row spi_write
|
|
297
|
-
// chunks. A full 480x320 clear is ~40 writes instead of ~320, dropping it from
|
|
298
|
-
// ~110ms to ~15ms — the ESP32 SPI driver's per-transaction overhead (not SPI
|
|
299
|
-
// bandwidth) is the binding cost, so fewer/larger writes win. Scatter-gather
|
|
300
|
-
// descriptor lists tested slower (the driver walks each descriptor), so this
|
|
301
|
-
// uses one contiguous buffer per write.
|
|
302
|
-
static void __tc_op_fillRect(void* /*ctx*/, int16_t x, int16_t y, int16_t rw, int16_t rh, uint16_t c) {
|
|
303
|
-
if (rw <= 0 || rh <= 0) return;
|
|
304
|
-
uint8_t __b0 = static_cast<uint8_t>((c >> 8) & 0xF8u);
|
|
305
|
-
uint8_t __b1 = static_cast<uint8_t>((c >> 3) & 0xFCu);
|
|
306
|
-
uint8_t __b2 = static_cast<uint8_t>((c << 3) & 0xF8u);
|
|
307
|
-
// Build one 18-bit row, then tile it into the block buffer.
|
|
308
|
-
for (int16_t i = 0; i < rw; i++) {
|
|
309
|
-
__tc_display_row3[i * 3] = __b0;
|
|
310
|
-
__tc_display_row3[i * 3 + 1] = __b1;
|
|
311
|
-
__tc_display_row3[i * 3 + 2] = __b2;
|
|
312
|
-
}
|
|
313
|
-
size_t rowBytes = static_cast<size_t>(rw) * 3U;
|
|
314
|
-
for (int16_t r = 0; r < __TC_FILL_ROWS; r++) {
|
|
315
|
-
memcpy(&__tc_display_block3[static_cast<size_t>(r) * rowBytes], __tc_display_row3, rowBytes);
|
|
316
|
-
}
|
|
317
|
-
__tc_pnl_set_window(x, y, rw, rh);
|
|
318
|
-
__tc_pnl_ramwr_begin();
|
|
319
|
-
int16_t remaining = rh;
|
|
320
|
-
while (remaining > 0) {
|
|
321
|
-
int16_t chunk = (remaining > __TC_FILL_ROWS) ? __TC_FILL_ROWS : remaining;
|
|
322
|
-
struct spi_buf __bd = { __tc_display_block3, static_cast<size_t>(chunk) * rowBytes };
|
|
323
|
-
struct spi_buf_set __sd = { &__bd, 1 };
|
|
324
|
-
(void)spi_write(DEVICE_DT_GET(DT_NODELABEL(spi2)), &__tc_pnl_cfg8, &__sd);
|
|
325
|
-
remaining -= chunk;
|
|
326
|
-
}
|
|
327
|
-
__tc_pnl_ramwr_end();
|
|
328
|
-
}
|
|
329
|
-
|
|
530
|
+
${fillRectFn}
|
|
330
531
|
static int16_t __tc_op_width(void* /*ctx*/) { return ${w}; }
|
|
331
532
|
static int16_t __tc_op_height(void* /*ctx*/) { return ${h}; }
|
|
332
533
|
|
|
@@ -348,45 +549,7 @@ const CuttlefishPanelOps __tc_display_ops = {
|
|
|
348
549
|
|
|
349
550
|
// The live display target: a CuttlefishGFX driven by the panel-ops vtable.
|
|
350
551
|
CuttlefishGFX __tc_display(&__tc_display_ops, nullptr);
|
|
351
|
-
|
|
352
|
-
// ── Panel init ──────────────────────────────────────────────────────────
|
|
353
|
-
// Adafruit ST7796S init sequence (demo-st lib fork), byte for byte: hw reset
|
|
354
|
-
// pulse, SWRESET, manufacturer unlock, VCOM/MADCTL/COLMOD/porch registers,
|
|
355
|
-
// lock, SLPOUT (150ms), DISPON (150ms), INVOFF. MADCTL 0x28 = MV (rotation 1
|
|
356
|
-
// landscape) + BGR=1. BGR=1 makes the controller route data R/B to the
|
|
357
|
-
// B/R subpixels (verified: red data shows blue with BGR=1), which combined
|
|
358
|
-
// with a lossless R/B data swap renders the UI correctly; BGR=0 leaves a
|
|
359
|
-
// half-lossy G/B quirk on this clone controller.
|
|
360
|
-
struct __tc_pnl_init_cmd { uint8_t cmd; uint8_t len; const uint8_t* data; uint16_t delay_ms; };
|
|
361
|
-
static const uint8_t __tc_pnl_i1[] = {0xC3};
|
|
362
|
-
static const uint8_t __tc_pnl_i2[] = {0x96};
|
|
363
|
-
static const uint8_t __tc_pnl_i3[] = {0x1C};
|
|
364
|
-
static const uint8_t __tc_pnl_i4[] = {0x28};
|
|
365
|
-
static const uint8_t __tc_pnl_i5[] = {0x66};
|
|
366
|
-
static const uint8_t __tc_pnl_i6[] = {0x80};
|
|
367
|
-
static const uint8_t __tc_pnl_i7[] = {0x00};
|
|
368
|
-
static const uint8_t __tc_pnl_i8[] = {0x80, 0x02, 0x3B};
|
|
369
|
-
static const uint8_t __tc_pnl_i9[] = {0xC6};
|
|
370
|
-
static const uint8_t __tc_pnl_i10[] = {0x69};
|
|
371
|
-
static const uint8_t __tc_pnl_i11[] = {0x3C};
|
|
372
|
-
static const struct __tc_pnl_init_cmd __tc_pnl_init_seq[] = {
|
|
373
|
-
{0x01, 0, NULL, 150}, // SWRESET
|
|
374
|
-
{0xF0, 1, __tc_pnl_i1, 0}, // unlock manufacturer
|
|
375
|
-
{0xF0, 1, __tc_pnl_i2, 0},
|
|
376
|
-
{0xC5, 1, __tc_pnl_i3, 0}, // VCOM control
|
|
377
|
-
{0x36, 1, __tc_pnl_i4, 0}, // MADCTL 0x28: MV (rotation 1) + BGR=1
|
|
378
|
-
{0x3A, 1, __tc_pnl_i5, 0}, // COLMOD 0x66 (18-bit, 262K) — clean channel routing
|
|
379
|
-
{0xB0, 1, __tc_pnl_i6, 0}, // interface control
|
|
380
|
-
{0xB4, 1, __tc_pnl_i7, 0}, // inversion control
|
|
381
|
-
{0xB6, 3, __tc_pnl_i8, 0}, // display function control
|
|
382
|
-
{0xB7, 1, __tc_pnl_i9, 0}, // entry mode
|
|
383
|
-
{0xF0, 1, __tc_pnl_i10, 0}, // lock manufacturer
|
|
384
|
-
{0xF0, 1, __tc_pnl_i11, 0},
|
|
385
|
-
{0x11, 0, NULL, 150}, // SLPOUT (sleep out — 120ms typical)
|
|
386
|
-
{0x29, 0, NULL, 150}, // DISPON
|
|
387
|
-
{0x20, 0, NULL, 0}, // INVOFF (non-inverted at power-on)
|
|
388
|
-
};
|
|
389
|
-
|
|
552
|
+
${initBlock}
|
|
390
553
|
// ── display_init (called from setup) ────────────────────────────────────
|
|
391
554
|
static inline void display_init() {
|
|
392
555
|
printk("TC_DISPLAY: device ready\\n");
|
|
@@ -406,7 +569,7 @@ ${blInit}
|
|
|
406
569
|
if (__tc_pnl_init_seq[i].delay_ms > 0) k_msleep(__tc_pnl_init_seq[i].delay_ms);
|
|
407
570
|
}
|
|
408
571
|
__tc_op_fillRect(nullptr, 0, 0, ${w}, ${h}, 0x0000);
|
|
409
|
-
printk("TC_DISPLAY: direct init done (
|
|
572
|
+
printk("TC_DISPLAY: direct init done (${wireTag}, black fill)\\n");
|
|
410
573
|
}
|
|
411
574
|
|
|
412
575
|
static inline void display_fillScreen(UI_COLOR_T color) {
|
|
@@ -527,6 +690,12 @@ export const zephyrDisplayAdapterGenerator = (display) => {
|
|
|
527
690
|
const profile = ZEPHYR_DISPLAY_PROFILES[display.driver];
|
|
528
691
|
if (!profile)
|
|
529
692
|
return undefined;
|
|
693
|
+
// The UI adapter is RGB565/SPI (TFT) only. Monochrome panels (OLED) use the
|
|
694
|
+
// direct display.* GFX runtime (gfx.ts mono branch) — there is no
|
|
695
|
+
// CuttlefishGFX UI rendering path for mono. Decline so cuttlefish does not
|
|
696
|
+
// emit an incompatible RGB565 adapter for a mono profile.
|
|
697
|
+
if (profile.colorFormat === 'mono')
|
|
698
|
+
return undefined;
|
|
530
699
|
return zephyrUiDisplayAdapter(profile, {
|
|
531
700
|
scanlineSync: display.scanlineSync,
|
|
532
701
|
miso: display.spiPins?.miso,
|
package/dist/doctor.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Verify
|
|
3
|
-
*
|
|
4
|
-
* process.exitCode = 1 on
|
|
2
|
+
* Verify west is installed + responsive, the Zephyr RTOS is inside the supported
|
|
3
|
+
* range, and the configured board target exists in the checkout. Sets
|
|
4
|
+
* process.exitCode = 1 on failure. Thin presenter over checkZephyrEnv.
|
|
5
5
|
*/
|
|
6
6
|
export declare function runDoctor(): void;
|