Using LPS22HH and LIS2DW12 Sensors
1. Overview
This application note describes how to configure LPS22HH and LIS2DW12 sensors on the SOM-NRF9151 baseboard in Zephyr BSP and use them in the user application.
2. LPS22HH and LIS2DW12 sensors in Zephyr BSP
2.1. Configuring LPS22HH Barometer
The LPS22HH device is declared in nrf9151som_nrf9151_ns.dts
as a child node of the i2c2
bus:
&i2c2 {
status = "okay";
lps22hh: lps22hh@5c {
compatible = "st,lps22hh";
reg = <0x5c>;
drdy-gpios = <&gpio0 5 GPIO_ACTIVE_HIGH>;
};
};
This node configures the following parameters:
Parameter | Value | Description |
---|---|---|
|
| Enables the |
|
| LPS22HH slave address on the I2C bus, which will be used by the driver to communicate with the barometer. |
|
| Host SoC GPIO, that will be used for LPS22HH interrupts. |
2.2. Configuring LIS2DW12 Accelerometer
The LIS2DW12 device is declared in nrf9151som_nrf9151_ns.dts
as a child node of the i2c2
bus:
&i2c2 {
status = "okay";
lis2dw12: lis2dw12@19 {
compatible = "st,lis2dw12";
reg = <0x19>;
irq-gpios = <&gpio0 7 GPIO_ACTIVE_HIGH>, <&gpio0 6 GPIO_ACTIVE_HIGH>;
int-pin = <1>;
tap-threshold = <1>, <1>, <1>;
};
};
This node configures the following parameters:
Parameter | Value | Description |
---|---|---|
|
| Enables the |
|
| LIS2DW12 slave address on the I2C bus, which will be used by the driver to communicate with the IMU. |
|
| Host SoC GPIO, that will be used for LIS2DW12 interrupts. |
|
| Select DRDY pin number (1 or 2). This number represents which of the two interrupt pins (INT1 or INT2) the drdy line is attached to. This property is not mandatory and if not present it defaults to 1 which is the configuration at power-up. |
|
| Tap X/Y/Z axes threshold. Default is power-up configuration. Thresholds to start the tap-event detection procedure on the X/Y/Z axes. For example, if you want to set the threshold for X to 12, for Z to 14 and want to disable tap detection on Y, you should specify in Device Tree, which is equivalent to X = 12 * 2g/32 = 750mg and Z = 14 * 2g/32 = 875mg. |
3. Controlling Sensors in User Application
3.1. Sensor C-binding API
The Customized Asset Tracker v2 application makes use of the Zephyr Sensor API, which is defined in zephyr/drivers/sensor.h
:
Function | Description | Comments |
| Set an attribute for a sensor. |
Returns 0 if successful, negative errno code if failure. |
| Get an attribute for a sensor. |
Returns 0 if successful, negative errno code if failure. |
| Fetch a sample from the sensor and store it in an internal driver buffer. |
Returns 0 if successful, negative errno code if failure. Read all of a sensor's active channels and, if necessary, perform any additional operations necessary to make the values useful. The user may then get individual channel values by calling The function blocks until the fetch operation is complete. Since the function communicates with the sensor device, it is unsafe to call it in an ISR if the device is connected via I2C or SPI. |
| Fetch a sample from the sensor and store it in an internal driver buffer. |
Returns 0 if successful, negative errno code if failure. Read and compute compensation for one type of sensor data (magnetometer, accelerometer, etc). The user may then get individual channel values by This is mostly implemented by multi function devices enabling reading at different sampling rates. The function blocks until the fetch operation is complete. Since the function communicates with the sensor device, it is unsafe to call it in an ISR if the device is connected via I2C or SPI. |
| Get a reading from a sensor device. |
Return a useful value for a particular channel, from the driver's internal data. Before calling this function, a sample must be obtained by calling |
| Activate a sensor's trigger and set the trigger handle. |
Returns 0 if successful, negative errno code if failure. The handler will be called from a thread, so I2C or SPI operations are safe. However, the thread's stack is limited and defined by the driver. It is currently up to the caller to ensure that the handler does not overflow the stack. The user-allocated trigger will be stored by the driver as a pointer, rather than a copy, and passed back to the handler. This enables the handler to use CONTAINER_OF to retrieve a context pointer when the trigger is embedded in a larger struct and requires that the trigger is not allocated on the stack. |
The Customized Asset Tracker v2 application also implements C-binding helper API to read the sensors data and configure external sensors in ext_sensors.*
and src/addons/sensors
:
Function | Description | Comments |
| Set the threshold that triggers callback on accelerometer data. |
Returns 0 on success or negative error value on failure. |
| Enable or disable accelerometer trigger handler. |
Returns 0 on success or negative error value on failure. |
| Set accelerometer full scale. | Returns 0 on success or negative error value on failure. |
| Get temperature from library. |
Returns 0 on success or negative error value on failure. |
| Get pressure from library. |
Returns 0 on success or negative error value on failure. |
| Initialize tap the LIS2DW12 accelerometer. |
|
| Initialize tap handler for LIS2DW12 accelerometer. |
|
| Initialize trigger for the LPS22HH barometer. |
|
3.2. LPS22HH Shell Commands
The Customized Asset Tracker v2 application provides a set of Zephyr shell commands for LPS22HH barometer, defined in the lps22hh_shell.c
file:
Command | Parameters | Comments |
|
| Prints out LPS22HH readings to the serial console in the following format: uart:~$ lps22hh get
Pressure: <pressure> kPa
Temperature: <temp> C |
|
| Set LPS22HH sampling frequency (1..200) |
|
| Set LPS22HH power mode (lc - low current, ln - low noise) |
3.3. LIS2DW12 Shell Commands
The Customized Asset Tracker v2 application provides a set of Zephyr shell commands for LIS2DW12 accelerometer, defined in the lis2dw12_shell.c
file:
Command | Parameters | Comments |
|
| Prints out LIS2DW12 readings to the serial console in the following format: uart:~$ lis2dw12 get
accel x:<X axis acceleration> ms/2 y:<Y axis acceleration> ms/2 z:<Z axis acceleration> ms/2
Trigger count: 0 |
|
| Set LIS2DW12 IMU sampling frequency (default is 12) |
|
| Set LIS2DW12 IMU power mode (1 - high performance, 2..4 low power mode) |
|
| Set LIS2DW12 data-ready handler on INT2 |
|
| Set LIS2DW12 tap handler on INT1 |
|
| Remove LIS2DW12 data-ready handler from INT2 |
3.4. Sending LPS22HH Data to nRF Cloud
The LPS22HH data is being collected and sent to the nRF Cloud by the sensor and data modules, defined in sensor_module.c
and data_module.c
:
When the sensor module receives
APP_EVT_DATA_GET
, it calls theenvironmental_data_get()
function to collect accelerometer data that should be sent to nRF Cloud.environmental_data_get()
reads the temperature and pressure readings by callingext_sensors_temperature_get()
andext_sensors_pressure_get()
, then it generates thesensor_module_event
, which contains the accelerometer and gyroscope data, timestamp andSENSOR_EVT_ENVIRONMENTAL_DATA_READY
event type.The data module receives the
sensor_module_event
from the sensor module and enqueues the IMU data to be sent to nRF Cloud.
The IMU data is being sent to the nRF Cloud in JSON format via MQTT transport:
{
"appId": "TEMP",
"messageType": "DATA",
"ts": 1743807100960,
"data": "34.86"
},
After receiving the message from the device, nRF Cloud converts it into the following JSON structure:
{
"topic": "prod/8ac47cbc-cc7f-43d0-bb92-de294d73db3e/m/d/50343959-3733-44f0-8015-1a1481b18ed5/d2c",
"deviceId": "50343959-3733-44f0-8015-1a1481b18ed5",
"receivedAt": "2025-04-04T22:51:43.823Z",
"message": {
"appId": "TEMP",
"messageType": "DATA",
"ts": 1743807100960,
"data": "34.86"
},
"tenantId": "8ac47cbc-cc7f-43d0-bb92-de294d73db3e"
},
The event and data structures used by the sensor and data modules have the following definitions:
/** @brief Sensor module event. */
struct sensor_module_event {
/** Sensor module application event header. */
struct app_event_header header;
/** Sensor module event type. */
enum sensor_module_event_type type;
union {
/** Variable that contains sensor readings. */
struct sensor_module_data sensors;
/** Variable that contains acceleration data. */
struct sensor_module_accel_data accel;
/** Variable that contains impact data. */
struct sensor_module_impact_data impact;
/** Variable that contains battery level data. */
struct sensor_module_batt_lvl_data bat;
/** Module ID, used when acknowledging shutdown requests. */
uint32_t id;
/** Code signifying the cause of error. */
int err;
} data;
};
/** @brief Structure used to provide environmental data. */
struct sensor_module_data {
/** Uptime when the data was sampled. */
int64_t timestamp;
/** Temperature in Celsius degrees. */
double temperature;
/** Humidity in percentage. */
double humidity;
/** Atmospheric pressure in kilopascal. */
double pressure;
/** BSEC air quality in Indoor-Air-Quality (IAQ) index.
* If -1, the value is not provided.
*/
int bsec_air_quality;
};
struct cloud_data_sensors {
/** Environmental sensors timestamp. UNIX milliseconds. */
int64_t env_ts;
/** Temperature in celcius. */
double temperature;
/** Humidity level in percentage. */
double humidity;
/** Atmospheric pressure in kilopascal. */
double pressure;
/** BSEC Air quality in Indoor-Air-Quality (IAQ) index.
* If -1, the value is not provided.
*/
int bsec_air_quality;
/** Flag signifying that the data entry is to be encoded. */
bool queued : 1;
};
4. Validating Sensor Operations
4.1. Validating LPS22HH Readings and Interrupts:
From the nRF9151 serial console, read the barometer data using the
lps22hh get
command.Observe pressure change data from recent measurement and temperature output on console:
uart:~$ lps22hh get Pressure: 100.741 kPa Temperature: 25.67 C uart:~$ lps22hh get Pressure: 100.748 kPa Temperature: 25.66 C
From the nRF9151 serial console, read the GPIO interrupt counter for P0.05:
uart:~$ gpio_interrupt 0.05 P0.05: 0
Trigger a barometer high pressure event, as follows:
Place the board with the barometer inside a plastic bag.
Insert the pipe from an air can into the bag.
Seal the bag firmly using the scotch tape to prevent any air from escaping.
Trigger the air can to release air into the bag, gradually increasing the pressure inside.
Press on the bag to further increase the pressure surrounding the barometer.
Read the GPIO interrupt counter for P0.05; verify that the number of interrupts has increased by 1:
uart:~$ gpio_interrupt 0.05 P0.05: 1
4.2. Validating Accelerometer Readings and Interrupts:
From the nRF9151 serial console, read the accelerometer data using the
lis2dw12 get
command:Observe accelerometer data output on console:
uart:~$ lis2dw12 get accel x:-0.306281 ms/2 y:0.459421 ms/2 z:9.801001 ms/2 Trigger count: 0
Read the GPIO interrupt counter for P0.7:
uart:~$ gpio_interrupt 0.7 P0.7: 0
Tap on the accelerometer to trigger an accelerometer event.
Read the GPIO interrupt counter for P0.7; verify that the number of interrupts has increased by 1:
uart:~$ gpio_interrupt 1.8 P1.8: 1
Read the GPIO interrupt counter for P0.6:
uart:~$ gpio_interrupt 0.6 P0.6: 0
Re-configure the accelerometer to trigger data-ready events on
INT2
:uart:~$ lis2dw12 init Setting data-ready handler on INT2
Wait 10 seconds.
Read the GPIO interrupt counter for P0.6; verify that the number of interrupts has increased.
uart:~$ gpio_interrupt 0.6 P0.6: 9
Reset the board by long-pressing (a 10+ seconds press) the user push-button.
4.3. Validating LPS22HH Integration with nRF Cloud
Check the board
uuid
from the nRF9151 console (it is assumed that the nRF Device provisioning procedure has been performed earlier):uart:~$ nrf_provisioning uuid 50343959-3733-4c71-806b-202470cee0bf
Check that the board has successfully connected to the cloud over LTE:
[00:00:02.824,615] <inf> app_event_manager: MODEM_EVT_LTE_CONNECTING [00:00:04.110,168] <inf> app_event_manager: MODEM_EVT_LTE_CELL_UPDATE [00:00:15.095,916] <inf> app_event_manager: MODEM_EVT_LTE_CONNECTED [00:00:15.234,283] <inf> cloud_module: DEVICE CERTIFICATE IS PRESENT [00:00:15.236,907] <inf> app_event_manager: CLOUD_EVT_CONNECTING [00:00:15.237,426] <inf> app_event_manager: MODEM_EVT_LTE_PSM_UPDATE [00:00:15.237,915] <inf> app_event_manager: DATA_EVT_DATE_TIME_OBTAINED [00:00:22.080,871] <inf> net_mqtt: Connect completed
Login to the nRF Cloud and go to the DEVICE MANAGEMENT / Devices page. Find the board by the
uuid
ID and open the board page.Click the Manage Cards button and check the Device Data checkbox so that the Device Data card is displayed on the board page.
In the Device Data card, check the Last connected attribute to make sure that the board has recently connected to the cloud.
Wait 110 seconds for the device data to be updated on the cloud. The default timeout of 110 seconds can be reduced for convenience: click the View Config button, then Edit Configuration. If activeMode is false then the timeout is no greater than movementResolution, otherwise, it is no greater than activeWaitTime.
From the nRF9151 console, confirm that the device data have been sent to the cloud:
[00:02:16.997,283] <inf> app_event_manager: DATA_EVT_DATA_READY [00:02:17.002,197] <inf> app_event_manager: DATA_EVT_DATA_SEND_BATCH [00:02:17.002,868] <inf> app_event_manager: CLOUD_EVT_DATA_SEND_QOS
In the Device Data card on the nRF Cloud, verify that the Temperature and Air Pressure attributes has just been updated and has a proper value:
Click the Show Temperature card icon to see the graphical representation of the temperature values on the time scale:
Click the View historical data icon and select appropriate time interval to see the temperature history:
Click the Show Air Pressure card icon to see the graphical representation of the air pressure values on the time scale:
Click the View historical data icon and select appropriate time interval to see the air pressure history:
4.4. Validating Accelerometer Integration with nRF Cloud
Login to the nRF Cloud and go to the DEVICE MANAGEMENT / Devices page. Find the board by the
uuid
ID and open the board page.Press the “View Config” button.
Press “Edit configuration” in “Device Configuration” window opened:
Change the "accThreshAct" and “accThreshInAct” parameters to 1:
Press the “Commit” button.
Wait for the board to connect to the cloud and download new configuration. Note that this process may take up to 5 minutes, since the Asset Tracker by default is configured to connect to the cloud once in 300 seconds. The “Reported” field will update when the board applies the new configuration.
Verify updated sensors data arrived on nRF9151 console:
[00:00:16.598,602] <inf> app_event_manager: CLOUD_EVT_CONFIG_RECEIVED ... [00:00:16.604,461] <inf> sensor_module: Received sensors configuration data
Shake the board.
Observe the activity detected message on nRF5340 console:
[00:02:36.250,457] <inf> ext_sensors: Activity detected
Observe the activity detected message on nRF9151 console:
[00:02:42.888,946] <inf> app_event_manager: SENSOR_EVT_MOVEMENT_ACTIVITY_DETECTED