Skip to main content
skill CX Codex

esp32c6-lcd147 — Claude Code skill: what it does, how to install

Hardware guides and firmware recipes for the Waveshare ESP32-C6-LCD-1.47 board: PlatformIO configs, ST7789 display setup, shared SPI, and USB console logging.

Install into Claude Code · Skills CLI (Vercel) All methods and platforms ↓
npx skills add alexex1993/mcu-skills --skill esp32c6-lcd147 -a claude-code
Open on GitHub

What esp32c6-lcd147 does

This skill equips coding assistants with board-specific details for the Waveshare ESP32-C6-LCD-1.47 (ESP32-C6FH4, QFN32). It covers pin mapping, memory layout, sdkconfig.defaults, and driver initialization for the 1.47-inch ST7789 panel alongside the onboard WS2812 RGB LED and microSD slot.

It prevents silent debugging dead-ends. For example, generic board definitions treat the chip as having 8 MB flash instead of 4 MB, and the default monitor target routes output to an unconnected UART instead of USB-Serial-JTAG. The skill provides tested snippets for platformio.ini, panel gap calibration, and color inversion.

Hardware constraints dictate software behavior here. The panel and the TF card share the SPI2 lines (MOSI on GPIO6, SCLK on GPIO7). Driving GPIO22 backlight directly at full power causes permanent screen discoloration; the skill enforces LEDC PWM brightness control capped strictly at 50%.

What it helps with

  • configure PlatformIO and ESP-IDF for the 4 MB ESP32-C6FH4 board
  • initialize the ST7789 LCD with color inversion and proper gap offsets
  • mount the microSD card on the shared SPI2 bus alongside the panel
  • route debugging logs to USB-Serial-JTAG via sdkconfig

Example prompts for the agent

  • Generate a platformio.ini and sdkconfig.defaults for Waveshare ESP32-C6-LCD-1.47
  • Show me how to initialize both the ST7789 display and TF card on SPI2
  • Write the LEDC backlight initialization code clamped to 50 percent duty cycle

How to install esp32c6-lcd147

1Skills CLI (Vercel)

npx skills add alexex1993/mcu-skills --skill esp32c6-lcd147 -a claude-code

2Manually: put the files in place

~/.claude/skills/esp32c6-lcd147/SKILL.md

Copy the whole skill folder; for one project use .claude/skills/esp32c6-lcd147/

Step by step, with commands for each platform: How to install skills in Claude Code: five ways

Questions about esp32c6-lcd147

How to install esp32c6-lcd147 in Claude Code?

Run npx skills add alexex1993/mcu-skills --skill esp32c6-lcd147 -a claude-code in your terminal.

What does the esp32c6-lcd147 skill do?

It injects hardware reference data, recipes, and setup rules for Waveshare's ESP32-C6 1.47-inch display board into your AI coding assistant.

Why is the LCD backlight limited to 50% PWM?

Direct GPIO high levels or excessive brightness overheat the liquid crystal panel, leaving permanent dark shadows. Driving GPIO22 through LEDC PWM with a strict 50% limit protects the hardware.

Source text

SKILL.md · MIT
---
name: esp32c6-lcd147
description: Firmware development for the Waveshare ESP32-C6-LCD-1.47 board (ESP32-C6FH4, QFN32) — its 1.47" 172x320 ST7789 LCD, WS2812 RGB LED, microSD/TF slot, USB-Serial-JTAG console, Wi-Fi 6/BLE/802.15.4 radio, and the ESP-IDF + PlatformIO setup around them. Use when working on this board or the ESP32-C6-LCD-1.47-M variant (SKU 28563 / 30381, WS-28563): project setup, platformio.ini and sdkconfig, pin mapping and strapping pins, LCD or SD bring-up on the shared SPI bus, backlight brightness, display frame rate, flashing over Type-C, or debugging why something on the board does not work.
---

# Waveshare ESP32-C6-LCD-1.47

Board-specific firmware knowledge. Most failure modes on this board are silent — the
firmware runs, the panel lights up, and something is subtly wrong — so read the
reference file rather than guessing.

- `reference/board-hardware.md` — the complete board reference: pin table, reset-time
  pin states, strapping analysis, free pins, peripheral availability, power budget,
  memory and partitions, the display's quirks (Part I), **plus** a development guide
  (Part II: §10 toolchain, §11 sdkconfig, §12 flashing, §13 peripheral cookbook,
  §14 symptom → cause → fix table).
