Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
.pio
release/
.venv-pio/
.vscode/.browse.c_cpp.db*
.vscode/c_cpp_properties.json
.vscode/launch.json
.vscode/ipch

# Local Wi-Fi / location overrides (copy from include/secrets.h.example)
include/secrets.h
47 changes: 47 additions & 0 deletions docs/FORK_AND_UPSTREAM.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Fork vs upstream contribution

Upstream: [MatixYo/ESP32-Plane-Radar](https://github.com/MatixYo/ESP32-Plane-Radar) (MIT).

## Recommended split

| Track | Purpose |
|-------|---------|
| **Upstream PR** | Generic `esp32-tft-round` port: pins, polled buttons, CH343 notes, display fixes — **no secrets**, default env stays `supermini` |
| **Your fork** | Bench branch with `include/secrets.h` (gitignored) for fixed Wi-Fi / location |

Contributing the board port upstream helps other HackerBox #0107 / 88267 owners. Keep personal network settings in `secrets.h` only on your fork.

## Prepare an upstream PR

1. Ensure `include/secrets.h` is **not** tracked (`git status` clean of secrets).
2. Default `platformio.ini` → `default_envs = supermini`.
3. Commit:
- `include/board/esp32_tft_round.h` (pins only)
- `include/board/supermini.h` (if shared button abstractions changed)
- `include/config.h`, WiFi/button/display fixes
- `docs/PORT_ESP32_TFT_ROUND.md`
- `scripts/flash-esp32-tft.sh`, `esptool.cfg`
- `include/secrets.h.example` (template only)
4. Open PR to `MatixYo/ESP32-Plane-Radar` with title e.g. **Add ESP32-TFT round (GC9A01 integrated) board profile**.

## Fork for bench use

```bash
gh repo fork MatixYo/ESP32-Plane-Radar --clone
cd ESP32-Plane-Radar
cp include/secrets.h.example include/secrets.h
# edit secrets.h
pio run -e esp32-tft-round -t upload --upload-port /dev/cu.wchusbserial*
```

Add your fork as `origin`, keep `upstream` pointing at MatixYo; rebase bench branches on upstream `main` when merging PR feedback.

## Secrets policy

| File | Commit? |
|------|---------|
| `include/secrets.h.example` | Yes — placeholders only |
| `include/secrets.h` | **Never** — in `.gitignore` |
| `include/board/*.h` | Yes — hardware only, no SSIDs/passwords |

If secrets were ever committed, rotate Wi-Fi password and `git filter-repo` / BFG before pushing public.
88 changes: 88 additions & 0 deletions docs/PORT_ESP32_P4_WAVESHARE_4C.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# ESP32-Plane-Radar — Waveshare ESP32-P4 4C port

Target: [Waveshare ESP32-P4-WIFI6-Touch-LCD-4C](https://www.waveshare.com/wiki/ESP32-P4-WIFI6-Touch-LCD-4C) — 720×720 round MIPI DSI, GT911 touch, ESP32-C6 Wi-Fi 6 coprocessor.

| | |
|---|---|
| MCU | ESP32-P4NRW32 |
| Display | JD9365, 720×720, MIPI DSI 2-lane |
| Touch | GT911 / GT9271 (I2C SDA **GPIO7**, SCL **GPIO8**) |
| Wi-Fi | ESP32-C6 via esp_hosted (pre-flashed on board) |
| PlatformIO env | **`esp32-p4-waveshare-4c`** |
| Pin map | `include/board/esp32_p4_waveshare_4c.h` |

## Prerequisites

- **Python 3.10+** for pioarduino (macOS system Python 3.9 is too old). Use a venv:

```bash
python3.12 -m venv .venv-pio
.venv-pio/bin/pip install platformio
.venv-pio/bin/pio run -e esp32-p4-waveshare-4c
```

- **pioarduino** platform (configured in `platformio.ini`; first build downloads the SDK)
- Arduino-esp32 **3.2+** with ESP32-P4 support (via pioarduino)
- LovyanGFX **develop** branch (MIPI DSI / `Bus_DSI`)

## Local Wi-Fi (required for this port)

Hardcoded STA credentials via gitignored `include/secrets.h`:

```bash
cp include/secrets.h.example include/secrets.h
# kWifiSkipPortal = true, set SSID/password
```

Never commit `secrets.h`.

## Build & flash

```bash
pio run -e esp32-p4-waveshare-4c -t upload
pio device monitor -b 115200
```

Or:

```bash
chmod +x scripts/flash-esp32-p4-waveshare-4c.sh
./scripts/flash-esp32-p4-waveshare-4c.sh
```

Use the **USB TO UART** Type-C port for flashing. Hold **BOOT** while resetting if upload fails.

## Controls

| Input | Effect |
|-------|--------|
| **Pinch out** (two fingers spread) | Larger range (5 → 10 → 15 → 25 km) |
| **Pinch in** (two fingers close) | Smaller range |
| **BOOT (GPIO35) short tap** | Cycle range (fallback) |
| **BOOT long press** | Disabled (hardcoded Wi-Fi) |

## Display init

JD9365 vendor init sequence from [xiaozhi-esp32 Waveshare P4 board](https://github.com/78/xiaozhi-esp32/tree/main/boards/waveshare/esp32-p4-wifi6-touch-lcd), converted to LovyanGFX `Panel_DSI` lists:

```bash
python3 scripts/convert_jd9365_init.py # regenerates include/hardware/panel_jd9365_waveshare_4c.hpp
```

## Merged binary

```bash
pio run -e esp32-p4-waveshare-4c -t merge
# .pio/build/esp32-p4-waveshare-4c/firmware-merged.bin @ 0x0
```

## Troubleshooting

| Symptom | Check |
|---------|--------|
| Blank display | Backlight GPIO26 PWM; MIPI LDO channel 3 @ 2.5 V |
| Wi-Fi never connects | C6 coprocessor powered; serial for esp_hosted errors |
| No pinch response | Serial for `touch: GT911 @ 0x..`; I2C 7/8 |
| Sprite alloc failed | 32 MB PSRAM; `BOARD_HAS_PSRAM` in build flags |

See also [FORK_AND_UPSTREAM.md](FORK_AND_UPSTREAM.md).
65 changes: 65 additions & 0 deletions docs/PORT_ESP32_TFT_ROUND.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# ESP32-Plane-Radar — board port notes

Upstream targets **ESP32-C3 Super Mini + wired GC9A01** (`env:supermini`).

## ESP32-TFT round (HackerBox #0107 / 88267)

Parts-catalog slug: `ESP32_Round_240x240_IPS_Module`

**Kit:** [HackerBox #0107 — Dock](https://www.instructables.com/HackerBox-0107-Dock/) (round ESP32 + GC9A01 module, USB dock, RTL8812BU Wi‑Fi stick).

| | |
|---|---|
| MCU | ESP32-D0WD-V3 |
| Flash | 16 MB |
| USB | WCH CH343 (`1A86:55D3`) |
| Display | GC9A01 240×240 round (integrated SPI) |
| PlatformIO env | **`esp32-tft-round`** |

Pin map: `include/board/esp32_tft_round.h` (hardware only — no credentials).

### Local dev credentials (optional)

```bash
cp include/secrets.h.example include/secrets.h
# Edit secrets.h — gitignored; never commit
```

See [FORK_AND_UPSTREAM.md](FORK_AND_UPSTREAM.md).

### Power before USB (HackerBox module)

1. Plug USB — green LED only, display off.
2. Press the **middle button** — red LED on.
3. CH343 enumerates only when powered on.

Side keys: GPIO **34** (range tap), GPIO **35** (unused in firmware — floats).

### macOS CH343 driver (Apple Silicon)

Use WCH **CH34xVCPDriver.dmg** + Driver Extension → port `/dev/cu.wchusbserial*`. Apple `usbmodem` often fails esptool writes.

Display pins (Setup200 integrated PCB): MOSI **15**, SCLK **14**, CS **5**, DC **27**, RST **33**, BL **22**, invert **true**, rgb_order **false**.

### Build & flash

```bash
pio run -e esp32-tft-round -t upload --upload-port /dev/cu.wchusbserialXXXX
./scripts/flash-esp32-tft.sh /dev/cu.wchusbserialXXXX
pio device monitor -b 115200
```

Upload uses `--no-stub` (required for CH343). If upload fails, hold GPIO **34** or BOOT0 through flash.

### Controls (esp32-tft-round)

- **Short tap GPIO 34** — cycle range (5 → 10 → 15 → 25 km), polled + debounced
- **GPIO 35** — not used (floating pin caused ghost events)
- **Wi-Fi setup** — captive portal unless `secrets.h` sets `kWifiSkipPortal`

### Merged binary

```bash
pio run -e esp32-tft-round -t merge
# .pio/build/esp32-tft-round/firmware-merged.bin @ 0x0
```
9 changes: 9 additions & 0 deletions esptool.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[esptool]
timeout = 10
mem_end_rom_timeout = 2
serial_write_timeout = 30
write_block_attempts = 5
connect_attempts = 15
reset_delay = 0.2
# Enter download mode and leave GPIO0 (BOOT) low
custom_reset_sequence = D0|R1|W0.15|D1|R0|W0.1|D1
25 changes: 25 additions & 0 deletions include/board/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Board profiles

Plane Radar selects hardware via PlatformIO `build_flags`:

| Environment | Board header | Target |
|-------------|--------------|--------|
| `supermini` | `include/board/supermini.h` | ESP32-C3 Super Mini + wired GC9A01 (upstream default) |
| `esp32-tft-round` | `include/board/esp32_tft_round.h` | HackerBox #0107 / ESP32-TFT 88267 integrated round module |
| `esp32-p4-waveshare-4c` | `include/board/esp32_p4_waveshare_4c.h` | Waveshare ESP32-P4 4″ 720×720 MIPI DSI round touch |

Add `-DPLANE_RADAR_BOARD_ESP32_TFT_ROUND` only for the classic ESP32 round env.
Add `-DPLANE_RADAR_BOARD_ESP32_P4_WAVESHARE_4C` for the Waveshare P4 4C env.

## Local Wi-Fi / location (optional)

For development without the captive portal:

```bash
cp include/secrets.h.example include/secrets.h
# edit include/secrets.h — file is gitignored
```

Never commit `include/secrets.h`. Upstream PRs must not include credentials.

See [docs/FORK_AND_UPSTREAM.md](../docs/FORK_AND_UPSTREAM.md).
64 changes: 64 additions & 0 deletions include/board/esp32_p4_waveshare_4c.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#pragma once

/** Waveshare ESP32-P4-WIFI6-Touch-LCD-4C — 720×720 round MIPI DSI (JD9365). */
#include <driver/gpio.h>

namespace board {

constexpr gpio_num_t kBootPin = GPIO_NUM_35;
constexpr bool kBootPinInternalPullup = true;
constexpr gpio_num_t kWifiResetPin = GPIO_NUM_NC;
constexpr bool kWifiResetPinInternalPullup = false;
constexpr bool kBootUsePolledTap = false;
constexpr gpio_num_t kRangePin2 = GPIO_NUM_NC;
constexpr bool kButtonActiveLow = true;
constexpr unsigned long kBootResetHoldMs = 5000UL;
constexpr uint8_t kBootLowStreakRequired = 1;
constexpr uint8_t kButtonStableSamplesRequired = 1;
constexpr unsigned long kBootTapMinMs = 120UL;
constexpr unsigned long kButtonTapCooldownMs = 600UL;
constexpr uint8_t kButtonReadSamples = 1;
constexpr uint8_t kButtonReadThreshold = 1;

/** Hardcoded Wi-Fi — no portal long-press wipe. */
constexpr bool kEnableWifiLongPressReset = false;

constexpr gpio_num_t kSdCardPinCs = GPIO_NUM_NC;

/** MIPI DSI panel reset / backlight (xiaozhi Waveshare P4 config). */
constexpr gpio_num_t kDisplayPinRst = GPIO_NUM_27;
constexpr gpio_num_t kDisplayPinBl = GPIO_NUM_26;
constexpr bool kDisplayBacklightInvert = true;

/** Not used on DSI path. */
constexpr gpio_num_t kDisplayPinCs = GPIO_NUM_NC;
constexpr gpio_num_t kDisplayPinDc = GPIO_NUM_NC;
constexpr gpio_num_t kDisplayPinMosi = GPIO_NUM_NC;
constexpr gpio_num_t kDisplayPinSclk = GPIO_NUM_NC;
constexpr uint32_t kDisplaySpiWriteHz = 0;
constexpr bool kDisplayInvert = false;
constexpr bool kDisplayRgbOrder = true;

constexpr int kDisplayWidth = 720;
constexpr int kDisplayHeight = 720;

/** MIPI DSI PHY / timing (Waveshare 4C). */
constexpr uint16_t kMipiLaneMbps = 1500;
constexpr uint8_t kMipiLaneNum = 2;
constexpr uint8_t kMipiLdoChan = 3;
constexpr uint32_t kMipiLdoVoltageMv = 2500;
constexpr uint16_t kDpiClockMhz = 46;
constexpr uint16_t kDpiHsyncPulse = 20;
constexpr uint16_t kDpiHsyncBackPorch = 20;
constexpr uint16_t kDpiHsyncFrontPorch = 40;
constexpr uint16_t kDpiVsyncPulse = 4;
constexpr uint16_t kDpiVsyncBackPorch = 12;
constexpr uint16_t kDpiVsyncFrontPorch = 24;

/** GT911 touch on shared codec I2C bus. */
constexpr gpio_num_t kTouchPinSda = GPIO_NUM_7;
constexpr gpio_num_t kTouchPinScl = GPIO_NUM_8;
constexpr uint8_t kTouchI2cAddrPrimary = 0x5D;
constexpr uint8_t kTouchI2cAddrBackup = 0x14;

} // namespace board
46 changes: 46 additions & 0 deletions include/board/esp32_tft_round.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#pragma once

/** HackerBox #0107 / ESP32-TFT 88267 — ESP32-D0WD + integrated GC9A01 round panel.
* Pin map matches official kit TFT_eSPI Setup200_GC9A01 (Instructables HackerBox 0107). */
#include <driver/gpio.h>
#include <driver/spi_master.h>

namespace board {

constexpr gpio_num_t kBootPin = GPIO_NUM_34;
constexpr bool kBootPinInternalPullup = false;
constexpr gpio_num_t kWifiResetPin = GPIO_NUM_35;
constexpr bool kWifiResetPinInternalPullup = false;
/** GPIO 34–39 have no internal pull-up; poll in loop with heavy debounce. */
constexpr bool kBootUsePolledTap = true;
/** Only GPIO 34 cycles range; GPIO 35 floats on this PCB. */
constexpr gpio_num_t kRangePin2 = GPIO_NUM_NC;
constexpr bool kButtonActiveLow = true;
constexpr unsigned long kBootResetHoldMs = 5000UL;
constexpr uint8_t kBootLowStreakRequired = 8;
constexpr uint8_t kButtonStableSamplesRequired = 10;
constexpr unsigned long kBootTapMinMs = 120UL;
constexpr unsigned long kButtonTapCooldownMs = 600UL;
constexpr uint8_t kButtonReadSamples = 5;
constexpr uint8_t kButtonReadThreshold = 4;

/** GPIO 35 floats — disable long-press Wi-Fi wipe unless external pull-ups added. */
constexpr bool kEnableWifiLongPressReset = false;

/** microSD (if populated) — not used by Plane Radar; do not drive GPIO 5 (display CS). */
constexpr gpio_num_t kSdCardPinCs = GPIO_NUM_NC;

constexpr gpio_num_t kDisplayPinMosi = GPIO_NUM_15;
constexpr gpio_num_t kDisplayPinSclk = GPIO_NUM_14;
constexpr gpio_num_t kDisplayPinCs = GPIO_NUM_5;
constexpr gpio_num_t kDisplayPinDc = GPIO_NUM_27;
constexpr gpio_num_t kDisplayPinRst = GPIO_NUM_33;
constexpr gpio_num_t kDisplayPinBl = GPIO_NUM_22;

constexpr spi_host_device_t kDisplaySpiHost = SPI2_HOST;

constexpr uint32_t kDisplaySpiWriteHz = 27000000;
constexpr bool kDisplayInvert = true;
constexpr bool kDisplayRgbOrder = false;

} // namespace board
Loading