Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

enable wake-on-motion (WOM) for MPU6886 #122

Merged
merged 5 commits into from
Aug 3, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 102 additions & 0 deletions examples/Advanced/IMU_Wake_On_Motion/IMU_Wake_On_Motion.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
#include <Arduino.h>
#include <M5StickC.h>
#include <driver/rtc_io.h> // from ESP-IDF


void mpu6886_wake_on_motion_isr(void); // declaration of ISR


#define WOM_ATTACH_ISR
volatile uint32_t g_wom_count = 0;
volatile uint32_t g_wom_last_millis = 0;
void IRAM_ATTR mpu6886_wake_on_motion_isr(void) {
g_wom_count++;
g_wom_last_millis = millis();
}


/* Method to print the reason by which ESP32 has been awoken from sleep */
void get_wakeup_reason_string(char *cbuf, int cbuf_len){
esp_sleep_wakeup_cause_t wakeup_reason;
wakeup_reason = esp_sleep_get_wakeup_cause();
switch(wakeup_reason) {
case ESP_SLEEP_WAKEUP_EXT0 : snprintf(cbuf, cbuf_len, "ext0"); break;
case ESP_SLEEP_WAKEUP_EXT1 : snprintf(cbuf, cbuf_len, "ext1"); break;
case ESP_SLEEP_WAKEUP_TIMER : snprintf(cbuf, cbuf_len, "timer"); break;
case ESP_SLEEP_WAKEUP_TOUCHPAD : snprintf(cbuf, cbuf_len, "touchpad"); break;
case ESP_SLEEP_WAKEUP_ULP : snprintf(cbuf, cbuf_len, "ULP"); break;
default : snprintf(cbuf, cbuf_len, "%d",wakeup_reason); break;
}
}


RTC_DATA_ATTR int bootCount = 0;
#define WAKE_REASON_BUF_LEN 100
void setup() {
char wake_reason_buf[WAKE_REASON_BUF_LEN];

// put your setup code here, to run once:
M5.begin();
M5.Axp.ScreenBreath(8);
M5.Lcd.setRotation(3);
M5.Lcd.fillScreen(BLACK);
M5.Lcd.setTextSize(1);

get_wakeup_reason_string(wake_reason_buf, WAKE_REASON_BUF_LEN);
M5.Lcd.setCursor( 0, 0); M5.Lcd.printf("WOM: BOOT=%d, SRC=%s", bootCount, wake_reason_buf);
M5.Lcd.setCursor( 0, 10); M5.Lcd.printf("Battery: ");
M5.Lcd.setCursor( 0, 20); M5.Lcd.printf("V: %.3f v", M5.Axp.GetBatVoltage());
M5.Lcd.setCursor( 0, 30); M5.Lcd.printf("I: %.3f ma", M5.Axp.GetBatCurrent());
M5.Lcd.setCursor( 0, 40); M5.Lcd.printf("P: %.3f mw", M5.Axp.GetBatPower());



#ifdef WOM_GPIO_DEBUG_TEST
pinMode(GPIO_NUM_26, OUTPUT);
pinMode(GPIO_NUM_36, INPUT);
#endif // #ifdef WOM_GPIO_DEBUG_TEST


#ifdef WOM_ATTACH_ISR
// set up ISR to trigger on GPIO35
delay(100);
pinMode(GPIO_NUM_35, INPUT);
delay(100);
attachInterrupt(GPIO_NUM_35, mpu6886_wake_on_motion_isr, FALLING);
#endif // #ifdef WOM_ATTACH_ISR

//Increment boot number and print it every reboot
++bootCount;
Serial.println("Boot number: " + String(bootCount));

// set up mpu6886 for low-power operation
M5.Mpu6886.Init(); // basic init
M5.Mpu6886.enableWakeOnMotion(M5.Mpu6886.AFS_16G, 10);

// wait until IMU ISR hasn't triggered for X milliseconds
while(1) {
uint32_t since_last_wom_millis = millis() - g_wom_last_millis;
if(since_last_wom_millis > 5000) {
break;
}
Serial.printf("waiting : %d", since_last_wom_millis);
delay(1000);
}

// disable all wakeup sources
esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_ALL);

