Closed standarddeviant closed 4 years ago
I'm playing around with receiving interrupts from the AXP192 power managment chip, so here are some thoughts:
-> I think therefore the best solution to make all 3 interrupts work is to configure all as active low, open drain and register the ISR routine as FALLING edge. The ISR can then set a flag as in your code, and the loop must read the status of all devices whose interrupt is active (in your project this is just the IMU, for me it's just the AXP, but it would be exciting to have all 3 possible, e.g. with the wake-up when power is supplied or power button is short pressed etc.)
If I get any further with this, I might also be submitting a PR to correctly init the INT_PIN_CFG on MPU6886. My idea is to add IMU.Init() (or a new function IMU.Reset()) to the M5.begin() method which sets the interrupts correctly and possibly puts the IMU in low power state. Then, if someone actually needs to use the IMU, they call IMU.Init() maybe with optional arguments to enable only Accel or Gyro, whether to enable interrupt and so forth.
@ldoyle That sounds interesting to me! I have wake-on-motion working from deep sleep on the ESP32 - I'll share a gist of that once I iron out a few things. I'd be happy to collaborate on APIs etc. That's neat info about the active-low open-drain config of the MPU6886 - I just checked the datasheet for myself. I plan to put some basic MPU6886 config logic in to a branch soon - maybe adding a special argument to enable "wake-on-motion" interrupts. Let's keep chatting!
@ldoyle I made a proof-of-concept that wakes up on motion from deep sleep, per your suggestion. It doesn't configure as open-drain, but it could probably be made to work that way. I'm a bit naive on details re: open-drain vs. not. Here's my updated sketch that just counts the number of boots as a variable in RTC memory. That sketch is here: https://gist.github.com/standarddeviant/85c31cf34eb51e10aa3bb02dcd0bcbd1
@ldoyle I want to clean up the API/example a bit, but I've made some progress here: https://github.com/standarddeviant/M5StickC/tree/mpu6886_wake_on_motion/examples/Advanced/IMU_Wake_On_Motion
I'm wondering if certain use-cases for waking up from GPIO35 from the 3 sources should coordinate. I'm thinking about better APIs to accomplish that example. There's still a few finnicky things in there that might intimidate newbies. Specifically, I'm thinking of more convenient APIs to handle the rtc_gpio_[de]init
logic and where those APIs belong - i.e. AXP192 vs. IMU vs. RTC. More to come. :-)
I didn't have time to test much, but here are some thoughts:
WOM_STEP2P5_INT_PIN_CFG_ACTIVE_LOW_NO_LATCH(r) ((r | 0x88) & 0xDF)
to ((r | 0xC0) & 0xDF)
, so bit 6 to high, FSYNC seems to be disabled/not used, so no need to set bit 3 (counting from 0).0xC0
as 0b11000000
, maybe this is more readable here?regdata = ((regdata | 0b11000000) & 0b11011111)
I can immediately see on the current line which bits are changed, and the comment which bit does what then can also be right there with the register name etc. Also, as I recently learned flooding the code with defines can have unwanted effects (see issue #113, although this problem only occurs with #define
s in headers, yours in the .cpp
file should not be a problem)rtc_gpio_[de]init
? Does it still work if you comment them out? I tested a simple script using button A (GPIO37) as interrupt source (pinMode(INPUT)
and attachInterrupt
) and also as deep sleep wakeup source, and it works fine without the init/deinit. I could not find clear documentation on this, but the doc suggests rtc_gpio_init
is necessary only when using the analog functions and maybe when using rtc_gpio_hold_en
. My guess (could be wrong) would be in deep sleep, the pin is configured as RTC pin anyway since the main processor won't need it, and once we're back in the main program the default GPIO mode is fine.g_wom_last_millis
from being corrupted? I might be too unexperienced here with ESP or C++ in general, but I think it should be fine without since you're only accessing that value a single time, after which a valid number in memory is used for subtraction etc. Or is it somehow because of millis()
?MPU6886.Init()
currently).Init()
would potentially make it harder to keep both libraries in sync and profit from mutual improvments on the long term.Thanks for the detailed reply! Point-by-point...
0b...
instead of 0x...
seems like a good suggestion for readability. I'm okay with hex, and I still messed a few things up along the way. :-) I'll change that soon. rtc_gpio_deinit
, but I'm pretty sure I need the rtc_gpio_init
before going to deep sleep. I'll test this thoroughly at some point.g_wom_last_millis
is probably a single clock cycle, so in this case it's probably overly paranoid. This example should work without the disable/re-enable of interrupts.SYS_INT
from GPIO35, that might require reading various states of AXP/MPU/RTC. This probably requires digging in to multiple datasheets maybe along with careful init procedure, etc. This seems like a longer term goal, but interesting.SYS_INT
is wired internally. I plan to check that wiring connection to GPIO35 (or some other pin) empirically. The same logic might be nice on that board too.I'll ping this thread when I've made and tested those changes.
@ldoyle I made the changes you suggested. You were right about the rtc_gpio_[de]init
- they don't seem to be needed. I still can't get the open drain to work - not sure what that's all about. After reading a bit on EIS FSYNC, that's definitely not needed for wake-on-motion and I think has to do with integrating in to a camera for image stabilization.
I also got rid of the macros and now use binary masks instead of hex masks. I'm going to test a bit more with this, but might submit a PR soon.
Nice to see you're making progress, I haven't found any time to play with my M5 unfortunately. Yeah, some tutorials seem to have the gpio_init
, some not. Interesting point about disabling interrupts, you're absolutely right once you read both variables set by the Irq things can be confusing without the "lock".
I'm not sure what is going wrong with the open-drain issue, I got my Axp interrupt working according to #110, specifically by setting also the IMU (although not in use) to active-low with this command:
// set int active is LOW
M5.I2C.writeByte(0x68, 0x37, 0xc8); //actually also sets open-drain
I can think of 2 things that might be going wrong:
Both ways Push-Pull would work while open-drain does not because: IMU has interrupt, sets line LOW, Axp or RTC has no interrupt: Pin35 is LOW correctly IMU has interrupt, sets line LOW, Axp or RTC has interrupt (pulls LOW which already is): Pin35 is LOW correctly IMU has no interrupt, sets line HIGH, Axp or RTC has no interrupt, so essentially "disconnected": Pin35 is HIGH correctly IMU has no interrupt, sets line HIGH, Axp or RTC has an interrupt pulling to LOW: depending on internal resistances Pin35 might measure LOW correctly, but a high current can flow out of the IMU high pin into the e.g. Axp low pin, worst case maybe harming the device.
Hi Guys, there is official example for wake-up-on-motion MPU here: https://github.com/m5stack/M5StickC/blob/master/examples/Advanced/IMU_Wake_On_Motion/IMU_Wake_On_Motion.ino
Is it the same one you all been looking for?
Hi Zontex, as you can see from the linked merge request, it's actually @standarddeviant's work in the official repo now :) But yes, it seems the issue is therefore solved.
I made a proof of concept Arduino sketch to enable wake-on-motion for the MPU6886 inside the M5StickC. I'd like to fork the repo, add support for wake-on-motion (to GPIO Pin 35), and then submit a pull request. Is there a testing/integration process for doing that or coding guidelines I should follow?
For those curious, the proof-of-concept sketch is here: https://gist.github.com/standarddeviant/ea0b7f12a32bf5de96992a8ef350351d
A demo video of that sketch is here: https://www.youtube.com/watch?v=v5GpsvjFsEw
I documented a few notes on this here on the m5stack community page: https://community.m5stack.com/topic/2039/wake-up-on-pick-up
Cheers!