Lis3dh interrupt pins configuration

Hello everyone! I'm trying to implement the usage of accelerometer LIS3DH on a custom board. My board has nRF52832 microcontroller as the brain and a few ICs for different parts of the device like a lithium-ion solar battery charger, a LDO voltage regulator with output of 3.3v, the LIS3DH sensor, an Ultrasonic sensor connected trhough UART, and a few LEDs.

The LIS3DH MEMs sensor has a few implemented functions like free fall deection, tap and doubl tap, among others. This functions, according to datasheet, can be use to generate interrupts calls in pins INT1 and INT2.

This is the current .dts I'm working with:

// Copyright (c) 2022 Nordic Semiconductor ASA
// SPDX-License-Identifier: Apache-2.0

/dts-v1/;
#include <nordic/nrf52832_qfaa.dtsi>

/ {
	model = "HBL6232";
	compatible = "horatech,horatech-hbl6232-nrf52832";

	chosen {
		zephyr,sram = &sram0;
		zephyr,flash = &flash0;
		zephyr,code-partition = &slot0_partition;
	};

	aliases {
		lora0 = &lora;
		acel0 = &acel;
		hbluart = &uart0;
		watchdog0 = &wdt0;
	};

	cpus {
		cpu@0 {
						device_type = "cpu";
						cpu-power-states = <&state2>;
		};
	};

	power-states {
		// state0: state0 {
		// 				compatible = "zephyr,power-state";
		// 				power-state-name = "active";
		// 				min-residency-us = <10000>;
		// 				exit-latency-us = <100>;
		// };
		// state1: state1 {
		// 				compatible = "zephyr,power-state";
		// 				power-state-name = "runtime-idle";
		// 				min-residency-us = <10000>;
		// 				exit-latency-us = <100>;
		// };
		state2: state2 {
						compatible = "zephyr,power-state";
						power-state-name = "suspend-to-idle";
						min-residency-us = <10000>;
						exit-latency-us = <100>;
		};
	};
};

&gpio0 {
	status = "okay";
	gpio-controller;
  #gpio-cells = <2>;
};

&adc {
	status = "okay";
};

&uart0 {
	status = "okay";
};

&spi0 {
	compatible = "nordic,nrf-spi";
	status = "okay";
	sck-pin = <11>;
	mosi-pin = <13>;
	miso-pin = <12>;
	cs-gpios = <&gpio0 14 GPIO_ACTIVE_LOW>;
	lora: sx1262@0 {
		compatible = "semtech,sx1262";
		reg = <0>;
		label = "sx1262";
		reset-gpios = <&gpio0 9 GPIO_ACTIVE_HIGH>;
		busy-gpios = <&gpio0 8 GPIO_OPEN_SOURCE>;
		// antenna-enable-gpios = <&gpio0 10 0>;
		rx-enable-gpios = < &gpio0 26 GPIO_ACTIVE_HIGH >;
		// radio-enable-gpios = <&gpio0 26 0>;
		tx-enable-gpios = < &gpio0 10 GPIO_ACTIVE_HIGH >;
		dio1-gpios = <&gpio0 7 GPIO_OPEN_SOURCE>;
		spi-max-frequency = <4000000>;
		dio2-tx-enable;
		dio3-tcxo-voltage = < 0x07 >;
		tcxo-power-startup-delay-ms = < 100 >;
	};

};

&i2c1 {
	compatible = "nordic,nrf-twi";
	status = "okay";
	sda-pin = < 17 >;
	scl-pin = < 18 >;
	acel: lis3dh@19 {
		compatible = "st,lis3dh", "st,lis2dh";
		reg = <0x19>;
		label = "lis3dh";
		disconnect-sdo-sa0-pull-up;
		irq-gpios = < &gpio0 20 GPIO_OPEN_SOURCE >, < &gpio0 19	GPIO_OPEN_SOURCE >;
	};
};

&flash0 {
	partitions {
		compatible = "fixed-partitions";
		#address-cells = <1>;
		#size-cells = <1>;

		boot_partition: partition@0 {
			label = "mcuboot";
			reg = <0x00000000 0xc000>;
		};
		slot0_partition: partition@c000 {
			label = "image-0";
			reg = <0x0000C000 0x32000>;
		};
		slot1_partition: partition@3e000 {
			label = "image-1";
			reg = <0x0003E000 0x32000>;
		};
		scratch_partition: partition@70000 {
			label = "image-scratch";
			reg = <0x00070000 0xa000>;
		};
		storage_partition: partition@7a000 {
			label = "storage";
			reg = <0x0007a000 0x00006000>;
		};
	};
};

And this is the .overlay:

