From 6afca0822a8e4b88b2799a0ecb7d26bba58686fa Mon Sep 17 00:00:00 2001 From: STC Date: Mon, 20 Apr 2026 22:02:36 +0900 Subject: [PATCH] M5atom Matrix and S3 migrate MPU6886 from pins/i2c to Ecma-419 --- .../targets/m5atom_matrix/host/provider.js | 26 +++- .../esp32/targets/m5atom_matrix/manifest.json | 4 +- .../targets/m5atom_matrix/setup-target.js | 62 +-------- .../esp32/targets/m5atom_s3/host/provider.js | 23 +++- .../esp32/targets/m5atom_s3/manifest.json | 4 +- .../esp32/targets/m5atom_s3/setup-target.js | 62 --------- .../m5atom_s3_echo_base/host/provider.js | 23 +++- .../targets/m5atom_s3_echo_base/manifest.json | 3 +- .../m5atom_s3_echo_base/setup-target.js | 59 -------- examples/drivers/atoms3-imu/main.js | 63 ++++----- .../drivers/sensors/mpu6886/bounce/ball.png | Bin 0 -> 16817 bytes .../drivers/sensors/mpu6886/bounce/main.js | 130 ++++++++++++++++++ .../sensors/mpu6886/bounce/manifest.json | 23 ++++ examples/drivers/sensors/mpu6886/poll/main.js | 31 +++++ .../sensors/mpu6886/poll/manifest.json | 10 ++ modules/drivers/sensors/mpu6886/mpu6886.js | 4 +- 16 files changed, 297 insertions(+), 230 deletions(-) create mode 100644 examples/drivers/sensors/mpu6886/bounce/ball.png create mode 100644 examples/drivers/sensors/mpu6886/bounce/main.js create mode 100644 examples/drivers/sensors/mpu6886/bounce/manifest.json create mode 100644 examples/drivers/sensors/mpu6886/poll/main.js create mode 100644 examples/drivers/sensors/mpu6886/poll/manifest.json diff --git a/build/devices/esp32/targets/m5atom_matrix/host/provider.js b/build/devices/esp32/targets/m5atom_matrix/host/provider.js index 79ed00ea53..cb61a02adc 100644 --- a/build/devices/esp32/targets/m5atom_matrix/host/provider.js +++ b/build/devices/esp32/targets/m5atom_matrix/host/provider.js @@ -28,6 +28,7 @@ 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 MPU6886 from "embedded:sensor/Accelerometer-Gyroscope/MPU6886"; const device = { I2C: { @@ -56,9 +57,32 @@ const device = { pin: 33 } }, - io: {Analog, Digital, DigitalBank, I2C, PulseCount, PulseWidth, PWM, Serial, SMBus, SPI}, + io: { Analog, Digital, DigitalBank, I2C, PulseCount, PulseWidth, PWM, Serial, SMBus, SPI }, pin: { button: 39 + }, + + sensor: { + IMU: class extends MPU6886 { + constructor(options) { + super({ + ...options, + sensor: { + ...device.I2C.internal, + io: device.io.SMBus + } + }); + } + sample() { + const sample = super.sample(); + sample.accelerometer.y *= -1; + sample.accelerometer.z *= -1; + sample.gyroscope.x = sample.gyroscope.y * -1; + sample.gyroscope.y = sample.gyroscope.x; + sample.gyroscope.z *= -1; + return sample; + } + } } }; diff --git a/build/devices/esp32/targets/m5atom_matrix/manifest.json b/build/devices/esp32/targets/m5atom_matrix/manifest.json index b514aeaa82..32f0bab916 100644 --- a/build/devices/esp32/targets/m5atom_matrix/manifest.json +++ b/build/devices/esp32/targets/m5atom_matrix/manifest.json @@ -1,7 +1,7 @@ { "include": [ + "$(MODDABLE)/modules/io/manifest.json", "$(MODULES)/pins/digital/monitor/manifest.json", - "$(MODULES)/pins/smbus/manifest.json", "$(MODULES)/drivers/sensors/mpu6886/manifest.json", "$(MODULES)/drivers/neopixel/manifest.json" ], @@ -11,14 +11,12 @@ }, "modules": { "*": [ - "$(MODULES)/drivers/mpu6886/*", "../m5stack_fire/m5button" ], "setup/target": "./setup-target" }, "preload": [ "m5button", - "mpu6886", "setup/target" ], "creation": { diff --git a/build/devices/esp32/targets/m5atom_matrix/setup-target.js b/build/devices/esp32/targets/m5atom_matrix/setup-target.js index db2705db1d..3e8988b294 100644 --- a/build/devices/esp32/targets/m5atom_matrix/setup-target.js +++ b/build/devices/esp32/targets/m5atom_matrix/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. * @@ -18,64 +18,8 @@ * */ -import Timer from "timer"; - import M5Button from "m5button"; - import NeoPixel from "neopixel"; -import MPU6886 from "mpu6886"; - -class Accelerometer { - #sensor; - #timer; - - constructor(sensor) { - this.#sensor = sensor; - } - start(frequency) { - this.stop(); - this.#timer = Timer.repeat(id => { - if (!this.onreading) - return; - - this.#sensor.configure({ operation: "accelerometer" }); - const sample = this.#sensor.sample(); - if (sample) - this.onreading(sample); - }, frequency); - } - stop() { - if (undefined !== this.#timer) - Timer.clear(this.#timer); - this.#timer = undefined; - } -} - -class Gyro { - #sensor; - #timer; - - constructor(sensor) { - this.#sensor = sensor; - } - start(frequency) { - this.stop(); - this.#timer = Timer.repeat(id => { - if (!this.onreading) - return; - - this.#sensor.configure({ operation: "gyroscope" }); - const sample = this.#sensor.sample(); - if (sample) - this.onreading({x: -sample.y, y: -sample.x, z: sample.z}); - }, frequency); - } - stop() { - if (undefined !== this.#timer) - Timer.clear(this.#timer); - this.#timer = undefined; - } -} export default function (done) { globalThis.button = { @@ -97,9 +41,5 @@ export default function (done) { } }); - const sensor = new MPU6886; - globalThis.accelerometer = new Accelerometer(sensor); - globalThis.gyro = new Gyro(sensor); - done(); } diff --git a/build/devices/esp32/targets/m5atom_s3/host/provider.js b/build/devices/esp32/targets/m5atom_s3/host/provider.js index 37d5d32d64..6ed13b9fe1 100644 --- a/build/devices/esp32/targets/m5atom_s3/host/provider.js +++ b/build/devices/esp32/targets/m5atom_s3/host/provider.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. * @@ -27,6 +27,7 @@ import PWM from "embedded:io/pwm"; import Serial from "embedded:io/serial"; import SMBus from "embedded:io/smbus"; import SPI from "embedded:io/spi"; +import MPU6886 from "embedded:sensor/Accelerometer-Gyroscope/MPU6886"; const device = { I2C: { @@ -61,6 +62,26 @@ const device = { backlight: 16, displayDC: 33, displaySelect: 15 + }, + sensor: { + IMU: class extends MPU6886 { + constructor(options) { + super({ + ...options, + sensor: { + ...device.I2C.internal, + io: device.io.SMBus + } + }); + } + sample() { + const sample = super.sample(); + sample.accelerometer.x *= -1; + sample.accelerometer.y *= -1; + sample.gyroscope.x *= -1; + return sample; + } + } } }; diff --git a/build/devices/esp32/targets/m5atom_s3/manifest.json b/build/devices/esp32/targets/m5atom_s3/manifest.json index 15d29fd5fc..de7e1054b6 100644 --- a/build/devices/esp32/targets/m5atom_s3/manifest.json +++ b/build/devices/esp32/targets/m5atom_s3/manifest.json @@ -8,7 +8,7 @@ "BEFORE_DEBUGGING_MESSAGE": "Press and release the Reset button." }, "include": [ - "$(MODULES)/pins/smbus/manifest.json", + "$(MODDABLE)/modules/io/manifest.json", "$(MODULES)/pins/digital/manifest.json", "$(MODULES)/pins/digital/monitor/manifest.json", "$(MODDABLE)/modules/drivers/ili9341/manifest.json", @@ -17,14 +17,12 @@ ], "modules": { "*": [ - "$(MODULES)/drivers/mpu6886/*", "../m5stack_fire/m5button" ], "setup/target": "./setup-target" }, "preload": [ "setup/target", - "mpu6886", "m5button" ], "config": { diff --git a/build/devices/esp32/targets/m5atom_s3/setup-target.js b/build/devices/esp32/targets/m5atom_s3/setup-target.js index d3e256d419..fd864a8b88 100644 --- a/build/devices/esp32/targets/m5atom_s3/setup-target.js +++ b/build/devices/esp32/targets/m5atom_s3/setup-target.js @@ -1,11 +1,5 @@ -import Digital from "pins/digital"; -//import Monitor from "monitor"; import M5Button from "m5button"; -import config from "mc/config"; -import Timer from "timer"; import Button from "button"; -import I2C from "pins/i2c"; -import MPU6886 from "mpu6886"; class Flash { constructor(options) { @@ -29,61 +23,5 @@ export default function (done) { a: new M5Button(41) }; - const sensor = new MPU6886; - globalThis.accelerometer = new Accelerometer(sensor); - globalThis.gyro = new Gyro(sensor); - done(); } - -class Accelerometer { - #sensor; - #timer; - - constructor(sensor) { - this.#sensor = sensor; - } - start(frequency) { - this.stop(); - this.#timer = Timer.repeat(id => { - if (!this.onreading) - return; - - this.#sensor.configure({ operation: "accelerometer" }); - const sample = this.#sensor.sample(); - if (sample) - this.onreading({x: sample.x, y: -sample.y, z: -sample.z}); - }, frequency); - } - stop() { - if (undefined !== this.#timer) - Timer.clear(this.#timer); - this.#timer = undefined; - } -} - -class Gyro { - #sensor; - #timer; - - constructor(sensor) { - this.#sensor = sensor; - } - start(frequency) { - this.stop(); - this.#timer = Timer.repeat(id => { - if (!this.onreading) - return; - - this.#sensor.configure({ operation: "gyroscope" }); - const sample = this.#sensor.sample(); - if (sample) - this.onreading({x: -sample.y, y: -sample.x, z: -sample.z}); - }, frequency); - } - stop() { - if (undefined !== this.#timer) - Timer.clear(this.#timer); - this.#timer = undefined; - } -} diff --git a/build/devices/esp32/targets/m5atom_s3_echo_base/host/provider.js b/build/devices/esp32/targets/m5atom_s3_echo_base/host/provider.js index 37d5d32d64..6ed13b9fe1 100644 --- a/build/devices/esp32/targets/m5atom_s3_echo_base/host/provider.js +++ b/build/devices/esp32/targets/m5atom_s3_echo_base/host/provider.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. * @@ -27,6 +27,7 @@ import PWM from "embedded:io/pwm"; import Serial from "embedded:io/serial"; import SMBus from "embedded:io/smbus"; import SPI from "embedded:io/spi"; +import MPU6886 from "embedded:sensor/Accelerometer-Gyroscope/MPU6886"; const device = { I2C: { @@ -61,6 +62,26 @@ const device = { backlight: 16, displayDC: 33, displaySelect: 15 + }, + sensor: { + IMU: class extends MPU6886 { + constructor(options) { + super({ + ...options, + sensor: { + ...device.I2C.internal, + io: device.io.SMBus + } + }); + } + sample() { + const sample = super.sample(); + sample.accelerometer.x *= -1; + sample.accelerometer.y *= -1; + sample.gyroscope.x *= -1; + return sample; + } + } } }; diff --git a/build/devices/esp32/targets/m5atom_s3_echo_base/manifest.json b/build/devices/esp32/targets/m5atom_s3_echo_base/manifest.json index 0c38cf8202..35bad455b1 100644 --- a/build/devices/esp32/targets/m5atom_s3_echo_base/manifest.json +++ b/build/devices/esp32/targets/m5atom_s3_echo_base/manifest.json @@ -8,6 +8,7 @@ "BEFORE_DEBUGGING_MESSAGE": "Press and release the Reset button." }, "include": [ + "$(MODDABLE)/modules/io/manifest.json", "$(MODULES)/pins/smbus/manifest.json", "$(MODULES)/pins/digital/manifest.json", "$(MODULES)/pins/digital/monitor/manifest.json", @@ -20,7 +21,6 @@ "pins/audioout": "$(MODULES)/pins/i2s/*", "pins/smbus": "$(MODULES)/pins/smbus/smbus", "*": [ - "$(MODULES)/drivers/mpu6886/*", "../m5stack_fire/m5button" ] }, @@ -28,7 +28,6 @@ "pins/audioout", "audioin", "setup/target", - "mpu6886", "m5button" ], "config": { diff --git a/build/devices/esp32/targets/m5atom_s3_echo_base/setup-target.js b/build/devices/esp32/targets/m5atom_s3_echo_base/setup-target.js index 589cadfcc0..6eb0c681e7 100644 --- a/build/devices/esp32/targets/m5atom_s3_echo_base/setup-target.js +++ b/build/devices/esp32/targets/m5atom_s3_echo_base/setup-target.js @@ -5,7 +5,6 @@ import config from "mc/config"; import Timer from "timer"; import Button from "button"; import I2C from "pins/i2c"; -import MPU6886 from "mpu6886"; import AudioOut from "pins/audioout"; import Resource from "Resource"; import SMBus from "pins/smbus"; @@ -61,12 +60,6 @@ export default function (done) { } - - // accelerometer and gyrometer - const sensor = new MPU6886; - globalThis.accelerometer = new Accelerometer(sensor); - globalThis.gyro = new Gyro(sensor); - done?.(); } @@ -148,55 +141,3 @@ class PI4IOE5V6408 { } } - -class Accelerometer { - #sensor; - #timer; - - constructor(sensor) { - this.#sensor = sensor; - } - start(frequency) { - this.stop(); - this.#timer = Timer.repeat(id => { - if (!this.onreading) - return; - - this.#sensor.configure({ operation: "accelerometer" }); - const sample = this.#sensor.sample(); - if (sample) - this.onreading({x: sample.x, y: -sample.y, z: -sample.z}); - }, frequency); - } - stop() { - if (undefined !== this.#timer) - Timer.clear(this.#timer); - this.#timer = undefined; - } -} - -class Gyro { - #sensor; - #timer; - - constructor(sensor) { - this.#sensor = sensor; - } - start(frequency) { - this.stop(); - this.#timer = Timer.repeat(id => { - if (!this.onreading) - return; - - this.#sensor.configure({ operation: "gyroscope" }); - const sample = this.#sensor.sample(); - if (sample) - this.onreading({x: -sample.y, y: -sample.x, z: -sample.z}); - }, frequency); - } - stop() { - if (undefined !== this.#timer) - Timer.clear(this.#timer); - this.#timer = undefined; - } -} diff --git a/examples/drivers/atoms3-imu/main.js b/examples/drivers/atoms3-imu/main.js index ad841986bd..db59f5d0e2 100644 --- a/examples/drivers/atoms3-imu/main.js +++ b/examples/drivers/atoms3-imu/main.js @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2022 Moddable Tech, Inc. + * Copyright (c) 2016-2026 Moddable Tech, Inc. * * This file is part of the Moddable SDK. * @@ -17,15 +17,16 @@ import parseBMP from "commodetto/parseBMP"; import Poco from "commodetto/Poco"; import Resource from "Resource"; import config from "mc/config"; +import Timer from "timer"; const GYRO_SCALER = 0.002; -let render = new Poco(screen, {rotation: config?.rotation ?? screen.rotation}); +const render = new Poco(screen, {rotation: config?.rotation ?? screen.rotation}); const width = render.width, height = render.height; -let font = parseBMF(new Resource("OpenSans-Semibold-16.bf4")); +const font = parseBMF(new Resource("OpenSans-Semibold-16.bf4")); -let ball = parseBMP(new Resource("ball-color.bmp")); +const ball = parseBMP(new Resource("ball-color.bmp")); ball.alpha = parseBMP(new Resource("ball-alpha.bmp")); ball.x = width >> 1; ball.y = height >> 1; @@ -43,47 +44,40 @@ render.begin(); render.fillRectangle(ball.backgroundColor, 0, ball.yMin, width, height); render.end(); -accelerometer.onreading = function(values){ - onReading(values, "a"); -} - -gyro.onreading = function(values){ - let {x, y, z} = values; - x *= GYRO_SCALER; - y *= GYRO_SCALER; - z *= GYRO_SCALER; - onReading({x,y,z}, "g"); -} +const imu = new device.sensor.IMU() +imu.configure({ + "GYRO_SCALER": (2000.0 / 32768.0) * GYRO_SCALER +}) +Timer.repeat(() => { + const sample = imu.sample(); + if(flag) { + onReading(sample.accelerometer, "a"); + } else { + onReading(sample.gyroscope, "g"); + } +}, 17) -accelerometer.start(17); -let flag = 0; +let flag = true; -button.a.onChanged = function(){ - let value = button.a.read(); +globalThis.button.a.onChanged = () =>{ + const value = globalThis.button.a.read(); if (value) { - accelerometer.stop(); - gyro.stop(); - if (flag) { - accelerometer.start(17); - flag = 0; - } else { - gyro.start(17); - flag = 1; - } + flag = !flag; } } function onReading(values, labelPrefix){ - let { x, y, z } = values; + const { x, y, z } = values; + // trace(`${labelPrefix}X: ${formatValue(x)} - ${labelPrefix}Y: ${formatValue(y)} - ${labelPrefix}Z: ${formatValue(z)}\n`); render.begin(0, 0, width, ball.yMin); render.fillRectangle(backgroundColor, 0, 0, width, height); - drawBar(labelPrefix + "X", x, 0, 0, width, font.height); - drawBar(labelPrefix + "Y", y, 0, font.height, width, font.height); - drawBar(labelPrefix + "Z", z, 0, font.height * 2, width, font.height); + drawBar(`${labelPrefix}X`, x, 0, 0, width, font.height); + drawBar(`${labelPrefix}Y`, y, 0, font.height, width, font.height); + drawBar(`${labelPrefix}Z`, z, 0, font.height * 2, width, font.height); render.end(); - ball.vx = (ball.vx - x) * 0.98; + ball.vx = (ball.vx + x) * 0.98; ball.vy = (ball.vy - y) * 0.98; let nx = ball.x + ball.vx; let ny = ball.y + ball.vy; @@ -106,13 +100,12 @@ function onReading(values, labelPrefix){ moveBallTo(nx, ny) } - function formatValue(value) { if (!value) return value; if (value < 0) return value.toFixed(3); - return "+" + value.toFixed(3); + return `+${value.toFixed(3)}`; } function drawBar(label, value, x, y, width, height) { diff --git a/examples/drivers/sensors/mpu6886/bounce/ball.png b/examples/drivers/sensors/mpu6886/bounce/ball.png new file mode 100644 index 0000000000000000000000000000000000000000..e0d0f0cca6c777d68ca132ca8a67f9ab7b21ff62 GIT binary patch literal 16817 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. + * or send a letter to Creative Commons, PO Box 1866, + * Mountain View, CA 94042, USA. + * + */ + +import config from "mc/config"; +import Timer from "timer"; +import parseBMF from "commodetto/parseBMF"; +import parseBMP from "commodetto/parseBMP"; +import Poco from "commodetto/Poco"; +import Resource from "Resource"; +import device from "embedded:provider/builtin"; +import Accelerometer from "embedded:sensor/Accelerometer-Gyroscope/MPU6886"; + +const width = screen.width; +const height = screen.height; + +const render = new Poco(screen); +const font = parseBMF(new Resource("OpenSans-Semibold-18.bf4")); + +const ball = parseBMP(new Resource("ball-color.bmp")); +ball.alpha = parseBMP(new Resource("ball-alpha.bmp")); +ball.x = width >> 1; +ball.y = height >> 1; +ball.vx = 0; +ball.vy = 0; +ball.yMin = font.height * 3; +ball.backGroundColor = render.makeColor(0, 0, 0); + +const textColor = render.makeColor(255, 255, 255); +const backgroundColor = render.makeColor(64, 64, 64); +const barColor = render.makeColor(128, 128, 128); + +render.begin(); + render.fillRectangle(backgroundColor, 0, 0, width, ball.yMin); + render.fillRectangle(ball.backgroundColor, 0, ball.yMin, width, height); +render.end(); + +const sensor = new Accelerometer({ + sensor: { + ...device.I2C.default, + io: device.io.SMBus + } +}); + +Timer.repeat(() => { + const values = sensor.sample(); + + if (180 === parseInt(config.orientation)) { + values.accelerometer.x = -values.accelerometer.x; + } + + render.begin(0, 0, width, ball.yMin); + render.fillRectangle(backgroundColor, 0, 0, width, height); + + drawBar("X", values.accelerometer.x, 0, 0, width, font.height); + drawBar("Y", values.accelerometer.y, 0, font.height, width, font.height); + drawBar("Z", values.accelerometer.z, 0, font.height * 2, width, font.height); + render.end(); + + ball.vx = (ball.vx + values.accelerometer.y) * 0.98; + ball.vy = (ball.vy + values.accelerometer.x) * 0.98; + let x = ball.x + ball.vx; + let y = ball.y + ball.vy; + if (x < 0) { + x = -x; + ball.vx = -ball.vx; + } + else if (x > (width - ball.width)) { + x = width - ball.width; + ball.vx = -ball.vx; + } + if (y < ball.yMin) { + y = ball.yMin; + ball.vy = -ball.vy; + } + else if (y > (height - ball.height)) { + y = height - ball.height; + ball.vy = -ball.vy; + } + moveBallTo(x, y) +}, 17); + +function formatValue(value) { + if (!value) + return value; + if (value < 0) + return value.toFixed(3); + return `+${value.toFixed(3)}`; +} + +function drawBar(label, value, x, y, width, height) { + const halfWidth = width >> 1; + const barWidth = (value * halfWidth) | 0; + + if (value > 0) + render.fillRectangle(barColor, x + halfWidth, y, barWidth, height); + else + render.fillRectangle(barColor, x + halfWidth + barWidth, y, -barWidth, height); + + render.drawText(`${label} ${formatValue(value)}`, font, textColor, x + 50, y); +} + +function moveBallTo(x, y) { + const w = ball.width, h = ball.height; + + if ((Math.abs(ball.x - x) <= w) && (Math.abs(ball.y - y) <= h)) + render.begin(Math.min(ball.x, x), Math.min(ball.y, y), w << 1, h << 1); // often overdrawing + else { + render.begin(ball.x, ball.y, w, h); + render.fillRectangle(ball.backgroundColor, 0, 0, width, height); + render.continue(x, y, w, h); + } + + render.fillRectangle(ball.backgroundColor, 0, 0, width, height); + render.drawMasked(ball, x, y, 0, 0, w, h, ball.alpha, 0, 0); + render.end(); + + ball.x = x; + ball.y = y; +} diff --git a/examples/drivers/sensors/mpu6886/bounce/manifest.json b/examples/drivers/sensors/mpu6886/bounce/manifest.json new file mode 100644 index 0000000000..17a8117f1b --- /dev/null +++ b/examples/drivers/sensors/mpu6886/bounce/manifest.json @@ -0,0 +1,23 @@ +{ + "include": [ + "$(MODDABLE)/examples/manifest_base.json", + "$(MODDABLE)/examples/manifest_commodetto.json", + "$(MODDABLE)/modules/drivers/sensors/mpu6886/manifest.json", + "$(MODDABLE)/modules/io/manifest.json" + ], + "modules": { + "*": [ + "./main" + ] + }, + "config": { + "orientation": "180" + }, + "preload": [ + "pins/*" + ], + "resources": { + "*": "./ball", + "*-mask": "$(MODDABLE)/examples/assets/fonts/OpenSans-Semibold-18" + } +} diff --git a/examples/drivers/sensors/mpu6886/poll/main.js b/examples/drivers/sensors/mpu6886/poll/main.js new file mode 100644 index 0000000000..c1d5e8b060 --- /dev/null +++ b/examples/drivers/sensors/mpu6886/poll/main.js @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2026 Satoshi Tanaka + * + * This file is part of the Moddable SDK. + * + * This work is licensed under the + * Creative Commons Attribution 4.0 International License. + * To view a copy of this license, visit + * . + * or send a letter to Creative Commons, PO Box 1866, + * Mountain View, CA 94042, USA. + * + */ + +import MPU6886 from "embedded:sensor/Accelerometer-Gyroscope/MPU6886"; +import Timer from "timer"; + +const sensor = new MPU6886({ + sensor: { + ...device.I2C.default, + io: device.io.SMBus + } +}); + +Timer.repeat(() => { + const sample = sensor.sample(); + + trace(`Accel: [${sample.accelerometer.x?.toFixed(2)}, ${sample.accelerometer.y?.toFixed(2)}, ${sample.accelerometer.z?.toFixed(2)}] - `); + trace(`Gyro: [${sample.gyroscope.x?.toFixed(2)}, ${sample.gyroscope.y?.toFixed(2)}, ${sample.gyroscope.z?.toFixed(2)}]\n`); +}, 1000); + diff --git a/examples/drivers/sensors/mpu6886/poll/manifest.json b/examples/drivers/sensors/mpu6886/poll/manifest.json new file mode 100644 index 0000000000..1e27eb4737 --- /dev/null +++ b/examples/drivers/sensors/mpu6886/poll/manifest.json @@ -0,0 +1,10 @@ +{ + "include": [ + "$(MODDABLE)/examples/manifest_base.json", + "$(MODDABLE)/modules/io/manifest.json", + "$(MODDABLE)/modules/drivers/sensors/mpu6886/manifest.json" + ], + "modules": { + "*": "./main" + } +} diff --git a/modules/drivers/sensors/mpu6886/mpu6886.js b/modules/drivers/sensors/mpu6886/mpu6886.js index 0c715d7d72..d1f47eb194 100644 --- a/modules/drivers/sensors/mpu6886/mpu6886.js +++ b/modules/drivers/sensors/mpu6886/mpu6886.js @@ -91,7 +91,7 @@ class MPU6886 { this.#view = new DataView(new ArrayBuffer(14)); this.operation = "gyroscope"; - if (io.readUint8(REGISTERS.WHO_AM_I) != EXPECTED_WHO_AM_I) + if (io.readUint8(REGISTERS.WHO_AM_I) !== EXPECTED_WHO_AM_I) throw new Error("unrecognized") Timer.delay(1); @@ -129,7 +129,7 @@ class MPU6886 { this.#io = undefined; } configure(dictionary) { //@@ revisit - for (let property in dictionary) { + for (const property in dictionary) { switch (property) { case "GYRO_SCALER": this.#gyroScale = dictionary.GYRO_SCALER;