diff --git a/build/devices/pico/targets/ws_round/host/provider.js b/build/devices/pico/targets/ws_round/host/provider.js index 479c62ec37..91f216dd9d 100644 --- a/build/devices/pico/targets/ws_round/host/provider.js +++ b/build/devices/pico/targets/ws_round/host/provider.js @@ -26,6 +26,7 @@ import PulseCount from "embedded:io/pulsecount"; import PWM from "embedded:io/pwm"; import SMBus from "embedded:io/smbus"; import SPI from "embedded:io/spi"; +import QMI8658 from "embedded:sensor/Accelerometer-Gyroscope/QMI8658"; class Backlight { #io; @@ -92,6 +93,27 @@ const device = { return new Backlight({pin: device.pin.backlight }); } } + }, + sensor: { + IMU: class extends QMI8658 { + constructor(options) { + super({ + ...options, + sensor: { + ...device.I2C.default, + io: device.io.SMBus + } + }); + } + sample() { + const sample = super.sample(); + [sample.accelerometer.x, sample.accelerometer.y] = [sample.accelerometer.y, sample.accelerometer.x]; + sample.accelerometer.z *= -1; + [sample.gyroscope.x, sample.gyroscope.y] = [sample.gyroscope.y, sample.gyroscope.x]; + sample.gyroscope.z *= -1; + return sample; + } + } } }; diff --git a/build/devices/pico/targets/ws_round/manifest.json b/build/devices/pico/targets/ws_round/manifest.json index e848870169..3fd7abf0db 100644 --- a/build/devices/pico/targets/ws_round/manifest.json +++ b/build/devices/pico/targets/ws_round/manifest.json @@ -2,9 +2,7 @@ "include": [ "$(MODDABLE)/modules/io/manifest.json", "$(MODDABLE)/modules/drivers/gc9a01/manifest.json", - "$(MODULES)/drivers/led/manifest.json", - "$(MODULES)/drivers/button/manifest.json", - "$(MODULES)/pins/pwm/manifest.json" + "$(MODDABLE)/modules/drivers/sensors/qmi8658/manifest.json" ], "modules": { "setup/target": "./setup-target" @@ -19,11 +17,6 @@ "lcd_cs_pin": 9 }, "defines": { - "i2c": { - "sda_pin": 6, - "scl_pin": 7, - "port": 1 - }, "spi": { "mosi_pin": 11, "sck_pin": 10 diff --git a/build/devices/pico/targets/ws_round/setup-target.js b/build/devices/pico/targets/ws_round/setup-target.js index 7de3913958..b6c11db6ad 100644 --- a/build/devices/pico/targets/ws_round/setup-target.js +++ b/build/devices/pico/targets/ws_round/setup-target.js @@ -1,45 +1,20 @@ -import Digital from "pins/digital"; import config from "mc/config"; import Timer from "timer"; -import PWM from "pins/pwm"; - -class Backlight extends PWM { - constructor(brightness = 100) { - super({pin: config.backlight}); - this.write(brightness); - } - write(value) { - if (value <= 0) - value = 0; - else if (value >= 100) - value = 1023; - else - value = (value / 100) * 1023; - super.write(value); - } -} - -globalThis.Host = Object.freeze({ - Backlight -}, true); export default function (done) { - if ((undefined == config.brightness) || ("none" === config.brightness)) - Digital.write(config.backlight, 0); - else if ("off" === config.backlight) - Digital.write(config.backlight, 1); - else { - globalThis.backlight = new device.peripheral.Backlight; - backlight.brightness = parseInt(config.brigtness) / 100; - } + const Digital = device.io.Digital; + + const displayResetPin = new Digital({ pin: config.lcd_rst_pin, mode: Digital.Output }); + const displayCSPin = new Digital({ pin: config.lcd_cs_pin, mode: Digital.Output }); - Digital.write(config.lcd_rst_pin, 1); + displayResetPin.write(1); Timer.delay(100); - Digital.write(config.lcd_rst_pin, 0); + displayResetPin.write(0); Timer.delay(100); - Digital.write(config.lcd_rst_pin, 0); - Digital.write(config.lcd_cs_pin, 0); + displayCSPin.write(0); Timer.delay(100); + displayResetPin.close(); + displayCSPin.close(); done(); } diff --git a/build/devices/pico/targets/ws_round_touch/host/provider.js b/build/devices/pico/targets/ws_round_touch/host/provider.js index e7b6d04b06..fae6c42c9b 100644 --- a/build/devices/pico/targets/ws_round_touch/host/provider.js +++ b/build/devices/pico/targets/ws_round_touch/host/provider.js @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022-2025 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 SMBus from "embedded:io/smbus"; import SPI from "embedded:io/spi"; import Touch from "embedded:sensor/Touch/CST816"; +import QMI8658 from "embedded:sensor/Accelerometer-Gyroscope/QMI8658"; class Backlight { #io; @@ -117,6 +118,25 @@ const device = { result.configure({ }); return result; } + }, + IMU: class extends QMI8658 { + constructor(options) { + super({ + ...options, + sensor: { + ...device.I2C.default, + io: device.io.SMBus + } + }); + } + sample() { + const sample = super.sample(); + [sample.accelerometer.x, sample.accelerometer.y] = [sample.accelerometer.y, sample.accelerometer.x]; + sample.accelerometer.z *= -1; + [sample.gyroscope.x, sample.gyroscope.y] = [sample.gyroscope.y, sample.gyroscope.x]; + sample.gyroscope.z *= -1; + return sample; + } } } }; diff --git a/build/devices/pico/targets/ws_round_touch/manifest.json b/build/devices/pico/targets/ws_round_touch/manifest.json index 86d49d7a98..b1297660e2 100644 --- a/build/devices/pico/targets/ws_round_touch/manifest.json +++ b/build/devices/pico/targets/ws_round_touch/manifest.json @@ -1,10 +1,8 @@ { "include": [ "$(MODDABLE)/modules/io/manifest.json", - "$(MODDABLE)/modules/drivers/gc9a01/manifest.json", - "$(MODULES)/drivers/led/manifest.json", - "$(MODULES)/drivers/button/manifest.json", - "$(MODULES)/pins/pwm/manifest.json", + "$(MODULES)/drivers/gc9a01/manifest.json", + "$(MODULES)/drivers/sensors/qmi8658/manifest.json", "$(MODULES)/drivers/sensors/cst816/manifest.json" ], "modules": { @@ -20,11 +18,6 @@ "lcd_cs_pin": 9 }, "defines": { - "i2c": { - "sda_pin": 26, - "scl_pin": 27, - "port": 1 - }, "spi": { "mosi_pin": 11, "sck_pin": 10 diff --git a/documentation/devices/pico.md b/documentation/devices/pico.md index 8f1cd0f835..032ea26cb6 100644 --- a/documentation/devices/pico.md +++ b/documentation/devices/pico.md @@ -88,7 +88,7 @@ The Moddable SDK supports devices built with the Pico. The following table lists |
Adafruit
QT Py | `pico/qtpy` | STEMMA/Qwiic connector, Neopixel, 1 button |
  • [Adafruit product page](https://www.adafruit.com/product/4900)
  • | |
    Adafruit
    Trinkey QT2040 | `pico/qt_trinkey` | STEMMA/Qwiic connector, Neopixel, 1 button |
  • [Adafruit product page](https://www.adafruit.com/product/5056)
  • | |
    Pimoroni
    Tiny 2040 | `pico/tiny2040` | RGB LED, 1 button|
  • [Pimoroni product page](https://shop.pimoroni.com/products/tiny-2040?variant=39560012234835)
  • | -|
    WAVESHARE
    1.28inch Round LCD | `pico/ws_round`
    `pico/ws_round_touch` | 1.28" IPS 240×240 Round Display|
  • [WAVESHARE product page](https://www.waveshare.com/rp2040-lcd-1.28.htm)
  • [touch LCD version](https://www.waveshare.com/product/rp2040-touch-lcd-1.28.htm)
  • | +|
    WAVESHARE
    1.28inch Round LCD | `pico/ws_round`
    `pico/ws_round_touch` | 1.28" IPS 240×240 Round Display
    IMU|
  • [WAVESHARE product page](https://www.waveshare.com/rp2040-lcd-1.28.htm)
  • [touch LCD version](https://www.waveshare.com/product/rp2040-touch-lcd-1.28.htm)
  • | |
    Seeed Studio
    XIAO RP2040 | `pico/xiao_rp2040` | Neopixel |
  • [Seeed Studio product page](https://www.seeedstudio.com/XIAO-RP2040-v1-0-p-5026.html)
  • | |
    ili9341 | `pico/xiao_ili9341` | ili9341 QVGA display
    320 x 240
    16-bit color |
  • [Wiring Guide - Pico](../displays/images/xiao-qtpy-ili9341-wiring.png)
  • | |
    ili9341 | `pico/ili9341` | ili9341 QVGA display
    320 x 240
    16-bit color |
  • [Generic 2.4" & 2.8" Displays (Resistive Touch) Wiring Guide - Pico](../displays/wiring-guide-generic-2.4-spi-pico.md)
  • | diff --git a/examples/drivers/sensors/qmi8658/bounce/ball.png b/examples/drivers/sensors/qmi8658/bounce/ball.png new file mode 100644 index 0000000000..e0d0f0cca6 Binary files /dev/null and b/examples/drivers/sensors/qmi8658/bounce/ball.png differ diff --git a/examples/drivers/sensors/qmi8658/bounce/main.js b/examples/drivers/sensors/qmi8658/bounce/main.js new file mode 100644 index 0000000000..ff94d6f6ef --- /dev/null +++ b/examples/drivers/sensors/qmi8658/bounce/main.js @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2016-2017 Moddable Tech, Inc. + * + * 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 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 ILI9341 from "ili9341"; +import device from "embedded:provider/builtin"; +import Accelerometer from "embedded:sensor/Accelerometer-Gyroscope/MPU6050"; + +let pixelsOut = new ILI9341({}); +const width = pixelsOut.width; +const height = pixelsOut.height; + +let render = new Poco(pixelsOut); +let font = parseBMF(new Resource("OpenSans-Semibold-18.bf4")); + +let 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(); + +let sensor = new Accelerometer({ + sensor: { + ...device.I2C.default, + io: device.io.SMBus + } +}); + +Timer.repeat(() => { + let 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/qmi8658/bounce/manifest.json b/examples/drivers/sensors/qmi8658/bounce/manifest.json new file mode 100644 index 0000000000..0404bcd7cd --- /dev/null +++ b/examples/drivers/sensors/qmi8658/bounce/manifest.json @@ -0,0 +1,24 @@ +{ + "include": [ + "$(MODDABLE)/examples/manifest_base.json", + "$(MODDABLE)/examples/manifest_commodetto.json", + "$(MODDABLE)/modules/drivers/ili9341/manifest.json", + "$(MODDABLE)/modules/drivers/sensors/mpu6050/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/qmi8658/poll/main.js b/examples/drivers/sensors/qmi8658/poll/main.js new file mode 100644 index 0000000000..53b5dfe8a7 --- /dev/null +++ b/examples/drivers/sensors/qmi8658/poll/main.js @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2026 Moddable Tech, Inc. ,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 QMI8658 from "embedded:sensor/Accelerometer-Gyroscope/QMI8658"; +import Timer from "timer"; + +const sensor = new QMI8658({ + sensor: { + ...device.I2C.default, + io: device.io.SMBus + } +}); + +sensor.configure({ + ACCEL_SCALE: 8.0 / 32768.0, // AFS_8G + GYRO_SCALE: 1024.0 / 32768.0 // GFS_1024DPS +}); + +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`); +}, 2000); + diff --git a/examples/drivers/sensors/qmi8658/poll/manifest.json b/examples/drivers/sensors/qmi8658/poll/manifest.json new file mode 100644 index 0000000000..f65a323cb7 --- /dev/null +++ b/examples/drivers/sensors/qmi8658/poll/manifest.json @@ -0,0 +1,9 @@ +{ + "include": [ + "$(MODDABLE)/examples/manifest_base.json", + "$(MODDABLE)/modules/drivers/sensors/qmi8658/manifest.json" + ], + "modules": { + "*": "./main" + } +}