/ {
  aliases {
    pine50 = &pine5;
		pinpg0 = &pinpg;
    pinlse0 = &pinlse;
    ledrojo = &led0;
    ledazul = &led1;
    uartus = &uart0;
  };

  pines {
		compatible = "gpio-keys";
		pine5: pin_e_5 {
			gpios = < &gpio0 30 GPIO_ACTIVE_HIGH >;
			label = "PIN ENABLE 5V";
		};
		pinpg: pin_power_good {
			gpios = < &gpio0 28 GPIO_OPEN_SOURCE >;
			label = "PIN POWER GOOD";
		};
		pinlse: pin_lvl_shifter {
			gpios = < &gpio0 4 GPIO_ACTIVE_HIGH >;
			label = "PIN LVL SHIFTER ENABLE";
		};
	};

  leds {
    compatible = "gpio-leds";
    led0: led_rojo {
      gpios = < &gpio0 27 GPIO_ACTIVE_HIGH >;
      label = "LED ROJO";
    };
    led1: led_azul {
      gpios = < &gpio0 29 GPIO_ACTIVE_HIGH >;
      label = "LED AZUL";
    };
  };

  vbatt {
		status = "okay";
		compatible = "voltage-divider";
		io-channels = <&adc 3>;
		output-ohms = <10000>;
		full-ohms = <(10000 + 10000)>;
	};
};

&uart0 {
  compatible = "nordic,nrf-uart";
  current-speed = <9600>;
  tx-pin = <2>;
  rx-pin = <3>;
  label = "uart_ultrasonido";
};

I'm trying to findout how to set INT2 to trigger on free fall detection, and INT1 to trigger on excesive movement.

But I don't seem able to figure out how to do that.

Previously I was working in this exact same configuration with SAMR34 module from Microchip, and I had to make a library to achieve free fall detection wired to INT2 pin and excesive movement wired to INT1 pin. So I'm a bit familiar with LIS3DH sensor.

However, nRF Connect SDK poses a bigger challenge than expected sometimes.

To clarify, I'm working with Visual Studio Code with nRF Connect

- NCS version 2.1.0
- Zephyr version 3.1.0

Here is and extract of the code:

#include "acel.h"

#include <zephyr.h>
#include <device.h>
#include <logging/log.h>
#include <drivers/sensor.h>
#include <pm/device_runtime.h>
#include <pm/device.h>

#include "config.h"
#include "mbox_gpe.h"

LOG_MODULE_REGISTER(acel_gpe, LOG_LEVEL_INF);

K_MSGQ_DEFINE(trigg_event, 1, 2, 1);

typedef enum {
  ACEL_STATUS_OK,
  ACEL_STATUS_ERROR
} acel_status_t;

const struct device *dev_acel = DEVICE_DT_GET(DT_ALIAS(acel0));
acel_t *acel_data = NULL;
int64_t acel_uptime_notif = 0;
int64_t acel_uptime_gps = 0;

acel_status_t acel_init(void);
static void acel_trigg_ff(const struct device *dev, struct sensor_trigger *trig);
void acel_trigg_event(void);
int32_t acel_trigg_level(uint8_t level);

void acel_task(void *arg, void *unused1, void *unused2) {
  acel_data = (acel_t *)arg;
  acel_status_t status = acel_init();
  if (status != ACEL_STATUS_OK) {
    LOG_ERR("Error al inicializar acelerometro!%s", "");
    return;
  }
  while(1) {
		acel_trigg_event();
    k_sleep(K_SECONDS(5));
  }
}

acel_status_t acel_init(void) {
  if (!device_is_ready(dev_acel)) {
    LOG_ERR("Acel device not found!%s\n","");
    return ACEL_STATUS_ERROR;
  }
	if (acel_data->trigger_enable == 0) {
		LOG_INF("Acel trigger disabled%s", "");
		return ACEL_STATUS_OK;
	}
	struct sensor_value attr;
	attr.val1 = acel_trigg_level(acel_data->trigger_level_ths);
	attr.val2 = 0;
	int rc = sensor_attr_set(dev_acel, SENSOR_CHAN_ACCEL_XYZ, SENSOR_ATTR_SLOPE_TH, &attr);
	if (rc != 0) {
		LOG_ERR("sensor_attr_set SLOPE TH failed: %d", rc);
	}
	attr.val1 = acel_trigg_level(acel_data->trigger_level_dur);
	attr.val2 = 0;
	rc = sensor_attr_set(dev_acel, SENSOR_CHAN_ACCEL_XYZ, SENSOR_ATTR_SLOPE_DUR, &attr);
	if (rc != 0) {
		LOG_ERR("sensor_attr_set SLOPE DUR failed: %d", rc);
	}
	acel_uptime_notif = k_uptime_get();
	acel_uptime_gps = k_uptime_get();
	struct sensor_trigger trig;
	trig.type = SENSOR_TRIG_FREEFALL;
	trig.chan = SENSOR_CHAN_ACCEL_XYZ;
	rc = sensor_trigger_set(dev_acel, &trig, (sensor_trigger_handler_t)acel_trigg_ff);
	if (rc != 0) {
		LOG_ERR("sensor_trigger_set DELTA failed: %d", rc);
	}
  return ACEL_STATUS_OK;
}