- `reference/recipes.md` — copy-paste code: `platformio.ini`, `sdkconfig.defaults`,
  `board.h`, LCD bring-up, LEDC backlight, frame presentation, partial redraw, the
  WS2812 driver, TF card on the shared bus, ADC, the BOOT button, font generation.
- `reference/esp32c6-soc.md` — the ESP32-C6 silicon datasheet digest, for chip-level
  questions: IO MUX and LP IO tables, boot straps, memory, every peripheral's feature
  list, electrical and RF characteristics.
- `reference/esp32-family.md` — the rest of the family, for "should this be a different
  ESP32?" questions: what does and does not port between chips, radio and USB capability
  per chip, the RMT generation table (WS2812 under Wi-Fi load), deep-sleep memory and
  ULP/LP-core availability, and a chip-selection table.
- `template/` — a **project that builds clean**, in two variants, plus a scaffold
  script. See `template/README.md`.

## Confirm the board first

Waveshare also sells the **ESP32-C6-Touch-LCD-1.47** — same vendor, same 1.47" 172×320
panel, different board. If the screen responds to a finger, or there is no WS2812 next to
the panel, it is that one: a JD9853 controller instead of the ST7789, an 8 MB C6FH8
instead of the 4 MB C6FH4, a 22-pin header instead of 18, and a pin map in which only
`LCD_CS`, `LCD_DC` and `TF_CS` match this board's. Use the `esp32c6-touch-lcd147` skill
and do not port pin numbers between them — the wrong map gives a dark screen, not an
error.

## Orientation

| | |
|---|---|
| SoC | ESP32-C6FH4, RISC-V RV32IMAC @ 160 MHz + LP core @ 20 MHz, **QFN32, 22 GPIOs** |
| Memory | **4 MB** in-package flash (1 MB default app partition), 512 KB HP SRAM (~320 KB linkable), 16 KB LP SRAM |
| Display | **ST7789 172×320** on **SPI2** — MOSI **GPIO6**, SCLK **GPIO7**, CS GPIO14, DC GPIO15, RST GPIO21, BL GPIO22. Write-only, no MISO |
| Storage | microSD on the **same** SPI2 bus, CS **GPIO4**, MISO **GPIO5**. SPI 1-bit mode only |
| LED | one WS2812-family RGB LED on **GPIO8** (a strapping pin — safe at factory eFuse settings) |
| Buttons | **BOOT** GPIO9, **pressed = low** · **RESET** acts on `CHIP_PU`, not a GPIO |
| USB | Type-C straight to the SoC's USB-Serial-JTAG (GPIO12/13). **No bridge chip, no debug header** — console, flashing and JTAG all share it |
| Free pins | GPIO0, 1, 2, 3, 18, 19, 20, 23. GPIO0–3 are also the only ADC channels and the only deep-sleep wake pins left |
| Radio | Wi-Fi 6 / BLE 5 / 802.15.4, onboard ceramic antenna, nothing to configure |
| Toolchain | PlatformIO 6.1.19 + `platform-espressif32` 7.0.1 + ESP-IDF 6.0.1, `board = esp32-c6-devkitc-1` |

## Rules that prevent the expensive mistakes

Each of these produces a failure that looks like something else.

1. **`CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG=y`** in `sdkconfig.defaults`. Without it the
   console defaults to UART0 on GPIO16/17, which is wired to nothing on this board:
   the monitor is silent while the firmware runs perfectly, and you debug blind.
2. **`board_upload.flash_size = 4MB` + `CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y`.** There is
   no PlatformIO board definition for this board, so it borrows
   `esp32-c6-devkitc-1`, which claims 8 MB. Both lines are needed — they feed
   different tools — or an oversized image links happily and fails to boot.
3. **`esp_lcd_panel_invert_color(panel, true)`.** The IPS panel ships inverted.
   Without it every colour is a photographic negative, which reads as "my RGB565
   packing is broken" and sends you off debugging the wrong thing.
4. **`esp_lcd_panel_set_gap(panel, 34, 0)`.** The 172-pixel glass is centred in the
   ST7789's 240-column RAM: (240 − 172) / 2 = 34. Without it the image is shifted and
   wraps at the edge.
5. **`.data_endian = LCD_RGB_DATA_ENDIAN_BIG`** in the panel config, and byte-swap
   RGB565 **once, at compile time** in the colour macro. Swapping per pixel at runtime
   costs more than the effect being drawn.
6. **`.miso_io_num = -1`** for the panel. It is write-only. A project that also wants
   the SD card must initialise the shared bus with `miso_io_num = 5` instead.
