From 063a0688868beaafe3ed5c707a53b43584239523 Mon Sep 17 00:00:00 2001 From: STC Date: Mon, 10 Aug 2026 19:48:30 +0900 Subject: [PATCH 1/2] add device M5nanoH3 --- .../esp32/targets/m5nanoh2/host/provider.js | 36 ++++++++ .../esp32/targets/m5nanoh2/manifest.json | 48 +++++++++++ .../targets/m5nanoh2/sdkconfig/partitions.csv | 24 ++++++ .../m5nanoh2/sdkconfig/sdkconfig.defaults | 4 + .../esp32/targets/m5nanoh2/setup-target.js | 80 ++++++++++++++++++ documentation/assets/devices/m5nanoh2.png | Bin 0 -> 23668 bytes documentation/devices/esp32.md | 1 + modules/io/manifests/esp32/manifest.json | 5 ++ 8 files changed, 198 insertions(+) create mode 100644 build/devices/esp32/targets/m5nanoh2/host/provider.js create mode 100644 build/devices/esp32/targets/m5nanoh2/manifest.json create mode 100644 build/devices/esp32/targets/m5nanoh2/sdkconfig/partitions.csv create mode 100644 build/devices/esp32/targets/m5nanoh2/sdkconfig/sdkconfig.defaults create mode 100644 build/devices/esp32/targets/m5nanoh2/setup-target.js create mode 100644 documentation/assets/devices/m5nanoh2.png diff --git a/build/devices/esp32/targets/m5nanoh2/host/provider.js b/build/devices/esp32/targets/m5nanoh2/host/provider.js new file mode 100644 index 0000000000..45701f4d95 --- /dev/null +++ b/build/devices/esp32/targets/m5nanoh2/host/provider.js @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2026 Satoshi Tanaka + * + * This file is part of the Moddable SDK Runtime. + * + * The Moddable SDK Runtime is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Moddable SDK Runtime is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with the Moddable SDK Runtime. If not, see . + * + */ + +import I2C from "embedded:io/i2c"; +import SMBus from "embedded:io/smbus"; +import Digital from "embedded:io/digital"; + +const device = { + I2C: { + default: { + io: I2C, + data: 2, + clock: 1 + } + }, + io: {I2C, SMBus, Digital} +}; + +export default device; diff --git a/build/devices/esp32/targets/m5nanoh2/manifest.json b/build/devices/esp32/targets/m5nanoh2/manifest.json new file mode 100644 index 0000000000..9951324b26 --- /dev/null +++ b/build/devices/esp32/targets/m5nanoh2/manifest.json @@ -0,0 +1,48 @@ +{ + "build": { + "ESP32_SUBCLASS": "esp32h2", + "USE_USB": "2", + "SDKCONFIGPATH": "./sdkconfig", + "PARTITIONS_FILE_FOR_TARGET": "./sdkconfig/partitions.csv", + "PROGRAMMING_MODE_MESSAGE": "INSTRUCTIONS: Hold the BOOT button and press then release the RST button.", + "BEFORE_DEBUGGING_MESSAGE": "Press and release the RST button." + }, + "include": [ + "$(MODULES)/drivers/button/manifest.json", + "$(MODULES)/drivers/led/manifest.json", + "$(MODULES)/drivers/neopixel/manifest.json" + ], + "modules": { + "setup/target": "./setup-target" + }, + "preload": [ + "setup/target", + "neopixel" + ], + "config": { + "screen": "", + "led": { + "rgb": { + "power_pin": 10, + "data_pin": 11, + "rainbow": false, + "brightness": 32 + }, + "blue": { + "pin": 4 + } + } + }, + "creation": { + "static": 0, + "chunk": { + "initial": 78848, + "incremental": 0 + }, + "heap": { + "initial": 4928, + "incremental": 0 + }, + "stack": 512 + } +} diff --git a/build/devices/esp32/targets/m5nanoh2/sdkconfig/partitions.csv b/build/devices/esp32/targets/m5nanoh2/sdkconfig/partitions.csv new file mode 100644 index 0000000000..251bf913b5 --- /dev/null +++ b/build/devices/esp32/targets/m5nanoh2/sdkconfig/partitions.csv @@ -0,0 +1,24 @@ +# +# Copyright (c) 2016-2023 Moddable Tech, Inc. +# +# This file is part of the Moddable SDK Tools. +# +# The Moddable SDK Tools is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# The Moddable SDK Tools is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with the Moddable SDK Tools. If not, see . +# + +# Name, Type, SubType, Offset, Size, Flags +# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild,,,, +nvs, data, nvs, 0x9000, 0x006000, +phy_init, data, phy, 0xf000, 0x001000, +factory, app, factory, 0x10000, 0x3E0000, diff --git a/build/devices/esp32/targets/m5nanoh2/sdkconfig/sdkconfig.defaults b/build/devices/esp32/targets/m5nanoh2/sdkconfig/sdkconfig.defaults new file mode 100644 index 0000000000..70d3b27ae1 --- /dev/null +++ b/build/devices/esp32/targets/m5nanoh2/sdkconfig/sdkconfig.defaults @@ -0,0 +1,4 @@ +CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y +CONFIG_ESPTOOLPY_FLASHSIZE_2MB=n + + diff --git a/build/devices/esp32/targets/m5nanoh2/setup-target.js b/build/devices/esp32/targets/m5nanoh2/setup-target.js new file mode 100644 index 0000000000..7ab2cbe0de --- /dev/null +++ b/build/devices/esp32/targets/m5nanoh2/setup-target.js @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2026 Satoshi Tanaka + * + * This file is part of the Moddable SDK Runtime. + * + * The Moddable SDK Runtime is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The Moddable SDK Runtime is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with the Moddable SDK Runtime. If not, see . + * + */ + +import config from "mc/config"; +import NeoPixel from "neopixel"; +import Button from "button"; +import LED from "led"; +import Digital from "pins/digital"; + +class NeoPixelLED extends NeoPixel { + constructor(options) { + return new NeoPixel({ + ...options, + pin: config.led.rgb.data_pin, + length: 1, + order: "GRB", + }); + } +} + +class BlueLED { + constructor(options) { + return new LED({ + ...options, + pin: config.led.blue.pin, + }); + } +} + +class buttonA { + constructor(options) { + return new Button({ + ...options, + pin: 9, + invert: true, + }); + } +} + +globalThis.Host = Object.freeze( + { + LED: { + Default: NeoPixelLED, + RGB: NeoPixelLED, + Blue: BlueLED, + }, + Button: { + Default: buttonA, + a: buttonA, + }, + }, + true +); + +export default function (done) { + // Enable RGB LED Power + const power = new Digital({ + pin: config.led.rgb.power_pin, + mode: Digital.Output, + }); + power.write(1); + done?.(); +} diff --git a/documentation/assets/devices/m5nanoh2.png b/documentation/assets/devices/m5nanoh2.png new file mode 100644 index 0000000000000000000000000000000000000000..195e295870407331b567b300d1ab79c6680c7073 GIT binary patch literal 23668 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 GGUR{aB;J4k literal 0 HcmV?d00001 diff --git a/documentation/devices/esp32.md b/documentation/devices/esp32.md index 813dc72270..5e0e41a549 100644 --- a/documentation/devices/esp32.md +++ b/documentation/devices/esp32.md @@ -246,6 +246,7 @@ The Moddable SDK supports these ESP32-H2 development kits: | Name | Platform identifier | Key features | Links | | :---: | :--- | :--- | :--- | |
ESP32-H2-DevKitM-1 | `esp32/esp32h2` | NeoPixel, Button |
  • [Product page](https://docs.espressif.com/projects/espressif-esp-dev-kits/en/latest/esp32h2/esp32-h2-devkitm-1/user_guide.html)
  • | +|
    M5NanoH2 | `esp32/m5nanoh2` | LED, NeoPixel, Button |
  • [Product page](https://docs.m5stack.com/en/core/NanoH2)
  • | ### Specifying ESP32 Subclass in Manifest diff --git a/modules/io/manifests/esp32/manifest.json b/modules/io/manifests/esp32/manifest.json index 2371e27329..32db349a87 100644 --- a/modules/io/manifests/esp32/manifest.json +++ b/modules/io/manifests/esp32/manifest.json @@ -121,6 +121,11 @@ "embedded:provider/builtin": "$(SUBPLATFORMDIRECTORY)/host/provider" } }, + "esp32/m5nanoh2": { + "modules": { + "embedded:provider/builtin": "$(SUBPLATFORMDIRECTORY)/host/provider" + } + }, "esp32/*": { "include": [ "$(MODDABLE)/examples/manifest_net.json" From d65eebc563a2e8cbdfc663772377f2403b9e2c85 Mon Sep 17 00:00:00 2001 From: STC Date: Mon, 10 Aug 2026 20:07:57 +0900 Subject: [PATCH 2/2] revised the setup-target to match the M5NanoH2. --- .../esp32/targets/m5nanoc6/setup-target.js | 44 +++++-------------- 1 file changed, 11 insertions(+), 33 deletions(-) diff --git a/build/devices/esp32/targets/m5nanoc6/setup-target.js b/build/devices/esp32/targets/m5nanoc6/setup-target.js index f5a3622e2c..937dbd0bb3 100644 --- a/build/devices/esp32/targets/m5nanoc6/setup-target.js +++ b/build/devices/esp32/targets/m5nanoc6/setup-target.js @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Moddable Tech, Inc. + * Copyright (c) 2026 Moddable Tech, Inc., Satoshi Tanaka * * This file is part of the Moddable SDK Runtime. * @@ -20,46 +20,18 @@ import config from "mc/config"; import NeoPixel from "neopixel"; -import Timer from "timer"; import Button from "button"; import LED from "led"; import Digital from "pins/digital"; class NeoPixelLED extends NeoPixel { - #value = 0; constructor(options) { - // Enable RGB LED Power - const power = new Digital({ - pin: config.led.rgb.power_pin, - mode: Digital.Output, - }); - power.write(1); - - super({ + return new NeoPixel({ ...options, pin: config.led.rgb.data_pin, length: 1, order: "GRB", }); - super.brightness = config.led.rgb.brightness; - } - read() { - return this.#value; - } - write(value) { - this.#value = value; - if (value) { - super.setPixel(0, super.makeRGB(255, 255, 255)); - } else { - super.setPixel(0, super.makeRGB(0, 0, 0)); - } - super.update(); - } - on() { - this.write(1); - } - off() { - this.write(0); } } @@ -72,7 +44,7 @@ class BlueLED { } } -class Flash { +class buttonA { constructor(options) { return new Button({ ...options, @@ -90,13 +62,19 @@ globalThis.Host = Object.freeze( Blue: BlueLED, }, Button: { - Default: Flash, - Flash, + Default: buttonA, + a: buttonA, }, }, true ); export default function (done) { + // Enable RGB LED Power + const power = new Digital({ + pin: config.led.rgb.power_pin, + mode: Digital.Output, + }); + power.write(1); done?.(); }