static void acel_trigg_ff(const struct device *dev, struct sensor_trigger *trig) {
	uint8_t event = 1;
	k_msgq_put(&trigg_event, &event, K_NO_WAIT);
}

void acel_trigg_event(void) {
	int64_t trigg_uptime = k_uptime_get();
	if (trigg_uptime - acel_uptime_notif <= acel_data->trigger_timeout) {
		return;
	}
	acel_uptime_notif = trigg_uptime;
	uint8_t event;
	int rc = k_msgq_get(&trigg_event, &event, K_SECONDS(1));
	if (rc != 0) return;
	LOG_INF("Acelerometro detecto movimiento!%s", "");
	struct k_mbox_msg msgAcel;
	int bufferSize = 2;
	uint8_t buffer[bufferSize];
	buffer[0] = PUERTO_UL_ALERTA_ACEL;
	buffer[1] = 0;
 	msgAcel.info = MBOX_GPE_LORAWAN_TX;
 	msgAcel.size = bufferSize;
 	msgAcel.tx_data = buffer;
 	msgAcel.tx_target_thread = acel_data->lora_handle;
 	k_mbox_put(acel_data->gpe_mailbox_gps, &msgAcel, K_SECONDS(2));
	LOG_INF("Enviado evento de acelerometro%s","");
	trigg_uptime = k_uptime_get();
	if (trigg_uptime - acel_uptime_gps <= acel_data->trigger_gps_timeout) {
		return;
	}
	acel_uptime_gps = trigg_uptime;
	msgAcel.info = MBOX_GPE_GPS_GET;
	msgAcel.size = 0;
	msgAcel.tx_data = NULL;
	msgAcel.tx_block.data = NULL;
	msgAcel.tx_target_thread = acel_data->gps_handle;
	k_mbox_put(acel_data->gpe_mailbox_gps, &msgAcel, K_SECONDS(2));
	LOG_INF("GPS enviado%s","");
}

int32_t acel_trigg_level(uint8_t level) {
	switch(level) {
		default:
		case 0:
			LOG_INF("Trigger SENSOR_G * 0.5%s","");
			return (int32_t)(SENSOR_G * 0.5);
		case 1:
			LOG_INF("Trigger SENSOR_G * 1%s","");
			return (int32_t)(SENSOR_G * 1.0);
		case 2:
			LOG_INF("Trigger SENSOR_G * 1.5%s","");
			return (int32_t)(SENSOR_G * 1.5);
		case 3:
			LOG_INF("Trigger SENSOR_G * 2%s","");
			return (int32_t)(SENSOR_G * 2.0);
		case 4:
			LOG_INF("Trigger SENSOR_G * 2.5%s","");
			return (int32_t)(SENSOR_G * 2.5);
		case 5:
			LOG_INF("Trigger SENSOR_G * 3%s","");
			return (int32_t)(SENSOR_G * 3.0);
	}
}

To summarize, I'm not sure how to establish the INT1 pin function and the INT2 pin function.

I hope someone can help me understan better how to use the sensor implementation to it's full potential, or lead me in the right documentation to explore.

