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)
  • | | ![ESP32](./../assets/devices/esp32.png)
    Node MCU ESP32 | `esp32/nodemcu` | | -| ![M5Stack](./../assets/devices/m5stack.png)
    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](./../assets/devices/m5stack.png)
    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](./../assets/devices/m5stack-fire.png)
    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](./../assets/devices/m5stick-c.png)
    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](./../assets/devices/m5stick-cplus.png)
    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](./../assets/devices/m5stack_core2.png)
    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](./../assets/devices/m5atom.png)
    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](./../assets/devices/m5atomu.png)
    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];