From 99784d5856173bad60050faede1f0fc49223db72 Mon Sep 17 00:00:00 2001 From: liquidraver <504870+liquidraver@users.noreply.github.com> Date: Mon, 2 Mar 2026 08:31:38 +0100 Subject: [PATCH] update thinknode + example --- zephcore/boards/common/zephcore_common.conf | 3 +- zephcore/boards/example_board/README.md | 7 +-- zephcore/boards/example_board/board.conf | 18 +++++-- zephcore/boards/example_board/board.overlay | 49 ++++++++++++++++++- .../thinknode_m1/Kconfig.thinknode_m1 | 7 +++ .../boards/nrf52840/thinknode_m1/board.conf | 9 ++++ .../nrf52840/thinknode_m1/thinknode_m1.dts | 10 ++++ 7 files changed, 93 insertions(+), 10 deletions(-) diff --git a/zephcore/boards/common/zephcore_common.conf b/zephcore/boards/common/zephcore_common.conf index 0e2a28c..605dda4 100644 --- a/zephcore/boards/common/zephcore_common.conf +++ b/zephcore/boards/common/zephcore_common.conf @@ -187,7 +187,8 @@ CONFIG_USBD_LOG_LEVEL_WRN=y CONFIG_POWEROFF=y # ========== LoRa Power Saving ========== -# RX duty cycle OFF by default — causes marginal packet loss on repeaters. +# RX duty cycle OFF by default — LR1110 cannot lock on mid-preamble, +# causing packet loss with duty-cycled RX. SX1262/LLCC68 handle it fine. # Enable per-board via board.conf, or at runtime via CLI "set rxduty on". CONFIG_ZEPHCORE_LORA_RX_DUTY_CYCLE=n diff --git a/zephcore/boards/example_board/README.md b/zephcore/boards/example_board/README.md index 2a9292a..a581570 100644 --- a/zephcore/boards/example_board/README.md +++ b/zephcore/boards/example_board/README.md @@ -41,10 +41,11 @@ PATTERN 2: Fully Custom Board (new DTS) Use this when your board does NOT exist in Zephyr's tree. You need a full board definition: .dts, pinctrl, Kconfig, etc. -Examples: Ikoka Nano 30dBm (custom nRF52840 design) +Examples: Ikoka Nano 30dBm, ThinkNode M1 (custom nRF52840 designs) -Look at an existing custom board as a template: - zephcore/boards/nrf52840/ikoka_nano_30dbm/ +Look at existing custom boards as templates: + zephcore/boards/nrf52840/ikoka_nano_30dbm/ — minimal (LoRa only) + zephcore/boards/nrf52840/thinknode_m1/ — full-featured (EPD, GPS, QSPI, buzzer) A full custom board includes: board.conf — Kconfig (name, radio, overrides) diff --git a/zephcore/boards/example_board/board.conf b/zephcore/boards/example_board/board.conf index abb4357..8b76e46 100644 --- a/zephcore/boards/example_board/board.conf +++ b/zephcore/boards/example_board/board.conf @@ -56,6 +56,15 @@ CONFIG_BT_DIS_MODEL_NUMBER_STR="My Board v1" # 2. Set zephyr,display = &your_display; in the "chosen" block # 3. That's it — driver, CFB, and UI all auto-enable # +# HEAP WARNING: The CFB framebuffer is allocated via k_malloc at boot. +# The default heap (2048 in zephcore_common.conf) fits 128x64 OLEDs. +# Displays larger than 128x64 WILL fail silently (-ENOMEM, blank screen). +# Override the heap for your display resolution: +# 200x200 (SSD1681): CONFIG_HEAP_MEM_POOL_SIZE=6144 +# 296x128 (SSD1680): CONFIG_HEAP_MEM_POOL_SIZE=6144 +# On RAM-constrained MCUs (nRF52840), you may also need to shrink the +# RTT buffer: CONFIG_SEGGER_RTT_BUFFER_SIZE_UP=1024 (saves 3KB). +# # To DISABLE display on a board WITHOUT a screen (enables LED heartbeat): # CONFIG_ZEPHCORE_UI_DISPLAY=n # The heartbeat LED (led0 alias) only blinks when display is disabled @@ -124,7 +133,8 @@ CONFIG_BT_DIS_MODEL_NUMBER_STR="My Board v1" # ESP32-C3: 300 (limited DRAM) # CONFIG_ZEPHCORE_MAX_CONTACTS=450 -# ========== OPTIONAL: Disable RX Duty Cycle ========== -# Inherited from platform common config as enabled (power savings). -# Override here if your board is wall-powered. -# CONFIG_ZEPHCORE_LORA_RX_DUTY_CYCLE=n +# ========== OPTIONAL: RX Duty Cycle ========== +# Disabled by default in zephcore_common.conf because the LR1110 cannot lock +# on mid-preamble, causing packet loss with duty-cycled RX. +# SX1262/LLCC68 boards handle duty cycle fine — enable for battery savings: +# CONFIG_ZEPHCORE_LORA_RX_DUTY_CYCLE=y diff --git a/zephcore/boards/example_board/board.overlay b/zephcore/boards/example_board/board.overlay index 496bf8d..964ffbc 100644 --- a/zephcore/boards/example_board/board.overlay +++ b/zephcore/boards/example_board/board.overlay @@ -81,8 +81,9 @@ * MG24: skip (usart0 already set) */ - /* --- Display (uncomment if board has OLED/LCD) --- - * zephyr,display = &oled; + /* --- Display (uncomment if board has OLED/LCD/e-paper) --- + * zephyr,display = &oled; I2C OLED (SH1106, SSD1306) + * zephyr,display = &epd; SPI e-paper (SSD1681, etc.) */ }; }; @@ -774,6 +775,50 @@ * }; */ +/* --- E-Paper Display on SPI (any platform with SPI) --- + * + * Supported: "solomon,ssd1681" (1.54" 200x200 mono) + * Remember to set zephyr,display = &epd; in chosen block. + * + * IMPORTANT — HEAP: The CFB framebuffer is allocated via k_malloc at boot. + * The default heap (2048) is sized for 128x64 OLEDs (1024 bytes). + * Larger displays need more heap in board.conf: + * + * Display Resolution Framebuffer Heap needed + * SSD1306/SH1106 128x64 1024 bytes 2048 (default) + * SSD1681 200x200 5000 bytes 6144+ + * SSD1680 296x128 4736 bytes 6144+ + * + * If the heap is too small, cfb_framebuffer_init() silently fails + * with -ENOMEM and the display stays blank (white for e-paper). + * + * The MIPI DBI node wraps SPI with DC and RST GPIOs. + * The display node is a child of the MIPI DBI node. + * + * If your EPD has a separate power/boost-converter enable GPIO, + * add a regulator-fixed node with regulator-boot-on (see ThinkNode M1). + * + * / { + * mipi_dbi { + * compatible = "zephyr,mipi-dbi-spi"; + * spi-dev = <&spi3>; + * dc-gpios = <&gpio0 28 GPIO_ACTIVE_HIGH>; + * reset-gpios = <&gpio0 2 GPIO_ACTIVE_LOW>; + * #address-cells = <1>; + * #size-cells = <0>; + * + * epd: ssd16xxfb@0 { + * compatible = "solomon,ssd1681"; + * mipi-max-frequency = <4000000>; + * reg = <0>; + * width = <200>; + * height = <200>; + * busy-gpios = <&gpio0 3 GPIO_ACTIVE_HIGH>; + * }; + * }; + * }; + */ + /* --- I2C Environment Sensors (any platform with I2C) --- * * Auto-detected at runtime. Just include the common dtsi. diff --git a/zephcore/boards/nrf52840/thinknode_m1/Kconfig.thinknode_m1 b/zephcore/boards/nrf52840/thinknode_m1/Kconfig.thinknode_m1 index 7254be0..842aa94 100644 --- a/zephcore/boards/nrf52840/thinknode_m1/Kconfig.thinknode_m1 +++ b/zephcore/boards/nrf52840/thinknode_m1/Kconfig.thinknode_m1 @@ -4,3 +4,10 @@ config BOARD_THINKNODE_M1 select SOC_NRF52840_QIAA + +# Board power enable (P0.12) must be HIGH before QSPI flash can respond. +# QSPI NOR init priority is 41 — regulator must run first. +if REGULATOR_FIXED +config REGULATOR_FIXED_INIT_PRIORITY + default 30 +endif diff --git a/zephcore/boards/nrf52840/thinknode_m1/board.conf b/zephcore/boards/nrf52840/thinknode_m1/board.conf index ced8c7f..dbb02b9 100644 --- a/zephcore/boards/nrf52840/thinknode_m1/board.conf +++ b/zephcore/boards/nrf52840/thinknode_m1/board.conf @@ -26,3 +26,12 @@ CONFIG_ZEPHCORE_MAX_CONTACTS=510 # PWM for buzzer CONFIG_PWM=y + +# ========== RAM budget ========== +# SSD1681 200x200 CFB framebuffer needs 5000 bytes from k_malloc. +# Default heap (2048) is sized for SSD1306 128x64 (1024 bytes). +CONFIG_HEAP_MEM_POOL_SIZE=6144 + +# Shrink RTT buffer to free RAM (4096 → 1024, saves 3KB). +# Only used during J-Link debugging, 1KB is Zephyr's default. +CONFIG_SEGGER_RTT_BUFFER_SIZE_UP=1024 diff --git a/zephcore/boards/nrf52840/thinknode_m1/thinknode_m1.dts b/zephcore/boards/nrf52840/thinknode_m1/thinknode_m1.dts index 2075458..8c35440 100644 --- a/zephcore/boards/nrf52840/thinknode_m1/thinknode_m1.dts +++ b/zephcore/boards/nrf52840/thinknode_m1/thinknode_m1.dts @@ -172,6 +172,16 @@ }; }; + /* Display power enable (P1.11) — drives the EPD's boost converter / + * frontlight. Without this HIGH, SPI works but the charge pump + * cannot flip e-ink particles (display appears dead). */ + disp_pwr_enable: disp-pwr-enable { + compatible = "regulator-fixed"; + regulator-name = "disp-pwr-enable"; + enable-gpios = <&gpio1 11 GPIO_ACTIVE_HIGH>; + regulator-boot-on; + }; + /* ---- E-Paper display (MIPI DBI SPI) ---- * SSD1681 1.54" 200x200 monochrome EPD on SPI3. * The MIPI DBI node wraps the SPI bus with DC and RST GPIOs.