Parents
  • Hello,

    Maybe you are missing CONFIG_LIS2DH_TRIGGER=y , looking atht the lis2dh_driver_api this will expose the trigger_set() api. Maybe take a look at the zephyr\samples\sensor\lis2dh project and zephyr\drivers\sensor\lis2dh if you haven't already?

    Kenneth

  • Hello Kenneth, thank you for your reply.

    I'm sorry, I forgot to show the proj.conf.

    # Stack
    # CONFIG_CPLUSPLUS=y
    CONFIG_MAIN_STACK_SIZE=2048
    CONFIG_KERNEL_LOG_LEVEL_INF=y
    CONFIG_NUM_PREEMPT_PRIORITIES=6
    CONFIG_NUM_COOP_PRIORITIES=2
    # CONFIG_NEWLIB_LIBC=y
    # CONFIG_POSIX_API=y
    CONFIG_THREAD_NAME=y
    CONFIG_RESET_ON_FATAL_ERROR=y
    CONFIG_HEAP_MEM_POOL_SIZE=1024
    CONFIG_HWINFO=y
    
    # GPIO
    CONFIG_GPIO=y
    
    # Watchdog
    CONFIG_WATCHDOG=y
    CONFIG_WDT_LOG_LEVEL_DBG=y
    CONFIG_WDT_DISABLE_AT_BOOT=y
    CONFIG_TASK_WDT=y
    CONFIG_TASK_WDT_MIN_TIMEOUT=500
    
    # Power Management
    CONFIG_PM=y
    CONFIG_PM_DEVICE=y
    CONFIG_PM_DEVICE_RUNTIME=y
    
    # NVS
    CONFIG_FLASH=y
    CONFIG_FLASH_PAGE_LAYOUT=y
    CONFIG_NVS=y
    # CONFIG_NVS_LOG_LEVEL_DBG=y
    CONFIG_MPU_ALLOW_FLASH_WRITE=y
    
    # Bluetooth
    CONFIG_BT=y
    # CONFIG_BT_DEBUG_LOG=y
    CONFIG_BT_DEBUG_LOG=y
    CONFIG_BT_L2CAP_TX_BUF_COUNT=5
    CONFIG_BT_PERIPHERAL=y
    CONFIG_BT_LONG_WQ_PRIO=6
    CONFIG_BT_DEVICE_NAME_DYNAMIC=y
    CONFIG_BT_DEVICE_NAME_MAX=30
    
    # Logging
    CONFIG_LOG=y
    CONFIG_PRINTK=y
    CONFIG_LOG_BACKEND_RTT=y
    CONFIG_LOG_BACKEND_RTT_MODE_DROP=y
    CONFIG_LOG_PRINTK=y
    # CONFIG_LOG_PRINTK_MAX_STRING_LENGTH=256
    CONFIG_LOG_BACKEND_RTT_MESSAGE_SIZE=256
    # CONFIG_LOG_STRDUP_BUF_COUNT=64
    # CONFIG_LOG_STRDUP_MAX_STRING=64
    CONFIG_LOG_BACKEND_SHOW_COLOR=n
    CONFIG_LOG_BACKEND_FORMAT_TIMESTAMP=n
    CONFIG_LOG_PROCESS_THREAD_STACK_SIZE=1024
    CONFIG_CBPRINTF_FP_SUPPORT=y
    CONFIG_CONSOLE=n
    CONFIG_USE_SEGGER_RTT=y
    # CONFIG_RTT_CONSOLE=y
    # CONFIG_UART_CONSOLE=n
    CONFIG_GPIO_LOG_LEVEL_DBG=y
    CONFIG_LOG_PROCESS_THREAD_SLEEP_MS=300
    
    # UART
    CONFIG_SERIAL=y
    CONFIG_UART_INTERRUPT_DRIVEN=n
    CONFIG_UART_ASYNC_API=y
    
    # LORA
    CONFIG_SPI=y
    # CONFIG_SPI_LOG_LEVEL_DBG=y
    CONFIG_LORA=y
    CONFIG_LORA_SX12XX=y
    # CONFIG_LORA_LOG_LEVEL_DBG=y
    # LORAWAN
    CONFIG_LORAWAN=y
    CONFIG_LORAMAC_REGION_AU915=y
    # CONFIG_LORAWAN_LOG_LEVEL_DBG=y
    
    # LIS3DH
    CONFIG_I2C=y
    # CONFIG_I2C_LOG_LEVEL_DBG=y
    CONFIG_SENSOR=y
    CONFIG_LIS2DH=y
    CONFIG_LIS2DH_TRIGGER_GLOBAL_THREAD=y
    CONFIG_LIS2DH_ODR_3=y
    CONFIG_LIS2DH_ACCEL_RANGE_8G=y
    CONFIG_LIS2DH_OPER_MODE_LOW_POWER=y
    # CONFIG_SENSOR_LOG_LEVEL_DBG=y
    
    # ADC
    CONFIG_ADC=y
    
    # FUOTA
    # Enable mcumgr.
    # CONFIG_MCUMGR=y
    # # Enable most core commands.
    # CONFIG_MCUMGR_CMD_IMG_MGMT=y
    # CONFIG_MCUMGR_CMD_OS_MGMT=y
    # CONFIG_MCUMGR_SMP_BT=y
    # CONFIG_MCUMGR_SMP_BT_AUTHEN=n
    # CONFIG_IMG_ERASE_PROGRESSIVELY=y
    # # Ensure an MCUboot-compatible binary is generated.
    # CONFIG_BOOTLOADER_MCUBOOT=y
    
    # Hardcore
    CONFIG_STACK_USAGE=y
    
    

    I will look into it, CONFIG_LIS2DH_TRIGGER=y is not set in my current proj.conf

  • This is what happens when I try to add CONFIG_LIS2DH_TRIGGER=y in the proj.conf file.

    And it doesn't build anymore.

    This is the error that prompts when trying to build:

    Parsing C:/ncs/v2.1.0/zephyr/Kconfig
    Loaded configuration 'C:/Users/ig/Documents/GitHub/NFL2/boards/arm/horatech_hbl6232_nrf52832/horatech_hbl6232_nrf52832_defconfig'
    Merged configuration 'c:/Users/ig/Documents/GitHub/NFL2/prj.conf'
    
    error: LIS2DH_TRIGGER (defined at drivers/sensor/lis2dh/Kconfig:38) is assigned in a configuration
    file, but is not directly user-configurable (has no prompt). It gets its value indirectly from other
    symbols. See http://docs.zephyrproject.org/latest/kconfig.html#CONFIG_LIS2DH_TRIGGER and/or look up
    LIS2DH_TRIGGER in the menuconfig/guiconfig interface. The Application Development Primer, Setting
    Configuration Values, and Kconfig - Tips and Best Practices sections of the manual might be helpful
    too.
    
    CMake Error at C:/ncs/v2.1.0/zephyr/cmake/modules/kconfig.cmake:293 (message):
      command failed with return code: 1
    Call Stack (most recent call first):
      C:/ncs/v2.1.0/zephyr/cmake/modules/zephyr_default.cmake:121 (include)
      C:/ncs/v2.1.0/zephyr/share/zephyr-package/cmake/ZephyrConfig.cmake:66 (include)
      C:/ncs/v2.1.0/zephyr/share/zephyr-package/cmake/ZephyrConfig.cmake:92 (include_boilerplate)
      CMakeLists.txt:5 (find_package)
    
    
    -- Configuring incomplete, errors occurred!
    FATAL ERROR: command exited with status 1: 'C:\ncs\toolchains\v2.1.0\opt\bin\cmake.EXE' '-DWEST_PYTHON=C:\ncs\toolchains\v2.1.0\opt\bin\python.exe' '-Bc:\Users\ig\Documents\GitHub\NFL2\build' -GNinja -DBOARD=horatech_hbl6232_nrf52832 -DNCS_TOOLCHAIN_VERSION:STRING=NONE '-DBOARD_ROOT:STRING=c:/users/ig/documents/repos/npo-1;c:/users/ig/documents/github/nfl2;c:/users/ig/documents/github/nca7;c:/users/ig/documents/repos/nsr1' -DCONF_FILE:STRING=c:/Users/ig/Documents/GitHub/NFL2/prj.conf -DDTC_OVERLAY_FILE:STRING=c:/Users/ig/Documents/GitHub/NFL2/horatech_hbl6232_nrf52832.overlay '-Sc:\Users\ig\Documents\GitHub\NFL2'

    I tried looking in the url provided by the error but I don't see that the CONFIG_LIS2DH_TRIGGER=y is used, or more like I'm not really sure what I'm looking for:

    http://docs.zephyrproject.org/latest/kconfig.html#CONFIG_LIS2DH_TRIGGER

    Another thing that happens also is that: (without CONFIG_LIS2DH_TRIGGER=y)

    struct sensor_value attr;
    attr.val1 = acel_trigg_level(acel_data->trigger_level_ths);
    attr.val2 = 0;
    int rc = sensor_attr_set(dev_acel, SENSOR_CHAN_ACCEL_XYZ, SENSOR_ATTR_SLOPE_TH, &attr);

    returns error -22 (invalid argument)
    attr.val1 = acel_trigg_level(acel_data->trigger_level_dur);
    attr.val2 = 0;
    rc = sensor_attr_set(dev_acel, SENSOR_CHAN_ACCEL_XYZ, SENSOR_ATTR_SLOPE_DUR, &attr);
    returns error -134 (not supported)
    trig.type = SENSOR_TRIG_FREEFALL;
    trig.chan = SENSOR_CHAN_ACCEL_XYZ;
    rc = sensor_trigger_set(dev_acel, &trig, (sensor_trigger_handler_t)acel_trigg_ff);
    returns error -134 (not supported)
    I'm a bit lost to be honest.
    I looked at the sample code for lis2dh and used it as a base, but it is very changed from the sample code to meet the task and mailbox system the code has.
  • Sorry, you are right, looking at the zephyr/drivers/ensor/lis2dh/kconfig I can see that CONFIG_LIS2DH_TRIGGER is indirectly selected by either:

    choice LIS2DH_TRIGGER_MODE
        prompt "Trigger mode"
        help
          Specify the type of triggering to be used by the driver.

    config LIS2DH_TRIGGER_NONE
        bool "No trigger"

    config LIS2DH_TRIGGER_GLOBAL_THREAD
        bool "Use global thread"
        depends on GPIO
        select LIS2DH_TRIGGER

    config LIS2DH_TRIGGER_OWN_THREAD
        bool "Use own thread"
        depends on GPIO
        select LIS2DH_TRIGGER
    I suggest to study the driver and driver sample further, I don't have the sensor myself so not able to try this myself.
     
    Kenneth
  • Hello Kenneth, I've been studying the driver and the sample code for lis2dh as you suggested.

    For what I found the driver doesn't support freefall and a few other interrupt options I think...

    This is located in lis2dh.c for attribute configuration

    static int lis2dh_acc_config(const struct device *dev,
    			     enum sensor_channel chan,
    			     enum sensor_attribute attr,
    			     const struct sensor_value *val)
    {
    	switch (attr) {
    #ifdef CONFIG_LIS2DH_ACCEL_RANGE_RUNTIME
    	case SENSOR_ATTR_FULL_SCALE:
    		return lis2dh_acc_range_set(dev, sensor_ms2_to_g(val));
    #endif
    #ifdef CONFIG_LIS2DH_ODR_RUNTIME
    	case SENSOR_ATTR_SAMPLING_FREQUENCY:
    		return lis2dh_acc_odr_set(dev, val->val1);
    #endif
    #if defined(CONFIG_LIS2DH_TRIGGER)
    	case SENSOR_ATTR_SLOPE_TH:
    	case SENSOR_ATTR_SLOPE_DUR:
    		return lis2dh_acc_slope_config(dev, attr, val);
    #endif
    #ifdef CONFIG_LIS2DH_ACCEL_HP_FILTERS
    	case SENSOR_ATTR_CONFIGURATION:
    		return lis2dh_acc_hp_filter_set(dev, val->val1);
    #endif
    	default:
    		LOG_DBG("Accel attribute not supported.");
    		return -ENOTSUP;
    	}
    
    	return 0;
    }

    You may see here, that any attribute that is not listed in the switch(attr) is managed as "not supported".

    Furthermore, looking in the lis2dh_trigger.c I found the functions that directly configure INT1 and INT2 pins. But I'm unsure how to approach this change in the driver. And how to "wire" both interrups to outside the driver.

    What I mean is, in dts and overlay the options for lis2dh are anym-on-int1 and not much else. Do I need to add another option in dts file for INT2?

    I think I need more time studying this driver and it's interaction with the device tree.

    Any hint would be appreciated.

  • I don't know why freefall is not supported, but in terms of how to enable both INT1 and INT2 you first look at how only INT1 is used here:
    https://github.com/nrfconnect/sdk-zephyr/blob/main/boards/arm/thingy52_nrf52832/thingy52_nrf52832.dts#L184 

    The only difference to support INT1 and INT2 would be to modify irq-gpios to add a second pin, e.g.:
    irq-gpios = <&gpio0 12 GPIO_ACTIVE_HIGH>, <&gpio0 13 GPIO_ACTIVE_HIGH>; /* INT1 pin 12, INT2 pin 13 */

    Here are the devictree bindings listed:
    https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/zephyr/build/dts/api/bindings/sensor/st%2Clis2dh-i2c.html#dtbinding-st-lis2dh-i2c 

  • Hi ,


    I have been working with the lis3d and the lis2dh driver for some time now and from my point of view the driver does not support free fall or any tap functions.


    To make it work, as you pointed out a bit, you need to extend the switch(attr) for the function you want to implement (for example free-fall). Add a callback function with sensor_trigger_set(). This callback will be executed when the interrupt is being set from the lis accelerometer and do what you need in the functions.

    An online example can be found here, where the interrupt threshold is defined and the interrupt is waited for (no polling) : https://github.com/circuitdojo/nrf9160-feather-examples-and-drivers/blob/v2.4.x/samples/tracker/src/motion/app_motion.c 


    Here is the video from Circuit Dojo, he explain it is in his video: https://www.youtube.com/watch?v=EhSgynt1lj8&list=PLJKv3qSDEE-lYuq5hMpJ_sSHQcuhO1S-P&index=10 


    Here is the example, but simplified. If you update your main.c like this and update your prj.conf accordingly, then it should work. Now you have a good starting point for development.

    main:

    #include <stdio.h>
    #include <zephyr/kernel.h>
    #include <zephyr/device.h>
    #include <zephyr/drivers/sensor.h>
    
    
    static void fetch_and_display(const struct device *sensor)
    {
    	static unsigned int count;
    	struct sensor_value accel[3];
    	struct sensor_value temperature;
    	const char *overrun = "";
    	int rc = sensor_sample_fetch(sensor);
    
    	++count;
    	if (rc == -EBADMSG) {
    		/* Sample overrun.  Ignore in polled mode. */
    		if (IS_ENABLED(CONFIG_LIS2DH_TRIGGER)) {
    			overrun = "[OVERRUN] ";
    		}
    		rc = 0;
    	}
    	if (rc == 0) {
    		rc = sensor_channel_get(sensor,
    					SENSOR_CHAN_ACCEL_XYZ,
    					accel);
    	}
    	if (rc < 0) {
    		printf("ERROR: Update failed: %d\n", rc);
    	} else {
    		printf("#%u @ %u ms: %sx %f , y %f , z %f",
    		       count, k_uptime_get_32(), overrun,
    		       sensor_value_to_double(&accel[0]),
    		       sensor_value_to_double(&accel[1]),
    		       sensor_value_to_double(&accel[2]));
    	}
    
    	if (IS_ENABLED(CONFIG_LIS2DH_MEASURE_TEMPERATURE)) {
    		if (rc == 0) {
    			rc = sensor_channel_get(sensor, SENSOR_CHAN_DIE_TEMP, &temperature);
    			if (rc < 0) {
    				printf("\nERROR: Unable to read temperature:%d\n", rc);
    			} else {
    				printf(", t %f\n", sensor_value_to_double(&temperature));
    			}
    		}
    
    	} else {
    		printf("\n");
    	}
    }
    
    #ifdef CONFIG_LIS2DH_TRIGGER
    static void trigger_handler(const struct device *dev,
    			    const struct sensor_trigger *trig)
    {
    	fetch_and_display(dev);
    }
    #endif
    
    int main(void)
    {
    	const struct device *const sensor = DEVICE_DT_GET_ANY(st_lis2dh);
    
    	printf("Let's start.\n");
    	if (sensor == NULL) {
    		printf("No device found\n");
    		return 0;
    	}
    	if (!device_is_ready(sensor)) {
    		printf("Device %s is not ready\n", sensor->name);
    		return 0;
    	}
    
    #if CONFIG_LIS2DH_TRIGGER
    	{
    		struct sensor_trigger trig;
    		struct sensor_value attr;
    		int rc;
    
    		//trig.type = SENSOR_TRIG_DATA_READY; // data ready triggere every time the data is ready we got data. 
    		//trig.chan = SENSOR_CHAN_ACCEL_XYZ;
    
    
    		/* Set to 1.5G in m/s^2 */
        	attr.val1 = 0;
        	attr.val2 = (int32_t)(SENSOR_G * 1.3);
    
    		rc = sensor_attr_set(sensor, SENSOR_CHAN_ACCEL_XYZ,
                             SENSOR_ATTR_SLOPE_TH, &attr);
        	if (rc < 0)
        	{
            	printf("Cannot set slope threshold.");
    		}
    
    		// Set trigger values 
        	trig.type = SENSOR_TRIG_DELTA;
        	trig.chan = SENSOR_CHAN_ACCEL_XYZ;
    
    		rc = sensor_trigger_set(sensor, &trig, trigger_handler);
    		if (rc != 0) {
    			printf("Failed to set trigger: %d\n", rc);
    			return 0;
    		}
    
    		printf("Waiting for triggers\n");
    		while (true) {
    			//fetch_and_display(sensor);
    			k_sleep(K_MSEC(2000));
    		}
    	}
    #else /* CONFIG_LIS2DH_TRIGGER */
    	printf("Polling at 0.5 Hz\n");
    	while (true) {
    		fetch_and_display(sensor);
    		k_sleep(K_MSEC(2000));
    	}
    #endif /* CONFIG_LIS2DH_TRIGGER */
    }
    

    prj.conf:

    CONFIG_STDOUT_CONSOLE=y
    CONFIG_I2C=y
    CONFIG_SENSOR=y
    CONFIG_CBPRINTF_FP_SUPPORT=y
    
    
    CONFIG_LIS2DH=y
    CONFIG_LIS2DH_TRIGGER_GLOBAL_THREAD=y
    


    Peace out.