// enable waking up on pin 35 (from IMU)
esp_sleep_enable_ext0_wakeup(GPIO_NUM_35, LOW); //1 = High, 0 = Low

//Go to sleep now
Serial.println("Going to sleep now");
M5.Axp.SetSleep(); // conveniently turn off screen, etc.
delay(100);
esp_deep_sleep_start();
Serial.println("This will never be printed");
}


void loop() {
}
85 changes: 85 additions & 0 deletions src/utility/MPU6886.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,91 @@ int MPU6886::Init(void){
return 0;
}


void MPU6886::enableWakeOnMotion(Ascale ascale, uint8_t thresh_num_lsb) {
uint8_t regdata;
/* 5.1 WAKE-ON-MOTION INTERRUPT
The MPU-6886 provides motion detection capability. A qualifying motion sample is one where the high passed sample
from any axis has an absolute value exceeding a user-programmable threshold. The following steps explain how to
configure the Wake-on-Motion Interrupt.
*/

/* Step 0: this isn't explicitly listed in the steps, but configuring the
FSR or full-scale-range of the accelerometer is important to setting up
the accel/motion threshold in Step 4
*/
regdata = (ascale << 3);
I2C_Write_NBytes(MPU6886_ADDRESS, MPU6886_ACCEL_CONFIG, 1, &regdata);
delay(10);

/* Step 1: Ensure that Accelerometer is running
• In PWR_MGMT_1 register (0x6B) set CYCLE = 0, SLEEP = 0, and GYRO_STANDBY = 0
• In PWR_MGMT_2 register (0x6C) set STBY_XA = STBY_YA = STBY_ZA = 0, and STBY_XG = STBY_YG = STBY_ZG = 1
*/
I2C_Read_NBytes(MPU6886_ADDRESS, MPU6886_PWR_MGMT_1, 1, &regdata);
regdata = regdata & 0b10001111; // set cyle, sleep, and gyro to standby, i.e. 0
I2C_Write_NBytes(MPU6886_ADDRESS, MPU6886_PWR_MGMT_1, 1, &regdata);

regdata = 0b00000111; // set accel x, y, and z to standby
I2C_Write_NBytes(MPU6886_ADDRESS, MPU6886_PWR_MGMT_2, 1, &regdata);

/* Step 2: Set Accelerometer LPF bandwidth to 218.1 Hz
• In ACCEL_CONFIG2 register (0x1D) set ACCEL_FCHOICE_B = 0 and A_DLPF_CFG[2:0] = 1 (b001)
*/
I2C_Read_NBytes(MPU6886_ADDRESS, MPU6886_ACCEL_CONFIG2, 1, &regdata);
regdata = 0b00100001; // average 32 samples, use 218 Hz DLPF
I2C_Write_NBytes(MPU6886_ADDRESS, MPU6886_ACCEL_CONFIG2, 1, &regdata);

/* Step 2.5 - active low? */
I2C_Read_NBytes(MPU6886_ADDRESS, MPU6886_INT_PIN_CFG, 1, &regdata);
regdata = ((regdata | 0b10000000) & 0b11011111); // configure pin active-low, no latch
I2C_Write_NBytes(MPU6886_ADDRESS, MPU6886_INT_PIN_CFG, 1, &regdata);

/* Step 3: Enable Motion Interrupt
• In INT_ENABLE register (0x38) set WOM_INT_EN = 111 to enable motion interrupt
*/
regdata = 0b11100000; // enable wake-on-motion interrupt for X, Y, and Z axes
I2C_Write_NBytes(MPU6886_ADDRESS, MPU6886_INT_ENABLE, 1, &regdata);

/* Step 4: Set Motion Threshold
• Set the motion threshold in ACCEL_WOM_THR register (0x1F)
NOTE: the data sheet mentions 0x1F, but is probably referring to
registers 0x20, 0x21, and 0x22 based on empirical tests
*/
regdata = thresh_num_lsb; // set accel motion threshold for X, Y, and Z axes
I2C_Write_NBytes(MPU6886_ADDRESS, MPU6886_ACCEL_WOM_X_THR, 1, &regdata);
I2C_Write_NBytes(MPU6886_ADDRESS, MPU6886_ACCEL_WOM_Y_THR, 1, &regdata);
I2C_Write_NBytes(MPU6886_ADDRESS, MPU6886_ACCEL_WOM_Z_THR, 1, &regdata);

/* Step 5: Enable Accelerometer Hardware Intelligence
• In ACCEL_INTEL_CTRL register (0x69) set ACCEL_INTEL_EN = ACCEL_INTEL_MODE = 1;
Ensure that bit 0 is set to 0
*/
regdata = 0b11000010; // enable wake-on-motion if any of X, Y, or Z axes is above threshold
// WOM_STEP5_ACCEL_INTEL_CTRL_INTEL_EN_1_MODE_1_WOM_TH_MODE_0;
I2C_Write_NBytes(MPU6886_ADDRESS, MPU6886_ACCEL_INTEL_CTRL, 1, &regdata);

/* Step 7: Set Frequency of Wake-Up
• In SMPLRT_DIV register (0x19) set SMPLRT_DIV[7:0] = 3.9 Hz – 500 Hz
*/
// sample_rate = 1e3 / (1 + regdata)
// 4.0 Hz = 1e3 / (1 + 249)
// 10.0 Hz = 1e3 / (1 + 99)
// 20.0 Hz = 1e3 / (1 + 49)
// 25.0 Hz = 1e3 / (1 + 39)
// 50.0 Hz = 1e3 / (1 + 19) <----
// 500.0 Hz = 1e3 / (1 + 1)
regdata = 19;
I2C_Write_NBytes(MPU6886_ADDRESS, MPU6886_SMPLRT_DIV, 1, &regdata);

/* Step 8: Enable Cycle Mode (Accelerometer Low-Power Mode)
• In PWR_MGMT_1 register (0x6B) set CYCLE = 1
*/
I2C_Read_NBytes(MPU6886_ADDRESS, MPU6886_PWR_MGMT_1, 1, &regdata);
regdata = regdata | 0b00100000; // enable accelerometer low-power mode
I2C_Write_NBytes(MPU6886_ADDRESS, MPU6886_PWR_MGMT_1, 1, &regdata);
}

void MPU6886::getAccelAdc(int16_t* ax, int16_t* ay, int16_t* az){

uint8_t buf[6];
Expand Down
5 changes: 5 additions & 0 deletions src/utility/MPU6886.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@
#define MPU6886_SMPLRT_DIV 0x19
#define MPU6886_INT_PIN_CFG 0x37
#define MPU6886_INT_ENABLE 0x38
#define MPU6886_ACCEL_WOM_X_THR 0x20
#define MPU6886_ACCEL_WOM_Y_THR 0x21
#define MPU6886_ACCEL_WOM_Z_THR 0x22

#define MPU6886_ACCEL_XOUT_H 0x3B
#define MPU6886_ACCEL_XOUT_L 0x3C
#define MPU6886_ACCEL_YOUT_H 0x3D
Expand Down Expand Up @@ -70,6 +74,7 @@ class MPU6886 {
public:
MPU6886();
int Init(void);
void enableWakeOnMotion(Ascale ascale, uint8_t thresh_num_lsb);
void getAccelAdc(int16_t* ax, int16_t* ay, int16_t* az);
void getGyroAdc(int16_t* gx, int16_t* gy, int16_t* gz);
void getTempAdc(int16_t *t);
Expand Down