7. **The backlight is PWM, never `gpio_set_level()`.** Waveshare's own warning: above
   50 % duty for extended periods the panel overheats and develops **permanent dark
   shadows**. Drive GPIO22 from an LEDC channel and clamp at 50 %. This is a
   hardware-damage rule, not a style preference.
8. **The LCD and the TF card share MOSI (GPIO6) and SCLK (GPIO7)** and are separated
   only by chip select. Initialise SPI2 **once**; a second `spi_bus_initialize()`
   returns `ESP_ERR_INVALID_STATE`. Adding any SPI device means adding a third CS
   from the free pins, not a second bus.
9. **40 MHz is the pixel-clock ceiling and it is a wiring fact.** The board wires
   MOSI/SCLK onto the pads the IO MUX assigns to SCLK/MOSI, so SPI2 is routed through
   the GPIO Matrix at roughly half the 80 MHz IO-MUX ceiling. No software change
   recovers it.
10. **A full-screen flush is 22 ms → ~45 fps, hard.** 172 × 320 × 2 B = 110,080 B at
    40 MHz. If an animation looks slow this is the wall, not the CPU. See below.
11. **GPIO4–GPIO7 are gone, and they were the interesting ones.** They carry all four
    JTAG pads (so pad-JTAG is impossible — debug over the Type-C port), `ADC1_CH4-6`,
    and the fixed pins of **LP UART and LP I2C** (so neither LP peripheral is
    available while the card slot and display exist).
12. **Never burn `EFUSE_UART_PRINT_CONTROL` or `EFUSE_JTAG_SEL_ENABLE`.** Both hand a
    boot-time decision to a pin that already has a job here — the RGB LED's idle level
    (GPIO8) and the LCD's D/C line (GPIO15). eFuse bits are one-time programmable.
13. **The WS2812 wire order is GRB**, not RGB, and the LED is far brighter than its
    numbers suggest — it sits under clear acrylic beside the panel. Divide by ~10.
14. **Deep-sleep is 7 µA for the SoC, not for the board.** The LDO's quiescent draw,
    the backlight driver and the LED's standby current all add on top. Do not quote
    the datasheet figure for this board.

## When the task is display performance

The bus, not the CPU, is the limit: 110,080 bytes at 40 MHz is 22.0 ms on the wire,
and `gfx_present()` blocks on the transfer-done semaphore so that nothing scribbles
over the framebuffer mid-DMA. That gives a hard ~45 fps for full-screen redraws.

Three moves, in order of payoff:

1. **Redraw less.** `esp_lcd_panel_draw_bitmap()` takes a rectangle. A 172×40 status
   strip is 2.75 ms instead of 22 ms — an 8× win for the common case where only part
   of the UI changed. Coordinates are `(x_start, y_start, x_end, y_end)` with the end
   exclusive, and the source buffer's stride must equal the rectangle width, so
   full-width bands are just an offset into the framebuffer.
2. **Double-buffer**, if you have the RAM: another 110 KB out of ~320 KB. It overlaps
   CPU and DMA but does **not** raise the 45 fps ceiling.
3. Nothing else — do not go looking for a faster clock (rule 9).

Keep per-pixel loops integer-only. The RISC-V core here has **no FPU**; float belongs
in one-time init paths (palette and lookup-table generation), never in a frame loop.

## When the task is memory

A full framebuffer is 110,080 B — about a third of the ~320 KB the linker actually
hands out. The template's full variant links at 123 KB. A Wi-Fi stack is another
~50 KB, a second framebuffer another 110 KB, LVGL more again. **Framebuffer + Wi-Fi +
double-buffering does not fit — pick two.**

## Starting a new project

Do not hand-assemble one. `template/` builds clean; scaffold from it:

```sh
~/.claude/skills/esp32c6-lcd147/template/variants/new-project.sh <target-dir> [--full|--minimal]
cd <target-dir> && pio run
```

- `--minimal` — RGB LED sweep + console heartbeat, no display, no SPI bus. 167,888 B
  flash, 11,052 B RAM. **Flash this first on a new board**: it proves the toolchain,
  the flashing route and the console while the display cannot confuse the diagnosis,
  and its two outputs (log line, LED) fail independently.
- `--full` (default) — ST7789 effect carousel, 12×24 ASCII + Cyrillic font, LEDC
  backlight, RGB LED accent. 245,214 B flash, 123,052 B RAM.

Both build as-is with ESP-IDF 6.0.1 (verified). Nothing is generated and no paths are
embedded, so copying the tree by hand works identically. `template/README.md` maps
files to subsystems so a `--full` scaffold can be stripped back cleanly.

