mpu6050 usermod: allow to disable usermod

* added usermod config information (so it can be disabled)
* check that "INTERRUPT_PIN" does support interrupts (MM specific)
* expose "dmpReady" in public interface
* adjusted games usermod to switch to "simulation" in case mpu6050 is not active

Still toDo:
1. add interrupt PIN and errormessages to settings page.
2. de-alloc intPin when disabled (and disable interrupt)
3. usermod is still destroying DEBUG_PRINT macros.
4. temporarily disable MPU interrupt when  onUpdateBegin(true)
This commit is contained in:
Frank
2023-03-14 20:52:48 +01:00
parent a0576ba591
commit 2de7971623
5 changed files with 94 additions and 28 deletions

View File

@@ -94,17 +94,23 @@ class MPU6050Driver : public Usermod {
private:
MPU6050 mpu;
bool enabled = true;
bool initDone = false;
unsigned long lastUMRun = millis();
// MPU control/status vars
bool dmpReady = false; // set true if DMP init was successful
uint8_t mpuIntStatus; // holds actual interrupt status byte from MPU
uint8_t devStatus; // return status after each device operation (0 = success, !0 = error)
uint16_t packetSize; // expected DMP packet size (default is 42 bytes)
uint16_t fifoCount; // count of all bytes currently in FIFO
uint8_t fifoBuffer[64]; // FIFO storage buffer
// strings to reduce flash memory usage (used more than twice)
static const char _name[];
static const char _enabled[];
static const char _INT_pin[];
public:
bool dmpReady = false; // set true if DMP init was successful // WLEDMM expose this info in public interface
// orientation/motion vars
Quaternion qat; // [w, x, y, z] quaternion container
VectorInt16 aa; // [x, y, z] accel sensor measurements
@@ -123,6 +129,10 @@ class MPU6050Driver : public Usermod {
void setup() {
// WLEDMM begin
if (!enabled) {
dmpReady = false;
return;
}
USER_PRINTLN(F("mpu setup"));
PinManagerPinType pins[2] = { { i2c_scl, true }, { i2c_sda, true } };
if ((i2c_scl < 0) || (i2c_sda < 0)) {
@@ -171,16 +181,26 @@ class MPU6050Driver : public Usermod {
// initialize device
DEBUG_PRINT_IMULN(F("Initializing I2C devices..."));
// WLEDMM begin
if (!pinManager.allocatePin(INTERRUPT_PIN, false, PinOwner::UM_Unspecified))
if ((INTERRUPT_PIN < 0) || (!pinManager.isPinINT(INTERRUPT_PIN))) {
//enabled = false;
USER_PRINTF("mpu6050: warning - interrupt GPIO %d does not support interrupts.\n", INTERRUPT_PIN);
//INTERRUPT_PIN = -1;
//return;
}
if ((INTERRUPT_PIN >= 0) && (pinManager.getPinOwner(INTERRUPT_PIN) != PinOwner::UM_IMU) // only allocate pin if we don't ownn it already
&& !pinManager.allocatePin(INTERRUPT_PIN, false, PinOwner::UM_IMU))
{
//enabled = false;
USER_PRINTF("mpu6050: warning - failed to allocate interrupt GPIO %d\n", INTERRUPT_PIN);
//INTERRUPT_PIN = -1;
//return;
}
// WLEDMM end
mpu.initialize();
pinMode(INTERRUPT_PIN, INPUT);
if (INTERRUPT_PIN >= 0) { // WLEDMM only if pin is valid
pinMode(INTERRUPT_PIN, INPUT);
}
// verify connection
DEBUG_PRINT_IMULN(F("Testing device connections..."));
@@ -214,11 +234,13 @@ class MPU6050Driver : public Usermod {
DEBUG_PRINT_IMULN(F("Enabling DMP..."));
mpu.setDMPEnabled(true);
// enable Arduino interrupt detection
DEBUG_PRINT_IMU(F("Enabling interrupt detection (Arduino external interrupt "));
DEBUG_PRINT_IMU(digitalPinToInterrupt(INTERRUPT_PIN));
DEBUG_PRINT_IMULN(F(")..."));
attachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN), dmpDataReady, RISING);
if (INTERRUPT_PIN >= 0) {
// enable Arduino interrupt detection
DEBUG_PRINT_IMU(F("Enabling interrupt detection (Arduino external interrupt "));
DEBUG_PRINT_IMU(digitalPinToInterrupt(INTERRUPT_PIN));
DEBUG_PRINT_IMULN(F(")..."));
attachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN), dmpDataReady, RISING);
}
mpuIntStatus = mpu.getIntStatus();
// set our DMP Ready flag so the main loop() function knows it's okay to use it
@@ -235,7 +257,9 @@ class MPU6050Driver : public Usermod {
DEBUG_PRINT(F("DMP Initialization failed (code "));
DEBUG_PRINT(devStatus);
DEBUG_PRINTLN(")");
dmpReady = false;
}
initDone = true;
}
void connected() {
@@ -244,6 +268,7 @@ class MPU6050Driver : public Usermod {
void loop() {
// if programming failed, don't try to do anything
if (!initDone) return;
if (!enabled || (strip.isUpdating() && (millis() - lastUMRun < 2))) return; // be nice, but not too nice
lastUMRun = millis(); // update time keeping
@@ -265,6 +290,8 @@ class MPU6050Driver : public Usermod {
void addToJsonInfo(JsonObject& root)
{
if (!initDone) return;
if (!enabled && !dmpReady) return; // WLEDMM no info when usermod disabled
JsonObject user = root["u"];
if (user.isNull()) user = root.createNestedObject("u");
@@ -328,29 +355,67 @@ class MPU6050Driver : public Usermod {
//{
//}
// void addToConfig(JsonObject& root)
// {
// JsonObject top = root.createNestedObject("MPU6050");
// top[FPSTR("enabled")] = enabled;
void addToConfig(JsonObject& root)
{
JsonObject top = root.createNestedObject(FPSTR(_name));
top[FPSTR(_enabled)] = enabled;
//JsonObject interruptPin = top.createNestedObject(FPSTR(_INT_pin));
//interruptPin["pin"] = INTERRUPT_PIN;
DEBUG_PRINTLN(F("MPU6050 IMU config saved."));
}
// JsonObject interruptPin = top.createNestedObject(FPSTR("interruptPin"));
// interruptPin["pin"] = interruptPin;
// }
//WLEDMM: add appendConfigData
void appendConfigData()
{
oappend(SET_F("addHB('MPU6050 Motion Sensor (IMU)');"));
/*
#ifdef MPU6050_INT_GPIO
oappend(SET_F("xOpt('mpu6050-IMU:interrupt_pin',0,' ⎌',")); oappendi(MPU6050_INT_GPIO); oappend(");");
#endif
//WLEDMM add errorMessage to um settings
if (strcmp(errorMessage, "") != 0) {
oappend(SET_F("addInfo('errorMessage', 0, '<i>error: ")); oappend(errorMessage); oappend("! Correct and reboot</i>');");
}
*/
}
// bool readFromConfig(JsonObject& root)
// {
// JsonObject top = root[FPSTR("MPU6050")];
// bool configComplete = !top.isNull();
bool readFromConfig(JsonObject& root)
{
JsonObject top = root[FPSTR(_name)];
// configComplete &= getJsonValue(top[FPSTR("enabled")], enabled);
// configComplete &= getJsonValue(top[FPSTR("interruptPin")]["pin"], interruptPin);
if (top.isNull()) {
DEBUG_PRINT(FPSTR(_name));
DEBUG_PRINTLN(F(": No config found. (Using defaults.)"));
return false;
}
// return configComplete;
// }
bool configComplete = !top.isNull();
configComplete &= getJsonValue(top[FPSTR(_enabled)], enabled);
//configComplete &= getJsonValue(top[FPSTR(_INT_pin)]["pin"], INTERRUPT_PIN);
DEBUG_PRINT(FPSTR(_name));
if (!initDone) {
// first run: reading from cfg.json
DEBUG_PRINTLN(F(" config loaded."));
} else {
DEBUG_PRINTLN(F(" config (re)loaded."));
if (enabled || dmpReady) setup(); // re-run setup if user has checked "enabled"
if (!enabled) dmpReady = false; // not enabled inplies "no DMP data ready"
}
return configComplete;
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features
//return !top[FPSTR(_INT_pin)].isNull();
}
uint16_t getId()
{
return USERMOD_ID_IMU;
}
};
};
// strings to reduce flash memory usage (used more than twice)
const char MPU6050Driver::_name[] PROGMEM = "mpu6050-IMU";
const char MPU6050Driver::_enabled[] PROGMEM = "enabled";
const char MPU6050Driver::_INT_pin[] PROGMEM = "interrupt_pin";

View File

@@ -183,7 +183,7 @@ uint16_t mode_IMUTest(void) {
uint8_t y = 0;
if (IMU != nullptr) {
if ((IMU != nullptr) && (IMU->dmpReady)) {
SEGMENT.setPixelColorXY(SEGMENT.virtualWidth() * (IMU->aa.x+INT16_MAX)/(2*INT16_MAX), y+=1, BLUE);
SEGMENT.setPixelColorXY(SEGMENT.virtualWidth() * (IMU->aa.y+INT16_MAX)/(2*INT16_MAX), y+=1, BLUE);
SEGMENT.setPixelColorXY(SEGMENT.virtualWidth() * (IMU->aa.z+INT16_MAX)/(2*INT16_MAX), y+=1, BLUE);
@@ -280,7 +280,7 @@ uint16_t mode_3DIMUCube(void) {
float roll = 0;
#ifdef USERMOD_MPU6050_IMU
if (IMU != nullptr) {
if ((IMU != nullptr) && (IMU->dmpReady)) {
yaw = -IMU->ypr[0];
pitch = IMU->ypr[1];
roll = IMU->ypr[2];

View File

@@ -49,6 +49,7 @@ String PinManagerClass::getOwnerText(PinOwner tag) {
case PinOwner::UM_Audioreactive : return(F("AudioReactive (UM)")); break; // audioreative usermod - analog or digital audio input
case PinOwner::UM_Temperature : return(F("Temperature (UM)")); break; // "usermod_temperature.h"
case PinOwner::UM_PIR : return(F("PIR (UM)")); break; // "usermod_PIR_sensor_switch.h"
case PinOwner::UM_IMU : return(F("IMU mpu6050 (UM)")); break; // "usermod_mpu6050_imu.h"
case PinOwner::UM_FourLineDisplay : return(F("4Line Display (UM)")); break; // "usermod_v2_four_line_display.h -- May use "standard" HW_I2C pins
case PinOwner::UM_RotaryEncoderUI : return(F("Rotary Enc. (UM)")); break; // "usermod_v2_rotary_encoder_ui.h"
case PinOwner::UM_MultiRelay : return(F("Multi Relay (UM)")); break; // "usermod_multi_relay.h"

View File

@@ -41,7 +41,7 @@ enum struct PinOwner : uint8_t {
UM_Temperature = USERMOD_ID_TEMPERATURE, // 0x03 // Usermod "usermod_temperature.h"
// #define USERMOD_ID_FIXNETSERVICES // 0x04 // Usermod "usermod_Fix_unreachable_netservices.h" -- Does not allocate pins
UM_PIR = USERMOD_ID_PIRSWITCH, // 0x05 // Usermod "usermod_PIR_sensor_switch.h"
// #define USERMOD_ID_IMU // 0x06 // Usermod "usermod_mpu6050_imu.h" -- Uses "standard" HW_I2C pins
UM_IMU = USERMOD_ID_IMU, // 0x06 // Usermod "usermod_mpu6050_imu.h" -- Uses "standard" HW_I2C pins
UM_FourLineDisplay = USERMOD_ID_FOUR_LINE_DISP, // 0x07 // Usermod "usermod_v2_four_line_display.h -- May use "standard" HW_I2C pins
UM_RotaryEncoderUI = USERMOD_ID_ROTARY_ENC_UI, // 0x08 // Usermod "usermod_v2_rotary_encoder_ui.h"
// #define USERMOD_ID_AUTO_SAVE // 0x09 // Usermod "usermod_v2_auto_save.h" -- Does not allocate pins

View File

@@ -8,7 +8,7 @@
*/
// version code in format yymmddb (b = daily build)
#define VERSION 2303130
#define VERSION 2303141
//uncomment this if you have a "my_config.h" file you'd like to use
//#define WLED_USE_MY_CONFIG