diff --git a/build/devices/esp32/targets/m5stack_core2/Core2IMU.js b/build/devices/esp32/targets/m5stack_core2/Core2IMU.js
new file mode 100644
index 000000000..9b0438a1a
--- /dev/null
+++ b/build/devices/esp32/targets/m5stack_core2/Core2IMU.js
@@ -0,0 +1,71 @@
+/*
+ * 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 MPU6886 from "embedded:sensor/Accelerometer-Gyroscope/MPU6886";
+import BMI270 from "embedded:sensor/Accelerometer-Gyroscope-Magnetometer/BMI270";
+
+class Core2PMU6886 extends MPU6886 {
+ sample() {
+ const sample = super.sample();
+ sample.accelerometer.x *= -1;
+ sample.accelerometer.y *= -1;
+ sample.gyroscope.y *= -1;
+
+ return sample;
+ }
+}
+
+const ACCELERATION_SCALER = 1 / 9.80665;
+class Core2BMI270 extends BMI270 {
+ sample() {
+ const sample = super.sample();
+
+ if (sample.accelerometer) {
+ sample.accelerometer.x *= ACCELERATION_SCALER;
+ sample.accelerometer.y *= ACCELERATION_SCALER;
+ sample.accelerometer.z *= ACCELERATION_SCALER;
+ }
+
+ return sample;
+ }
+}
+
+export class Core2IMU {
+ constructor(options) {
+ const s = new device.io.SMBus({
+ ...device.I2C.internal,
+ address: 0x68,
+ hz: 400_000
+ });
+
+ if (0x19 === s.readUint8(0x75)){
+ s.close();
+ return new Core2PMU6886(options);
+ }
+
+ if (0x24 === s.readUint8(0x00)){
+ s.close();
+ return new Core2BMI270(options);
+ }
+ s.close();
+ throw new Error("IMU not found");
+ }
+}
+export default Core2IMU;
\ No newline at end of file
diff --git a/build/devices/esp32/targets/m5stack_core2/Core2Power.js b/build/devices/esp32/targets/m5stack_core2/Core2Power.js
new file mode 100644
index 000000000..17f27db2a
--- /dev/null
+++ b/build/devices/esp32/targets/m5stack_core2/Core2Power.js
@@ -0,0 +1,158 @@
+/*
+ * 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 AXP192 from "embedded:peripheral/Power/axp192";
+import AXP2101 from "embedded:peripheral/Power/axp2101";
+import Timer from "timer";
+
+class PowerAXP192 extends AXP192 {
+ constructor(options) {
+ super(options);
+ this.writeByte(0x30, (this.readByte(0x30) & 0x04) | 0x02); //AXP192 30H
+ this.writeByte(0x92, this.readByte(0x92) & 0xf8); //AXP192 GPIO1:OD OUTPUT
+ this.writeByte(0x93, this.readByte(0x93) & 0xf8); //AXP192 GPIO2:OD OUTPUT
+ this.writeByte(0x35, (this.readByte(0x35) & 0x1c) | 0xa3); //AXP192 RTC CHG
+
+ // main power line
+ this._dcdc1.voltage = 3350;
+ this.chargeCurrent = AXP192.CHARGE_CURRENT.Ch_100mA;
+
+ // LCD
+ this.lcd = this._dcdc3;
+ this.lcd.voltage = 2800;
+
+ // internal LCD logic
+ this._ldo2.voltage = 3300;
+ this._ldo2.enable = true;
+
+ // Vibration
+ this.vibration = this._ldo3;
+ this.vibration.voltage = 2000;
+
+ // Speaker
+ this.speaker = this._gpio2;
+
+ // AXP192 GPIO4
+ this.writeByte(0x95, (this.readByte(0x95) & 0x72) | 0x84);
+ this.writeByte(0x36, 0x4c);
+ this.writeByte(0x82, 0xff);
+ // reset LCD
+ this._gpio4.enable = false
+ Timer.delay(20);
+ this._gpio4.enable = true
+ this.busPowerMode = 0; // bus power mode_output
+ Timer.delay(200);
+ }
+ set busPowerMode(mode) {
+ if (mode === 0) {
+ this.writeByte(0x91, (this.readByte(0x91) & 0x0f) | 0xf0);
+ this.writeByte(0x90, (this.readByte(0x90) & 0xf8) | 0x02); //set GPIO0 to LDO OUTPUT , pullup N_VBUSEN to disable supply from BUS_5V
+ this.writeByte(0x12, this.readByte(0x12) | 0x40); //set EXTEN to enable 5v boost
+ } else {
+ this.writeByte(0x12, this.readByte(0x12) & 0xbf); //set EXTEN to disable 5v boost
+ this.writeByte(0x90, (this.readByte(0x90) & 0xf8) | 0x01); //set GPIO0 to float , using enternal pulldown resistor to enable supply from BUS_5VS
+ }
+ }
+
+ // value 0 - 100 %
+ set brightness(value) {
+ if (value <= 0)
+ value = 2500;
+ else if (value >= 100)
+ value = 3300;
+ else
+ value = (value / 100) * 800 + 2500;
+ this.lcd.voltage = value;
+ }
+
+ get brightness() {
+ return (this.lcd.voltage - 2500) / 800 * 100;
+ }
+}
+
+class PowerAXP2101 extends AXP2101 {
+ constructor(options) {
+ super(options);
+ this.writeByte(0x27, 0x00); // PowerKey Hold=1sec / PowerOff=4sec
+ this.writeByte(0x10, 0x30); // PMU common config (internal off-discharge enable)
+ this.writeByte(0x12, 0x00); // BATFET disable
+ this.writeByte(0x68, 0x01); // Battery detection enabled.
+ this.writeByte(0x69, 0x13); // CHGLED setting
+ this.writeByte(0x99, 0x00); // DLDO1 set 0.5v (vibration motor)
+
+ // DCDC1&3 Enable
+ this.writeByte(0x80, this.readByte(0x00) | 0x04);
+
+ // main power line
+ this._dcdc1.voltage = 3350;
+
+ // LCD
+ this.lcd = this._bldo1;
+ this.lcd.voltage = 2800;
+ this.lcd.enable = true;
+
+ // internal LCD logic
+ this._aldo4.voltage = 3300;
+ this._aldo4.enable = true;
+
+ // Vibration
+ this.vibration = this._dldo1;
+ this.vibration.voltage = 2000;
+
+ // Speaker
+ this.speaker = this._aldo3;
+ this.speaker.voltage = 3300;
+
+ // LCD Reset
+ this._aldo2.voltage = 3300;
+ this._aldo2.enable = false;
+ Timer.delay(20);
+ this._aldo2.enable = true;
+
+ // bus power mode_output
+ this._bldo2.voltage = 3300;
+ this._bldo2.enable = true;
+ Timer.delay(200);
+ }
+ // value 0 - 100 %
+ set brightness(value) {
+ if (value <= 0) value = 2500;
+ else if (value >= 100) value = 3300;
+ else value = (value / 100) * 800 + 2500;
+ this.lcd.voltage = value;
+ }
+
+ get brightness() {
+ return ((this.lcd.voltage - 2500) / 800) * 100;
+ }
+}
+
+export default class Core2Power {
+ constructor(options) {
+ const s = new device.io.SMBus({
+ ...device.I2C.internal,
+ address: 0x34,
+ hz: 400_000
+ });
+ const powerICID = s.readByte(0x03);
+ s.close();
+ return powerICID === 0x03 ? new PowerAXP192(options) : new PowerAXP2101(options)
+ }
+}
diff --git a/build/devices/esp32/targets/m5stack_core2/M5StackCoreTouch.js b/build/devices/esp32/targets/m5stack_core2/M5StackCoreTouch.js
index 0228217f7..dbdc132f9 100644
--- a/build/devices/esp32/targets/m5stack_core2/M5StackCoreTouch.js
+++ b/build/devices/esp32/targets/m5stack_core2/M5StackCoreTouch.js
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022 Moddable Tech, Inc.
+ * Copyright (c) 2022-2026 Moddable Tech, Inc.
*
* This file is part of the Moddable SDK Runtime.
*
@@ -17,28 +17,60 @@
* along with the Moddable SDK Runtime. If not, see .
*
*/
-
- import Touch from "ft6206"
+
+import Touch from "embedded:sensor/Touch/FT6x06";
class M5StackCoreTouch extends Touch {
#captured; // undefined or pressed button instance
+ #capturedID; // touch id captured as virtual button
+
+ sample() {
+ const points = super.sample();
+ if (!points)
+ return points;
- read(points) {
- super.read(points);
+ let capturedPointIndex = -1;
if (this.#captured) {
- if (0 === points[0].state) {
+ for (let i = 0, length = points.length; i < length; i++) {
+ const point = points[i];
+
+ if (point.id === this.#capturedID) {
+ capturedPointIndex = i;
+ break;
+ }
+ }
+
+ if (-1 === capturedPointIndex) {
this.#captured.write(0);
this.#captured = undefined;
+ this.#capturedID = undefined;
}
}
- else if ((1 === points[0].state) && (points[0].y >= 240)) {
- this.#captured = button[String.fromCharCode('a'.charCodeAt() + Math.idiv(points[0].x, 107))];
- this.#captured?.write(1);
+ else {
+ for (let i = 0, length = points.length; i < length; i++) {
+ const point = points[i];
+
+ if (point.y >= 240) {
+ const index = Math.idiv(point.x, 107);
+ this.#captured = globalThis.button[String.fromCharCode('a'.charCodeAt() + index)];
+
+ if (this.#captured) {
+ this.#capturedID = point.id;
+ this.#captured.write(1);
+ capturedPointIndex = i;
+ }
+
+ break;
+ }
+ }
+ }
+
+ if (-1 !== capturedPointIndex) {
+ points.splice(capturedPointIndex, 1);
}
- if (this.#captured)
- points[0].state = 0;
+ return points;
}
}
diff --git a/build/devices/esp32/targets/m5stack_core2/host/provider.js b/build/devices/esp32/targets/m5stack_core2/host/provider.js
index cb0c7cae1..ee46afa38 100644
--- a/build/devices/esp32/targets/m5stack_core2/host/provider.js
+++ b/build/devices/esp32/targets/m5stack_core2/host/provider.js
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021 Moddable Tech, Inc.
+ * Copyright (c) 2021-2026 Moddable Tech, Inc.
*
* This file is part of the Moddable SDK Runtime.
*
@@ -28,29 +28,10 @@ import Serial from "embedded:io/serial";
import SMBus from "embedded:io/smbus";
import SPI from "embedded:io/spi";
import PulseWidth from "embedded:io/pulsewidth";
-import BMI270 from "embedded:sensor/Accelerometer-Gyroscope-Magnetometer/BMI270";
-import MPU6886 from "embedded:sensor/Accelerometer-Gyroscope/MPU6886";
-
-const ACCELERATION_SCALER = 1 / 9.80665;
-const IMU_ADDRESS = 0x68;
-const BMI270_CHIP_ID_ADDR = 0x00;
-const BMI270_CHIP_ID = 0x24;
-const MPU6886_WHO_AM_I_ADDR = 0x75;
-const MPU6886_WHO_AM_I = 0x19;
-
-class Core2BMI270 extends BMI270 {
- sample() {
- const sample = super.sample();
-
- if (sample.accelerometer) {
- sample.accelerometer.x *= ACCELERATION_SCALER;
- sample.accelerometer.y *= ACCELERATION_SCALER;
- sample.accelerometer.z *= ACCELERATION_SCALER;
- }
-
- return sample;
- }
-}
+import RTC from "embedded:RTC/BM8563";
+import Touch from "M5StackCoreTouch";
+import Core2Power from "Core2Power";
+import Core2IMU from "Core2IMU";
const device = {
I2C: {
@@ -94,48 +75,60 @@ const device = {
displaySelect: 5
},
sensor: {
+ Touch: class {
+ constructor(options) {
+ const result = new Touch({
+ ...options,
+ sensor: {
+ ...device.I2C.internal,
+ io: device.io.SMBus,
+ },
+ interrupt: {
+ io: Digital,
+ mode: Digital.Input,
+ pin: 39
+ }
+ });
+ result.configure({threshold: 20});
+ return result;
+ }
+ },
IMU: class {
constructor(options) {
- const sensor = {
- ...device.I2C.internal,
- address: IMU_ADDRESS,
- io: device.io.SMBus
- };
-
- if (MPU6886_WHO_AM_I === readIMURegister(MPU6886_WHO_AM_I_ADDR))
- return new MPU6886({
- ...options,
- sensor
- });
-
- if (BMI270_CHIP_ID === readIMURegister(BMI270_CHIP_ID_ADDR))
- return new Core2BMI270({
- ...options,
- sensor
- });
-
- throw new Error("IMU not found");
+ return new Core2IMU({
+ ...options,
+ sensor: {
+ ...device.I2C.internal,
+ io: device.io.SMBus
+ }
+ });
}
}
+ },
+ peripheral: {
+ Power: class {
+ constructor(options) {
+ return new Core2Power({
+ ...options,
+ peripheral: {
+ ...device.I2C.internal,
+ io: device.io.SMBus
+ }
+ });
+ }
+ },
+ RTC: class {
+ constructor(options) {
+ return new RTC({
+ ...options,
+ clock: {
+ ...device.I2C.internal,
+ io: SMBus,
+ },
+ });
+ }
+ },
}
};
-function readIMURegister(register) {
- let io;
- try {
- io = new device.io.SMBus({
- data: device.I2C.internal.data,
- clock: device.I2C.internal.clock,
- hz: 400_000,
- address: IMU_ADDRESS
- });
- return io.readUint8(register);
- }
- catch (e) {
- }
- finally {
- io?.close();
- }
-}
-
export default device;
diff --git a/build/devices/esp32/targets/m5stack_core2/manifest.json b/build/devices/esp32/targets/m5stack_core2/manifest.json
index 229346644..b4bd23dab 100644
--- a/build/devices/esp32/targets/m5stack_core2/manifest.json
+++ b/build/devices/esp32/targets/m5stack_core2/manifest.json
@@ -8,23 +8,18 @@
"include": [
"$(MODDABLE)/modules/io/manifest.json",
"$(MODDABLE)/modules/drivers/ili9341/manifest.json",
- "$(MODDABLE)/modules/drivers/ft6206/manifest.json",
+ "$(MODDABLE)/modules/drivers/sensors/ft6206/manifest.json",
"$(MODDABLE)/modules/drivers/sensors/bmi270/manifest.json",
"$(MODDABLE)/modules/drivers/sensors/mpu6886/manifest.json",
- "$(MODDABLE)/modules/drivers/axp192/manifest.json",
- "$(MODDABLE)/modules/drivers/axp2101/manifest.json"
+ "$(MODDABLE)/modules/drivers/peripherals/bm8563/manifest.json",
+ "$(MODDABLE)/modules/drivers/peripherals/axp192/manifest.json",
+ "$(MODDABLE)/modules/drivers/peripherals/axp2101/manifest.json"
],
"config": {
"screen": "ili9341",
- "touch": "M5StackCoreTouch",
- "startupSound": "bflatmajor.maud",
- "startupVibration": 600
+ "enablePowerButton": false
},
"defines": {
- "i2c": {
- "sda_pin": 32,
- "scl_pin": 33
- },
"spi": {
"mosi_pin": 23,
"miso_pin": 38,
@@ -55,18 +50,6 @@
"0xFF, 0"
]
},
- "ft6206": {
- "width": 320,
- "height": 280,
- "hz": 400000,
- "sda": 21,
- "scl": 22,
- "threshold": 128,
- "flipX": false,
- "flipY": false,
- "fitX": false,
- "fitY": false
- },
"audioOut": {
"bitsPerSample": 16,
"numChannels": 1,
@@ -94,18 +77,18 @@
"modules": {
"setup/target": "./setup-target",
"pins/audioout": "$(MODULES)/pins/i2s/*",
- "pins/smbus": "$(MODULES)/pins/smbus/smbus",
"*": [
- "$(MODULES)/drivers/mpu6886/*",
- "./M5StackCoreTouch"
+ "./M5StackCoreTouch",
+ "./Core2Power",
+ "./Core2IMU"
]
},
"preload": [
"pins/audioout",
"setup/target",
- "mpu6886",
- "pins/smbus",
- "M5StackCoreTouch"
+ "M5StackCoreTouch",
+ "Core2Power",
+ "Core2IMU"
],
"resources": {
"*": "$(MODDABLE)/examples/assets/sounds/bflatmajor"
diff --git a/build/devices/esp32/targets/m5stack_core2/setup-target.js b/build/devices/esp32/targets/m5stack_core2/setup-target.js
index 13ec79dce..1f6ddd389 100644
--- a/build/devices/esp32/targets/m5stack_core2/setup-target.js
+++ b/build/devices/esp32/targets/m5stack_core2/setup-target.js
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020-2023 Moddable Tech, Inc.
+ * Copyright (c) 2020-2026 Moddable Tech, Inc.
*
* This file is part of the Moddable SDK Runtime.
*
@@ -17,112 +17,11 @@
* along with the Moddable SDK Runtime. If not, see .
*
*/
-
-import AXP192 from "axp192";
-import AXP2101 from "axp2101";
-import BMI270 from "embedded:sensor/Accelerometer-Gyroscope-Magnetometer/BMI270";
-import EmbeddedSMBus from "embedded:io/smbus";
-import MPU6886 from "mpu6886";
+
import AudioOut from "pins/audioout";
import Resource from "Resource";
import Timer from "timer";
import config from "mc/config";
-import I2C from "pins/i2c";
-import SMBus from "pins/smbus";
-
-const INTERNAL_I2C = Object.freeze({
- sda: 21,
- scl: 22
-});
-
-const INTERNAL_I2C_IO = Object.freeze({
- data: 21,
- clock: 22
-});
-const ACCELERATION_SCALER = 1 / 9.80665;
-const IMU_ADDRESS = 0x68;
-const BMI270_CHIP_ID_ADDR = 0x00;
-const BMI270_CHIP_ID = 0x24;
-const MPU6886_WHO_AM_I_ADDR = 0x75;
-const MPU6886_WHO_AM_I = 0x19;
-
-const state = {
- handleRotation: nop,
-};
-
-class Core2BMI270 extends BMI270 {
- #operation = "gyroscope";
-
- constructor() {
- super({
- sensor: {
- ...INTERNAL_I2C_IO,
- address: IMU_ADDRESS,
- io: EmbeddedSMBus
- }
- });
- }
-
- configure(dictionary) {
- if (dictionary?.operation)
- this.#operation = dictionary.operation;
- }
-
- sample() {
- const sample = super.sample();
- let result;
-
- switch (this.#operation) {
- case "accelerometer":
- result = sample.accelerometer;
- if (result) {
- result.x *= ACCELERATION_SCALER;
- result.y *= ACCELERATION_SCALER;
- result.z *= ACCELERATION_SCALER;
- }
- return result;
- case "gyroscope":
- return sample.gyroscope;
- case "temp":
- return sample.thermometer?.temperature;
- }
- }
-}
-
-function createAccelerometerGyro() {
- if (MPU6886_WHO_AM_I === readIMURegister(MPU6886_WHO_AM_I_ADDR))
- return new MPU6886(INTERNAL_I2C);
-
- if (BMI270_CHIP_ID === readIMURegister(BMI270_CHIP_ID_ADDR))
- return new Core2BMI270;
-}
-
-function getAccelerometerGyro() {
- if (undefined === state.accelerometerGyro)
- state.accelerometerGyro = createAccelerometerGyro();
- return state.accelerometerGyro;
-}
-
-function readIMURegister(register) {
- let io;
- try {
- io = new I2C({...INTERNAL_I2C, address: IMU_ADDRESS, throw: false});
- let result = io.write(register, false);
- if (result instanceof Error)
- return;
-
- result = io.read(1);
- if (result instanceof Error)
- return;
-
- return result?.[0];
- }
- catch (e) {
- }
- finally {
- io?.close();
- }
-}
globalThis.Host = {
Backlight: class {
@@ -133,299 +32,99 @@ globalThis.Host = {
if (undefined !== globalThis.power)
globalThis.power.brightness = value;
}
- close() {}
+ close() { }
}
}
class M5Core2Button { // M5StackCoreTouch calls write when button changes
- #value = 0;
- read() {
- return this.#value;
- }
- write(value) {
- if (this.#value === value)
- return;
- this.#value = value;
- this.onChanged?.();
- }
+ #value = 0;
+ read() {
+ return this.#value;
+ }
+ write(value) {
+ if (this.#value === value)
+ return;
+ this.#value = value;
+ this.onChanged?.();
+ }
}
export default function (done) {
- // buttons
- globalThis.button = {
- a: new M5Core2Button,
- b: new M5Core2Button,
- c: new M5Core2Button,
- };
+ // buttons
+ globalThis.button = {
+ a: new M5Core2Button,
+ b: new M5Core2Button,
+ c: new M5Core2Button,
+ };
- // power
- const s = new SMBus({
- ...INTERNAL_I2C,
- address: 0x34,
- })
- const powerICID = s.readByte(0x03)
- s.close();
+ // power
+ globalThis.power = new device.peripheral.Power()
- globalThis.power =
- powerICID === 0x03 ? new PowerAXP192() : new PowerAXP2101() /* expects 0x4a */;
+ if (config.enablePowerButton) {
+ globalThis.button.power = new M5Core2Button();
+ // AXP192/AXP2101 PEK reports latched press events, so expose them as a short 1 -> 0 pulse.
+ Timer.repeat(() => {
+ const state = globalThis.power.getPekState();
+ globalThis.button.power.write(state ? 1 : 0);
+ }, 100);
+ }
- // speaker
- power.speaker.enable = true;
+ // speaker
+ globalThis.power.speaker.enable = true;
- // start-up sound
- if (config.startupSound) {
- const speaker = new AudioOut({streams: 1});
- speaker.callback = function () {
- this.stop();
- this.close();
- Timer.set(this.done);
- };
- speaker.done = done;
- done = undefined;
+ // start-up sound
+ if (config.startupSound) {
+ const speaker = new AudioOut({ streams: 1 });
+ speaker.callback = function () {
+ this.stop();
+ this.close();
+ Timer.set(this.done);
+ };
+ speaker.done = done;
+ done = undefined;
- speaker.enqueue(0, AudioOut.Samples, new Resource(config.startupSound));
- speaker.enqueue(0, AudioOut.Callback, 0);
- speaker.start();
- }
+ speaker.enqueue(0, AudioOut.Samples, new Resource(config.startupSound));
+ speaker.enqueue(0, AudioOut.Callback, 0);
+ speaker.start();
+ }
// vibration
globalThis.vibration = {
- read: function () {
- return power.vibration.enable;
+ read: () => {
+ return globalThis.power.vibration.enable;
},
- write: function (v) {
- power.vibration.enable = v;
+ write: (v) => {
+ globalThis.power.vibration.enable = v;
},
};
if (config.startupVibration) {
- vibration.write(true);
+ globalThis.vibration.write(true);
Timer.set(() => {
- vibration.write(false);
+ globalThis.vibration.write(false);
}, config.startupVibration);
}
- // accelerometer and gyrometer
- globalThis.accelerometer = {
- onreading: nop,
- };
-
- globalThis.gyro = {
- onreading: nop,
- };
-
- accelerometer.start = function (frequency) {
- accelerometer.stop();
- state.accelerometerTimerID = Timer.repeat((id) => {
- const accelerometerGyro = getAccelerometerGyro();
- if (undefined === accelerometerGyro)
- return;
-
- accelerometerGyro.configure({
- operation: "accelerometer",
- });
- const sample = accelerometerGyro.sample();
- if (sample) {
- state.handleRotation(sample);
- accelerometer.onreading(sample);
- }
- }, frequency);
- };
-
- gyro.start = function (frequency) {
- gyro.stop();
- state.gyroTimerID = Timer.repeat((id) => {
- const accelerometerGyro = getAccelerometerGyro();
- if (undefined === accelerometerGyro)
- return;
-
- accelerometerGyro.configure({
- operation: "gyroscope",
- });
- const sample = accelerometerGyro.sample();
- if (sample) {
- let { x, y, z } = sample;
- const temp = x;
- x = y * -1;
- y = temp * -1;
- z *= -1;
- gyro.onreading({
- x,
- y,
- z,
- });
- }
- }, frequency);
- };
-
- accelerometer.stop = function () {
- if (undefined !== state.accelerometerTimerID)
- Timer.clear(state.accelerometerTimerID);
- delete state.accelerometerTimerID;
- };
-
- gyro.stop = function () {
- if (undefined !== state.gyroTimerID) Timer.clear(state.gyroTimerID);
- delete state.gyroTimerID;
- };
-
- // autorotate
- if (config.autorotate && globalThis.Application && globalThis.accelerometer) {
- state.handleRotation = function (reading) {
- if (globalThis.application === undefined) return;
-
- if (Math.abs(reading.y) > Math.abs(reading.x)) {
- if (reading.y < -0.7 && application.rotation != 180) {
- application.rotation = 180;
- } else if (reading.y > 0.7 && application.rotation != 0) {
- application.rotation = 0;
- }
- } else {
- if (reading.x < -0.7 && application.rotation != 270) {
+ if (config.autorotate && globalThis.Application) {
+ const imu = new device.sensor.IMU();
+ Timer.repeat(id => {
+ const sample = imu.sample();
+ const { x, y } = sample.accelerometer;
+ if (Math.abs(y) > Math.abs(x)) {
+ if (y < -0.7 && application.rotation !== 270) {
application.rotation = 270;
- } else if (reading.x > 0.7 && application.rotation != 90) {
+ } else if (y > 0.7 && application.rotation !== 90) {
application.rotation = 90;
}
+ } else {
+ if (x < -0.7 && application.rotation !== 180) {
+ application.rotation = 180;
+ } else if (x > 0.7 && application.rotation !== 0) {
+ application.rotation = 0;
+ }
}
- };
- accelerometer.start(300);
+ }, 300);
}
done?.();
}
-
-class PowerAXP192 extends AXP192 {
- constructor() {
- super(INTERNAL_I2C);
-
- // TODO: encapsulate direct register access by class method
- this.writeByte(0x30, (this.readByte(0x30) & 0x04) | 0x02); //AXP192 30H
- this.writeByte(0x92, this.readByte(0x92) & 0xf8); //AXP192 GPIO1:OD OUTPUT
- this.writeByte(0x93, this.readByte(0x93) & 0xf8); //AXP192 GPIO2:OD OUTPUT
- this.writeByte(0x35, (this.readByte(0x35) & 0x1c) | 0xa3); //AXP192 RTC CHG
-
- // main power line
- this._dcdc1.voltage = 3350;
- this.chargeCurrent = AXP192.CHARGE_CURRENT.Ch_100mA;
-
- // LCD
- this.lcd = this._dcdc3;
- this.lcd.voltage = 2800;
-
- // internal LCD logic
- this._ldo2.voltage = 3300;
- this._ldo2.enable = true;
-
- // Vibration
- this.vibration = this._ldo3;
- this.vibration.voltage = 2000;
-
- // Speaker
- this.speaker = this._gpio2;
-
- // AXP192 GPIO4
- this.writeByte(0x95, (this.readByte(0x95) & 0x72) | 0x84);
- this.writeByte(0x36, 0x4c);
- this.writeByte(0x82, 0xff);
- this.resetLcd();
- this.busPowerMode = 0; // bus power mode_output
- Timer.delay(200);
- }
-
- resetLcd() {
- this._gpio4.enable = false
- Timer.delay(20);
- this._gpio4.enable = true
- }
-
- set busPowerMode(mode) {
- if (mode == 0) {
- this.writeByte(0x91, (this.readByte(0x91) & 0x0f) | 0xf0);
- this.writeByte(0x90, (this.readByte(0x90) & 0xf8) | 0x02); //set GPIO0 to LDO OUTPUT , pullup N_VBUSEN to disable supply from BUS_5V
- this.writeByte(0x12, this.readByte(0x12) | 0x40); //set EXTEN to enable 5v boost
- } else {
- this.writeByte(0x12, this.readByte(0x12) & 0xbf); //set EXTEN to disable 5v boost
- this.writeByte(0x90, (this.readByte(0x90) & 0xf8) | 0x01); //set GPIO0 to float , using enternal pulldown resistor to enable supply from BUS_5VS
- }
- }
-
- // value 0 - 100 %
- set brightness(value) {
- if (value <= 0)
- value = 2500;
- else if (value >= 100)
- value = 3300;
- else
- value = (value / 100) * 800 + 2500;
- this.lcd.voltage = value;
- }
-
- get brightness() {
- return (this.lcd.voltage - 2500) / 800 * 100;
- }
-}
-
-class PowerAXP2101 extends AXP2101 {
- constructor() {
- super(INTERNAL_I2C);
-
- this.writeByte(0x27, 0x00); // PowerKey Hold=1sec / PowerOff=4sec
- this.writeByte(0x10, 0x30); // PMU common config (internal off-discharge enable)
- this.writeByte(0x12, 0x00); // BATFET disable
- this.writeByte(0x68, 0x01); // Battery detection enabled.
- this.writeByte(0x69, 0x13); // CHGLED setting
- this.writeByte(0x99, 0x00); // DLDO1 set 0.5v (vibration motor)
-
- // DCDC1&3 Enable
- this.writeByte(0x80, this.readByte(0x00) | 0x04);
-
- // main power line
- this._dcdc1.voltage = 3350;
-
- // LCD
- this.lcd = this._bldo1;
- this.lcd.voltage = 2800;
- this.lcd.enable = true;
-
- // internal LCD logic
- this._aldo4.voltage = 3300;
- this._aldo4.enable = true;
-
- // Vibration
- this.vibration = this._dldo1;
- this.vibration.voltage = 2000;
-
- // Speaker
- this.speaker = this._aldo3;
- this.speaker.voltage = 3300;
-
- // LCD Reset
- this._aldo2.voltage = 3300;
- this.resetLcd();
-
- // bus power mode_output
- this._bldo2.voltage = 3300;
- this._bldo2.enable = true;
- Timer.delay(200);
- }
-
- resetLcd() {
- this._aldo2.enable = false;
- Timer.delay(20);
- this._aldo2.enable = true;
- }
-
- // value 0 - 100 %
- set brightness(value) {
- if (value <= 0) value = 2500;
- else if (value >= 100) value = 3300;
- else value = (value / 100) * 800 + 2500;
- this.lcd.voltage = value;
- }
-
- get brightness() {
- return ((this.lcd.voltage - 2500) / 800) * 100;
- }
-}
-
-function nop() {}
diff --git a/build/devices/esp32/targets/m5stack_cores3/manifest.json b/build/devices/esp32/targets/m5stack_cores3/manifest.json
index dc3b05a87..03ff8366e 100644
--- a/build/devices/esp32/targets/m5stack_cores3/manifest.json
+++ b/build/devices/esp32/targets/m5stack_cores3/manifest.json
@@ -24,7 +24,8 @@
"frameSize": "QVGA"
},
"virtualButton": false,
- "startupSound": "bflatmajor.maud"
+ "startupSound": "bflatmajor.maud",
+ "enablePowerButton": false
},
"modules": {
"setup/target": "./setup-target",
diff --git a/build/devices/esp32/targets/m5stack_cores3/setup-target.js b/build/devices/esp32/targets/m5stack_cores3/setup-target.js
index 9d7adcc15..cf8af85d2 100644
--- a/build/devices/esp32/targets/m5stack_cores3/setup-target.js
+++ b/build/devices/esp32/targets/m5stack_cores3/setup-target.js
@@ -62,6 +62,8 @@ export default function (done) {
b: new M5CoreS3Button(),
c: new M5CoreS3Button(),
};
+ } else {
+ globalThis.button = {}
}
// power
@@ -70,6 +72,15 @@ export default function (done) {
globalThis.mic = new ES7210({sensor: { ...device.I2C.internal, io: device.io.SMBus }});
globalThis.mic.init();
+ if (config.enablePowerButton) {
+ globalThis.button.power = new M5CoreS3Button();
+ // AXP2101 PEK reports latched press events, so expose them as a short 1 -> 0 pulse.
+ Timer.repeat(() => {
+ const state = globalThis.power.getPekState();
+ globalThis.button.power.write(state ? 1 : 0);
+ }, 100);
+ }
+
// start-up sound
if (config.startupSound) {
const buf = new Resource(config.startupSound);
@@ -215,7 +226,7 @@ class Power { // extends AXP2101 {
constructor(options) {
const axp2101 = this.#axp2101 = new AXP2101({ address:0x34, ...options });
axp2101.writeByte(0x90, 0xbf);
- axp2101.writeByte(0x92, 13);
+ axp2101.writeByte(0x92, 13);
axp2101.writeByte(0x93, 28);
axp2101.writeByte(0x94, 28);
axp2101.writeByte(0x95, 28);
@@ -241,7 +252,9 @@ class Power { // extends AXP2101 {
Timer.delay(20);
this.expander.writeByteMask(0x03, 0b00100000, 0xff);
}
-
+ getPekState() {
+ return this.#axp2101.getPekState();
+ }
}
/**
diff --git a/documentation/assets/devices/m5stack_core2.png b/documentation/assets/devices/m5stack_core2.png
new file mode 100644
index 000000000..8a13fa565
Binary files /dev/null and b/documentation/assets/devices/m5stack_core2.png differ
diff --git a/documentation/devices/esp32.md b/documentation/devices/esp32.md
index 66c274c2c..fd5ded93d 100644
--- a/documentation/devices/esp32.md
+++ b/documentation/devices/esp32.md
@@ -78,10 +78,11 @@ The Moddable SDK supports many devices built on ESP32. The following table lists
| 
Moddable Two | `esp32/moddable_two`
`simulator/moddable_two` | **2.4" IPS display**
240 x 320 QVGA
16-bit color
Capacitive touch
20 External pins |
[Moddable Two developer guide](./moddable-two.md)[Moddable product page](https://www.moddable.com/hardware) |
| 
Moddable Display 2 | `esp32/moddable_display_2`
`simulator/moddable_two` | **2.4" IPS display**
240 x 320 QVGA
16-bit color
Capacitive touch
20 External pins | [Moddable Display developer guide](./moddable-display.md)[Moddable product page](https://www.moddable.com/hardware) |
| 
Node MCU ESP32 | `esp32/nodemcu` | |
-| 
M5Stack | `esp32/m5stack`
`esp32/m5stack_core2` | **1.8" LCD display**
320 x 240 QVGA
16-bit color
Audio playback
Accelerometer
NeoPixels | [Product page](https://m5stack.com/collections/m5-core/products/basic-core-iot-development-kit) |
+| 
M5Stack | `esp32/m5stack` | **1.8" LCD display**
320 x 240 QVGA
16-bit color
Audio playback
NeoPixels | [Product page](https://m5stack.com/collections/m5-core/products/basic-core-iot-development-kit) |
| 
M5Stack Fire | `esp32/m5stack_fire` | **1.8" LCD display**
320 x 240 QVGA
16-bit color
Audio playback
Accelerometer
NeoPixels | [Product page](https://m5stack.com/collections/m5-core/products/fire-iot-development-kit?variant=16804798169178) |
| 
M5Stick C | `esp32/m5stick_c`
`simulator/m5stick_c` | **0.96" LCD display**
80 x 160
16-bit color
IMU
Microphone | [Product page](https://m5stack.com/collections/m5-core/products/stick-c?variant=17203451265114) |
| 
M5Stick C PLUS | `esp32/m5stick_cplus` | **1.14" LCD display**
135 x 240
16-bit color
IMU
Microphone | [Product page](https://docs.m5stack.com/en/core/m5stickc_plus) |
+| 
M5Stack Core2 | `esp32/m5stack_core2` | **1.8" LCD display**
320 x 240 QVGA
16-bit color
Touch screen
Speaker
Microphone
IMU
BM8563 RTC
8MB PSRAM | [Product page](https://shop.m5stack.com/products/m5stack-core2-esp32-iot-development-kit) |
| 
M5Atom | `esp32/m5atom_echo`
`esp32/m5atom_lite`
`esp32/m5atom_matrix` | 5 x 5 RGB LED matrix panel
MPU6886 Inertial Sensor
6 External Pins | [Product page](https://m5stack.com/collections/m5-atom/products/atom-matrix-esp32-development-kit) |
| 
M5AtomU | `esp32/m5atom_u` | Neopixel, 1 button
Microphone
6 External Pins | [Product page](https://docs.m5stack.com/en/core/atom_us) |
| 
M5 Paper | `esp32/m5paper`
`simulator/m5paper` | **960 x 540 ePaper touch screen**
Temperature sensor | [Product page](https://shop.m5stack.com/products/m5paper-esp32-development-kit-960x540-4-7-eink-display-235-ppi?variant=37595977908396)[Moddable SDK docs](./m5paper.md) |
diff --git a/modules/drivers/peripherals/axp2101/axp2101.js b/modules/drivers/peripherals/axp2101/axp2101.js
index 167f94c9f..8f7b7fbb4 100644
--- a/modules/drivers/peripherals/axp2101/axp2101.js
+++ b/modules/drivers/peripherals/axp2101/axp2101.js
@@ -353,6 +353,12 @@ class AXP2101 {
return ADC_LSB * this.#read12Bit(0x62) + OFFSET_DEG_C;
}
+ getPekState() {
+ const state = this.readByte(0x49) & 0x0C;
+ if (state) this.writeByte(0x49, state);
+ return state;
+ }
+
#read24Bit(address) {
const buff = this.readBlock(address, 3);
return (buff[0] << 16) + (buff[1] << 8) + buff[2];