Reply
  • Hi ,


    I have been working with the lis3d and the lis2dh driver for some time now and from my point of view the driver does not support free fall or any tap functions.


    To make it work, as you pointed out a bit, you need to extend the switch(attr) for the function you want to implement (for example free-fall). Add a callback function with sensor_trigger_set(). This callback will be executed when the interrupt is being set from the lis accelerometer and do what you need in the functions.

    An online example can be found here, where the interrupt threshold is defined and the interrupt is waited for (no polling) : https://github.com/circuitdojo/nrf9160-feather-examples-and-drivers/blob/v2.4.x/samples/tracker/src/motion/app_motion.c 


    Here is the video from Circuit Dojo, he explain it is in his video: https://www.youtube.com/watch?v=EhSgynt1lj8&list=PLJKv3qSDEE-lYuq5hMpJ_sSHQcuhO1S-P&index=10 


    Here is the example, but simplified. If you update your main.c like this and update your prj.conf accordingly, then it should work. Now you have a good starting point for development.

    main:

    #include <stdio.h>
    #include <zephyr/kernel.h>
    #include <zephyr/device.h>
    #include <zephyr/drivers/sensor.h>
    
    
    static void fetch_and_display(const struct device *sensor)
    {
    	static unsigned int count;
    	struct sensor_value accel[3];
    	struct sensor_value temperature;
    	const char *overrun = "";
    	int rc = sensor_sample_fetch(sensor);
    
    	++count;
    	if (rc == -EBADMSG) {
    		/* Sample overrun.  Ignore in polled mode. */
    		if (IS_ENABLED(CONFIG_LIS2DH_TRIGGER)) {
    			overrun = "[OVERRUN] ";
    		}
    		rc = 0;
    	}
    	if (rc == 0) {
    		rc = sensor_channel_get(sensor,
    					SENSOR_CHAN_ACCEL_XYZ,
    					accel);
    	}
    	if (rc < 0) {
    		printf("ERROR: Update failed: %d\n", rc);
    	} else {
    		printf("#%u @ %u ms: %sx %f , y %f , z %f",
    		       count, k_uptime_get_32(), overrun,
    		       sensor_value_to_double(&accel[0]),
    		       sensor_value_to_double(&accel[1]),
    		       sensor_value_to_double(&accel[2]));
    	}
    
    	if (IS_ENABLED(CONFIG_LIS2DH_MEASURE_TEMPERATURE)) {
    		if (rc == 0) {
    			rc = sensor_channel_get(sensor, SENSOR_CHAN_DIE_TEMP, &temperature);
    			if (rc < 0) {
    				printf("\nERROR: Unable to read temperature:%d\n", rc);
    			} else {
    				printf(", t %f\n", sensor_value_to_double(&temperature));
    			}
    		}
    
    	} else {
    		printf("\n");
    	}
    }
    
    #ifdef CONFIG_LIS2DH_TRIGGER
    static void trigger_handler(const struct device *dev,
    			    const struct sensor_trigger *trig)
    {
    	fetch_and_display(dev);
    }
    #endif
    
    int main(void)
    {
    	const struct device *const sensor = DEVICE_DT_GET_ANY(st_lis2dh);
    
    	printf("Let's start.\n");
    	if (sensor == NULL) {
    		printf("No device found\n");
    		return 0;
    	}
    	if (!device_is_ready(sensor)) {
    		printf("Device %s is not ready\n", sensor->name);
    		return 0;
    	}
    
    #if CONFIG_LIS2DH_TRIGGER
    	{
    		struct sensor_trigger trig;
    		struct sensor_value attr;
    		int rc;
    
    		//trig.type = SENSOR_TRIG_DATA_READY; // data ready triggere every time the data is ready we got data. 
    		//trig.chan = SENSOR_CHAN_ACCEL_XYZ;
    
    
    		/* Set to 1.5G in m/s^2 */
        	attr.val1 = 0;
        	attr.val2 = (int32_t)(SENSOR_G * 1.3);
    
    		rc = sensor_attr_set(sensor, SENSOR_CHAN_ACCEL_XYZ,
                             SENSOR_ATTR_SLOPE_TH, &attr);
        	if (rc < 0)
        	{
            	printf("Cannot set slope threshold.");
    		}
    
    		// Set trigger values 
        	trig.type = SENSOR_TRIG_DELTA;
        	trig.chan = SENSOR_CHAN_ACCEL_XYZ;
    
    		rc = sensor_trigger_set(sensor, &trig, trigger_handler);
    		if (rc != 0) {
    			printf("Failed to set trigger: %d\n", rc);
    			return 0;
    		}
    
    		printf("Waiting for triggers\n");
    		while (true) {
    			//fetch_and_display(sensor);
    			k_sleep(K_MSEC(2000));
    		}
    	}
    #else /* CONFIG_LIS2DH_TRIGGER */
    	printf("Polling at 0.5 Hz\n");
    	while (true) {
    		fetch_and_display(sensor);
    		k_sleep(K_MSEC(2000));
    	}
    #endif /* CONFIG_LIS2DH_TRIGGER */
    }
    

    prj.conf:

    CONFIG_STDOUT_CONSOLE=y
    CONFIG_I2C=y
    CONFIG_SENSOR=y
    CONFIG_CBPRINTF_FP_SUPPORT=y
    
    
    CONFIG_LIS2DH=y
    CONFIG_LIS2DH_TRIGGER_GLOBAL_THREAD=y
    


    Peace out.

Children
Related