Skip to main content

Boards & custom hardware

Kog describes each board in one declarative file, board.yaml (schema): the chip, memory, display, touch controller, and pins. Today those descriptions live in the Kog repository (boards/*.yaml). They drive the flash manifest, the Studio picker, and the simulator's board geometry. Each blessed board's runtime image carries a matching hand-written firmware descriptor, which is where its display setup and reserved pins come from. The CLI doesn't read a project's own board.yaml yet. To target a board, flash it with kog flash --board <slug> and set board: '<slug>' in kog.config.ts so the simulator matches its size and shape.

Blessed boards​

These are the boards we test and host prebuilt images for. A scaffolded project's board.yaml names one of them with an extends: line (commented out until you pick):

extends: waveshare-esp32-s3-touch-lcd-1.46b

Current blessed boards:

BoardChipDisplayFlash target
Waveshare ESP32-S3-Touch-LCD-1.46BESP32-S3 (PSRAM)round touch LCDwaveshare-1.46b
Waveshare ESP32-S3-Touch-AMOLED-2.06ESP32-S3 (PSRAM)2.06″ rounded-rect touch AMOLEDwaveshare-amoled-2.06
ESP32-2432S028R "Cheap Yellow Display"ESP32SPI 320×240, resistive touchcyd
ESP32-2432S028R, classic panelESP32same board, ILI9341-generation glass (BGR + mirrored scan)cyd-classic
Which CYD do I have?

The CYD ships in two panel generations with the same silkscreen. You can't tell them apart by looking at the board, or over USB (both are plain ESP32). Flash the standard cyd image first. If the screen comes up left/right mirrored with orange buttons where the UI should be blue, your unit is the classic generation. Reflash with kog flash --board cyd-classic (the browser flasher offers the same choice). Touch works identically on both.

What each board's firmware drives beyond display and touch:

AMOLED-2.061.46BCYD
Battery (expo-battery)AXP2101 gauge——
Brightness (expo-brightness)AMOLED register (DCS)backlight PWMbacklight PWM
Accelerometer, gyroscope (expo-sensors)QMI8658QMI8658 (axes not yet checked on hardware)—
Haptics, Vibrationmotor——
Board keys (useButton)BOOT 0, PWR 10——
Wall clock (clock)PCF85063 RTCPCF85063 RTCSoC counter
microSD (file:///sd/)SD 1-bitSD 1-bit—

A dash means the board doesn't have the part: the API throws or rejects with an error that names the board and the board.yaml entry, and each module's isAvailableAsync() returns false (Device services).

You don't pick between the two ESP32-S3 boards: they're the same chip but ship different flash parts, so kog flash, the browser flasher and Studio read the flash size and choose (32 MB is the AMOLED-2.06, 16 MB the 1.46B). Only when the flash size can't be read do they ask, with --board or the board picker.

Waveshare ESP32-S3-Touch-AMOLED-2.06​

A watch-form board: ESP32-S3R8 with 8 MB octal PSRAM and a 32 MB flash part (the Kog image uses the same 16 MB layout as the 1.46B). The 2.06″ 410×502 CO5300 AMOLED runs at ui_scale: 2, so apps lay out in 205×251 logical px. The glass is a rounded rectangle (corner radius 114 physical px, measured from Waveshare's dimension drawing); useDisplay().safeRect is { x: 15, y: 19, width: 175, height: 213 } in logical px, and <SafeAreaView> keeps content inside it.

What works today:

  • Display and touch: the CO5300 panel and the FT3168 capacitive touch controller (FT5x06-compatible, I2C 0x38). Colors, orientation and tap accuracy have been checked on glass; the touch-test example draws a dot under every press if you want to check your own unit.
  • Brightness: expo-brightness writes the panel's own brightness register. The panel boots at full brightness, and hot reload restores it.
  • Battery: expo-battery reads the AXP2101's fuel gauge and charger state, every 2 seconds. Kog only reads the PMIC: it never switches a power rail or changes the charger settings.
  • Motion: expo-sensors' Accelerometer (g) and Gyroscope (rad/s) read the QMI8658, in the display's frame (x right, y up, z out of the glass; flat on a table reads z ≈ +1).
  • Vibration: expo-haptics and Vibration drive the motor on GPIO 18. It is off at boot and stops on hot reload.
  • Keys: useButton(0) reads the BOOT key (pressed = low) and useButton(10, { activeLow: false }) the PWR key, which the AXP2101 mirrors on SYS_OUT (pressed = high). Holding PWR for several seconds powers the board off; the PMIC does that in hardware. Neither pin is reserved. BOOT is also the download-mode strap, so don't hold it while resetting.
  • Wall clock: the PCF85063 battery RTC. clock.source() returns 'external-rtc', and the time survives a reboot.
  • Flash and the dev loop: kog flash, kog dev hot reload and kog deploy are confirmed on the board.
  • microSD: SD 1-bit over SDMMC, like the 1.46B. Not yet tested on this board (no card on the bench).
  • The rest runs the same ESP32-S3 runtime as the 1.46B: bundled and network images, the 4 MB asset pack, networking, and the 256 KB bundle ceiling.

examples/watch-demo shows all of these on one screen.

Declared, API coming: the speaker and microphones. The firmware reserves their pins now.

Other boards (planned)​

spec/06 plans two more ways to run Kog on hardware that isn't blessed. Neither is available yet:

  • Generic image + board.yaml, no compiling (Tier B): a generic prebuilt image per chip and PSRAM class, configured at boot by a binary blob generated from your board.yaml. Neither the blob nor a generic image exists yet, and kog board validate (schema validation) isn't wired up.
  • Custom firmware build (Tier C): npx kog firmware build would compile a runtime from your board.yaml with a pinned, managed ESP-IDF installed into ~/.kog/toolchains. Today the command exits with "isn't wired up yet".

Until then, supporting a new board means building the firmware from the Kog repository (native/firmware). The runtime's compiled-in drivers today are the ST7789, ILI9341, SPD2010 and CO5300 panels (SPI and QSPI buses) and XPT2046 (SPI), SPD2010 (I2C) and FT3168 (I2C) touch.