I was doing a demo code to implement a wake up triggered by motion. I was able to make it work with the integrated low power accelerometer on thingy52 but it only worked 1 time after turning off and on the board. After some research I found out that the problem might be in the internal latch of the accelerometer and it was suggested to read the register to clear that latch. I started doing that before configuring the interrupt, but the behavior is not consistent. Sometimes it works, other times not.
Here is the code I amusing:
main.c
#include "bt_service.h"#include "accelerometer.h"#include <zephyr/sys/poweroff.h>#include <zephyr/logging/log.h>LOG_MODULE_REGISTER(STATE_MACHINE, LOG_LEVEL_INF);int main(void){ init_bt_service(); init_advertise(); k_sleep(K_SECONDS(10)); LOG_INF("%s system off demo\n", CONFIG_BOARD); init_accelerometer(); k_sleep(K_SECONDS(10)); sys_poweroff(); return 0;}#include <zephyr/drivers/gpio.h>#include "accelerometer.h"LOG_MODULE_REGISTER(ACCELEROMETER, LOG_LEVEL_INF);const struct device *accelerometer = DEVICE_DT_GET_ANY(st_lis2dh12);const struct gpio_dt_spec accelerometer_gpio = GPIO_DT_SPEC_GET(DT_NODELABEL(lis2dh12), irq_gpios);const struct i2c_dt_spec accelerometer_i2c = I2C_DT_SPEC_GET(DT_NODELABEL(lis2dh12));static void lis2dh_trigger_handler(const struct device *accelerometer, const struct sensor_trigger *trig){ struct sensor_value xyz[3]; if (sensor_sample_fetch(accelerometer)) { LOG_ERR("Failed to fetch sensor sample"); return; } if (sensor_channel_get(accelerometer, SENSOR_CHAN_ACCEL_XYZ, xyz)) { LOG_ERR("Failed to get sensor channel: accel"); return; } LOG_INF("Movement detected: X=%d mg, Y=%d mg, Z=%d mg", (int)(sensor_value_to_double(&xyz[0]) * 1000), (int)(sensor_value_to_double(&xyz[1]) * 1000), (int)(sensor_value_to_double(&xyz[2]) * 1000)); stop_accelerometer();}static void clear_accelerometer_interrupt_line(){ uint8_t src; if (!device_is_ready(accelerometer_i2c.bus)) { LOG_ERR("I2C bus not ready to clear LIS2DH interrupt"); return; } if (i2c_reg_read_byte(accelerometer_i2c.bus, LIS2DH_ADDR, LIS2DH_REG_INT1_SRC, &src)) { LOG_ERR("Failed to read INT1_SRC"); } LOG_INF("Cleared LIS2DH interrupt, INT1_SRC=0x%02X", src);}void configure_accelerometer_wakeup_gpio() { if(gpio_pin_configure_dt(&accelerometer_gpio, GPIO_INPUT)) { LOG_INF("Could not configure accelerometer GPIO"); return; } if (gpio_pin_interrupt_configure_dt(&accelerometer_gpio, GPIO_INT_LEVEL_ACTIVE)) { LOG_INF("Could not configure accelerometer GPIO interrupt"); return; } NRF_GPIO->PIN_CNF[accelerometer_gpio.pin] |= (GPIO_PIN_CNF_SENSE_High << GPIO_PIN_CNF_SENSE_Pos);}void init_accelerometer(void){ if (accelerometer == NULL) { LOG_ERR("Accelerometer device not found"); return; } if (!device_is_ready(accelerometer)) { LOG_ERR("Accelerometer not ready"); return; } clear_accelerometer_interrupt_line(); k_sleep(K_SECONDS(1)); double sensitivity_value = ACCELEROMETER_TRIGGER_SENSITIVITY_VALUE * GRAVITY_CONSTANT; struct sensor_value attr; attr.val1 = (int32_t)sensitivity_value; attr.val2 = (int32_t)((double)(sensitivity_value - (int32_t)(sensitivity_value)) * 1000000); if(sensor_attr_set(accelerometer, SENSOR_CHAN_ACCEL_XYZ, SENSOR_ATTR_SLOPE_TH, &attr)){ LOG_ERR("Failed to set slope"); return; } struct sensor_trigger trig = { .type = SENSOR_TRIG_DELTA, .chan = SENSOR_CHAN_ACCEL_XYZ, }; if (IS_ENABLED(CONFIG_LIS2DH_ODR_RUNTIME)) { struct sensor_value odr = { .val1 = SAMPLE_FREQUENCY, .val2 = 0, }; if (sensor_attr_set(accelerometer, trig.chan, SENSOR_ATTR_SAMPLING_FREQUENCY, &odr)) { LOG_ERR("Failed to set odr"); return; } } if (sensor_trigger_set(accelerometer, &trig, lis2dh_trigger_handler)) { LOG_ERR("Failed to set trigger"); return; } configure_accelerometer_wakeup_gpio(); LOG_INF("Accelerometer device is ready");}void stop_accelerometer() { struct sensor_value odr = { .val1 = 0, .val2 = 0 }; if (sensor_attr_set(accelerometer, SENSOR_CHAN_ACCEL_XYZ, SENSOR_ATTR_SAMPLING_FREQUENCY, &odr)) { LOG_ERR("Failed to set ODR to 0"); } LOG_INF("Accelerometer stopped");}The Bluetooth initialization is standard and it's just to see when the device wakes up without needing the terminal.