When the user already has a project, prefer bringing it in line with the template's
`platformio.ini`, `sdkconfig.defaults` and `board.h` over rewriting their code.

## Flashing

Nothing to press:

```sh
pio run -t upload -t monitor        # or: idf.py -p <port> flash monitor
```

The USB Serial/JTAG controller supports host-controlled reset and download-mode entry,
so esptool drives the whole cycle over the Type-C cable. The board appears as CDC-ACM
(`/dev/cu.usbmodem*`, `/dev/ttyACM*`, or a COM port).

When firmware has wedged USB, or a console config change broke enumeration: **hold
BOOT, tap RESET, release BOOT** → Joint Download Boot. ROM code enumerates with no
valid application present, so **bad firmware cannot brick this board**. If it still
fails, `esptool.py -p <port> erase_flash` — a 4 MB erase takes 20–60 s, so it is
probably not hung.

There is no debug header. JTAG is the same Type-C port, via the built-in USB
Serial/JTAG controller — but not with the openocd PlatformIO installs for this board.
`platform-espressif32`'s `platform.json` pins `tool-openocd-esp32` to `~2.1100.0`
(installed: `2.1100.20220706`), and that build predates the ESP32-C6 entirely: it ships
`board/esp32c3-builtin.cfg` and `board/esp32s3-builtin.cfg` but no `esp32c6-builtin.cfg`
and no `target/esp32c6.cfg` anywhere in the package. `pio debug` / a bare
`openocd -f board/esp32c6-builtin.cfg` fails with "Can't find board/esp32c6-builtin.cfg"
on this toolchain, which reads like a typo rather than a missing chip target. Use a
current upstream `openocd-esp32` release (Espressif's fork, not PlatformIO's pinned
copy) or an ESP-IDF export'd environment's own `idf.py openocd`, either of which does
carry ESP32-C6 support.

## Reporting

Say what is verified on hardware and what is derived. In this skill the **display
path** (pin map, 40 MHz clock, gap 34, colour inversion, big-endian RGB565, the 45 fps
ceiling) ran on a real board. The **LEDC backlight** and the **WS2812 driver** are
compile-verified and derived from the vendor documents — the original firmware drove
the backlight as a plain GPIO and never touched the RGB LED. Recipes marked
"⚠︎ compile-checked only" in `reference/recipes.md` (TF card, ADC, BOOT button) are in
the same category. Everything marked **⚠︎ Inference** in
`reference/board-hardware.md` is a conclusion combining the Waveshare wiki with the
Espressif datasheet, not a printed vendor statement — flag it as such rather than
presenting it as fact.

© alexex1993 · MIT · alexex1993/mcu-skills

Similar skills

All skills for Programming languages →

From the same set22

esp32s3-cam-40pin A skill for the 40-pin ESP32-S3-WROOM-1 camera board: pin maps, PSRAM setup, SDMMC and the usual failure modes. CX Codex +1 ★ 22repo stars esp32p4-jc4880p443 Hardware reference and project recipes for building firmware on Guition JC4880P443 with ESP32-P4, ST7701S MIPI display, and ESP32-C6 Wi-Fi. CX Codex +1 ★ 22repo stars esp32p4-jc-m3-dev A firmware development skill for the Guition JC-ESP32P4-M3-DEV board, covering project setup, board pins, peripherals, and common build issues. CX Codex +1 ★ 22repo stars esp32c6-touch-lcd147 A skill that gives your coding agent a reference for the Waveshare ESP32-C6-Touch-LCD-1.47: pin map, JD9853 panel, AXS5106L touch, PlatformIO setup. Most bugs on this board fail quietly. CX Codex +1 ★ 22repo stars esp32c3-oled042 This skill guides firmware work on the ESP32-C3 0.42-inch OLED board, from display setup to I2C peripherals. Use it to troubleshoot board behavior or start a project. CX Codex +1 ★ 22repo stars esp32-wroom-38pin A skill for firmware work on 38-pin ESP32-WROOM-32 boards: header map, safe GPIOs, flash-pin and IO0 traps, working code recipes. CX Codex +1 ★ 22repo stars esp32-wroom-36pin Hardware pin mapping and firmware reference for the 36-pin ESP32-WROOM-32 dev board. Guards against bus conflicts, strapping traps, and bad builds. CX Codex +1 ★ 22repo stars esp32-wroom-30pin This skill helps configure firmware for 30-pin ESP32-WROOM-32 boards and troubleshoot pin, power, and peripheral issues. Use it when your board matches this form factor. CX Codex +1 ★ 22repo stars

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor