Skip to content
Open
66 changes: 66 additions & 0 deletions build/devices/esp32/targets/m5stack_core2/host/provider.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,29 @@ 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;
}
}

const device = {
I2C: {
Expand Down Expand Up @@ -69,7 +92,50 @@ const device = {
pin: {
displayDC: 15,
displaySelect: 5
},
sensor: {
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");
}
}
}
};

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;
5 changes: 4 additions & 1 deletion build/devices/esp32/targets/m5stack_core2/manifest.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
{
"build": {
"UPLOAD_SPEED": "1500000",
"DEBUGGER_SPEED": "921600",
"DEBUGGER_SPEED": "460800",
"SDKCONFIGPATH": "./sdkconfig",
"PARTITIONS_FILE_FOR_TARGET": "./sdkconfig/partitions.csv"
},
"include": [
"$(MODDABLE)/modules/io/manifest.json",
"$(MODDABLE)/modules/drivers/ili9341/manifest.json",
"$(MODDABLE)/modules/drivers/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"
],
Expand Down
199 changes: 143 additions & 56 deletions build/devices/esp32/targets/m5stack_core2/setup-target.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@

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";
Expand All @@ -33,10 +35,95 @@ const INTERNAL_I2C = Object.freeze({
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 {
constructor(brightness = 100) {
Expand Down Expand Up @@ -119,68 +206,68 @@ export default function (done) {
}

// accelerometer and gyrometer
const test = new I2C({...INTERNAL_I2C, address: 0x68, throw: false});
test.write(0x75, false);
const ok = test.read(1);
test.close();
if (undefined !== ok) {
state.accelerometerGyro = new MPU6886(INTERNAL_I2C);

globalThis.accelerometer = {
onreading: nop,
};
globalThis.accelerometer = {
onreading: nop,
};

globalThis.gyro = {
onreading: nop,
};
globalThis.gyro = {
onreading: nop,
};

accelerometer.start = function (frequency) {
accelerometer.stop();
state.accelerometerTimerID = Timer.repeat((id) => {
state.accelerometerGyro.configure({
operation: "accelerometer",
});
const sample = state.accelerometerGyro.sample();
if (sample) {
state.handleRotation(sample);
accelerometer.onreading(sample);
}
}, frequency);
};
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) => {
state.accelerometerGyro.configure({
operation: "gyroscope",
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,
});
const sample = state.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);
};
}
}, frequency);
};

accelerometer.stop = function () {
if (undefined !== state.accelerometerTimerID)
Timer.clear(state.accelerometerTimerID);
delete state.accelerometerTimerID;
};
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;
};
}
gyro.stop = function () {
if (undefined !== state.gyroTimerID) Timer.clear(state.gyroTimerID);
delete state.gyroTimerID;
};

// autorotate
if (config.autorotate && globalThis.Application && globalThis.accelerometer) {
Expand Down
Loading