Add Waveshare ESP32-S3-Touch-AMOLED-1.8 (368×448) board support
Port the firmware to a second Waveshare AMOLED board variant alongside
the original 2.16" / 480×480. Selection is at build time via a board
macro; both envs continue to build and flash independently.
Hardware delta vs AMOLED-2.16:
* Display: SH8601 QSPI (vs CO5300), 368×448 portrait (vs 480² square),
SCLK on GPIO 11 (vs 38), RST routed through an XCA9554 I/O expander
(vs direct GPIO).
* Touch: FT3168 @ 0x38 (vs CST9220 @ 0x5A). Driven by a ~30-line
inline FocalTech-protocol reader in main.cpp — Waveshare's
Arduino_DriveBus library is GPLv3 and would force the project's
license, which the README explicitly avoids.
* I/O expander: new XCA9554/PCA9554 @ I2C 0x20 gates LCD_RST, TP_RST,
audio amp enable, and the PWR button. Wrapped in io_expander.{h,cpp}.
Must initialize BEFORE display/touch or both stay in reset.
* PMU + IMU: same AXP2101 + QMI8658 as 2.16, so power.cpp/imu.cpp
largely reuse. IMU is initialized for I2C bus health but rotation
is fixed at 0° (the portrait panel doesn't benefit from auto-rotate
and the strip-rotation CPU path is excluded entirely).
* Buttons: only BOOT (GPIO 0) is a direct GPIO; PWR is read via
XCA9554 EXIO4 polling. No third button — the AMOLED-2.16's
Shift+Tab key (GPIO 18) is dropped for this board.
* Flash: 16MB (vs 8MB), partition table set to default_16MB.csv.
Code structure:
* display_cfg.h hosts a #ifdef BOARD_AMOLED_18 / #else / #endif split
with a PlatformDisplay typedef so call sites elsewhere stay clean.
* main.cpp, power.cpp, ui.cpp, splash.cpp gate board-specific bits on
the same macro. Layout constants (panel heights, content Y, font
choices on the Bluetooth screen) compress for the 368×448 portrait
footprint so two usage panels + bottom animation label fit without
horizontal overflow.
* Splash scales the 20×20 pixel-art grid to 360×360 (CELL=18 vs 24)
and centers in the portrait canvas.
* Old AMOLED-2.16 env is unchanged at the source level (gated under
#ifndef BOARD_AMOLED_18) and continues to compile + flash on the
original hardware.
CLAUDE.md updated with the two-board pin maps, build/flash commands
for both envs (macOS + Linux device paths), and the per-board gotchas.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
57e5d73c6e
commit
f3ed2425bf
+68
-23
@@ -7,12 +7,31 @@
|
||||
|
||||
// Custom fonts (scaled for 314 PPI, ~1.9x from original 165 PPI)
|
||||
LV_FONT_DECLARE(font_tiempos_56);
|
||||
LV_FONT_DECLARE(font_tiempos_34);
|
||||
LV_FONT_DECLARE(font_styrene_48);
|
||||
LV_FONT_DECLARE(font_styrene_28);
|
||||
LV_FONT_DECLARE(font_styrene_24);
|
||||
LV_FONT_DECLARE(font_styrene_20);
|
||||
LV_FONT_DECLARE(font_styrene_16);
|
||||
LV_FONT_DECLARE(font_styrene_14);
|
||||
LV_FONT_DECLARE(font_mono_32);
|
||||
|
||||
// AMOLED-1.8 (368 wide) needs smaller fonts on the Bluetooth screen so the
|
||||
// MAC address and credit lines don't overflow horizontally.
|
||||
#ifdef BOARD_AMOLED_18
|
||||
#define BT_TITLE_FONT font_tiempos_34
|
||||
#define BT_STATUS_FONT font_styrene_28
|
||||
#define BT_DEVICE_FONT font_styrene_20
|
||||
#define BT_CREDIT_1_FONT font_styrene_16
|
||||
#define BT_CREDIT_2_FONT font_styrene_14
|
||||
#else
|
||||
#define BT_TITLE_FONT font_tiempos_56
|
||||
#define BT_STATUS_FONT font_styrene_48
|
||||
#define BT_DEVICE_FONT font_styrene_28
|
||||
#define BT_CREDIT_1_FONT font_styrene_24
|
||||
#define BT_CREDIT_2_FONT font_styrene_20
|
||||
#endif
|
||||
|
||||
// Anthropic brand palette — design tokens live in theme.h
|
||||
#include "theme.h"
|
||||
#define COL_BG THEME_BG
|
||||
@@ -25,13 +44,19 @@ LV_FONT_DECLARE(font_mono_32);
|
||||
#define COL_RED THEME_RED
|
||||
#define COL_BAR_BG THEME_BAR_BG
|
||||
|
||||
// ---- Layout constants for 480x480 (scaled for 2.16" high-DPI + rounded corners) ----
|
||||
#define SCR_W 480
|
||||
#define SCR_H 480
|
||||
#define MARGIN 20 // wider margin for rounded display corners
|
||||
// ---- Layout constants ----
|
||||
// Width/height track the active display (480x480 for AMOLED-2.16, 368x448 for AMOLED-1.8).
|
||||
// MARGIN clears rounded display corners on both panels.
|
||||
#define SCR_W LCD_WIDTH
|
||||
#define SCR_H LCD_HEIGHT
|
||||
#define MARGIN 20
|
||||
#define TITLE_Y 30
|
||||
#ifdef BOARD_AMOLED_18
|
||||
#define CONTENT_Y 85 // tighter vertical packing for 448-tall portrait
|
||||
#else
|
||||
#define CONTENT_Y 100
|
||||
#define CONTENT_W (SCR_W - 2 * MARGIN) // 440
|
||||
#endif
|
||||
#define CONTENT_W (SCR_W - 2 * MARGIN)
|
||||
|
||||
// ---- Usage screen widgets ----
|
||||
static lv_obj_t* usage_container;
|
||||
@@ -218,14 +243,26 @@ static void init_battery_icons(void) {
|
||||
init_icon_dsc_rgb565a8(&battery_dscs[4], ICON_BATTERY_CHARGING_W, ICON_BATTERY_CHARGING_H, icon_battery_charging_data);
|
||||
}
|
||||
|
||||
// ======== Usage Screen (480x480) ========
|
||||
// ======== Usage Screen ========
|
||||
|
||||
#define PANEL_H 150
|
||||
#define PANEL_GAP 16
|
||||
#ifdef BOARD_AMOLED_18
|
||||
// 368x448 portrait — compressed vertical layout so two panels + bottom anim
|
||||
// label fit without overlap.
|
||||
#define PANEL_H 130
|
||||
#define PANEL_GAP 12
|
||||
#define PANEL_BAR_Y 48
|
||||
#define PANEL_RESET_Y 78
|
||||
#else
|
||||
// 480x480 square (original)
|
||||
#define PANEL_H 150
|
||||
#define PANEL_GAP 16
|
||||
#define PANEL_BAR_Y 56
|
||||
#define PANEL_RESET_Y 94
|
||||
#endif
|
||||
|
||||
// One Session/Weekly panel: big % label, pill on the right, bar, reset label.
|
||||
// Pill y=1: symmetric inside the panel — panel-outer-top → pill-top equals
|
||||
// pill-bottom → bar-top (pill height 42 + panel pad_top 12 + bar y=56).
|
||||
// pill-bottom → bar-top.
|
||||
static void make_usage_panel(lv_obj_t* parent, int y, const char* pill_text,
|
||||
lv_obj_t** out_pct, lv_obj_t** out_pill,
|
||||
lv_obj_t** out_bar, lv_obj_t** out_reset) {
|
||||
@@ -240,13 +277,13 @@ static void make_usage_panel(lv_obj_t* parent, int y, const char* pill_text,
|
||||
*out_pill = make_pill(panel, pill_text);
|
||||
lv_obj_align(*out_pill, LV_ALIGN_TOP_RIGHT, 0, 1);
|
||||
|
||||
*out_bar = make_bar(panel, 0, 56, CONTENT_W - 32, 24);
|
||||
*out_bar = make_bar(panel, 0, PANEL_BAR_Y, CONTENT_W - 32, 24);
|
||||
|
||||
*out_reset = lv_label_create(panel);
|
||||
lv_label_set_text(*out_reset, "---");
|
||||
lv_obj_set_style_text_font(*out_reset, &font_styrene_28, 0);
|
||||
lv_obj_set_style_text_color(*out_reset, COL_DIM, 0);
|
||||
lv_obj_set_pos(*out_reset, 0, 94);
|
||||
lv_obj_set_pos(*out_reset, 0, PANEL_RESET_Y);
|
||||
}
|
||||
|
||||
static void init_usage_screen(lv_obj_t* scr) {
|
||||
@@ -279,7 +316,15 @@ static void init_usage_screen(lv_obj_t* scr) {
|
||||
lv_obj_align(lbl_anim, LV_ALIGN_BOTTOM_MID, 0, -15);
|
||||
}
|
||||
|
||||
// ======== Bluetooth Screen (480x480) ========
|
||||
// ======== Bluetooth Screen ========
|
||||
|
||||
#ifdef BOARD_AMOLED_18
|
||||
#define BT_INFO_PANEL_H 140
|
||||
#define BT_RESET_ZONE_H 90
|
||||
#else
|
||||
#define BT_INFO_PANEL_H 160
|
||||
#define BT_RESET_ZONE_H 110
|
||||
#endif
|
||||
|
||||
static void init_bluetooth_screen(lv_obj_t* scr) {
|
||||
ble_container = lv_obj_create(scr);
|
||||
@@ -293,12 +338,12 @@ static void init_bluetooth_screen(lv_obj_t* scr) {
|
||||
// Title
|
||||
lv_obj_t* lbl_ble_title = lv_label_create(ble_container);
|
||||
lv_label_set_text(lbl_ble_title, "Bluetooth");
|
||||
lv_obj_set_style_text_font(lbl_ble_title, &font_tiempos_56, 0);
|
||||
lv_obj_set_style_text_font(lbl_ble_title, &BT_TITLE_FONT, 0);
|
||||
lv_obj_set_style_text_color(lbl_ble_title, COL_TEXT, 0);
|
||||
lv_obj_align(lbl_ble_title, LV_ALIGN_TOP_MID, 16, TITLE_Y);
|
||||
|
||||
// Info panel (taller for 480x480)
|
||||
lv_obj_t* p_info = make_panel(ble_container, MARGIN, CONTENT_Y, CONTENT_W, 160);
|
||||
// Info panel
|
||||
lv_obj_t* p_info = make_panel(ble_container, MARGIN, CONTENT_Y, CONTENT_W, BT_INFO_PANEL_H);
|
||||
|
||||
// Bluetooth icon + status row
|
||||
static lv_image_dsc_t icon_bt_dsc;
|
||||
@@ -310,27 +355,27 @@ static void init_bluetooth_screen(lv_obj_t* scr) {
|
||||
|
||||
lbl_ble_status = lv_label_create(p_info);
|
||||
lv_label_set_text(lbl_ble_status, "Initializing...");
|
||||
lv_obj_set_style_text_font(lbl_ble_status, &font_styrene_48, 0);
|
||||
lv_obj_set_style_text_font(lbl_ble_status, &BT_STATUS_FONT, 0);
|
||||
lv_obj_set_style_text_color(lbl_ble_status, COL_DIM, 0);
|
||||
lv_obj_set_pos(lbl_ble_status, 56, 2);
|
||||
|
||||
lbl_ble_device = lv_label_create(p_info);
|
||||
lv_label_set_text(lbl_ble_device, "Device: ---");
|
||||
lv_obj_set_style_text_font(lbl_ble_device, &font_styrene_28, 0);
|
||||
lv_obj_set_style_text_font(lbl_ble_device, &BT_DEVICE_FONT, 0);
|
||||
lv_obj_set_style_text_color(lbl_ble_device, COL_DIM, 0);
|
||||
lv_obj_set_pos(lbl_ble_device, 0, 64);
|
||||
|
||||
lbl_ble_mac = lv_label_create(p_info);
|
||||
lv_label_set_text(lbl_ble_mac, "Address: ---");
|
||||
lv_obj_set_style_text_font(lbl_ble_mac, &font_styrene_28, 0);
|
||||
lv_obj_set_style_text_font(lbl_ble_mac, &BT_DEVICE_FONT, 0);
|
||||
lv_obj_set_style_text_color(lbl_ble_mac, COL_DIM, 0);
|
||||
lv_obj_set_pos(lbl_ble_mac, 0, 100);
|
||||
|
||||
// Reset Bluetooth tap zone with trash icon
|
||||
int reset_y = CONTENT_Y + 160 + 16;
|
||||
int reset_y = CONTENT_Y + BT_INFO_PANEL_H + 16;
|
||||
lv_obj_t* reset_zone = lv_obj_create(ble_container);
|
||||
lv_obj_set_pos(reset_zone, MARGIN, reset_y);
|
||||
lv_obj_set_size(reset_zone, CONTENT_W, 110);
|
||||
lv_obj_set_size(reset_zone, CONTENT_W, BT_RESET_ZONE_H);
|
||||
lv_obj_set_style_bg_color(reset_zone, COL_PANEL, 0);
|
||||
lv_obj_set_style_bg_opa(reset_zone, LV_OPA_COVER, 0);
|
||||
lv_obj_set_style_radius(reset_zone, 8, 0);
|
||||
@@ -348,19 +393,19 @@ static void init_bluetooth_screen(lv_obj_t* scr) {
|
||||
|
||||
lv_obj_t* reset_lbl = lv_label_create(reset_zone);
|
||||
lv_label_set_text(reset_lbl, "Reset Bluetooth");
|
||||
lv_obj_set_style_text_font(reset_lbl, &font_styrene_28, 0);
|
||||
lv_obj_set_style_text_font(reset_lbl, &BT_DEVICE_FONT, 0);
|
||||
lv_obj_set_style_text_color(reset_lbl, COL_DIM, 0);
|
||||
|
||||
// Attribution
|
||||
lv_obj_t* lbl_credit = lv_label_create(ble_container);
|
||||
lv_label_set_text(lbl_credit, "Built by @hermannbjorgvin");
|
||||
lv_obj_set_style_text_font(lbl_credit, &font_styrene_24, 0);
|
||||
lv_obj_set_style_text_font(lbl_credit, &BT_CREDIT_1_FONT, 0);
|
||||
lv_obj_set_style_text_color(lbl_credit, COL_DIM, 0);
|
||||
lv_obj_align(lbl_credit, LV_ALIGN_BOTTOM_MID, 0, -46);
|
||||
|
||||
lv_obj_t* lbl_credit2 = lv_label_create(ble_container);
|
||||
lv_label_set_text(lbl_credit2, "Clawd animation by @amaanbuilds");
|
||||
lv_obj_set_style_text_font(lbl_credit2, &font_styrene_20, 0);
|
||||
lv_obj_set_style_text_font(lbl_credit2, &BT_CREDIT_2_FONT, 0);
|
||||
lv_obj_set_style_text_color(lbl_credit2, COL_DIM, 0);
|
||||
lv_obj_align(lbl_credit2, LV_ALIGN_BOTTOM_MID, 0, -20);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user